From 0069bbc05c3065be4827de8a5b499ff151bee1ca Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:58:13 -0400 Subject: [PATCH 01/52] multiwallet fixes --- .../OpenBazaar/multiwallet/api/pb/api.pb.go | 2602 +++++++++++++++++ .../OpenBazaar/multiwallet/api/pb/api.proto | 209 ++ .../OpenBazaar/multiwallet/api/rpc.go | 281 ++ .../OpenBazaar/multiwallet/bitcoin/sign.go | 17 +- .../OpenBazaar/multiwallet/bitcoin/wallet.go | 14 +- .../multiwallet/bitcoincash/sign.go | 17 +- .../multiwallet/bitcoincash/sign_test.go | 732 +++++ .../multiwallet/bitcoincash/wallet.go | 6 +- .../OpenBazaar/multiwallet/cli/cli.go | 323 ++ .../multiwallet/client/blockbook/client.go | 16 + .../multiwallet/client/pool_test.go | 254 ++ .../multiwallet/cmd/multiwallet/main.go | 83 + .../OpenBazaar/multiwallet/coverage.out | 2065 +++++++++++++ .../OpenBazaar/multiwallet/datastore/mock.go | 19 +- .../OpenBazaar/multiwallet/filecoin/addr.go | 56 + .../multiwallet/filecoin/service.go | 318 ++ .../OpenBazaar/multiwallet/filecoin/wallet.go | 458 +++ .../github.com/OpenBazaar/multiwallet/go.mod | 45 + .../github.com/OpenBazaar/multiwallet/go.sum | 1880 ++++++++++++ .../OpenBazaar/multiwallet/litecoin/sign.go | 17 +- .../OpenBazaar/multiwallet/litecoin/wallet.go | 6 +- .../multiwallet/model/mock/interfaces.go | 188 ++ .../multiwallet/model/mock/models.go | 283 ++ .../OpenBazaar/multiwallet/multiwallet.go | 11 + .../multiwallet/service/wallet_service.go | 14 +- .../multiwallet/test/factory/transaction.go | 50 + .../OpenBazaar/multiwallet/test/helper.go | 85 + .../OpenBazaar/multiwallet/util/balance.go | 5 + .../multiwallet/util/bitconprices.go | 239 ++ .../OpenBazaar/multiwallet/util/fees.go | 8 +- .../OpenBazaar/multiwallet/util/locktime.go | 33 + .../OpenBazaar/multiwallet/zcash/sign.go | 13 +- .../OpenBazaar/multiwallet/zcash/wallet.go | 6 +- 33 files changed, 10284 insertions(+), 69 deletions(-) create mode 100644 vendor/github.com/OpenBazaar/multiwallet/api/pb/api.pb.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/api/pb/api.proto create mode 100644 vendor/github.com/OpenBazaar/multiwallet/api/rpc.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign_test.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/cli/cli.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/client/pool_test.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/cmd/multiwallet/main.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/coverage.out create mode 100644 vendor/github.com/OpenBazaar/multiwallet/filecoin/addr.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/go.mod create mode 100644 vendor/github.com/OpenBazaar/multiwallet/go.sum create mode 100644 vendor/github.com/OpenBazaar/multiwallet/model/mock/interfaces.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/model/mock/models.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/test/factory/transaction.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/test/helper.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/util/bitconprices.go create mode 100644 vendor/github.com/OpenBazaar/multiwallet/util/locktime.go diff --git a/vendor/github.com/OpenBazaar/multiwallet/api/pb/api.pb.go b/vendor/github.com/OpenBazaar/multiwallet/api/pb/api.pb.go new file mode 100644 index 0000000000..c903b33f60 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/api/pb/api.pb.go @@ -0,0 +1,2602 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: api.proto + +package pb + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type CoinType int32 + +const ( + CoinType_BITCOIN CoinType = 0 + CoinType_BITCOIN_CASH CoinType = 1 + CoinType_ZCASH CoinType = 2 + CoinType_LITECOIN CoinType = 3 + CoinType_ETHEREUM CoinType = 4 +) + +var CoinType_name = map[int32]string{ + 0: "BITCOIN", + 1: "BITCOIN_CASH", + 2: "ZCASH", + 3: "LITECOIN", + 4: "ETHEREUM", +} +var CoinType_value = map[string]int32{ + "BITCOIN": 0, + "BITCOIN_CASH": 1, + "ZCASH": 2, + "LITECOIN": 3, + "ETHEREUM": 4, +} + +func (x CoinType) String() string { + return proto.EnumName(CoinType_name, int32(x)) +} +func (CoinType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{0} +} + +type KeyPurpose int32 + +const ( + KeyPurpose_INTERNAL KeyPurpose = 0 + KeyPurpose_EXTERNAL KeyPurpose = 1 +) + +var KeyPurpose_name = map[int32]string{ + 0: "INTERNAL", + 1: "EXTERNAL", +} +var KeyPurpose_value = map[string]int32{ + "INTERNAL": 0, + "EXTERNAL": 1, +} + +func (x KeyPurpose) String() string { + return proto.EnumName(KeyPurpose_name, int32(x)) +} +func (KeyPurpose) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{1} +} + +type FeeLevel int32 + +const ( + FeeLevel_ECONOMIC FeeLevel = 0 + FeeLevel_NORMAL FeeLevel = 1 + FeeLevel_PRIORITY FeeLevel = 2 +) + +var FeeLevel_name = map[int32]string{ + 0: "ECONOMIC", + 1: "NORMAL", + 2: "PRIORITY", +} +var FeeLevel_value = map[string]int32{ + "ECONOMIC": 0, + "NORMAL": 1, + "PRIORITY": 2, +} + +func (x FeeLevel) String() string { + return proto.EnumName(FeeLevel_name, int32(x)) +} +func (FeeLevel) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{2} +} + +type Empty struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{0} +} +func (m *Empty) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Empty.Unmarshal(m, b) +} +func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Empty.Marshal(b, m, deterministic) +} +func (dst *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(dst, src) +} +func (m *Empty) XXX_Size() int { + return xxx_messageInfo_Empty.Size(m) +} +func (m *Empty) XXX_DiscardUnknown() { + xxx_messageInfo_Empty.DiscardUnknown(m) +} + +var xxx_messageInfo_Empty proto.InternalMessageInfo + +type CoinSelection struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CoinSelection) Reset() { *m = CoinSelection{} } +func (m *CoinSelection) String() string { return proto.CompactTextString(m) } +func (*CoinSelection) ProtoMessage() {} +func (*CoinSelection) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{1} +} +func (m *CoinSelection) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CoinSelection.Unmarshal(m, b) +} +func (m *CoinSelection) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CoinSelection.Marshal(b, m, deterministic) +} +func (dst *CoinSelection) XXX_Merge(src proto.Message) { + xxx_messageInfo_CoinSelection.Merge(dst, src) +} +func (m *CoinSelection) XXX_Size() int { + return xxx_messageInfo_CoinSelection.Size(m) +} +func (m *CoinSelection) XXX_DiscardUnknown() { + xxx_messageInfo_CoinSelection.DiscardUnknown(m) +} + +var xxx_messageInfo_CoinSelection proto.InternalMessageInfo + +func (m *CoinSelection) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +type Row struct { + Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Row) Reset() { *m = Row{} } +func (m *Row) String() string { return proto.CompactTextString(m) } +func (*Row) ProtoMessage() {} +func (*Row) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{2} +} +func (m *Row) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Row.Unmarshal(m, b) +} +func (m *Row) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Row.Marshal(b, m, deterministic) +} +func (dst *Row) XXX_Merge(src proto.Message) { + xxx_messageInfo_Row.Merge(dst, src) +} +func (m *Row) XXX_Size() int { + return xxx_messageInfo_Row.Size(m) +} +func (m *Row) XXX_DiscardUnknown() { + xxx_messageInfo_Row.DiscardUnknown(m) +} + +var xxx_messageInfo_Row proto.InternalMessageInfo + +func (m *Row) GetData() string { + if m != nil { + return m.Data + } + return "" +} + +type KeySelection struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Purpose KeyPurpose `protobuf:"varint,2,opt,name=purpose,proto3,enum=pb.KeyPurpose" json:"purpose,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *KeySelection) Reset() { *m = KeySelection{} } +func (m *KeySelection) String() string { return proto.CompactTextString(m) } +func (*KeySelection) ProtoMessage() {} +func (*KeySelection) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{3} +} +func (m *KeySelection) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_KeySelection.Unmarshal(m, b) +} +func (m *KeySelection) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_KeySelection.Marshal(b, m, deterministic) +} +func (dst *KeySelection) XXX_Merge(src proto.Message) { + xxx_messageInfo_KeySelection.Merge(dst, src) +} +func (m *KeySelection) XXX_Size() int { + return xxx_messageInfo_KeySelection.Size(m) +} +func (m *KeySelection) XXX_DiscardUnknown() { + xxx_messageInfo_KeySelection.DiscardUnknown(m) +} + +var xxx_messageInfo_KeySelection proto.InternalMessageInfo + +func (m *KeySelection) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *KeySelection) GetPurpose() KeyPurpose { + if m != nil { + return m.Purpose + } + return KeyPurpose_INTERNAL +} + +type Address struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Address) Reset() { *m = Address{} } +func (m *Address) String() string { return proto.CompactTextString(m) } +func (*Address) ProtoMessage() {} +func (*Address) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{4} +} +func (m *Address) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Address.Unmarshal(m, b) +} +func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Address.Marshal(b, m, deterministic) +} +func (dst *Address) XXX_Merge(src proto.Message) { + xxx_messageInfo_Address.Merge(dst, src) +} +func (m *Address) XXX_Size() int { + return xxx_messageInfo_Address.Size(m) +} +func (m *Address) XXX_DiscardUnknown() { + xxx_messageInfo_Address.DiscardUnknown(m) +} + +var xxx_messageInfo_Address proto.InternalMessageInfo + +func (m *Address) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *Address) GetAddr() string { + if m != nil { + return m.Addr + } + return "" +} + +type Height struct { + Height uint32 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Height) Reset() { *m = Height{} } +func (m *Height) String() string { return proto.CompactTextString(m) } +func (*Height) ProtoMessage() {} +func (*Height) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{5} +} +func (m *Height) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Height.Unmarshal(m, b) +} +func (m *Height) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Height.Marshal(b, m, deterministic) +} +func (dst *Height) XXX_Merge(src proto.Message) { + xxx_messageInfo_Height.Merge(dst, src) +} +func (m *Height) XXX_Size() int { + return xxx_messageInfo_Height.Size(m) +} +func (m *Height) XXX_DiscardUnknown() { + xxx_messageInfo_Height.DiscardUnknown(m) +} + +var xxx_messageInfo_Height proto.InternalMessageInfo + +func (m *Height) GetHeight() uint32 { + if m != nil { + return m.Height + } + return 0 +} + +type Balances struct { + Confirmed uint64 `protobuf:"varint,1,opt,name=confirmed,proto3" json:"confirmed,omitempty"` + Unconfirmed uint64 `protobuf:"varint,2,opt,name=unconfirmed,proto3" json:"unconfirmed,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Balances) Reset() { *m = Balances{} } +func (m *Balances) String() string { return proto.CompactTextString(m) } +func (*Balances) ProtoMessage() {} +func (*Balances) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{6} +} +func (m *Balances) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Balances.Unmarshal(m, b) +} +func (m *Balances) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Balances.Marshal(b, m, deterministic) +} +func (dst *Balances) XXX_Merge(src proto.Message) { + xxx_messageInfo_Balances.Merge(dst, src) +} +func (m *Balances) XXX_Size() int { + return xxx_messageInfo_Balances.Size(m) +} +func (m *Balances) XXX_DiscardUnknown() { + xxx_messageInfo_Balances.DiscardUnknown(m) +} + +var xxx_messageInfo_Balances proto.InternalMessageInfo + +func (m *Balances) GetConfirmed() uint64 { + if m != nil { + return m.Confirmed + } + return 0 +} + +func (m *Balances) GetUnconfirmed() uint64 { + if m != nil { + return m.Unconfirmed + } + return 0 +} + +type Key struct { + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Key) Reset() { *m = Key{} } +func (m *Key) String() string { return proto.CompactTextString(m) } +func (*Key) ProtoMessage() {} +func (*Key) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{7} +} +func (m *Key) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Key.Unmarshal(m, b) +} +func (m *Key) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Key.Marshal(b, m, deterministic) +} +func (dst *Key) XXX_Merge(src proto.Message) { + xxx_messageInfo_Key.Merge(dst, src) +} +func (m *Key) XXX_Size() int { + return xxx_messageInfo_Key.Size(m) +} +func (m *Key) XXX_DiscardUnknown() { + xxx_messageInfo_Key.DiscardUnknown(m) +} + +var xxx_messageInfo_Key proto.InternalMessageInfo + +func (m *Key) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +type Keys struct { + Keys []*Key `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Keys) Reset() { *m = Keys{} } +func (m *Keys) String() string { return proto.CompactTextString(m) } +func (*Keys) ProtoMessage() {} +func (*Keys) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{8} +} +func (m *Keys) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Keys.Unmarshal(m, b) +} +func (m *Keys) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Keys.Marshal(b, m, deterministic) +} +func (dst *Keys) XXX_Merge(src proto.Message) { + xxx_messageInfo_Keys.Merge(dst, src) +} +func (m *Keys) XXX_Size() int { + return xxx_messageInfo_Keys.Size(m) +} +func (m *Keys) XXX_DiscardUnknown() { + xxx_messageInfo_Keys.DiscardUnknown(m) +} + +var xxx_messageInfo_Keys proto.InternalMessageInfo + +func (m *Keys) GetKeys() []*Key { + if m != nil { + return m.Keys + } + return nil +} + +type Addresses struct { + Addresses []*Address `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Addresses) Reset() { *m = Addresses{} } +func (m *Addresses) String() string { return proto.CompactTextString(m) } +func (*Addresses) ProtoMessage() {} +func (*Addresses) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{9} +} +func (m *Addresses) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Addresses.Unmarshal(m, b) +} +func (m *Addresses) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Addresses.Marshal(b, m, deterministic) +} +func (dst *Addresses) XXX_Merge(src proto.Message) { + xxx_messageInfo_Addresses.Merge(dst, src) +} +func (m *Addresses) XXX_Size() int { + return xxx_messageInfo_Addresses.Size(m) +} +func (m *Addresses) XXX_DiscardUnknown() { + xxx_messageInfo_Addresses.DiscardUnknown(m) +} + +var xxx_messageInfo_Addresses proto.InternalMessageInfo + +func (m *Addresses) GetAddresses() []*Address { + if m != nil { + return m.Addresses + } + return nil +} + +type BoolResponse struct { + Bool bool `protobuf:"varint,1,opt,name=bool,proto3" json:"bool,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BoolResponse) Reset() { *m = BoolResponse{} } +func (m *BoolResponse) String() string { return proto.CompactTextString(m) } +func (*BoolResponse) ProtoMessage() {} +func (*BoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{10} +} +func (m *BoolResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BoolResponse.Unmarshal(m, b) +} +func (m *BoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BoolResponse.Marshal(b, m, deterministic) +} +func (dst *BoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_BoolResponse.Merge(dst, src) +} +func (m *BoolResponse) XXX_Size() int { + return xxx_messageInfo_BoolResponse.Size(m) +} +func (m *BoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_BoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_BoolResponse proto.InternalMessageInfo + +func (m *BoolResponse) GetBool() bool { + if m != nil { + return m.Bool + } + return false +} + +type NetParams struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NetParams) Reset() { *m = NetParams{} } +func (m *NetParams) String() string { return proto.CompactTextString(m) } +func (*NetParams) ProtoMessage() {} +func (*NetParams) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{11} +} +func (m *NetParams) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NetParams.Unmarshal(m, b) +} +func (m *NetParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NetParams.Marshal(b, m, deterministic) +} +func (dst *NetParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_NetParams.Merge(dst, src) +} +func (m *NetParams) XXX_Size() int { + return xxx_messageInfo_NetParams.Size(m) +} +func (m *NetParams) XXX_DiscardUnknown() { + xxx_messageInfo_NetParams.DiscardUnknown(m) +} + +var xxx_messageInfo_NetParams proto.InternalMessageInfo + +func (m *NetParams) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type TransactionList struct { + Transactions []*Tx `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TransactionList) Reset() { *m = TransactionList{} } +func (m *TransactionList) String() string { return proto.CompactTextString(m) } +func (*TransactionList) ProtoMessage() {} +func (*TransactionList) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{12} +} +func (m *TransactionList) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TransactionList.Unmarshal(m, b) +} +func (m *TransactionList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TransactionList.Marshal(b, m, deterministic) +} +func (dst *TransactionList) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransactionList.Merge(dst, src) +} +func (m *TransactionList) XXX_Size() int { + return xxx_messageInfo_TransactionList.Size(m) +} +func (m *TransactionList) XXX_DiscardUnknown() { + xxx_messageInfo_TransactionList.DiscardUnknown(m) +} + +var xxx_messageInfo_TransactionList proto.InternalMessageInfo + +func (m *TransactionList) GetTransactions() []*Tx { + if m != nil { + return m.Transactions + } + return nil +} + +type Tx struct { + Txid string `protobuf:"bytes,1,opt,name=txid,proto3" json:"txid,omitempty"` + Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` + Height int32 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` + Timestamp *timestamp.Timestamp `protobuf:"bytes,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + WatchOnly bool `protobuf:"varint,5,opt,name=watchOnly,proto3" json:"watchOnly,omitempty"` + Raw []byte `protobuf:"bytes,6,opt,name=raw,proto3" json:"raw,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Tx) Reset() { *m = Tx{} } +func (m *Tx) String() string { return proto.CompactTextString(m) } +func (*Tx) ProtoMessage() {} +func (*Tx) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{13} +} +func (m *Tx) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Tx.Unmarshal(m, b) +} +func (m *Tx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Tx.Marshal(b, m, deterministic) +} +func (dst *Tx) XXX_Merge(src proto.Message) { + xxx_messageInfo_Tx.Merge(dst, src) +} +func (m *Tx) XXX_Size() int { + return xxx_messageInfo_Tx.Size(m) +} +func (m *Tx) XXX_DiscardUnknown() { + xxx_messageInfo_Tx.DiscardUnknown(m) +} + +var xxx_messageInfo_Tx proto.InternalMessageInfo + +func (m *Tx) GetTxid() string { + if m != nil { + return m.Txid + } + return "" +} + +func (m *Tx) GetValue() int64 { + if m != nil { + return m.Value + } + return 0 +} + +func (m *Tx) GetHeight() int32 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *Tx) GetTimestamp() *timestamp.Timestamp { + if m != nil { + return m.Timestamp + } + return nil +} + +func (m *Tx) GetWatchOnly() bool { + if m != nil { + return m.WatchOnly + } + return false +} + +func (m *Tx) GetRaw() []byte { + if m != nil { + return m.Raw + } + return nil +} + +type Txid struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Txid) Reset() { *m = Txid{} } +func (m *Txid) String() string { return proto.CompactTextString(m) } +func (*Txid) ProtoMessage() {} +func (*Txid) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{14} +} +func (m *Txid) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Txid.Unmarshal(m, b) +} +func (m *Txid) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Txid.Marshal(b, m, deterministic) +} +func (dst *Txid) XXX_Merge(src proto.Message) { + xxx_messageInfo_Txid.Merge(dst, src) +} +func (m *Txid) XXX_Size() int { + return xxx_messageInfo_Txid.Size(m) +} +func (m *Txid) XXX_DiscardUnknown() { + xxx_messageInfo_Txid.DiscardUnknown(m) +} + +var xxx_messageInfo_Txid proto.InternalMessageInfo + +func (m *Txid) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *Txid) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + +type FeeLevelSelection struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + FeeLevel FeeLevel `protobuf:"varint,2,opt,name=feeLevel,proto3,enum=pb.FeeLevel" json:"feeLevel,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FeeLevelSelection) Reset() { *m = FeeLevelSelection{} } +func (m *FeeLevelSelection) String() string { return proto.CompactTextString(m) } +func (*FeeLevelSelection) ProtoMessage() {} +func (*FeeLevelSelection) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{15} +} +func (m *FeeLevelSelection) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FeeLevelSelection.Unmarshal(m, b) +} +func (m *FeeLevelSelection) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FeeLevelSelection.Marshal(b, m, deterministic) +} +func (dst *FeeLevelSelection) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeeLevelSelection.Merge(dst, src) +} +func (m *FeeLevelSelection) XXX_Size() int { + return xxx_messageInfo_FeeLevelSelection.Size(m) +} +func (m *FeeLevelSelection) XXX_DiscardUnknown() { + xxx_messageInfo_FeeLevelSelection.DiscardUnknown(m) +} + +var xxx_messageInfo_FeeLevelSelection proto.InternalMessageInfo + +func (m *FeeLevelSelection) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *FeeLevelSelection) GetFeeLevel() FeeLevel { + if m != nil { + return m.FeeLevel + } + return FeeLevel_ECONOMIC +} + +type FeePerByte struct { + Fee uint64 `protobuf:"varint,1,opt,name=fee,proto3" json:"fee,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FeePerByte) Reset() { *m = FeePerByte{} } +func (m *FeePerByte) String() string { return proto.CompactTextString(m) } +func (*FeePerByte) ProtoMessage() {} +func (*FeePerByte) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{16} +} +func (m *FeePerByte) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FeePerByte.Unmarshal(m, b) +} +func (m *FeePerByte) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FeePerByte.Marshal(b, m, deterministic) +} +func (dst *FeePerByte) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeePerByte.Merge(dst, src) +} +func (m *FeePerByte) XXX_Size() int { + return xxx_messageInfo_FeePerByte.Size(m) +} +func (m *FeePerByte) XXX_DiscardUnknown() { + xxx_messageInfo_FeePerByte.DiscardUnknown(m) +} + +var xxx_messageInfo_FeePerByte proto.InternalMessageInfo + +func (m *FeePerByte) GetFee() uint64 { + if m != nil { + return m.Fee + } + return 0 +} + +type Fee struct { + Fee uint64 `protobuf:"varint,1,opt,name=fee,proto3" json:"fee,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Fee) Reset() { *m = Fee{} } +func (m *Fee) String() string { return proto.CompactTextString(m) } +func (*Fee) ProtoMessage() {} +func (*Fee) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{17} +} +func (m *Fee) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Fee.Unmarshal(m, b) +} +func (m *Fee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Fee.Marshal(b, m, deterministic) +} +func (dst *Fee) XXX_Merge(src proto.Message) { + xxx_messageInfo_Fee.Merge(dst, src) +} +func (m *Fee) XXX_Size() int { + return xxx_messageInfo_Fee.Size(m) +} +func (m *Fee) XXX_DiscardUnknown() { + xxx_messageInfo_Fee.DiscardUnknown(m) +} + +var xxx_messageInfo_Fee proto.InternalMessageInfo + +func (m *Fee) GetFee() uint64 { + if m != nil { + return m.Fee + } + return 0 +} + +type SpendInfo struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + Amount uint64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` + FeeLevel FeeLevel `protobuf:"varint,4,opt,name=feeLevel,proto3,enum=pb.FeeLevel" json:"feeLevel,omitempty"` + Memo string `protobuf:"bytes,5,opt,name=memo,proto3" json:"memo,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SpendInfo) Reset() { *m = SpendInfo{} } +func (m *SpendInfo) String() string { return proto.CompactTextString(m) } +func (*SpendInfo) ProtoMessage() {} +func (*SpendInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{18} +} +func (m *SpendInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SpendInfo.Unmarshal(m, b) +} +func (m *SpendInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SpendInfo.Marshal(b, m, deterministic) +} +func (dst *SpendInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_SpendInfo.Merge(dst, src) +} +func (m *SpendInfo) XXX_Size() int { + return xxx_messageInfo_SpendInfo.Size(m) +} +func (m *SpendInfo) XXX_DiscardUnknown() { + xxx_messageInfo_SpendInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_SpendInfo proto.InternalMessageInfo + +func (m *SpendInfo) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *SpendInfo) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *SpendInfo) GetAmount() uint64 { + if m != nil { + return m.Amount + } + return 0 +} + +func (m *SpendInfo) GetFeeLevel() FeeLevel { + if m != nil { + return m.FeeLevel + } + return FeeLevel_ECONOMIC +} + +func (m *SpendInfo) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + +type Confirmations struct { + Confirmations uint32 `protobuf:"varint,1,opt,name=confirmations,proto3" json:"confirmations,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Confirmations) Reset() { *m = Confirmations{} } +func (m *Confirmations) String() string { return proto.CompactTextString(m) } +func (*Confirmations) ProtoMessage() {} +func (*Confirmations) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{19} +} +func (m *Confirmations) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Confirmations.Unmarshal(m, b) +} +func (m *Confirmations) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Confirmations.Marshal(b, m, deterministic) +} +func (dst *Confirmations) XXX_Merge(src proto.Message) { + xxx_messageInfo_Confirmations.Merge(dst, src) +} +func (m *Confirmations) XXX_Size() int { + return xxx_messageInfo_Confirmations.Size(m) +} +func (m *Confirmations) XXX_DiscardUnknown() { + xxx_messageInfo_Confirmations.DiscardUnknown(m) +} + +var xxx_messageInfo_Confirmations proto.InternalMessageInfo + +func (m *Confirmations) GetConfirmations() uint32 { + if m != nil { + return m.Confirmations + } + return 0 +} + +type Utxo struct { + Txid string `protobuf:"bytes,1,opt,name=txid,proto3" json:"txid,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + Value uint64 `protobuf:"varint,3,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Utxo) Reset() { *m = Utxo{} } +func (m *Utxo) String() string { return proto.CompactTextString(m) } +func (*Utxo) ProtoMessage() {} +func (*Utxo) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{20} +} +func (m *Utxo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Utxo.Unmarshal(m, b) +} +func (m *Utxo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Utxo.Marshal(b, m, deterministic) +} +func (dst *Utxo) XXX_Merge(src proto.Message) { + xxx_messageInfo_Utxo.Merge(dst, src) +} +func (m *Utxo) XXX_Size() int { + return xxx_messageInfo_Utxo.Size(m) +} +func (m *Utxo) XXX_DiscardUnknown() { + xxx_messageInfo_Utxo.DiscardUnknown(m) +} + +var xxx_messageInfo_Utxo proto.InternalMessageInfo + +func (m *Utxo) GetTxid() string { + if m != nil { + return m.Txid + } + return "" +} + +func (m *Utxo) GetIndex() uint32 { + if m != nil { + return m.Index + } + return 0 +} + +func (m *Utxo) GetValue() uint64 { + if m != nil { + return m.Value + } + return 0 +} + +type SweepInfo struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Utxos []*Utxo `protobuf:"bytes,2,rep,name=utxos,proto3" json:"utxos,omitempty"` + Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"` + RedeemScript []byte `protobuf:"bytes,5,opt,name=redeemScript,proto3" json:"redeemScript,omitempty"` + FeeLevel FeeLevel `protobuf:"varint,6,opt,name=feeLevel,proto3,enum=pb.FeeLevel" json:"feeLevel,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SweepInfo) Reset() { *m = SweepInfo{} } +func (m *SweepInfo) String() string { return proto.CompactTextString(m) } +func (*SweepInfo) ProtoMessage() {} +func (*SweepInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{21} +} +func (m *SweepInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SweepInfo.Unmarshal(m, b) +} +func (m *SweepInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SweepInfo.Marshal(b, m, deterministic) +} +func (dst *SweepInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_SweepInfo.Merge(dst, src) +} +func (m *SweepInfo) XXX_Size() int { + return xxx_messageInfo_SweepInfo.Size(m) +} +func (m *SweepInfo) XXX_DiscardUnknown() { + xxx_messageInfo_SweepInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_SweepInfo proto.InternalMessageInfo + +func (m *SweepInfo) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *SweepInfo) GetUtxos() []*Utxo { + if m != nil { + return m.Utxos + } + return nil +} + +func (m *SweepInfo) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *SweepInfo) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *SweepInfo) GetRedeemScript() []byte { + if m != nil { + return m.RedeemScript + } + return nil +} + +func (m *SweepInfo) GetFeeLevel() FeeLevel { + if m != nil { + return m.FeeLevel + } + return FeeLevel_ECONOMIC +} + +type Input struct { + Txid string `protobuf:"bytes,1,opt,name=txid,proto3" json:"txid,omitempty"` + Index uint32 `protobuf:"varint,2,opt,name=index,proto3" json:"index,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Input) Reset() { *m = Input{} } +func (m *Input) String() string { return proto.CompactTextString(m) } +func (*Input) ProtoMessage() {} +func (*Input) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{22} +} +func (m *Input) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Input.Unmarshal(m, b) +} +func (m *Input) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Input.Marshal(b, m, deterministic) +} +func (dst *Input) XXX_Merge(src proto.Message) { + xxx_messageInfo_Input.Merge(dst, src) +} +func (m *Input) XXX_Size() int { + return xxx_messageInfo_Input.Size(m) +} +func (m *Input) XXX_DiscardUnknown() { + xxx_messageInfo_Input.DiscardUnknown(m) +} + +var xxx_messageInfo_Input proto.InternalMessageInfo + +func (m *Input) GetTxid() string { + if m != nil { + return m.Txid + } + return "" +} + +func (m *Input) GetIndex() uint32 { + if m != nil { + return m.Index + } + return 0 +} + +type Output struct { + ScriptPubKey []byte `protobuf:"bytes,1,opt,name=scriptPubKey,proto3" json:"scriptPubKey,omitempty"` + Value uint64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Output) Reset() { *m = Output{} } +func (m *Output) String() string { return proto.CompactTextString(m) } +func (*Output) ProtoMessage() {} +func (*Output) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{23} +} +func (m *Output) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Output.Unmarshal(m, b) +} +func (m *Output) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Output.Marshal(b, m, deterministic) +} +func (dst *Output) XXX_Merge(src proto.Message) { + xxx_messageInfo_Output.Merge(dst, src) +} +func (m *Output) XXX_Size() int { + return xxx_messageInfo_Output.Size(m) +} +func (m *Output) XXX_DiscardUnknown() { + xxx_messageInfo_Output.DiscardUnknown(m) +} + +var xxx_messageInfo_Output proto.InternalMessageInfo + +func (m *Output) GetScriptPubKey() []byte { + if m != nil { + return m.ScriptPubKey + } + return nil +} + +func (m *Output) GetValue() uint64 { + if m != nil { + return m.Value + } + return 0 +} + +type Signature struct { + Index uint32 `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Signature) Reset() { *m = Signature{} } +func (m *Signature) String() string { return proto.CompactTextString(m) } +func (*Signature) ProtoMessage() {} +func (*Signature) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{24} +} +func (m *Signature) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Signature.Unmarshal(m, b) +} +func (m *Signature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Signature.Marshal(b, m, deterministic) +} +func (dst *Signature) XXX_Merge(src proto.Message) { + xxx_messageInfo_Signature.Merge(dst, src) +} +func (m *Signature) XXX_Size() int { + return xxx_messageInfo_Signature.Size(m) +} +func (m *Signature) XXX_DiscardUnknown() { + xxx_messageInfo_Signature.DiscardUnknown(m) +} + +var xxx_messageInfo_Signature proto.InternalMessageInfo + +func (m *Signature) GetIndex() uint32 { + if m != nil { + return m.Index + } + return 0 +} + +func (m *Signature) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +type CreateMultisigInfo struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Inputs []*Input `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` + Outputs []*Output `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` + Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"` + RedeemScript []byte `protobuf:"bytes,5,opt,name=redeemScript,proto3" json:"redeemScript,omitempty"` + FeePerByte uint64 `protobuf:"varint,6,opt,name=feePerByte,proto3" json:"feePerByte,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateMultisigInfo) Reset() { *m = CreateMultisigInfo{} } +func (m *CreateMultisigInfo) String() string { return proto.CompactTextString(m) } +func (*CreateMultisigInfo) ProtoMessage() {} +func (*CreateMultisigInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{25} +} +func (m *CreateMultisigInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateMultisigInfo.Unmarshal(m, b) +} +func (m *CreateMultisigInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateMultisigInfo.Marshal(b, m, deterministic) +} +func (dst *CreateMultisigInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateMultisigInfo.Merge(dst, src) +} +func (m *CreateMultisigInfo) XXX_Size() int { + return xxx_messageInfo_CreateMultisigInfo.Size(m) +} +func (m *CreateMultisigInfo) XXX_DiscardUnknown() { + xxx_messageInfo_CreateMultisigInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateMultisigInfo proto.InternalMessageInfo + +func (m *CreateMultisigInfo) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *CreateMultisigInfo) GetInputs() []*Input { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *CreateMultisigInfo) GetOutputs() []*Output { + if m != nil { + return m.Outputs + } + return nil +} + +func (m *CreateMultisigInfo) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *CreateMultisigInfo) GetRedeemScript() []byte { + if m != nil { + return m.RedeemScript + } + return nil +} + +func (m *CreateMultisigInfo) GetFeePerByte() uint64 { + if m != nil { + return m.FeePerByte + } + return 0 +} + +type SignatureList struct { + Sigs []*Signature `protobuf:"bytes,1,rep,name=sigs,proto3" json:"sigs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SignatureList) Reset() { *m = SignatureList{} } +func (m *SignatureList) String() string { return proto.CompactTextString(m) } +func (*SignatureList) ProtoMessage() {} +func (*SignatureList) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{26} +} +func (m *SignatureList) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SignatureList.Unmarshal(m, b) +} +func (m *SignatureList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SignatureList.Marshal(b, m, deterministic) +} +func (dst *SignatureList) XXX_Merge(src proto.Message) { + xxx_messageInfo_SignatureList.Merge(dst, src) +} +func (m *SignatureList) XXX_Size() int { + return xxx_messageInfo_SignatureList.Size(m) +} +func (m *SignatureList) XXX_DiscardUnknown() { + xxx_messageInfo_SignatureList.DiscardUnknown(m) +} + +var xxx_messageInfo_SignatureList proto.InternalMessageInfo + +func (m *SignatureList) GetSigs() []*Signature { + if m != nil { + return m.Sigs + } + return nil +} + +type MultisignInfo struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Inputs []*Input `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` + Outputs []*Output `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` + Sig1 []*Signature `protobuf:"bytes,4,rep,name=sig1,proto3" json:"sig1,omitempty"` + Sig2 []*Signature `protobuf:"bytes,5,rep,name=sig2,proto3" json:"sig2,omitempty"` + RedeemScript []byte `protobuf:"bytes,6,opt,name=redeemScript,proto3" json:"redeemScript,omitempty"` + FeePerByte uint64 `protobuf:"varint,7,opt,name=feePerByte,proto3" json:"feePerByte,omitempty"` + Broadcast bool `protobuf:"varint,8,opt,name=broadcast,proto3" json:"broadcast,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MultisignInfo) Reset() { *m = MultisignInfo{} } +func (m *MultisignInfo) String() string { return proto.CompactTextString(m) } +func (*MultisignInfo) ProtoMessage() {} +func (*MultisignInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{27} +} +func (m *MultisignInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MultisignInfo.Unmarshal(m, b) +} +func (m *MultisignInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MultisignInfo.Marshal(b, m, deterministic) +} +func (dst *MultisignInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_MultisignInfo.Merge(dst, src) +} +func (m *MultisignInfo) XXX_Size() int { + return xxx_messageInfo_MultisignInfo.Size(m) +} +func (m *MultisignInfo) XXX_DiscardUnknown() { + xxx_messageInfo_MultisignInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_MultisignInfo proto.InternalMessageInfo + +func (m *MultisignInfo) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *MultisignInfo) GetInputs() []*Input { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *MultisignInfo) GetOutputs() []*Output { + if m != nil { + return m.Outputs + } + return nil +} + +func (m *MultisignInfo) GetSig1() []*Signature { + if m != nil { + return m.Sig1 + } + return nil +} + +func (m *MultisignInfo) GetSig2() []*Signature { + if m != nil { + return m.Sig2 + } + return nil +} + +func (m *MultisignInfo) GetRedeemScript() []byte { + if m != nil { + return m.RedeemScript + } + return nil +} + +func (m *MultisignInfo) GetFeePerByte() uint64 { + if m != nil { + return m.FeePerByte + } + return 0 +} + +func (m *MultisignInfo) GetBroadcast() bool { + if m != nil { + return m.Broadcast + } + return false +} + +type RawTx struct { + Tx []byte `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RawTx) Reset() { *m = RawTx{} } +func (m *RawTx) String() string { return proto.CompactTextString(m) } +func (*RawTx) ProtoMessage() {} +func (*RawTx) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{28} +} +func (m *RawTx) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RawTx.Unmarshal(m, b) +} +func (m *RawTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RawTx.Marshal(b, m, deterministic) +} +func (dst *RawTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_RawTx.Merge(dst, src) +} +func (m *RawTx) XXX_Size() int { + return xxx_messageInfo_RawTx.Size(m) +} +func (m *RawTx) XXX_DiscardUnknown() { + xxx_messageInfo_RawTx.DiscardUnknown(m) +} + +var xxx_messageInfo_RawTx proto.InternalMessageInfo + +func (m *RawTx) GetTx() []byte { + if m != nil { + return m.Tx + } + return nil +} + +type EstimateFeeData struct { + Coin CoinType `protobuf:"varint,1,opt,name=coin,proto3,enum=pb.CoinType" json:"coin,omitempty"` + Inputs []*Input `protobuf:"bytes,2,rep,name=inputs,proto3" json:"inputs,omitempty"` + Outputs []*Output `protobuf:"bytes,3,rep,name=outputs,proto3" json:"outputs,omitempty"` + FeePerByte uint64 `protobuf:"varint,4,opt,name=feePerByte,proto3" json:"feePerByte,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EstimateFeeData) Reset() { *m = EstimateFeeData{} } +func (m *EstimateFeeData) String() string { return proto.CompactTextString(m) } +func (*EstimateFeeData) ProtoMessage() {} +func (*EstimateFeeData) Descriptor() ([]byte, []int) { + return fileDescriptor_api_2ff753dddd9b028a, []int{29} +} +func (m *EstimateFeeData) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_EstimateFeeData.Unmarshal(m, b) +} +func (m *EstimateFeeData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_EstimateFeeData.Marshal(b, m, deterministic) +} +func (dst *EstimateFeeData) XXX_Merge(src proto.Message) { + xxx_messageInfo_EstimateFeeData.Merge(dst, src) +} +func (m *EstimateFeeData) XXX_Size() int { + return xxx_messageInfo_EstimateFeeData.Size(m) +} +func (m *EstimateFeeData) XXX_DiscardUnknown() { + xxx_messageInfo_EstimateFeeData.DiscardUnknown(m) +} + +var xxx_messageInfo_EstimateFeeData proto.InternalMessageInfo + +func (m *EstimateFeeData) GetCoin() CoinType { + if m != nil { + return m.Coin + } + return CoinType_BITCOIN +} + +func (m *EstimateFeeData) GetInputs() []*Input { + if m != nil { + return m.Inputs + } + return nil +} + +func (m *EstimateFeeData) GetOutputs() []*Output { + if m != nil { + return m.Outputs + } + return nil +} + +func (m *EstimateFeeData) GetFeePerByte() uint64 { + if m != nil { + return m.FeePerByte + } + return 0 +} + +func init() { + proto.RegisterType((*Empty)(nil), "pb.Empty") + proto.RegisterType((*CoinSelection)(nil), "pb.CoinSelection") + proto.RegisterType((*Row)(nil), "pb.Row") + proto.RegisterType((*KeySelection)(nil), "pb.KeySelection") + proto.RegisterType((*Address)(nil), "pb.Address") + proto.RegisterType((*Height)(nil), "pb.Height") + proto.RegisterType((*Balances)(nil), "pb.Balances") + proto.RegisterType((*Key)(nil), "pb.Key") + proto.RegisterType((*Keys)(nil), "pb.Keys") + proto.RegisterType((*Addresses)(nil), "pb.Addresses") + proto.RegisterType((*BoolResponse)(nil), "pb.BoolResponse") + proto.RegisterType((*NetParams)(nil), "pb.NetParams") + proto.RegisterType((*TransactionList)(nil), "pb.TransactionList") + proto.RegisterType((*Tx)(nil), "pb.Tx") + proto.RegisterType((*Txid)(nil), "pb.Txid") + proto.RegisterType((*FeeLevelSelection)(nil), "pb.FeeLevelSelection") + proto.RegisterType((*FeePerByte)(nil), "pb.FeePerByte") + proto.RegisterType((*Fee)(nil), "pb.Fee") + proto.RegisterType((*SpendInfo)(nil), "pb.SpendInfo") + proto.RegisterType((*Confirmations)(nil), "pb.Confirmations") + proto.RegisterType((*Utxo)(nil), "pb.Utxo") + proto.RegisterType((*SweepInfo)(nil), "pb.SweepInfo") + proto.RegisterType((*Input)(nil), "pb.Input") + proto.RegisterType((*Output)(nil), "pb.Output") + proto.RegisterType((*Signature)(nil), "pb.Signature") + proto.RegisterType((*CreateMultisigInfo)(nil), "pb.CreateMultisigInfo") + proto.RegisterType((*SignatureList)(nil), "pb.SignatureList") + proto.RegisterType((*MultisignInfo)(nil), "pb.MultisignInfo") + proto.RegisterType((*RawTx)(nil), "pb.RawTx") + proto.RegisterType((*EstimateFeeData)(nil), "pb.EstimateFeeData") + proto.RegisterEnum("pb.CoinType", CoinType_name, CoinType_value) + proto.RegisterEnum("pb.KeyPurpose", KeyPurpose_name, KeyPurpose_value) + proto.RegisterEnum("pb.FeeLevel", FeeLevel_name, FeeLevel_value) +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// APIClient is the client API for API service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type APIClient interface { + Stop(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) + CurrentAddress(ctx context.Context, in *KeySelection, opts ...grpc.CallOption) (*Address, error) + NewAddress(ctx context.Context, in *KeySelection, opts ...grpc.CallOption) (*Address, error) + ChainTip(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Height, error) + Balance(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Balances, error) + MasterPrivateKey(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Key, error) + MasterPublicKey(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Key, error) + HasKey(ctx context.Context, in *Address, opts ...grpc.CallOption) (*BoolResponse, error) + Params(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*NetParams, error) + Transactions(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*TransactionList, error) + GetTransaction(ctx context.Context, in *Txid, opts ...grpc.CallOption) (*Tx, error) + GetFeePerByte(ctx context.Context, in *FeeLevelSelection, opts ...grpc.CallOption) (*FeePerByte, error) + Spend(ctx context.Context, in *SpendInfo, opts ...grpc.CallOption) (*Txid, error) + BumpFee(ctx context.Context, in *Txid, opts ...grpc.CallOption) (*Txid, error) + AddWatchedScript(ctx context.Context, in *Address, opts ...grpc.CallOption) (*Empty, error) + GetConfirmations(ctx context.Context, in *Txid, opts ...grpc.CallOption) (*Confirmations, error) + SweepAddress(ctx context.Context, in *SweepInfo, opts ...grpc.CallOption) (*Txid, error) + CreateMultisigSignature(ctx context.Context, in *CreateMultisigInfo, opts ...grpc.CallOption) (*SignatureList, error) + Multisign(ctx context.Context, in *MultisignInfo, opts ...grpc.CallOption) (*RawTx, error) + EstimateFee(ctx context.Context, in *EstimateFeeData, opts ...grpc.CallOption) (*Fee, error) + GetKey(ctx context.Context, in *Address, opts ...grpc.CallOption) (*Key, error) + ListKeys(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Keys, error) + ListAddresses(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Addresses, error) + WalletNotify(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (API_WalletNotifyClient, error) + DumpTables(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (API_DumpTablesClient, error) +} + +type aPIClient struct { + cc *grpc.ClientConn +} + +func NewAPIClient(cc *grpc.ClientConn) APIClient { + return &aPIClient{cc} +} + +func (c *aPIClient) Stop(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/pb.API/Stop", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) CurrentAddress(ctx context.Context, in *KeySelection, opts ...grpc.CallOption) (*Address, error) { + out := new(Address) + err := c.cc.Invoke(ctx, "/pb.API/CurrentAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) NewAddress(ctx context.Context, in *KeySelection, opts ...grpc.CallOption) (*Address, error) { + out := new(Address) + err := c.cc.Invoke(ctx, "/pb.API/NewAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) ChainTip(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Height, error) { + out := new(Height) + err := c.cc.Invoke(ctx, "/pb.API/ChainTip", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) Balance(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Balances, error) { + out := new(Balances) + err := c.cc.Invoke(ctx, "/pb.API/Balance", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) MasterPrivateKey(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Key, error) { + out := new(Key) + err := c.cc.Invoke(ctx, "/pb.API/MasterPrivateKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) MasterPublicKey(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Key, error) { + out := new(Key) + err := c.cc.Invoke(ctx, "/pb.API/MasterPublicKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) HasKey(ctx context.Context, in *Address, opts ...grpc.CallOption) (*BoolResponse, error) { + out := new(BoolResponse) + err := c.cc.Invoke(ctx, "/pb.API/HasKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) Params(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*NetParams, error) { + out := new(NetParams) + err := c.cc.Invoke(ctx, "/pb.API/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) Transactions(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*TransactionList, error) { + out := new(TransactionList) + err := c.cc.Invoke(ctx, "/pb.API/Transactions", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) GetTransaction(ctx context.Context, in *Txid, opts ...grpc.CallOption) (*Tx, error) { + out := new(Tx) + err := c.cc.Invoke(ctx, "/pb.API/GetTransaction", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) GetFeePerByte(ctx context.Context, in *FeeLevelSelection, opts ...grpc.CallOption) (*FeePerByte, error) { + out := new(FeePerByte) + err := c.cc.Invoke(ctx, "/pb.API/GetFeePerByte", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) Spend(ctx context.Context, in *SpendInfo, opts ...grpc.CallOption) (*Txid, error) { + out := new(Txid) + err := c.cc.Invoke(ctx, "/pb.API/Spend", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) BumpFee(ctx context.Context, in *Txid, opts ...grpc.CallOption) (*Txid, error) { + out := new(Txid) + err := c.cc.Invoke(ctx, "/pb.API/BumpFee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) AddWatchedScript(ctx context.Context, in *Address, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/pb.API/AddWatchedScript", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) GetConfirmations(ctx context.Context, in *Txid, opts ...grpc.CallOption) (*Confirmations, error) { + out := new(Confirmations) + err := c.cc.Invoke(ctx, "/pb.API/GetConfirmations", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) SweepAddress(ctx context.Context, in *SweepInfo, opts ...grpc.CallOption) (*Txid, error) { + out := new(Txid) + err := c.cc.Invoke(ctx, "/pb.API/SweepAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) CreateMultisigSignature(ctx context.Context, in *CreateMultisigInfo, opts ...grpc.CallOption) (*SignatureList, error) { + out := new(SignatureList) + err := c.cc.Invoke(ctx, "/pb.API/CreateMultisigSignature", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) Multisign(ctx context.Context, in *MultisignInfo, opts ...grpc.CallOption) (*RawTx, error) { + out := new(RawTx) + err := c.cc.Invoke(ctx, "/pb.API/Multisign", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) EstimateFee(ctx context.Context, in *EstimateFeeData, opts ...grpc.CallOption) (*Fee, error) { + out := new(Fee) + err := c.cc.Invoke(ctx, "/pb.API/EstimateFee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) GetKey(ctx context.Context, in *Address, opts ...grpc.CallOption) (*Key, error) { + out := new(Key) + err := c.cc.Invoke(ctx, "/pb.API/GetKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) ListKeys(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Keys, error) { + out := new(Keys) + err := c.cc.Invoke(ctx, "/pb.API/ListKeys", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) ListAddresses(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (*Addresses, error) { + out := new(Addresses) + err := c.cc.Invoke(ctx, "/pb.API/ListAddresses", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) WalletNotify(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (API_WalletNotifyClient, error) { + stream, err := c.cc.NewStream(ctx, &_API_serviceDesc.Streams[0], "/pb.API/WalletNotify", opts...) + if err != nil { + return nil, err + } + x := &aPIWalletNotifyClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type API_WalletNotifyClient interface { + Recv() (*Tx, error) + grpc.ClientStream +} + +type aPIWalletNotifyClient struct { + grpc.ClientStream +} + +func (x *aPIWalletNotifyClient) Recv() (*Tx, error) { + m := new(Tx) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *aPIClient) DumpTables(ctx context.Context, in *CoinSelection, opts ...grpc.CallOption) (API_DumpTablesClient, error) { + stream, err := c.cc.NewStream(ctx, &_API_serviceDesc.Streams[1], "/pb.API/DumpTables", opts...) + if err != nil { + return nil, err + } + x := &aPIDumpTablesClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type API_DumpTablesClient interface { + Recv() (*Row, error) + grpc.ClientStream +} + +type aPIDumpTablesClient struct { + grpc.ClientStream +} + +func (x *aPIDumpTablesClient) Recv() (*Row, error) { + m := new(Row) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// APIServer is the server API for API service. +type APIServer interface { + Stop(context.Context, *Empty) (*Empty, error) + CurrentAddress(context.Context, *KeySelection) (*Address, error) + NewAddress(context.Context, *KeySelection) (*Address, error) + ChainTip(context.Context, *CoinSelection) (*Height, error) + Balance(context.Context, *CoinSelection) (*Balances, error) + MasterPrivateKey(context.Context, *CoinSelection) (*Key, error) + MasterPublicKey(context.Context, *CoinSelection) (*Key, error) + HasKey(context.Context, *Address) (*BoolResponse, error) + Params(context.Context, *Empty) (*NetParams, error) + Transactions(context.Context, *CoinSelection) (*TransactionList, error) + GetTransaction(context.Context, *Txid) (*Tx, error) + GetFeePerByte(context.Context, *FeeLevelSelection) (*FeePerByte, error) + Spend(context.Context, *SpendInfo) (*Txid, error) + BumpFee(context.Context, *Txid) (*Txid, error) + AddWatchedScript(context.Context, *Address) (*Empty, error) + GetConfirmations(context.Context, *Txid) (*Confirmations, error) + SweepAddress(context.Context, *SweepInfo) (*Txid, error) + CreateMultisigSignature(context.Context, *CreateMultisigInfo) (*SignatureList, error) + Multisign(context.Context, *MultisignInfo) (*RawTx, error) + EstimateFee(context.Context, *EstimateFeeData) (*Fee, error) + GetKey(context.Context, *Address) (*Key, error) + ListKeys(context.Context, *CoinSelection) (*Keys, error) + ListAddresses(context.Context, *CoinSelection) (*Addresses, error) + WalletNotify(*CoinSelection, API_WalletNotifyServer) error + DumpTables(*CoinSelection, API_DumpTablesServer) error +} + +func RegisterAPIServer(s *grpc.Server, srv APIServer) { + s.RegisterService(&_API_serviceDesc, srv) +} + +func _API_Stop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).Stop(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/Stop", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).Stop(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_CurrentAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(KeySelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).CurrentAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/CurrentAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).CurrentAddress(ctx, req.(*KeySelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_NewAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(KeySelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).NewAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/NewAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).NewAddress(ctx, req.(*KeySelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_ChainTip_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CoinSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).ChainTip(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/ChainTip", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).ChainTip(ctx, req.(*CoinSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_Balance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CoinSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).Balance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/Balance", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).Balance(ctx, req.(*CoinSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_MasterPrivateKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CoinSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).MasterPrivateKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/MasterPrivateKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).MasterPrivateKey(ctx, req.(*CoinSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_MasterPublicKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CoinSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).MasterPublicKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/MasterPublicKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).MasterPublicKey(ctx, req.(*CoinSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_HasKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Address) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).HasKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/HasKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).HasKey(ctx, req.(*Address)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).Params(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_Transactions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CoinSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).Transactions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/Transactions", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).Transactions(ctx, req.(*CoinSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_GetTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Txid) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).GetTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/GetTransaction", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).GetTransaction(ctx, req.(*Txid)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_GetFeePerByte_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FeeLevelSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).GetFeePerByte(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/GetFeePerByte", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).GetFeePerByte(ctx, req.(*FeeLevelSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_Spend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SpendInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).Spend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/Spend", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).Spend(ctx, req.(*SpendInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_BumpFee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Txid) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).BumpFee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/BumpFee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).BumpFee(ctx, req.(*Txid)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_AddWatchedScript_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Address) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).AddWatchedScript(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/AddWatchedScript", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).AddWatchedScript(ctx, req.(*Address)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_GetConfirmations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Txid) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).GetConfirmations(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/GetConfirmations", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).GetConfirmations(ctx, req.(*Txid)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_SweepAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SweepInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).SweepAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/SweepAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).SweepAddress(ctx, req.(*SweepInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_CreateMultisigSignature_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateMultisigInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).CreateMultisigSignature(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/CreateMultisigSignature", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).CreateMultisigSignature(ctx, req.(*CreateMultisigInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_Multisign_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MultisignInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).Multisign(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/Multisign", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).Multisign(ctx, req.(*MultisignInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_EstimateFee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EstimateFeeData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).EstimateFee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/EstimateFee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).EstimateFee(ctx, req.(*EstimateFeeData)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_GetKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Address) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).GetKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/GetKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).GetKey(ctx, req.(*Address)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_ListKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CoinSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).ListKeys(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/ListKeys", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).ListKeys(ctx, req.(*CoinSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_ListAddresses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CoinSelection) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).ListAddresses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.API/ListAddresses", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).ListAddresses(ctx, req.(*CoinSelection)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_WalletNotify_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(CoinSelection) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(APIServer).WalletNotify(m, &aPIWalletNotifyServer{stream}) +} + +type API_WalletNotifyServer interface { + Send(*Tx) error + grpc.ServerStream +} + +type aPIWalletNotifyServer struct { + grpc.ServerStream +} + +func (x *aPIWalletNotifyServer) Send(m *Tx) error { + return x.ServerStream.SendMsg(m) +} + +func _API_DumpTables_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(CoinSelection) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(APIServer).DumpTables(m, &aPIDumpTablesServer{stream}) +} + +type API_DumpTablesServer interface { + Send(*Row) error + grpc.ServerStream +} + +type aPIDumpTablesServer struct { + grpc.ServerStream +} + +func (x *aPIDumpTablesServer) Send(m *Row) error { + return x.ServerStream.SendMsg(m) +} + +var _API_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pb.API", + HandlerType: (*APIServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Stop", + Handler: _API_Stop_Handler, + }, + { + MethodName: "CurrentAddress", + Handler: _API_CurrentAddress_Handler, + }, + { + MethodName: "NewAddress", + Handler: _API_NewAddress_Handler, + }, + { + MethodName: "ChainTip", + Handler: _API_ChainTip_Handler, + }, + { + MethodName: "Balance", + Handler: _API_Balance_Handler, + }, + { + MethodName: "MasterPrivateKey", + Handler: _API_MasterPrivateKey_Handler, + }, + { + MethodName: "MasterPublicKey", + Handler: _API_MasterPublicKey_Handler, + }, + { + MethodName: "HasKey", + Handler: _API_HasKey_Handler, + }, + { + MethodName: "Params", + Handler: _API_Params_Handler, + }, + { + MethodName: "Transactions", + Handler: _API_Transactions_Handler, + }, + { + MethodName: "GetTransaction", + Handler: _API_GetTransaction_Handler, + }, + { + MethodName: "GetFeePerByte", + Handler: _API_GetFeePerByte_Handler, + }, + { + MethodName: "Spend", + Handler: _API_Spend_Handler, + }, + { + MethodName: "BumpFee", + Handler: _API_BumpFee_Handler, + }, + { + MethodName: "AddWatchedScript", + Handler: _API_AddWatchedScript_Handler, + }, + { + MethodName: "GetConfirmations", + Handler: _API_GetConfirmations_Handler, + }, + { + MethodName: "SweepAddress", + Handler: _API_SweepAddress_Handler, + }, + { + MethodName: "CreateMultisigSignature", + Handler: _API_CreateMultisigSignature_Handler, + }, + { + MethodName: "Multisign", + Handler: _API_Multisign_Handler, + }, + { + MethodName: "EstimateFee", + Handler: _API_EstimateFee_Handler, + }, + { + MethodName: "GetKey", + Handler: _API_GetKey_Handler, + }, + { + MethodName: "ListKeys", + Handler: _API_ListKeys_Handler, + }, + { + MethodName: "ListAddresses", + Handler: _API_ListAddresses_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "WalletNotify", + Handler: _API_WalletNotify_Handler, + ServerStreams: true, + }, + { + StreamName: "DumpTables", + Handler: _API_DumpTables_Handler, + ServerStreams: true, + }, + }, + Metadata: "api.proto", +} + +func init() { proto.RegisterFile("api.proto", fileDescriptor_api_2ff753dddd9b028a) } + +var fileDescriptor_api_2ff753dddd9b028a = []byte{ + // 1449 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x72, 0xdb, 0x46, + 0x12, 0xe6, 0x0f, 0xf8, 0x83, 0x16, 0x28, 0xd3, 0xb3, 0xbb, 0x36, 0x57, 0xeb, 0x92, 0xe9, 0x59, + 0x1f, 0x64, 0xad, 0x57, 0xb6, 0xe8, 0x4a, 0xca, 0x87, 0xa4, 0x5c, 0x12, 0xad, 0x1f, 0x46, 0x12, + 0xc5, 0x1a, 0xd1, 0xe5, 0xc4, 0x17, 0xd7, 0x90, 0x68, 0x49, 0x28, 0x93, 0x00, 0x0a, 0x18, 0x58, + 0xe4, 0x3d, 0x8f, 0x91, 0x5c, 0xf2, 0x04, 0x79, 0x8b, 0x3c, 0x41, 0xde, 0x27, 0x35, 0x83, 0x01, + 0x01, 0xc8, 0xb4, 0x2d, 0xe7, 0xe0, 0x5b, 0x4f, 0xf7, 0x87, 0x99, 0xee, 0xaf, 0x7b, 0x7a, 0x1a, + 0x60, 0x72, 0xdf, 0xd9, 0xf2, 0x03, 0x4f, 0x78, 0xa4, 0xe4, 0x8f, 0xd6, 0xee, 0x5f, 0x78, 0xde, + 0xc5, 0x04, 0x9f, 0x28, 0xcd, 0x28, 0x3a, 0x7f, 0x22, 0x9c, 0x29, 0x86, 0x82, 0x4f, 0xfd, 0x18, + 0x44, 0x6b, 0x50, 0xd9, 0x9b, 0xfa, 0x62, 0x4e, 0xb7, 0xa1, 0xd1, 0xf5, 0x1c, 0xf7, 0x0c, 0x27, + 0x38, 0x16, 0x8e, 0xe7, 0x92, 0x36, 0x18, 0x63, 0xcf, 0x71, 0x5b, 0xc5, 0x76, 0x71, 0x63, 0xb5, + 0x63, 0x6d, 0xf9, 0xa3, 0x2d, 0x09, 0x18, 0xce, 0x7d, 0x64, 0xca, 0x42, 0xff, 0x0d, 0x65, 0xe6, + 0x5d, 0x11, 0x02, 0x86, 0xcd, 0x05, 0x57, 0x40, 0x93, 0x29, 0x99, 0xbe, 0x01, 0xeb, 0x08, 0xe7, + 0x5f, 0xb0, 0x19, 0xd9, 0x80, 0x9a, 0x1f, 0x05, 0xbe, 0x17, 0x62, 0xab, 0xa4, 0x40, 0xab, 0x12, + 0x74, 0x84, 0xf3, 0x41, 0xac, 0x65, 0x89, 0x99, 0xbe, 0x80, 0xda, 0x8e, 0x6d, 0x07, 0x18, 0x86, + 0x37, 0xd8, 0x96, 0x80, 0xc1, 0x6d, 0x3b, 0x50, 0x7b, 0x9a, 0x4c, 0xc9, 0xb4, 0x0d, 0xd5, 0x43, + 0x74, 0x2e, 0x2e, 0x05, 0xb9, 0x03, 0xd5, 0x4b, 0x25, 0xa9, 0x1d, 0x1a, 0x4c, 0xaf, 0xe8, 0x0f, + 0x50, 0xdf, 0xe5, 0x13, 0xee, 0x8e, 0x31, 0x24, 0xf7, 0xc0, 0x1c, 0x7b, 0xee, 0xb9, 0x13, 0x4c, + 0xd1, 0x56, 0x30, 0x83, 0xa5, 0x0a, 0xd2, 0x86, 0x95, 0xc8, 0x4d, 0xed, 0x25, 0x65, 0xcf, 0xaa, + 0xe8, 0x5d, 0x28, 0x1f, 0xe1, 0x9c, 0x34, 0xa1, 0xfc, 0x0e, 0xe7, 0x9a, 0x24, 0x29, 0xd2, 0xff, + 0x82, 0x71, 0x84, 0xf3, 0x90, 0xfc, 0x07, 0x8c, 0x77, 0x38, 0x0f, 0x5b, 0xc5, 0x76, 0x79, 0x63, + 0xa5, 0x53, 0xd3, 0x61, 0x33, 0xa5, 0xa4, 0xdf, 0x82, 0xa9, 0x83, 0xc5, 0x90, 0x3c, 0x02, 0x93, + 0x27, 0x0b, 0x0d, 0x5f, 0x91, 0x70, 0x8d, 0x60, 0xa9, 0x95, 0x52, 0xb0, 0x76, 0x3d, 0x6f, 0xc2, + 0x30, 0xf4, 0x3d, 0x37, 0x44, 0xc9, 0xc3, 0xc8, 0xf3, 0x26, 0xea, 0xfc, 0x3a, 0x53, 0x32, 0xbd, + 0x0f, 0x66, 0x1f, 0xc5, 0x80, 0x07, 0x7c, 0x1a, 0x4a, 0x80, 0xcb, 0xa7, 0x98, 0x64, 0x51, 0xca, + 0xf4, 0x7b, 0xb8, 0x35, 0x0c, 0xb8, 0x1b, 0x72, 0x95, 0xc4, 0x63, 0x27, 0x14, 0x64, 0x13, 0x2c, + 0x91, 0xaa, 0x12, 0x2f, 0xaa, 0xd2, 0x8b, 0xe1, 0x8c, 0xe5, 0x6c, 0xf4, 0xf7, 0x22, 0x94, 0x86, + 0x33, 0xb9, 0xb3, 0x98, 0x39, 0x76, 0xb2, 0xb3, 0x94, 0xc9, 0x3f, 0xa1, 0xf2, 0x9e, 0x4f, 0xa2, + 0x38, 0xd7, 0x65, 0x16, 0x2f, 0x32, 0xe9, 0x28, 0xb7, 0x8b, 0x1b, 0x95, 0x24, 0x1d, 0xe4, 0x39, + 0x98, 0x8b, 0xba, 0x6d, 0x19, 0xed, 0xe2, 0xc6, 0x4a, 0x67, 0x6d, 0x2b, 0xae, 0xec, 0xad, 0xa4, + 0xb2, 0xb7, 0x86, 0x09, 0x82, 0xa5, 0x60, 0x99, 0xbc, 0x2b, 0x2e, 0xc6, 0x97, 0xa7, 0xee, 0x64, + 0xde, 0xaa, 0xa8, 0xd8, 0x53, 0x85, 0xcc, 0x49, 0xc0, 0xaf, 0x5a, 0xd5, 0x76, 0x71, 0xc3, 0x62, + 0x52, 0xa4, 0xdf, 0x81, 0x31, 0x94, 0xfe, 0xdd, 0xa8, 0xb0, 0x2e, 0x79, 0x78, 0x99, 0x14, 0x96, + 0x94, 0xe9, 0x5b, 0xb8, 0xbd, 0x8f, 0x78, 0x8c, 0xef, 0x71, 0xf2, 0x65, 0xa5, 0x5f, 0x3f, 0xd7, + 0x9f, 0xe9, 0xda, 0x57, 0xa8, 0x64, 0x2b, 0xb6, 0xb0, 0xd2, 0x75, 0x80, 0x7d, 0xc4, 0x01, 0x06, + 0xbb, 0x73, 0x81, 0xd2, 0xfd, 0x73, 0x44, 0x5d, 0x93, 0x52, 0x94, 0xb5, 0xb6, 0x8f, 0xcb, 0x0c, + 0xbf, 0x16, 0xc1, 0x3c, 0xf3, 0xd1, 0xb5, 0x7b, 0xee, 0xb9, 0x77, 0x03, 0x97, 0x5a, 0x50, 0xd3, + 0xb5, 0xa4, 0x03, 0x4c, 0x96, 0x32, 0x47, 0x7c, 0xea, 0x45, 0x6e, 0x9c, 0x23, 0x83, 0xe9, 0x55, + 0x2e, 0x08, 0xe3, 0x53, 0x41, 0x48, 0xe6, 0xa6, 0x38, 0xf5, 0x54, 0x3a, 0x4c, 0xa6, 0x64, 0xfa, + 0x8d, 0xec, 0x3e, 0xea, 0xc6, 0x70, 0x55, 0x3b, 0xe4, 0x21, 0x34, 0xc6, 0x59, 0x85, 0xbe, 0xa0, + 0x79, 0x25, 0xdd, 0x07, 0xe3, 0x95, 0x98, 0x79, 0x1f, 0x2b, 0x31, 0xc7, 0xb5, 0x71, 0xa6, 0x02, + 0x68, 0xb0, 0x78, 0x91, 0x16, 0x5e, 0xec, 0x7d, 0xbc, 0xa0, 0x7f, 0x48, 0x7a, 0xae, 0x10, 0xfd, + 0x1b, 0xd2, 0xb3, 0x0e, 0x95, 0x48, 0xcc, 0x3c, 0x49, 0x8e, 0x2c, 0xff, 0xba, 0x84, 0x48, 0x47, + 0x58, 0xac, 0xce, 0xd2, 0x57, 0xce, 0xd3, 0xa7, 0xdb, 0x80, 0xb1, 0x68, 0x03, 0x84, 0x82, 0x15, + 0xa0, 0x8d, 0x38, 0x3d, 0x1b, 0x07, 0x8e, 0x2f, 0x14, 0x2d, 0x16, 0xcb, 0xe9, 0x72, 0xe4, 0x56, + 0x3f, 0x59, 0x21, 0xdb, 0x50, 0xe9, 0xb9, 0x7e, 0x24, 0x6e, 0x4e, 0x09, 0xdd, 0x85, 0xea, 0x69, + 0x24, 0xe4, 0x37, 0x14, 0xac, 0x50, 0x1d, 0x38, 0x88, 0x46, 0x47, 0xba, 0x59, 0x59, 0x2c, 0xa7, + 0xcb, 0xdf, 0xdc, 0x05, 0x81, 0x2f, 0xc0, 0x3c, 0x73, 0x2e, 0x5c, 0x2e, 0xa2, 0x00, 0xd3, 0x63, + 0x8a, 0x59, 0xe6, 0xef, 0x81, 0x19, 0x26, 0x10, 0xf5, 0xb1, 0xc5, 0x52, 0x05, 0xfd, 0xb3, 0x08, + 0xa4, 0x1b, 0x20, 0x17, 0x78, 0x12, 0x4d, 0x84, 0x13, 0x3a, 0x17, 0x37, 0x4c, 0xc5, 0x03, 0xa8, + 0x3a, 0x32, 0xe0, 0x24, 0x17, 0xa6, 0xc4, 0x28, 0x0a, 0x98, 0x36, 0x90, 0x87, 0x50, 0xf3, 0x54, + 0x80, 0x32, 0x1b, 0x12, 0x03, 0x12, 0x13, 0xc7, 0xcc, 0x12, 0xd3, 0xdf, 0xcc, 0xcc, 0x3a, 0xc0, + 0xf9, 0xe2, 0x46, 0xaa, 0xdc, 0x18, 0x2c, 0xa3, 0xa1, 0x1d, 0x68, 0x2c, 0x88, 0x51, 0x0d, 0xf4, + 0x01, 0x18, 0xa1, 0x73, 0x91, 0x34, 0xce, 0x86, 0xf4, 0x64, 0x01, 0x60, 0xca, 0x44, 0x7f, 0x2b, + 0x41, 0x23, 0x61, 0xc1, 0xfd, 0xda, 0x34, 0xc4, 0xfe, 0x6d, 0xb7, 0x8c, 0x8f, 0xf9, 0xb7, 0xad, + 0x21, 0x9d, 0x56, 0xe5, 0x63, 0x90, 0xce, 0x07, 0xd4, 0x55, 0x3f, 0x4b, 0x5d, 0xed, 0x3a, 0x75, + 0xb2, 0x60, 0x46, 0x81, 0xc7, 0xed, 0x31, 0x0f, 0x45, 0xab, 0x1e, 0xf7, 0xee, 0x85, 0x82, 0xde, + 0x85, 0x0a, 0xe3, 0x57, 0xc3, 0x19, 0x59, 0x85, 0x92, 0x98, 0xe9, 0x52, 0x2d, 0x89, 0x19, 0xfd, + 0xa5, 0x08, 0xb7, 0xf6, 0x42, 0xe1, 0x4c, 0xb9, 0xc0, 0x7d, 0xc4, 0x97, 0x5c, 0xf0, 0xaf, 0xc9, + 0x5f, 0x3e, 0x2a, 0xe3, 0x7a, 0x54, 0x9b, 0x03, 0xa8, 0x27, 0x47, 0x93, 0x15, 0xa8, 0xed, 0xf6, + 0x86, 0xdd, 0xd3, 0x5e, 0xbf, 0x59, 0x20, 0x4d, 0xb0, 0xf4, 0xe2, 0x6d, 0x77, 0xe7, 0xec, 0xb0, + 0x59, 0x24, 0x26, 0x54, 0xde, 0x28, 0xb1, 0x44, 0x2c, 0xa8, 0x1f, 0xf7, 0x86, 0x7b, 0x0a, 0x5a, + 0x96, 0xab, 0xbd, 0xe1, 0xe1, 0x1e, 0xdb, 0x7b, 0x75, 0xd2, 0x34, 0x36, 0x37, 0x00, 0xd2, 0x31, + 0x49, 0xda, 0x7a, 0xfd, 0xe1, 0x1e, 0xeb, 0xef, 0x1c, 0x37, 0x0b, 0x0a, 0xf9, 0xa3, 0x5e, 0x15, + 0x37, 0x3b, 0x50, 0x4f, 0x5a, 0x86, 0xb2, 0x74, 0x4f, 0xfb, 0xa7, 0x27, 0xbd, 0x6e, 0xb3, 0x40, + 0x00, 0xaa, 0xfd, 0x53, 0x76, 0x22, 0x51, 0xd2, 0x32, 0x60, 0xbd, 0x53, 0xd6, 0x1b, 0xfe, 0xd4, + 0x2c, 0x75, 0x7e, 0x36, 0xa1, 0xbc, 0x33, 0xe8, 0x91, 0x75, 0x30, 0xce, 0x84, 0xe7, 0x13, 0x45, + 0x8c, 0x1a, 0x19, 0xd7, 0x52, 0x91, 0x16, 0xc8, 0x36, 0xac, 0x76, 0xa3, 0x20, 0x40, 0x57, 0x24, + 0xc3, 0x59, 0x53, 0x4f, 0x32, 0x8b, 0xa7, 0x70, 0x2d, 0x3b, 0xac, 0xd0, 0x02, 0xf9, 0x3f, 0x40, + 0x1f, 0xaf, 0x6e, 0x0c, 0xff, 0x1f, 0xd4, 0xbb, 0x97, 0xdc, 0x71, 0x87, 0x8e, 0x4f, 0x6e, 0x27, + 0x29, 0x4c, 0xd1, 0x2a, 0x1b, 0xf1, 0x5c, 0x47, 0x0b, 0xe4, 0x31, 0xd4, 0xf4, 0x04, 0xb7, 0x0c, + 0xab, 0x2a, 0x20, 0x99, 0xf0, 0x68, 0x81, 0x3c, 0x85, 0xe6, 0x09, 0x0f, 0x05, 0x06, 0x83, 0xc0, + 0x79, 0xcf, 0x05, 0xca, 0x46, 0xb7, 0xe4, 0xb3, 0x64, 0x36, 0xa3, 0x05, 0xf2, 0x04, 0x6e, 0xe9, + 0x2f, 0xa2, 0xd1, 0xc4, 0x19, 0x7f, 0xfe, 0x83, 0x47, 0x50, 0x3d, 0xe4, 0xa1, 0xc4, 0x65, 0xc3, + 0x5a, 0x53, 0x51, 0x67, 0x27, 0x35, 0x5a, 0x20, 0x0f, 0xa1, 0xaa, 0x87, 0xb2, 0x0c, 0xd9, 0xea, + 0x9a, 0x2d, 0xc6, 0x35, 0x5a, 0x20, 0xcf, 0xc1, 0xca, 0x0c, 0x67, 0xe1, 0xb2, 0xe3, 0xff, 0xa1, + 0xc6, 0xb2, 0xfc, 0x04, 0xa7, 0xf6, 0x5f, 0x3d, 0x40, 0x91, 0xd1, 0x93, 0x7a, 0x3c, 0xbf, 0x39, + 0xf6, 0x9a, 0x9e, 0xe4, 0xd4, 0xfe, 0x8d, 0x03, 0x14, 0x99, 0x71, 0xe3, 0x5f, 0xd9, 0x27, 0x27, + 0x3d, 0x64, 0x55, 0xab, 0x93, 0x8e, 0x57, 0x20, 0x14, 0x2a, 0x6a, 0xd6, 0x20, 0x71, 0x6b, 0x48, + 0xc6, 0x8e, 0xb5, 0xc5, 0x29, 0xb4, 0x40, 0xee, 0x43, 0x6d, 0x37, 0x9a, 0xfa, 0x72, 0x5a, 0x49, + 0x0f, 0xcf, 0x02, 0x1e, 0x43, 0x73, 0xc7, 0xb6, 0x5f, 0xcb, 0x59, 0x0d, 0x6d, 0xdd, 0x31, 0x72, + 0xcc, 0x5d, 0xab, 0xbe, 0xe6, 0x01, 0x8a, 0xfc, 0x08, 0x91, 0xee, 0xab, 0xa9, 0xc9, 0x4e, 0x0e, + 0x32, 0x21, 0x96, 0x7a, 0xf2, 0x93, 0xfa, 0x8b, 0x9d, 0x4d, 0x86, 0x80, 0x9c, 0x2f, 0xfb, 0x70, + 0x37, 0xff, 0x36, 0xa5, 0x6f, 0xdd, 0x1d, 0xb5, 0xf5, 0x07, 0x0f, 0x57, 0x7c, 0x64, 0xae, 0xf3, + 0xab, 0x0a, 0x36, 0x17, 0x7d, 0x3d, 0xce, 0x57, 0xae, 0xcd, 0xc7, 0x21, 0xa9, 0xae, 0xa6, 0x6e, + 0xc7, 0x4a, 0xa6, 0x8d, 0x11, 0x95, 0xcb, 0x6b, 0x7d, 0x2d, 0xae, 0xaf, 0x7d, 0x94, 0xa4, 0xb7, + 0xa1, 0x7a, 0x80, 0xe2, 0x83, 0xfa, 0xca, 0x55, 0x60, 0x5d, 0xfa, 0xa1, 0xfe, 0x39, 0x96, 0x14, + 0x4b, 0x5d, 0x23, 0x25, 0x37, 0xcf, 0xa0, 0x21, 0xa1, 0xe9, 0x9f, 0xc7, 0x12, 0x7c, 0x23, 0x73, + 0x0c, 0xc6, 0xd7, 0xd9, 0x7a, 0xcd, 0x27, 0x13, 0x14, 0x7d, 0x4f, 0x38, 0xe7, 0x4b, 0xef, 0xc3, + 0xa2, 0xba, 0x9e, 0x16, 0xc9, 0x63, 0x80, 0x97, 0xd1, 0xd4, 0x1f, 0xf2, 0xd1, 0x64, 0xf9, 0x01, + 0xca, 0x75, 0xe6, 0x5d, 0x49, 0xf4, 0xa8, 0xaa, 0xe6, 0xfc, 0x67, 0x7f, 0x05, 0x00, 0x00, 0xff, + 0xff, 0x87, 0x69, 0x86, 0xca, 0xe0, 0x0e, 0x00, 0x00, +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/api/pb/api.proto b/vendor/github.com/OpenBazaar/multiwallet/api/pb/api.proto new file mode 100644 index 0000000000..791b442d0d --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/api/pb/api.proto @@ -0,0 +1,209 @@ +syntax = "proto3"; + +package pb; + +import "google/protobuf/timestamp.proto"; + +service API { + rpc Stop (Empty) returns (Empty) {} + rpc CurrentAddress (KeySelection) returns (Address) {} + rpc NewAddress (KeySelection) returns (Address) {} + rpc ChainTip (CoinSelection) returns (Height) {} + rpc Balance (CoinSelection) returns (Balances) {} + rpc MasterPrivateKey (CoinSelection) returns (Key) {} + rpc MasterPublicKey (CoinSelection) returns (Key) {} + rpc HasKey (Address) returns (BoolResponse) {} + rpc Params (Empty) returns (NetParams) {} + rpc Transactions (CoinSelection) returns (TransactionList) {} + rpc GetTransaction (Txid) returns (Tx) {} + rpc GetFeePerByte (FeeLevelSelection) returns (FeePerByte) {} + rpc Spend (SpendInfo) returns (Txid) {} + rpc BumpFee (Txid) returns (Txid) {} + rpc AddWatchedScript (Address) returns (Empty) {} + rpc GetConfirmations (Txid) returns (Confirmations) {} + rpc SweepAddress (SweepInfo) returns (Txid) {} + rpc CreateMultisigSignature (CreateMultisigInfo) returns (SignatureList) {} + rpc Multisign (MultisignInfo) returns (RawTx) {} + rpc EstimateFee (EstimateFeeData) returns (Fee) {} + rpc GetKey (Address) returns (Key) {} + rpc ListKeys (CoinSelection) returns (Keys) {} + rpc ListAddresses (CoinSelection) returns (Addresses) {} + rpc WalletNotify (CoinSelection) returns (stream Tx) {} + rpc DumpTables (CoinSelection) returns (stream Row) {} +} + +enum CoinType { + BITCOIN = 0; + BITCOIN_CASH = 1; + ZCASH = 2; + LITECOIN = 3; + ETHEREUM = 4; +} + +message Empty {} + +message CoinSelection { + CoinType coin = 1; +} + +enum KeyPurpose { + INTERNAL = 0; + EXTERNAL = 1; +} + +message Row { + string data = 1; +} + +message KeySelection { + CoinType coin = 1; + KeyPurpose purpose = 2; +} + +message Address { + CoinType coin = 1; + string addr = 2; +} + +message Height { + uint32 height = 1; +} + +message Balances { + uint64 confirmed = 1; + uint64 unconfirmed = 2; +} + +message Key { + string key = 1; +} + +message Keys { + repeated Key keys = 1; +} + +message Addresses { + repeated Address addresses = 1; +} + +message BoolResponse { + bool bool = 1; +} + +message NetParams { + string name = 1; +} + +message TransactionList { + repeated Tx transactions = 1; +} + +message Tx { + string txid = 1; + int64 value = 2; + int32 height = 3; + google.protobuf.Timestamp timestamp = 4; + bool watchOnly = 5; + bytes raw = 6; +} + +message Txid { + CoinType coin = 1; + string hash = 2; +} + +enum FeeLevel { + ECONOMIC = 0; + NORMAL = 1; + PRIORITY = 2; +} + +message FeeLevelSelection { + CoinType coin = 1; + FeeLevel feeLevel = 2; +} + +message FeePerByte { + uint64 fee = 1; +} + +message Fee { + uint64 fee = 1; +} + +message SpendInfo { + CoinType coin = 1; + string address = 2; + uint64 amount = 3; + FeeLevel feeLevel = 4; + string memo = 5; +} + +message Confirmations { + uint32 confirmations = 1; +} + +message Utxo { + string txid = 1; + uint32 index = 2; + uint64 value = 3; +} + +message SweepInfo { + CoinType coin = 1; + repeated Utxo utxos = 2; + string address = 3; + string key = 4; + bytes redeemScript = 5; + FeeLevel feeLevel = 6; +} + +message Input { + string txid = 1; + uint32 index = 2; +} + +message Output { + bytes scriptPubKey = 1; + uint64 value = 2; +} + +message Signature { + uint32 index = 1; + bytes signature = 2; +} + +message CreateMultisigInfo { + CoinType coin = 1; + repeated Input inputs = 2; + repeated Output outputs = 3; + string key = 4; + bytes redeemScript = 5; + uint64 feePerByte = 6; +} + +message SignatureList { + repeated Signature sigs = 1; +} + +message MultisignInfo { + CoinType coin = 1; + repeated Input inputs = 2; + repeated Output outputs = 3; + repeated Signature sig1 = 4; + repeated Signature sig2 = 5; + bytes redeemScript = 6; + uint64 feePerByte = 7; + bool broadcast = 8; +} + +message RawTx { + bytes tx = 1; +} + +message EstimateFeeData { + CoinType coin = 1; + repeated Input inputs = 2; + repeated Output outputs = 3; + uint64 feePerByte = 4; +} \ No newline at end of file diff --git a/vendor/github.com/OpenBazaar/multiwallet/api/rpc.go b/vendor/github.com/OpenBazaar/multiwallet/api/rpc.go new file mode 100644 index 0000000000..02586cbba4 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/api/rpc.go @@ -0,0 +1,281 @@ +package api + +import ( + "errors" + "net" + + "github.com/OpenBazaar/multiwallet" + "github.com/OpenBazaar/multiwallet/api/pb" + "github.com/OpenBazaar/multiwallet/bitcoin" + "github.com/OpenBazaar/multiwallet/bitcoincash" + "github.com/OpenBazaar/multiwallet/litecoin" + "github.com/OpenBazaar/multiwallet/zcash" + "github.com/OpenBazaar/wallet-interface" + "github.com/btcsuite/btcutil" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +const Addr = "127.0.0.1:8234" + +type server struct { + w multiwallet.MultiWallet +} + +func ServeAPI(w multiwallet.MultiWallet) error { + lis, err := net.Listen("tcp", Addr) + if err != nil { + return err + } + s := grpc.NewServer() + pb.RegisterAPIServer(s, &server{w}) + reflection.Register(s) + if err := s.Serve(lis); err != nil { + return err + } + return nil +} + +func coinType(coinType pb.CoinType) wallet.CoinType { + switch coinType { + case pb.CoinType_BITCOIN: + return wallet.Bitcoin + case pb.CoinType_BITCOIN_CASH: + return wallet.BitcoinCash + case pb.CoinType_ZCASH: + return wallet.Zcash + case pb.CoinType_LITECOIN: + return wallet.Litecoin + default: + return wallet.Bitcoin + } +} + +func (s *server) Stop(ctx context.Context, in *pb.Empty) (*pb.Empty, error) { + // Stub + return &pb.Empty{}, nil +} + +func (s *server) CurrentAddress(ctx context.Context, in *pb.KeySelection) (*pb.Address, error) { + var purpose wallet.KeyPurpose + if in.Purpose == pb.KeyPurpose_INTERNAL { + purpose = wallet.INTERNAL + } else if in.Purpose == pb.KeyPurpose_EXTERNAL { + purpose = wallet.EXTERNAL + } else { + return nil, errors.New("Unknown key purpose") + } + ct := coinType(in.Coin) + wal, err := s.w.WalletForCurrencyCode(ct.CurrencyCode()) + if err != nil { + return nil, err + } + addr := wal.CurrentAddress(purpose) + return &pb.Address{Coin: in.Coin, Addr: addr.String()}, nil +} + +func (s *server) NewAddress(ctx context.Context, in *pb.KeySelection) (*pb.Address, error) { + var purpose wallet.KeyPurpose + if in.Purpose == pb.KeyPurpose_INTERNAL { + purpose = wallet.INTERNAL + } else if in.Purpose == pb.KeyPurpose_EXTERNAL { + purpose = wallet.EXTERNAL + } else { + return nil, errors.New("Unknown key purpose") + } + ct := coinType(in.Coin) + wal, err := s.w.WalletForCurrencyCode(ct.CurrencyCode()) + if err != nil { + return nil, err + } + addr := wal.NewAddress(purpose) + return &pb.Address{Coin: in.Coin, Addr: addr.String()}, nil +} + +func (s *server) ChainTip(ctx context.Context, in *pb.CoinSelection) (*pb.Height, error) { + ct := coinType(in.Coin) + wal, err := s.w.WalletForCurrencyCode(ct.CurrencyCode()) + if err != nil { + return nil, err + } + h, _ := wal.ChainTip() + return &pb.Height{Height: h}, nil +} + +func (s *server) Balance(ctx context.Context, in *pb.CoinSelection) (*pb.Balances, error) { + ct := coinType(in.Coin) + wal, err := s.w.WalletForCurrencyCode(ct.CurrencyCode()) + if err != nil { + return nil, err + } + c, u := wal.Balance() + return &pb.Balances{Confirmed: uint64(c), Unconfirmed: uint64(u)}, nil +} + +func (s *server) MasterPrivateKey(ctx context.Context, in *pb.CoinSelection) (*pb.Key, error) { + // Stub + return &pb.Key{Key: ""}, nil +} + +func (s *server) MasterPublicKey(ctx context.Context, in *pb.CoinSelection) (*pb.Key, error) { + // Stub + return &pb.Key{Key: ""}, nil +} + +func (s *server) Params(ctx context.Context, in *pb.Empty) (*pb.NetParams, error) { + // Stub + return &pb.NetParams{Name: ""}, nil +} + +func (s *server) HasKey(ctx context.Context, in *pb.Address) (*pb.BoolResponse, error) { + // Stub + return &pb.BoolResponse{Bool: false}, nil +} + +func (s *server) Transactions(ctx context.Context, in *pb.CoinSelection) (*pb.TransactionList, error) { + // Stub + var list []*pb.Tx + return &pb.TransactionList{Transactions: list}, nil +} + +func (s *server) GetTransaction(ctx context.Context, in *pb.Txid) (*pb.Tx, error) { + // Stub + respTx := &pb.Tx{} + return respTx, nil +} + +func (s *server) GetFeePerByte(ctx context.Context, in *pb.FeeLevelSelection) (*pb.FeePerByte, error) { + // Stub + return &pb.FeePerByte{Fee: 0}, nil +} + +func (s *server) Spend(ctx context.Context, in *pb.SpendInfo) (*pb.Txid, error) { + var addr btcutil.Address + var err error + + ct := coinType(in.Coin) + wal, err := s.w.WalletForCurrencyCode(ct.CurrencyCode()) + if err != nil { + return nil, err + } + addr, err = wal.DecodeAddress(in.Address) + if err != nil { + return nil, err + } + + var feeLevel wallet.FeeLevel + switch in.FeeLevel { + case pb.FeeLevel_PRIORITY: + feeLevel = wallet.PRIOIRTY + case pb.FeeLevel_NORMAL: + feeLevel = wallet.NORMAL + case pb.FeeLevel_ECONOMIC: + feeLevel = wallet.ECONOMIC + default: + feeLevel = wallet.NORMAL + } + txid, err := wal.Spend(int64(in.Amount), addr, feeLevel, "", false) + if err != nil { + return nil, err + } + return &pb.Txid{Coin: in.Coin, Hash: txid.String()}, nil +} + +func (s *server) BumpFee(ctx context.Context, in *pb.Txid) (*pb.Txid, error) { + // Stub + return &pb.Txid{Coin: in.Coin, Hash: ""}, nil +} + +func (s *server) AddWatchedScript(ctx context.Context, in *pb.Address) (*pb.Empty, error) { + return nil, nil +} + +func (s *server) GetConfirmations(ctx context.Context, in *pb.Txid) (*pb.Confirmations, error) { + // Stub + return &pb.Confirmations{Confirmations: 0}, nil +} + +func (s *server) SweepAddress(ctx context.Context, in *pb.SweepInfo) (*pb.Txid, error) { + // Stub + return &pb.Txid{Coin: in.Coin, Hash: ""}, nil +} + +func (s *server) CreateMultisigSignature(ctx context.Context, in *pb.CreateMultisigInfo) (*pb.SignatureList, error) { + var retSigs []*pb.Signature + return &pb.SignatureList{Sigs: retSigs}, nil +} + +func (s *server) Multisign(ctx context.Context, in *pb.MultisignInfo) (*pb.RawTx, error) { + // Stub + return &pb.RawTx{Tx: []byte{}}, nil +} + +func (s *server) EstimateFee(ctx context.Context, in *pb.EstimateFeeData) (*pb.Fee, error) { + // Stub + return &pb.Fee{Fee: 0}, nil +} + +func (s *server) WalletNotify(in *pb.CoinSelection, stream pb.API_WalletNotifyServer) error { + // Stub + return nil +} + +func (s *server) GetKey(ctx context.Context, in *pb.Address) (*pb.Key, error) { + // Stub + return &pb.Key{Key: ""}, nil +} + +func (s *server) ListAddresses(ctx context.Context, in *pb.CoinSelection) (*pb.Addresses, error) { + // Stub + var list []*pb.Address + return &pb.Addresses{Addresses: list}, nil +} + +func (s *server) ListKeys(ctx context.Context, in *pb.CoinSelection) (*pb.Keys, error) { + // Stub + var list []*pb.Key + return &pb.Keys{Keys: list}, nil +} + +type HeaderWriter struct { + stream pb.API_DumpTablesServer +} + +func (h *HeaderWriter) Write(p []byte) (n int, err error) { + hdr := &pb.Row{Data: string(p)} + if err := h.stream.Send(hdr); err != nil { + return 0, err + } + return 0, nil +} + +func (s *server) DumpTables(in *pb.CoinSelection, stream pb.API_DumpTablesServer) error { + writer := HeaderWriter{stream} + ct := coinType(in.Coin) + wal, err := s.w.WalletForCurrencyCode(ct.CurrencyCode()) + if err != nil { + return err + } + bitcoinWallet, ok := wal.(*bitcoin.BitcoinWallet) + if ok { + bitcoinWallet.DumpTables(&writer) + return nil + } + bitcoincashWallet, ok := wal.(*bitcoincash.BitcoinCashWallet) + if ok { + bitcoincashWallet.DumpTables(&writer) + return nil + } + litecoinWallet, ok := wal.(*litecoin.LitecoinWallet) + if ok { + litecoinWallet.DumpTables(&writer) + return nil + } + zcashWallet, ok := wal.(*zcash.ZCashWallet) + if ok { + zcashWallet.DumpTables(&writer) + return nil + } + return nil +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go index 07baff1463..af20e56207 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go @@ -12,7 +12,6 @@ import ( "github.com/btcsuite/btcd/chaincfg" - "github.com/OpenBazaar/spvwallet" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcec" @@ -256,15 +255,15 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } func (w *BitcoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return nil, err } if txn.Height > 0 { - return nil, spvwallet.BumpFeeAlreadyConfirmedError + return nil, util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, spvwallet.BumpFeeTransactionDeadError + return nil, util.BumpFeeTransactionDeadError } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() @@ -297,7 +296,7 @@ func (w *BitcoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { return transactionID, nil } } - return nil, spvwallet.BumpFeeNotFoundError + return nil, util.BumpFeeNotFoundError } func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { @@ -335,7 +334,7 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add txType := P2PKH if redeemScript != nil { txType = P2SH_1of2_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(*redeemScript) + _, err := util.LockTimeFromRedeemScript(*redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_1Sig } @@ -399,7 +398,7 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add timeLocked = true tx.Version = 2 for _, txIn := range tx.TxIn { - locktime, err := spvwallet.LockTimeFromRedeemScript(*redeemScript) + locktime, err := util.LockTimeFromRedeemScript(*redeemScript) if err != nil { return nil, err } @@ -466,7 +465,7 @@ func (w *BitcoinWallet) createMultisigSignature(ins []wi.TransactionInput, outs // Subtract fee txType := P2SH_2of3_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(redeemScript) + _, err := util.LockTimeFromRedeemScript(redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_2Sigs } @@ -521,7 +520,7 @@ func (w *BitcoinWallet) multisign(ins []wi.TransactionInput, outs []wi.Transacti // Subtract fee txType := P2SH_2of3_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(redeemScript) + _, err := util.LockTimeFromRedeemScript(redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_2Sigs } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go index 147856b6c5..2cd9c4d2b9 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go @@ -17,8 +17,6 @@ import ( "github.com/OpenBazaar/multiwallet/model" "github.com/OpenBazaar/multiwallet/service" "github.com/OpenBazaar/multiwallet/util" - "github.com/OpenBazaar/spvwallet" - "github.com/OpenBazaar/spvwallet/exchangerates" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -38,7 +36,7 @@ type BitcoinWallet struct { params *chaincfg.Params client model.APIClient ws *service.WalletService - fp *spvwallet.FeeProvider + fp *util.FeeProvider mPrivKey *hd.ExtendedKey mPubKey *hd.ExtendedKey @@ -75,7 +73,7 @@ func NewBitcoinWallet(cfg config.CoinConfig, mnemonic string, params *chaincfg.P if err != nil { return nil, err } - er := exchangerates.NewBitcoinPriceFetcher(proxy) + er := util.NewBitcoinPriceFetcher(proxy) if !disableExchangeRates { go er.Run() } @@ -85,7 +83,7 @@ func NewBitcoinWallet(cfg config.CoinConfig, mnemonic string, params *chaincfg.P return nil, err } - fp := spvwallet.NewFeeProvider(cfg.MaxFee, cfg.HighFee, cfg.MediumFee, cfg.LowFee, cfg.SuperLowFee, cfg.FeeAPI, proxy) + fp := util.NewFeeProvider(cfg.MaxFee, cfg.HighFee, cfg.MediumFee, cfg.LowFee, cfg.SuperLowFee, er) return &BitcoinWallet{ db: cfg.DB, @@ -253,7 +251,7 @@ func (w *BitcoinWallet) Transactions() ([]wi.Txn, error) { } func (w *BitcoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -285,7 +283,7 @@ func (w *BitcoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { return txn, err } -func (w *BitcoinWallet) ChainTip() (uint32, chainhash.Hash) { +func (w *BitcoinWallet) ChainTip() (uint32, string) { return w.ws.ChainTip() } @@ -385,7 +383,7 @@ func (w *BitcoinWallet) ReSyncBlockchain(fromTime time.Time) { } func (w *BitcoinWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go index b7d88dba13..7b744f5b9e 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go @@ -11,7 +11,6 @@ import ( "github.com/btcsuite/btcd/chaincfg" - "github.com/OpenBazaar/spvwallet" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcec" @@ -262,15 +261,15 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } func (w *BitcoinCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return nil, err } if txn.Height > 0 { - return nil, spvwallet.BumpFeeAlreadyConfirmedError + return nil, util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, spvwallet.BumpFeeTransactionDeadError + return nil, util.BumpFeeTransactionDeadError } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() @@ -303,7 +302,7 @@ func (w *BitcoinCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error return transactionID, nil } } - return nil, spvwallet.BumpFeeNotFoundError + return nil, util.BumpFeeNotFoundError } func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { @@ -341,7 +340,7 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc txType := P2PKH if redeemScript != nil { txType = P2SH_1of2_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(*redeemScript) + _, err := util.LockTimeFromRedeemScript(*redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_1Sig } @@ -405,7 +404,7 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc timeLocked = true tx.Version = 2 for _, txIn := range tx.TxIn { - locktime, err := spvwallet.LockTimeFromRedeemScript(*redeemScript) + locktime, err := util.LockTimeFromRedeemScript(*redeemScript) if err != nil { return nil, err } @@ -473,7 +472,7 @@ func (w *BitcoinCashWallet) createMultisigSignature(ins []wi.TransactionInput, o // Subtract fee txType := P2SH_2of3_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(redeemScript) + _, err := util.LockTimeFromRedeemScript(redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_2Sigs } @@ -527,7 +526,7 @@ func (w *BitcoinCashWallet) multisign(ins []wi.TransactionInput, outs []wi.Trans // Subtract fee txType := P2SH_2of3_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(redeemScript) + _, err := util.LockTimeFromRedeemScript(redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_2Sigs } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign_test.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign_test.go new file mode 100644 index 0000000000..dea1e01419 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign_test.go @@ -0,0 +1,732 @@ +package bitcoincash + +import ( + "bytes" + "encoding/hex" + "github.com/OpenBazaar/multiwallet/util" + "github.com/gcash/bchd/txscript" + "os" + "testing" + "time" + + "github.com/OpenBazaar/multiwallet/cache" + "github.com/OpenBazaar/multiwallet/datastore" + "github.com/OpenBazaar/multiwallet/keys" + "github.com/OpenBazaar/multiwallet/model/mock" + "github.com/OpenBazaar/multiwallet/service" + "github.com/OpenBazaar/wallet-interface" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcutil/hdkeychain" + "github.com/cpacia/bchutil" + bchhash "github.com/gcash/bchd/chaincfg/chainhash" + bchwire "github.com/gcash/bchd/wire" +) + +type FeeResponse struct { + Priority int `json:"priority"` + Normal int `json:"normal"` + Economic int `json:"economic"` +} + +func newMockWallet() (*BitcoinCashWallet, error) { + mockDb := datastore.NewMockMultiwalletDatastore() + + db, err := mockDb.GetDatastoreForWallet(wallet.BitcoinCash) + if err != nil { + return nil, err + } + params := &chaincfg.MainNetParams + + seed, err := hex.DecodeString("16c034c59522326867593487c03a8f9615fb248406dd0d4ffb3a6b976a248403") + if err != nil { + return nil, err + } + master, err := hdkeychain.NewMaster(seed, params) + if err != nil { + return nil, err + } + km, err := keys.NewKeyManager(db.Keys(), params, master, wallet.BitcoinCash, bitcoinCashAddress) + if err != nil { + return nil, err + } + + fp := util.NewFeeProvider(2000, 300, 200, 100, nil) + + bw := &BitcoinCashWallet{ + params: params, + km: km, + db: db, + fp: fp, + } + cli := mock.NewMockApiClient(bw.AddressToScript) + ws, err := service.NewWalletService(db, km, cli, params, wallet.BitcoinCash, cache.NewMockCacher()) + if err != nil { + return nil, err + } + bw.client = cli + bw.ws = ws + return bw, nil +} + +func TestWalletService_VerifyWatchScriptFilter(t *testing.T) { + // Verify that AddWatchedAddress should never add a script which already represents a key from its own wallet + w, err := newMockWallet() + if err != nil { + t.Fatal(err) + } + keys := w.km.GetKeys() + + addr, err := w.km.KeyToAddress(keys[0]) + if err != nil { + t.Fatal(err) + } + err = w.AddWatchedAddresses(addr) + if err != nil { + t.Fatal(err) + } + + watchScripts, err := w.db.WatchedScripts().GetAll() + if err != nil { + t.Fatal(err) + } + + if len(watchScripts) != 0 { + t.Error("Put watched scripts fails on key manager owned key") + } +} + +func TestWalletService_VerifyWatchScriptPut(t *testing.T) { + // Verify that AddWatchedAddress should add a script which does not represent a key from its own wallet + w, err := newMockWallet() + if err != nil { + t.Fatal(err) + } + + addr, err := w.DecodeAddress("qqx0p0ja3xddkvwldaqwcvrkkgrzx6rjwuzla4ca90") + if err != nil { + t.Fatal(err) + } + + err = w.AddWatchedAddresses(addr) + if err != nil { + t.Fatal(err) + } + + watchScripts, err := w.db.WatchedScripts().GetAll() + if err != nil { + t.Fatal(err) + } + + if len(watchScripts) == 0 { + t.Error("Put watched scripts fails on non-key manager owned key") + } + +} + +func waitForTxnSync(t *testing.T, txnStore wallet.Txns) { + // Look for a known txn, this sucks a bit. It would be better to check if the + // number of stored txns matched the expected, but not all the mock + // transactions are relevant, so the numbers don't add up. + // Even better would be for the wallet to signal that the initial sync was + // done. + lastTxn := mock.MockTransactions[len(mock.MockTransactions)-2] + txHash, err := chainhash.NewHashFromStr(lastTxn.Txid) + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 100; i++ { + if _, err := txnStore.Get(*txHash); err == nil { + return + } + time.Sleep(100 * time.Millisecond) + } + t.Fatal("timeout waiting for wallet to sync transactions") +} + +func TestBitcoinCashWallet_buildTx(t *testing.T) { + w, err := newMockWallet() + if err != nil { + t.Error(err) + } + w.ws.Start() + time.Sleep(time.Second / 2) + + addr, err := w.DecodeAddress("qpf464w2g36kyklq9shvyjk9lvuf6ph7jv3k8qpq0m") + if err != nil { + t.Error(err) + } + // Test build normal tx + tx, err := w.buildTx(1500000, addr, wallet.NORMAL, nil) + if err != nil { + w.DumpTables(os.Stdout) + t.Error(err) + return + } + if !containsOutput(tx, addr) { + t.Error("Built tx does not contain the requested output") + } + if !validInputs(tx, w.db) { + t.Error("Built tx does not contain valid inputs") + } + if !validChangeAddress(tx, w.db, w.params) { + t.Error("Built tx does not contain a valid change output") + } + + // Insuffient funds + _, err = w.buildTx(1000000000, addr, wallet.NORMAL, nil) + if err != wallet.ErrorInsuffientFunds { + t.Error("Failed to throw insuffient funds error") + } + + // Dust + _, err = w.buildTx(1, addr, wallet.NORMAL, nil) + if err != wallet.ErrorDustAmount { + t.Error("Failed to throw dust error") + } +} + +func TestBitcoinCashWallet_buildSpendAllTx(t *testing.T) { + w, err := newMockWallet() + if err != nil { + t.Error(err) + } + w.ws.Start() + time.Sleep(time.Second / 2) + + waitForTxnSync(t, w.db.Txns()) + addr, err := w.DecodeAddress("qpyafty5hf6uwjtd8y5tvgzeawfeyfhj55ke8l2dy7") + if err != nil { + t.Error(err) + } + + // Test build spendAll tx + tx, err := w.buildSpendAllTx(addr, wallet.NORMAL) + if err != nil { + t.Error(err) + } + utxos, err := w.db.Utxos().GetAll() + if err != nil { + t.Fatal(err) + } + spendableUtxos := 0 + for _, u := range utxos { + if !u.WatchOnly { + spendableUtxos++ + } + } + if len(tx.TxIn) != spendableUtxos { + t.Error("Built tx does not spend all available utxos") + } + if !containsOutput(tx, addr) { + t.Error("Built tx does not contain the requested output") + } + if !validInputs(tx, w.db) { + t.Error("Built tx does not contain valid inputs") + } + if len(tx.TxOut) != 1 { + t.Error("Built tx should only have one output") + } + + bchTx := bchwire.MsgTx{ + Version: tx.Version, + LockTime: tx.LockTime, + } + for _, in := range tx.TxIn { + hash := bchhash.Hash(in.PreviousOutPoint.Hash) + op := bchwire.NewOutPoint(&hash, in.PreviousOutPoint.Index) + newIn := bchwire.TxIn{ + PreviousOutPoint: *op, + Sequence: in.Sequence, + SignatureScript: in.SignatureScript, + } + bchTx.TxIn = append(bchTx.TxIn, &newIn) + } + for _, out := range tx.TxOut { + newOut := bchwire.TxOut{ + Value: out.Value, + PkScript: out.PkScript, + } + bchTx.TxOut = append(bchTx.TxOut, &newOut) + } + + // Verify the signatures on each input using the scripting engine + for i, in := range tx.TxIn { + var prevScript []byte + var amt int64 + for _, u := range utxos { + if util.OutPointsEqual(u.Op, in.PreviousOutPoint) { + prevScript = u.ScriptPubkey + amt = u.Value + break + } + } + vm, err := txscript.NewEngine(prevScript, &bchTx, i, txscript.StandardVerifyFlags, nil, nil, amt) + if err != nil { + t.Fatal(err) + } + if err := vm.Execute(); err != nil { + t.Error(err) + } + } +} + +func containsOutput(tx *wire.MsgTx, addr btcutil.Address) bool { + for _, o := range tx.TxOut { + script, _ := bchutil.PayToAddrScript(addr) + if bytes.Equal(script, o.PkScript) { + return true + } + } + return false +} + +func validInputs(tx *wire.MsgTx, db wallet.Datastore) bool { + utxos, _ := db.Utxos().GetAll() + uMap := make(map[wire.OutPoint]bool) + for _, u := range utxos { + uMap[u.Op] = true + } + for _, in := range tx.TxIn { + if !uMap[in.PreviousOutPoint] { + return false + } + } + return true +} + +func validChangeAddress(tx *wire.MsgTx, db wallet.Datastore, params *chaincfg.Params) bool { + for _, out := range tx.TxOut { + addr, err := bchutil.ExtractPkScriptAddrs(out.PkScript, params) + if err != nil { + continue + } + _, err = db.Keys().GetPathForKey(addr.ScriptAddress()) + if err == nil { + return true + } + } + return false +} + +func TestBitcoinCashWallet_GenerateMultisigScript(t *testing.T) { + w, err := newMockWallet() + if err != nil { + t.Error(err) + } + key1, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + pubkey1, err := key1.ECPubKey() + if err != nil { + t.Error(err) + } + key2, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + pubkey2, err := key2.ECPubKey() + if err != nil { + t.Error(err) + } + key3, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + pubkey3, err := key3.ECPubKey() + if err != nil { + t.Error(err) + } + keys := []hdkeychain.ExtendedKey{*key1, *key2, *key3} + + // test without timeout + addr, redeemScript, err := w.generateMultisigScript(keys, 2, 0, nil) + if err != nil { + t.Error(err) + } + if addr.String() != "pzjfg2pg2q6uz445vx7hvmuw6rp0ay5f9q9vnhwqfl" { + t.Error("Returned invalid address") + } + + rs := "52" + // OP_2 + "21" + // OP_PUSHDATA(33) + hex.EncodeToString(pubkey1.SerializeCompressed()) + // pubkey1 + "21" + // OP_PUSHDATA(33) + hex.EncodeToString(pubkey2.SerializeCompressed()) + // pubkey2 + "21" + // OP_PUSHDATA(33) + hex.EncodeToString(pubkey3.SerializeCompressed()) + // pubkey3 + "53" + // OP_3 + "ae" // OP_CHECKMULTISIG + rsBytes, err := hex.DecodeString(rs) + if err != nil { + t.Error(err) + } + if !bytes.Equal(rsBytes, redeemScript) { + t.Error("Returned invalid redeem script") + } + + // test with timeout + key4, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + pubkey4, err := key4.ECPubKey() + if err != nil { + t.Error(err) + } + addr, redeemScript, err = w.generateMultisigScript(keys, 2, time.Hour*10, key4) + if err != nil { + t.Error(err) + } + if addr.String() != "ppx5mmammxfs42m0p6ypvf6znnkq3llskvlz0texus" { + t.Error("Returned invalid address") + } + + rs = "63" + // OP_IF + "52" + // OP_2 + "21" + // OP_PUSHDATA(33) + hex.EncodeToString(pubkey1.SerializeCompressed()) + // pubkey1 + "21" + // OP_PUSHDATA(33) + hex.EncodeToString(pubkey2.SerializeCompressed()) + // pubkey2 + "21" + // OP_PUSHDATA(33) + hex.EncodeToString(pubkey3.SerializeCompressed()) + // pubkey3 + "53" + // OP_3 + "ae" + // OP_CHECKMULTISIG + "67" + // OP_ELSE + "01" + // OP_PUSHDATA(1) + "3c" + // 60 blocks + "b2" + // OP_CHECKSEQUENCEVERIFY + "75" + // OP_DROP + "21" + // OP_PUSHDATA(33) + hex.EncodeToString(pubkey4.SerializeCompressed()) + // timeout pubkey + "ac" + // OP_CHECKSIG + "68" // OP_ENDIF + rsBytes, err = hex.DecodeString(rs) + if !bytes.Equal(rsBytes, redeemScript) { + t.Error("Returned invalid redeem script") + } +} + +func TestBitcoinCashWallet_newUnsignedTransaction(t *testing.T) { + w, err := newMockWallet() + w.ws.Start() + time.Sleep(time.Second / 2) + if err != nil { + t.Error(err) + } + utxos, err := w.db.Utxos().GetAll() + if err != nil { + t.Error(err) + } + addr, err := w.DecodeAddress("ppx5mmammxfs42m0p6ypvf6znnkq3llskvlz0texus") + if err != nil { + t.Error(err) + } + + script, err := bchutil.PayToAddrScript(addr) + if err != nil { + t.Error(err) + } + out := wire.NewTxOut(10000, script) + outputs := []*wire.TxOut{out} + + changeSource := func() ([]byte, error) { + addr := w.CurrentAddress(wallet.INTERNAL) + script, err := bchutil.PayToAddrScript(addr) + if err != nil { + return []byte{}, err + } + return script, nil + } + + inputSource := func(target btcutil.Amount) (total btcutil.Amount, inputs []*wire.TxIn, inputValues []btcutil.Amount, scripts [][]byte, err error) { + total += btcutil.Amount(utxos[0].Value) + in := wire.NewTxIn(&utxos[0].Op, []byte{}, [][]byte{}) + in.Sequence = 0 // Opt-in RBF so we can bump fees + inputs = append(inputs, in) + return total, inputs, inputValues, scripts, nil + } + + // Regular transaction + authoredTx, err := newUnsignedTransaction(outputs, btcutil.Amount(1000), inputSource, changeSource) + if err != nil { + t.Error(err) + } + if len(authoredTx.Tx.TxOut) != 2 { + t.Error("Returned incorrect number of outputs") + } + if len(authoredTx.Tx.TxIn) != 1 { + t.Error("Returned incorrect number of inputs") + } + + // Insufficient funds + outputs[0].Value = 1000000000 + _, err = newUnsignedTransaction(outputs, btcutil.Amount(1000), inputSource, changeSource) + if err == nil { + t.Error("Failed to return insuffient funds error") + } +} + +func TestBitcoinCashWallet_CreateMultisigSignature(t *testing.T) { + w, err := newMockWallet() + if err != nil { + t.Error(err) + } + ins, outs, redeemScript, err := buildTxData(w) + if err != nil { + t.Error(err) + } + + key1, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + + sigs, err := w.CreateMultisigSignature(ins, outs, key1, redeemScript, 50) + if err != nil { + t.Error(err) + } + if len(sigs) != 2 { + t.Error(err) + } + for _, sig := range sigs { + if len(sig.Signature) == 0 { + t.Error("Returned empty signature") + } + } +} + +func buildTxData(w *BitcoinCashWallet) ([]wallet.TransactionInput, []wallet.TransactionOutput, []byte, error) { + redeemScript := "522103c157f2a7c178430972263232c9306110090c50b44d4e906ecd6d377eec89a53c210205b02b9dbe570f36d1c12e3100e55586b2b9dc61d6778c1d24a8eaca03625e7e21030c83b025cd6bdd8c06e93a2b953b821b4a8c29da211335048d7dc3389706d7e853ae" + redeemScriptBytes, err := hex.DecodeString(redeemScript) + if err != nil { + return nil, nil, nil, err + } + h1, err := hex.DecodeString("1a20f4299b4fa1f209428dace31ebf4f23f13abd8ed669cebede118343a6ae05") + if err != nil { + return nil, nil, nil, err + } + in1 := wallet.TransactionInput{ + OutpointHash: h1, + OutpointIndex: 1, + } + h2, err := hex.DecodeString("458d88b4ae9eb4a347f2e7f5592f1da3b9ddf7d40f307f6e5d7bc107a9b3e90e") + if err != nil { + return nil, nil, nil, err + } + in2 := wallet.TransactionInput{ + OutpointHash: h2, + OutpointIndex: 0, + } + addr, err := w.DecodeAddress("ppx5mmammxfs42m0p6ypvf6znnkq3llskvlz0texus") + if err != nil { + return nil, nil, nil, err + } + + out := wallet.TransactionOutput{ + Value: 20000, + Address: addr, + } + return []wallet.TransactionInput{in1, in2}, []wallet.TransactionOutput{out}, redeemScriptBytes, nil +} + +func TestBitcoinCashWallet_Multisign(t *testing.T) { + w, err := newMockWallet() + if err != nil { + t.Error(err) + } + ins, outs, redeemScript, err := buildTxData(w) + if err != nil { + t.Error(err) + } + + key1, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + + key2, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + + sigs1, err := w.CreateMultisigSignature(ins, outs, key1, redeemScript, 50) + if err != nil { + t.Error(err) + } + if len(sigs1) != 2 { + t.Error(err) + } + sigs2, err := w.CreateMultisigSignature(ins, outs, key2, redeemScript, 50) + if err != nil { + t.Error(err) + } + if len(sigs2) != 2 { + t.Error(err) + } + txBytes, err := w.Multisign(ins, outs, sigs1, sigs2, redeemScript, 50, false) + if err != nil { + t.Error(err) + } + + tx := wire.NewMsgTx(0) + tx.BtcDecode(bytes.NewReader(txBytes), wire.ProtocolVersion, wire.WitnessEncoding) + if len(tx.TxIn) != 2 { + t.Error("Transactions has incorrect number of inputs") + } + if len(tx.TxOut) != 1 { + t.Error("Transactions has incorrect number of outputs") + } + for _, in := range tx.TxIn { + if len(in.SignatureScript) == 0 { + t.Error("Input script has zero length") + } + } +} + +func TestBitcoinCashWallet_bumpFee(t *testing.T) { + w, err := newMockWallet() + w.ws.Start() + time.Sleep(time.Second / 2) + if err != nil { + t.Error(err) + } + txns, err := w.db.Txns().GetAll(false) + if err != nil { + t.Error(err) + } + ch, err := chainhash.NewHashFromStr(txns[2].Txid) + if err != nil { + t.Error(err) + } + utxos, err := w.db.Utxos().GetAll() + if err != nil { + t.Error(err) + } + for _, u := range utxos { + if u.Op.Hash.IsEqual(ch) { + u.AtHeight = 0 + w.db.Utxos().Put(u) + } + } + + w.db.Txns().UpdateHeight(*ch, 0, time.Now()) + + // Test unconfirmed + _, err = w.bumpFee(*ch) + if err != nil { + t.Error(err) + } + + err = w.db.Txns().UpdateHeight(*ch, 1289597, time.Now()) + if err != nil { + t.Error(err) + } + + // Test confirmed + _, err = w.bumpFee(*ch) + if err == nil { + t.Error("Should not be able to bump fee of confirmed txs") + } +} + +func TestBitcoinCashWallet_sweepAddress(t *testing.T) { + w, err := newMockWallet() + w.ws.Start() + time.Sleep(time.Second / 2) + if err != nil { + t.Error(err) + } + utxos, err := w.db.Utxos().GetAll() + if err != nil { + t.Error(err) + } + var in wallet.TransactionInput + var key *hdkeychain.ExtendedKey + for _, ut := range utxos { + if ut.Value > 0 && !ut.WatchOnly { + addr, err := w.ScriptToAddress(ut.ScriptPubkey) + if err != nil { + t.Error(err) + } + key, err = w.km.GetKeyForScript(addr.ScriptAddress()) + if err != nil { + t.Error(err) + } + h, err := hex.DecodeString(ut.Op.Hash.String()) + if err != nil { + t.Error(err) + } + in = wallet.TransactionInput{ + LinkedAddress: addr, + Value: ut.Value, + OutpointIndex: ut.Op.Index, + OutpointHash: h, + } + break + } + } + // P2PKH addr + _, err = w.sweepAddress([]wallet.TransactionInput{in}, nil, key, nil, wallet.NORMAL) + if err != nil { + t.Error(err) + return + } + + // 1 of 2 P2WSH + for _, ut := range utxos { + if ut.Value > 0 && ut.WatchOnly { + h, err := hex.DecodeString(ut.Op.Hash.String()) + if err != nil { + t.Error(err) + } + addr, err := w.ScriptToAddress(ut.ScriptPubkey) + if err != nil { + t.Error(err) + } + in = wallet.TransactionInput{ + LinkedAddress: addr, + Value: ut.Value, + OutpointIndex: ut.Op.Index, + OutpointHash: h, + } + } + } + key1, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + + key2, err := w.km.GetFreshKey(wallet.INTERNAL) + if err != nil { + t.Error(err) + } + _, redeemScript, err := w.GenerateMultisigScript([]hdkeychain.ExtendedKey{*key1, *key2}, 1, 0, nil) + if err != nil { + t.Error(err) + } + _, err = w.sweepAddress([]wallet.TransactionInput{in}, nil, key1, &redeemScript, wallet.NORMAL) + if err != nil { + t.Error(err) + } +} + +func TestBitcoinCashWallet_estimateSpendFee(t *testing.T) { + w, err := newMockWallet() + w.ws.Start() + time.Sleep(time.Second / 2) + if err != nil { + t.Error(err) + } + fee, err := w.estimateSpendFee(1000, wallet.NORMAL) + if err != nil { + t.Error(err) + } + if fee <= 0 { + t.Error("Returned incorrect fee") + } +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go index 99328ce5a4..efa16a6e34 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go @@ -249,7 +249,7 @@ func (w *BitcoinCashWallet) Transactions() ([]wi.Txn, error) { } func (w *BitcoinCashWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -275,7 +275,7 @@ func (w *BitcoinCashWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) return txn, err } -func (w *BitcoinCashWallet) ChainTip() (uint32, chainhash.Hash) { +func (w *BitcoinCashWallet) ChainTip() (uint32, string) { return w.ws.ChainTip() } @@ -390,7 +390,7 @@ func (w *BitcoinCashWallet) ReSyncBlockchain(fromTime time.Time) { } func (w *BitcoinCashWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/cli/cli.go b/vendor/github.com/OpenBazaar/multiwallet/cli/cli.go new file mode 100644 index 0000000000..fcd61dc799 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/cli/cli.go @@ -0,0 +1,323 @@ +package cli + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "github.com/OpenBazaar/multiwallet/api" + "github.com/OpenBazaar/multiwallet/api/pb" + "github.com/jessevdk/go-flags" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +func SetupCli(parser *flags.Parser) { + // Add commands to parser + parser.AddCommand("stop", + "stop the wallet", + "The stop command disconnects from peers and shuts down the wallet", + &stop) + parser.AddCommand("currentaddress", + "get the current bitcoin address", + "Returns the first unused address in the keychain\n\n"+ + "Args:\n"+ + "1. coinType (string)\n"+ + "2. purpose (string default=external) The purpose for the address. Can be external for receiving from outside parties or internal for example, for change.\n\n"+ + "Examples:\n"+ + "> multiwallet currentaddress bitcoin\n"+ + "1DxGWC22a46VPEjq8YKoeVXSLzB7BA8sJS\n"+ + "> multiwallet currentaddress bitcoin internal\n"+ + "18zAxgfKx4NuTUGUEuB8p7FKgCYPM15DfS\n", + ¤tAddress) + parser.AddCommand("newaddress", + "get a new bitcoin address", + "Returns a new unused address in the keychain. Use caution when using this function as generating too many new addresses may cause the keychain to extend further than the wallet's lookahead window, meaning it might fail to recover all transactions when restoring from seed. CurrentAddress is safer as it never extends past the lookahead window.\n\n"+ + "Args:\n"+ + "1. coinType (string)\n"+ + "2. purpose (string default=external) The purpose for the address. Can be external for receiving from outside parties or internal for example, for change.\n\n"+ + "Examples:\n"+ + "> multiwallet newaddress bitcoin\n"+ + "1DxGWC22a46VPEjq8YKoeVXSLzB7BA8sJS\n"+ + "> multiwallet newaddress bitcoin internal\n"+ + "18zAxgfKx4NuTUGUEuB8p7FKgCYPM15DfS\n", + &newAddress) + parser.AddCommand("chaintip", + "return the height of the chain", + "Returns the height of the best chain of blocks", + &chainTip) + parser.AddCommand("dumptables", + "print out the database tables", + "Prints each row in the database tables", + &dumpTables) + parser.AddCommand("spend", + "send bitcoins", + "Send bitcoins to the given address\n\n"+ + "Args:\n"+ + "1. coinType (string)\n"+ + "2. address (string) The recipient's bitcoin address\n"+ + "3. amount (integer) The amount to send in satoshi"+ + "4. feelevel (string default=normal) The fee level: economic, normal, priority\n\n"+ + "5. memo (string) The orderID\n"+ + "Examples:\n"+ + "> multiwallet spend bitcoin 1DxGWC22a46VPEjq8YKoeVXSLzB7BA8sJS 1000000\n"+ + "82bfd45f3564e0b5166ab9ca072200a237f78499576e9658b20b0ccd10ff325c 1a3w"+ + "> multiwallet spend bitcoin 1DxGWC22a46VPEjq8YKoeVXSLzB7BA8sJS 3000000000 priority\n"+ + "82bfd45f3564e0b5166ab9ca072200a237f78499576e9658b20b0ccd10ff325c 4wq2", + &spend) + parser.AddCommand("balance", + "get the wallet's balances", + "Returns the confirmed and unconfirmed balances for the specified coin", + &balance) +} + +func coinType(args []string) pb.CoinType { + if len(args) == 0 { + return pb.CoinType_BITCOIN + } + switch strings.ToLower(args[0]) { + case "bitcoin": + return pb.CoinType_BITCOIN + case "bitcoincash": + return pb.CoinType_BITCOIN_CASH + case "zcash": + return pb.CoinType_ZCASH + case "litecoin": + return pb.CoinType_LITECOIN + case "ethereum": + return pb.CoinType_ETHEREUM + default: + return pb.CoinType_BITCOIN + } +} + +func newGRPCClient() (pb.APIClient, *grpc.ClientConn, error) { + // Set up a connection to the server. + conn, err := grpc.Dial(api.Addr, grpc.WithInsecure()) + if err != nil { + return nil, nil, err + } + client := pb.NewAPIClient(conn) + return client, conn, nil +} + +type Stop struct{} + +var stop Stop + +func (x *Stop) Execute(args []string) error { + client, conn, err := newGRPCClient() + if err != nil { + return err + } + defer conn.Close() + client.Stop(context.Background(), &pb.Empty{}) + return nil +} + +type CurrentAddress struct{} + +var currentAddress CurrentAddress + +func (x *CurrentAddress) Execute(args []string) error { + client, conn, err := newGRPCClient() + if err != nil { + return err + } + defer conn.Close() + var purpose pb.KeyPurpose + userSelection := "" + + t := coinType(args) + if len(args) == 1 { + userSelection = args[0] + } else if len(args) == 2 { + userSelection = args[1] + } + switch strings.ToLower(userSelection) { + case "internal": + purpose = pb.KeyPurpose_INTERNAL + case "external": + purpose = pb.KeyPurpose_EXTERNAL + default: + purpose = pb.KeyPurpose_EXTERNAL + } + + resp, err := client.CurrentAddress(context.Background(), &pb.KeySelection{Coin: t, Purpose: purpose}) + if err != nil { + return err + } + fmt.Println(resp.Addr) + return nil +} + +type NewAddress struct{} + +var newAddress NewAddress + +func (x *NewAddress) Execute(args []string) error { + client, conn, err := newGRPCClient() + if err != nil { + return err + } + defer conn.Close() + if len(args) == 0 { + return errors.New("Must select coin type") + } + t := coinType(args) + var purpose pb.KeyPurpose + userSelection := "" + if len(args) == 1 { + userSelection = args[0] + } else if len(args) == 2 { + userSelection = args[1] + } + switch strings.ToLower(userSelection) { + case "internal": + purpose = pb.KeyPurpose_INTERNAL + case "external": + purpose = pb.KeyPurpose_EXTERNAL + default: + purpose = pb.KeyPurpose_EXTERNAL + } + resp, err := client.NewAddress(context.Background(), &pb.KeySelection{Coin: t, Purpose: purpose}) + if err != nil { + return err + } + fmt.Println(resp.Addr) + return nil +} + +type ChainTip struct{} + +var chainTip ChainTip + +func (x *ChainTip) Execute(args []string) error { + client, conn, err := newGRPCClient() + if err != nil { + return err + } + defer conn.Close() + if len(args) == 0 { + return errors.New("Must select coin type") + } + t := coinType(args) + resp, err := client.ChainTip(context.Background(), &pb.CoinSelection{Coin: t}) + if err != nil { + return err + } + fmt.Println(resp.Height) + return nil +} + +type DumpTables struct{} + +var dumpTables DumpTables + +func (x *DumpTables) Execute(args []string) error { + client, conn, err := newGRPCClient() + if err != nil { + return err + } + defer conn.Close() + if len(args) == 0 { + return errors.New("Must select coin type") + } + t := coinType(args) + resp, err := client.DumpTables(context.Background(), &pb.CoinSelection{Coin: t}) + if err != nil { + return err + } + for { + row, err := resp.Recv() + if err != nil { + // errors when no more rows and exits + return err + } + fmt.Println(row.Data) + } +} + +type Spend struct{} + +var spend Spend + +func (x *Spend) Execute(args []string) error { + var ( + address string + feeLevel pb.FeeLevel + referenceID string + userSelection string + + client, conn, err = newGRPCClient() + ) + if err != nil { + return err + } + defer conn.Close() + + if len(args) == 0 { + return errors.New("Must select coin type") + } + if len(args) > 4 { + address = args[1] + userSelection = args[3] + referenceID = args[4] + } + if len(args) < 4 { + return errors.New("Address and amount are required") + } + + switch strings.ToLower(userSelection) { + case "economic": + feeLevel = pb.FeeLevel_ECONOMIC + case "normal": + feeLevel = pb.FeeLevel_NORMAL + case "priority": + feeLevel = pb.FeeLevel_PRIORITY + default: + feeLevel = pb.FeeLevel_NORMAL + } + + amt, err := strconv.Atoi(args[2]) + if err != nil { + return err + } + + resp, err := client.Spend(context.Background(), &pb.SpendInfo{ + Coin: coinType(args), + Address: address, + Amount: uint64(amt), + FeeLevel: feeLevel, + Memo: referenceID, + }) + if err != nil { + return err + } + + fmt.Println(resp.Hash) + return nil +} + +type Balance struct{} + +var balance Balance + +func (x *Balance) Execute(args []string) error { + client, conn, err := newGRPCClient() + if err != nil { + return err + } + defer conn.Close() + if len(args) == 0 { + return errors.New("Must select coin type") + } + t := coinType(args) + resp, err := client.Balance(context.Background(), &pb.CoinSelection{Coin: t}) + if err != nil { + return err + } + fmt.Printf("Confirmed: %d, Unconfirmed: %d\n", resp.Confirmed, resp.Unconfirmed) + return nil +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go b/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go index 46a15a0e1d..88091c2ded 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go +++ b/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go @@ -263,6 +263,7 @@ func (i *BlockBookClient) GetTransaction(txid string) (*model.Transaction, error type resOut struct { model.Output Spent bool `json:"spent"` + Addresses []string `json:"addresses"` } type resTx struct { model.Transaction @@ -281,6 +282,9 @@ func (i *BlockBookClient) GetTransaction(txid string) (*model.Transaction, error return nil, fmt.Errorf("error decoding transactions: %s", err) } for n, in := range tx.Vin { + if in.ValueIface == "" || in.ValueIface == nil { + in.ValueIface = "0" + } f, err := model.ToFloat(in.ValueIface) if err != nil { return nil, err @@ -288,6 +292,9 @@ func (i *BlockBookClient) GetTransaction(txid string) (*model.Transaction, error tx.Vin[n].Value = f } for n, out := range tx.Vout { + if out.ValueIface == "" || out.ValueIface == nil{ + out.ValueIface = "0" + } f, err := model.ToFloat(out.ValueIface) if err != nil { return nil, err @@ -334,6 +341,9 @@ func (i *BlockBookClient) GetTransaction(txid string) (*model.Transaction, error for i, addr := range newOut.ScriptPubKey.Addresses { newOut.ScriptPubKey.Addresses[i] = maybeTrimCashAddrPrefix(addr) } + if len(o.Addresses) > 0 { + newOut.ScriptPubKey.Addresses = o.Addresses + } ctx.Outputs = append(ctx.Outputs, newOut) } return &ctx, nil @@ -387,6 +397,7 @@ func (i *BlockBookClient) getTransactions(addr string) ([]model.Transaction, err type resAddr struct { TotalPages int `json:"totalPages"` Transactions []string `json:"transactions"` + Txids []string `json:"txids"` } type txOrError struct { Tx *model.Transaction @@ -409,6 +420,10 @@ func (i *BlockBookClient) getTransactions(addr string) ([]model.Transaction, err return nil, fmt.Errorf("error decoding addrs response: %s", err) } txChan := make(chan txOrError) + if len(res.Transactions) == 0 && len(res.Txids) > 0 { + res.Transactions = res.Txids + } + go func() { var wg sync.WaitGroup wg.Add(len(res.Transactions)) @@ -632,6 +647,7 @@ func (i *BlockBookClient) setupListeners() error { i.SocketClient.Emit("subscribe", protocol.ToArgArray("bitcoind/hashblock")) i.SocketClient.On("bitcoind/addresstxid", func(h *gosocketio.Channel, arg interface{}) { + fmt.Println("On addr txid", arg) m, ok := arg.(map[string]interface{}) if !ok { Log.Errorf("error checking type after socket notification: %T", arg) diff --git a/vendor/github.com/OpenBazaar/multiwallet/client/pool_test.go b/vendor/github.com/OpenBazaar/multiwallet/client/pool_test.go new file mode 100644 index 0000000000..dd547749a7 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/client/pool_test.go @@ -0,0 +1,254 @@ +package client_test + +import ( + "fmt" + "net/http" + "testing" + "time" + + "github.com/OpenBazaar/multiwallet/client" + "github.com/OpenBazaar/multiwallet/model" + "github.com/OpenBazaar/multiwallet/model/mock" + "github.com/OpenBazaar/multiwallet/test/factory" + "github.com/jarcoal/httpmock" +) + +func replaceHTTPClientOnClientPool(p *client.ClientPool, c http.Client) { + for _, cp := range p.Clients() { + cp.HTTPClient = c + } + p.HTTPClient = c +} + +func mustPrepareClientPool(endpoints []string) (*client.ClientPool, func()) { + var p, err = client.NewClientPool(endpoints, nil) + if err != nil { + panic(err.Error()) + } + + mockedHTTPClient := http.Client{} + httpmock.ActivateNonDefault(&mockedHTTPClient) + replaceHTTPClientOnClientPool(p, mockedHTTPClient) + + mock.MockWebsocketClientOnClientPool(p) + err = p.Start() + if err != nil { + panic(err.Error()) + } + + return p, func() { + httpmock.DeactivateAndReset() + p.Close() + } +} + +func TestRequestRotatesServersOn500(t *testing.T) { + var ( + endpointOne = "http://localhost:8332" + endpointTwo = "http://localhost:8336" + p, cleanup = mustPrepareClientPool([]string{endpointOne, endpointTwo}) + expectedTx = factory.NewTransaction() + txid = "1be612e4f2b79af279e0b307337924072b819b3aca09fcb20370dd9492b83428" + ) + defer cleanup() + + httpmock.RegisterResponder(http.MethodGet, fmt.Sprintf("%s/tx/%s", endpointOne, txid), + func(req *http.Request) (*http.Response, error) { + return httpmock.NewJsonResponse(http.StatusInternalServerError, expectedTx) + }, + ) + httpmock.RegisterResponder(http.MethodGet, fmt.Sprintf("%s/tx/%s", endpointTwo, txid), + func(req *http.Request) (*http.Response, error) { + return httpmock.NewJsonResponse(http.StatusOK, expectedTx) + }, + ) + + _, err := p.GetTransaction(txid) + if err != nil { + t.Errorf("expected successful transaction, but got error: %s", err.Error()) + } +} + +func TestRequestRetriesTimeoutsToExhaustionThenRotates(t *testing.T) { + var ( + endpointOne = "http://localhost:8332" + endpointTwo = "http://localhost:8336" + fastTimeoutClient = http.Client{Timeout: 500000 * time.Nanosecond} + p, err = client.NewClientPool([]string{endpointOne, endpointTwo}, nil) + ) + if err != nil { + t.Fatal(err) + } + + httpmock.DeactivateAndReset() + httpmock.ActivateNonDefault(&fastTimeoutClient) + replaceHTTPClientOnClientPool(p, fastTimeoutClient) + mock.MockWebsocketClientOnClientPool(p) + if err = p.Start(); err != nil { + t.Fatal(err) + } + defer func() { + httpmock.DeactivateAndReset() + p.Close() + }() + + var ( + txid = "1be612e4f2b79af279e0b307337924072b819b3aca09fcb20370dd9492b83428" + expectedAttempts = uint(3) + requestAttempts uint + laggyResponse = func(req *http.Request) (*http.Response, error) { + if requestAttempts < expectedAttempts { + requestAttempts++ + time.Sleep(1 * time.Second) + return nil, fmt.Errorf("timeout") + } + return httpmock.NewJsonResponse(http.StatusOK, factory.NewTransaction()) + } + ) + httpmock.RegisterResponder(http.MethodGet, fmt.Sprintf("%s/tx/%s", endpointOne, txid), laggyResponse) + httpmock.RegisterResponder(http.MethodGet, fmt.Sprintf("%s/tx/%s", endpointTwo, txid), laggyResponse) + + _, err = p.GetTransaction(txid) + if err == nil { + t.Errorf("expected getTransaction to respond with timeout error, but did not") + return + } + if requestAttempts != expectedAttempts { + t.Errorf("expected initial server to be attempted %d times, but was attempted only %d", expectedAttempts, requestAttempts) + } + _, err = p.GetTransaction(txid) + if err != nil { + t.Errorf("expected getTransaction to rotate to the next server and succeed, but returned error: %s", err.Error()) + } +} + +func TestPoolBlockNotifyWorksAfterRotation(t *testing.T) { + var ( + endpointOne = "http://localhost:8332" + endpointTwo = "http://localhost:8336" + testHash = "0000000000000000003f1fb88ac3dab0e607e87def0e9031f7bea02cb464a04f" + txid = "1be612e4f2b79af279e0b307337924072b819b3aca09fcb20370dd9492b83428" + testPath = func(host string) string { return fmt.Sprintf("%s/tx/%s", host, txid) } + p, cleanup = mustPrepareClientPool([]string{endpointOne, endpointTwo}) + ) + defer cleanup() + + // GetTransaction should fail for endpoint one and succeed for endpoint two + var ( + beenBad bool + badThenGood = func(req *http.Request) (*http.Response, error) { + if beenBad { + return httpmock.NewJsonResponse(http.StatusOK, factory.NewTransaction()) + } + beenBad = true + return httpmock.NewJsonResponse(http.StatusInternalServerError, nil) + } + ) + httpmock.RegisterResponder(http.MethodGet, testPath(endpointOne), badThenGood) + httpmock.RegisterResponder(http.MethodGet, testPath(endpointTwo), badThenGood) + + go func() { + c := p.PoolManager().AcquireCurrentWhenReady() + c.BlockChannel() <- model.Block{Hash: testHash} + p.PoolManager().ReleaseCurrent() + }() + + ticker := time.NewTicker(time.Second * 2) + select { + case <-ticker.C: + t.Error("Timed out waiting for block") + case b := <-p.BlockNotify(): + if b.Hash != testHash { + t.Error("Returned incorrect block hash") + } + } + ticker.Stop() + + // request transaction triggers rotation + if _, err := p.GetTransaction(txid); err != nil { + t.Fatal(err) + } + + go func() { + c := p.PoolManager().AcquireCurrentWhenReady() + c.BlockChannel() <- model.Block{Hash: testHash} + p.PoolManager().ReleaseCurrent() + }() + + ticker = time.NewTicker(time.Second * 2) + select { + case <-ticker.C: + t.Error("Timed out waiting for block") + case b := <-p.BlockNotify(): + if b.Hash != testHash { + t.Error("Returned incorrect block hash") + } + } + ticker.Stop() +} + +func TestTransactionNotifyWorksAfterRotation(t *testing.T) { + var ( + endpointOne = "http://localhost:8332" + endpointTwo = "http://localhost:8336" + expectedTx = factory.NewTransaction() + expectedTxid = "500000e4f2b79af279e0b307337924072b819b3aca09fcb20370dd9492b83428" + testPath = func(host string) string { return fmt.Sprintf("%s/tx/%s", host, expectedTxid) } + p, cleanup = mustPrepareClientPool([]string{endpointOne, endpointTwo}) + ) + defer cleanup() + expectedTx.Txid = expectedTxid + + // GetTransaction should fail for endpoint one and succeed for endpoint two + var ( + beenBad bool + badThenGood = func(req *http.Request) (*http.Response, error) { + if beenBad { + return httpmock.NewJsonResponse(http.StatusOK, expectedTx) + } + beenBad = true + return httpmock.NewJsonResponse(http.StatusInternalServerError, nil) + } + ) + httpmock.RegisterResponder(http.MethodGet, testPath(endpointOne), badThenGood) + httpmock.RegisterResponder(http.MethodGet, testPath(endpointTwo), badThenGood) + + go func() { + c := p.PoolManager().AcquireCurrentWhenReady() + c.TxChannel() <- expectedTx + p.PoolManager().ReleaseCurrent() + }() + + ticker := time.NewTicker(time.Second * 2) + select { + case <-ticker.C: + t.Error("Timed out waiting for tx") + case b := <-p.TransactionNotify(): + if b.Txid != expectedTx.Txid { + t.Error("Returned incorrect tx hash") + } + } + ticker.Stop() + + // request transaction triggers rotation + if _, err := p.GetTransaction(expectedTxid); err != nil { + t.Fatal(err) + } + + go func() { + c := p.PoolManager().AcquireCurrentWhenReady() + c.TxChannel() <- expectedTx + p.PoolManager().ReleaseCurrent() + }() + + ticker = time.NewTicker(time.Second * 2) + select { + case <-ticker.C: + t.Error("Timed out waiting for tx") + case b := <-p.TransactionNotify(): + if b.Txid != expectedTx.Txid { + t.Error("Returned incorrect tx hash") + } + } + ticker.Stop() +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/cmd/multiwallet/main.go b/vendor/github.com/OpenBazaar/multiwallet/cmd/multiwallet/main.go new file mode 100644 index 0000000000..b0210137ff --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/cmd/multiwallet/main.go @@ -0,0 +1,83 @@ +package main + +import ( + "fmt" + "os" + "os/signal" + "sync" + + "github.com/OpenBazaar/multiwallet" + "github.com/OpenBazaar/multiwallet/api" + "github.com/OpenBazaar/multiwallet/cli" + "github.com/OpenBazaar/multiwallet/config" + wi "github.com/OpenBazaar/wallet-interface" + "github.com/btcsuite/btcd/chaincfg" + "github.com/jessevdk/go-flags" +) + +const WALLET_VERSION = "0.1.0" + +var parser = flags.NewParser(nil, flags.Default) + +type Start struct { + Testnet bool `short:"t" long:"testnet" description:"use the test network"` +} +type Version struct{} + +var start Start +var version Version +var mw multiwallet.MultiWallet + +func main() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + for range c { + fmt.Println("Multiwallet shutting down...") + os.Exit(1) + } + }() + parser.AddCommand("start", + "start the wallet", + "The start command starts the wallet daemon", + &start) + parser.AddCommand("version", + "print the version number", + "Print the version number and exit", + &version) + cli.SetupCli(parser) + if _, err := parser.Parse(); err != nil { + os.Exit(1) + } +} + +func (x *Version) Execute(args []string) error { + fmt.Println(WALLET_VERSION) + return nil +} + +func (x *Start) Execute(args []string) error { + m := make(map[wi.CoinType]bool) + m[wi.Bitcoin] = true + m[wi.BitcoinCash] = true + m[wi.Zcash] = true + m[wi.Litecoin] = true + m[wi.Ethereum] = true + params := &chaincfg.MainNetParams + if x.Testnet { + params = &chaincfg.TestNet3Params + } + cfg := config.NewDefaultConfig(m, params) + cfg.Mnemonic = "bottle author ability expose illegal saddle antique setup pledge wife innocent treat" + var err error + mw, err = multiwallet.NewMultiWallet(cfg) + if err != nil { + return err + } + go api.ServeAPI(mw) + var wg sync.WaitGroup + wg.Add(1) + mw.Start() + wg.Wait() + return nil +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/coverage.out b/vendor/github.com/OpenBazaar/multiwallet/coverage.out new file mode 100644 index 0000000000..cdaaa0735b --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/coverage.out @@ -0,0 +1,2065 @@ +mode: set +github.com/OpenBazaar/multiwallet/zcash/wallet.go:99.2,99.65 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:96.16,98.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:94.90,96.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:78.2,91.8 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:74.27,76.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:73.2,74.27 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:69.16,71.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:68.2,69.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:64.16,66.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:63.2,64.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:59.16,61.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:58.2,59.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:55.16,57.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:54.2,55.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:51.16,53.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:494.54,496.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:490.80,492.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:485.2,486.23 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:482.16,484.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:481.2,482.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:47.175,51.16 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:469.3,479.46 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:466.17,468.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:464.31,466.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:464.2,464.31 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:450.3,462.43 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:447.17,449.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:446.3,447.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:441.55,443.10 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:440.28,441.55 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:438.29,440.28 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:438.2,438.29 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:435.16,437.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:426.2,435.16 3 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:423.16,425.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:421.65,423.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:415.26,417.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:413.2,415.26 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:410.26,412.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:407.48,410.26 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:403.56,405.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:398.31,401.2 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:394.2,395.67 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:391.21,393.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:391.2,391.21 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:388.16,390.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:386.85,388.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:382.60,384.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:378.85,380.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:374.2,375.12 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:371.16,373.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:370.2,371.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:367.16,369.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:365.61,367.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:361.2,362.12 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:357.16,359.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:356.2,357.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:353.3,353.50 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:350.17,352.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:348.29,350.17 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:345.75,348.29 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:341.190,343.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:337.205,339.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:333.188,335.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:329.179,331.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:325.92,327.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:320.2,322.20 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:315.27,319.3 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:313.117,315.27 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:309.77,311.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:306.2,306.39 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:302.16,304.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:301.2,302.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:296.17,298.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:294.8,296.17 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:291.17,293.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:289.14,291.17 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:284.147,289.14 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:280.66,282.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:276.59,278.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:273.2,273.17 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:271.3,271.21 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:264.4,269.29 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:261.18,263.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:259.32,261.18 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:258.3,259.32 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:255.17,257.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:251.16,255.17 4 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:249.75,251.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:246.2,246.18 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:242.3,244.15 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:238.19,240.25 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:235.32,237.25 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:233.61,234.26 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:231.62,232.33 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:229.18,230.26 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:228.3,228.10 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:225.21,227.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:221.26,225.21 4 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:221.2,221.26 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:218.16,220.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:215.56,218.16 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:212.2,212.38 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:209.26,211.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:201.64,209.26 3 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:198.2,198.13 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:195.16,197.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:193.57,195.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:189.77,191.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:186.2,186.18 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:183.16,185.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:181.79,183.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:177.75,179.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:174.2,174.13 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:171.72,173.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:171.2,171.72 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:168.16,170.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:167.2,168.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:164.16,166.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:162.73,164.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:159.2,159.13 1 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:156.16,158.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:155.2,156.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:152.16,154.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:150.77,152.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:139.2,147.23 2 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:136.8,138.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:134.18,136.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:131.111,134.18 3 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:127.57,129.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:123.58,125.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:119.49,121.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:114.8,116.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:112.50,114.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:111.45,112.50 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:107.49,109.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/wallet.go:102.31,105.2 2 0 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:248.2,248.22 1 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:245.32,247.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:244.73,245.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:236.2,240.13 1 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:231.36,232.58 1 0 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:229.35,230.58 1 0 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:227.26,228.53 1 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:225.26,226.53 1 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:223.13,224.42 1 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:221.2,222.19 2 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:216.21,219.3 2 1 +github.com/OpenBazaar/multiwallet/zcash/txsizes.go:213.113,216.21 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:98.3,98.50 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:94.4,96.48 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:923.2,929.13 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:920.31,922.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:918.45,920.31 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:91.18,92.13 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:909.2,915.13 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:904.29,908.3 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:902.46,904.29 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:90.4,91.18 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:893.2,899.13 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:882.29,892.3 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:880.46,882.29 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:877.2,877.25 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:873.16,875.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:872.2,873.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:87.18,88.13 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:867.16,869.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:866.2,867.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:861.16,863.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:860.2,861.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:855.16,857.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:854.2,855.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:849.16,851.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:846.2,849.16 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:841.16,843.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:838.2,841.16 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:833.17,835.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:832.3,833.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:828.17,830.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:823.30,828.17 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:823.2,823.30 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:819.16,821.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:817.2,819.16 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:812.17,814.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:809.3,812.17 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:805.17,807.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:804.3,805.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:800.17,802.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:797.3,800.17 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:793.17,795.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:790.29,793.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:790.2,790.29 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:785.16,787.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:783.2,785.16 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:78.35,87.18 9 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:778.16,780.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:777.2,778.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:772.16,774.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:767.88,772.16 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:76.3,78.35 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:73.17,75.4 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:709.2,762.18 30 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:704.8,706.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:700.82,704.3 3 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:700.8,700.82 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:70.2,70.136 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:70.136,73.17 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:698.48,700.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:697.2,698.48 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:689.8,691.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:687.48,689.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:685.2,687.48 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:678.8,680.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:676.48,678.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:672.2,676.48 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:67.25,69.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:665.16,667.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:664.2,665.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:659.16,661.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:655.2,659.16 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:649.26,651.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:645.146,649.26 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:642.2,642.59 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:64.2,67.25 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:638.16,640.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:637.2,638.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:634.16,636.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:631.83,634.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:625.2,625.36 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:622.20,624.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:622.2,622.20 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:616.107,618.10 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:615.30,616.107 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:614.32,615.30 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:614.2,614.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:611.16,613.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:61.16,63.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:609.2,611.16 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:606.34,608.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:605.2,606.34 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:602.16,604.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:601.2,602.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:598.16,600.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:595.92,598.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:592.2,592.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:589.16,591.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:588.2,589.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:584.16,586.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:580.2,584.16 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:577.29,579.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:575.2,577.29 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:572.3,572.33 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:569.17,571.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:567.27,569.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:566.2,567.27 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:560.27,564.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:560.2,560.27 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:556.54,558.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:555.186,556.54 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:552.2,552.44 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:55.2,61.16 5 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:548.44,550.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:547.2,547.15 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:547.15,548.44 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:544.3,544.36 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:541.17,543.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:535.3,541.17 7 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:529.32,531.10 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:528.3,528.29 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:528.29,529.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:523.32,525.10 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:522.29,523.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:519.32,522.29 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:517.2,519.32 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:511.35,513.4 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:51.89,53.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:51.2,51.89 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:509.23,511.35 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:507.2,509.23 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:502.3,503.38 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:499.17,501.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:497.27,499.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:497.2,497.27 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:493.3,495.35 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:490.17,492.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:488.25,490.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:486.205,488.25 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:483.2,483.18 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:480.3,481.26 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:48.16,50.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:477.17,478.12 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:475.25,477.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:475.2,475.25 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:471.16,473.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:468.2,471.16 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:462.35,464.4 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:460.23,462.35 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:458.2,460.23 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:453.3,454.38 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:450.17,452.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:45.134,48.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:448.27,450.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:448.2,448.27 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:443.3,446.35 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:440.17,442.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:438.25,440.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:434.188,438.25 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:431.2,431.39 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:428.16,430.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:427.2,428.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:423.3,423.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:420.17,422.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:419.3,420.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:416.26,418.4 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:413.3,416.26 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:410.17,412.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:408.31,410.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:408.2,408.31 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:404.16,406.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:390.2,404.16 5 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:387.16,389.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:380.2,387.16 5 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:377.8,379.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:374.17,376.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:371.25,374.17 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:368.2,371.25 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:363.3,366.44 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:360.17,362.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:359.3,360.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:356.17,358.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:352.25,356.17 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:348.2,352.25 5 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:344.16,346.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:343.2,344.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:340.8,342.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:338.20,340.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:336.175,338.20 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:333.2,333.44 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:330.4,330.29 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:327.18,329.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:320.4,327.18 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:317.18,319.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:316.4,317.18 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:313.18,315.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:312.4,313.18 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:309.18,311.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:307.50,309.18 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:306.26,307.50 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:305.2,306.26 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:301.20,303.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:301.2,301.20 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:298.20,300.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:298.2,298.20 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:295.16,297.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:293.77,295.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:284.3,289.22 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:278.4,281.19 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:274.45,277.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:274.4,274.45 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:271.18,273.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:269.51,271.18 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:260.3,269.51 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:255.39,257.12 2 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:252.3,255.39 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:248.43,250.4 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:248.3,248.43 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:245.17,247.4 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:242.6,245.17 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:239.2,242.6 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:235.32,237.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:232.186,235.32 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:229.2,229.16 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:227.3,227.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:224.17,226.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:220.3,224.17 5 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:217.17,219.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:216.3,217.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:213.17,215.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:212.3,213.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:209.17,211.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:206.31,209.17 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:206.2,206.31 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:204.3,204.46 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:201.10,203.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:198.88,201.10 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:191.2,198.88 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:186.94,188.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:181.2,186.94 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:176.16,178.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:170.2,176.16 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:167.16,169.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:162.100,167.16 4 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:159.2,159.27 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:157.3,157.32 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:154.17,156.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:150.3,154.17 5 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:147.17,149.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:145.3,147.17 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:142.17,144.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:141.3,142.17 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:138.17,140.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:135.42,138.17 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:135.2,135.42 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:130.88,134.3 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:127.2,130.88 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:122.16,124.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:121.2,122.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:118.27,120.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:117.2,118.27 2 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:114.3,114.21 1 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:111.17,113.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/sign.go:108.41,111.17 3 1 +github.com/OpenBazaar/multiwallet/zcash/sign.go:102.2,108.41 3 1 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:97.2,99.21 3 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:93.17,95.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:91.14,93.17 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:90.83,91.14 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:87.2,87.19 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:84.9,86.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:77.81,84.9 6 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:74.2,74.19 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:71.9,73.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:65.83,71.9 5 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:51.2,62.11 5 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:48.19,50.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:42.67,48.19 4 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:330.2,330.12 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:327.26,329.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:327.2,327.26 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:324.15,326.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:323.2,324.15 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:320.16,322.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:319.2,320.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:316.9,318.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:315.2,316.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:312.9,314.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:311.2,312.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:308.9,310.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:306.2,308.9 3 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:303.9,305.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:302.2,303.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:299.16,301.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:297.122,299.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:294.2,294.12 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:291.26,293.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:291.2,291.26 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:288.2,288.15 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:288.15,290.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:284.9,286.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:283.2,284.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:280.9,282.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:279.2,280.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:276.9,278.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:275.2,276.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:272.9,274.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:271.2,272.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:268.9,270.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:267.2,268.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:264.16,266.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:262.121,264.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:259.2,259.12 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:256.26,258.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:256.2,256.26 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:253.15,255.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:251.2,253.15 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:248.16,250.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:247.2,248.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:244.9,246.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:243.2,244.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:240.9,242.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:239.2,240.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:236.9,238.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:235.2,236.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:232.16,234.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:230.122,232.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:227.2,227.12 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:224.26,226.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:224.2,224.26 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:221.15,223.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:219.2,221.15 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:216.16,218.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:215.2,216.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:212.9,214.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:211.2,212.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:208.9,210.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:207.2,208.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:204.9,206.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:203.2,204.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:200.9,202.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:199.2,200.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:196.9,198.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:195.2,196.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:192.9,194.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:191.2,192.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:188.9,190.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:187.2,188.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:184.9,186.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:183.2,184.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:180.16,182.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:178.120,180.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:175.2,175.12 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:172.4,172.36 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:169.11,171.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:168.4,169.11 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:165.11,167.5 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:163.23,165.11 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:162.25,163.23 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:162.2,162.25 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:159.9,161.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:158.2,159.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:155.9,157.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:154.2,155.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:151.9,153.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:150.2,151.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:146.9,148.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:144.124,146.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:141.2,141.83 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:138.16,140.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:135.2,138.16 4 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:132.16,134.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:131.2,132.16 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:127.33,130.3 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:126.59,127.33 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:121.21,123.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:118.35,121.21 3 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:115.2,115.59 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:111.17,113.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:109.39,111.17 2 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:106.55,109.39 3 0 +github.com/OpenBazaar/multiwallet/zcash/exchange_rates.go:102.48,104.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:93.57,97.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:84.2,86.8 3 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:81.49,83.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:78.2,81.49 4 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:75.22,77.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:73.75,75.22 2 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:63.55,70.2 6 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:55.45,60.2 4 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:47.13,52.2 4 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:334.2,334.47 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:331.8,331.159 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:331.159,333.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:329.101,331.3 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:326.99,329.101 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:317.63,320.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:309.63,313.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:302.2,303.27 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:300.3,300.53 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:297.18,299.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:296.26,297.18 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:294.3,294.53 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:291.18,293.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:290.26,291.18 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:286.60,289.29 2 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:280.61,282.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:273.45,275.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:267.2,267.56 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:264.9,266.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:262.65,264.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:256.52,258.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:250.52,252.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:243.2,245.18 3 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:239.9,241.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:238.2,239.9 2 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:234.39,236.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:232.104,234.39 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:223.104,225.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:216.102,219.2 2 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:204.61,206.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:197.45,199.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:191.2,191.56 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:188.9,190.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:186.65,188.9 2 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:180.52,182.2 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:174.52,176.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:167.2,169.18 3 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:163.9,165.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:162.2,163.9 2 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:158.35,160.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:156.92,158.35 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:147.92,149.2 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:133.10,134.63 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:129.11,130.37 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:127.15,128.60 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:125.16,126.52 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:123.26,124.35 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:119.22,122.30 3 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:118.2,118.22 1 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:116.3,116.65 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:113.32,115.4 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:112.16,113.32 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:111.2,112.16 2 1 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:106.9,108.3 1 0 +github.com/OpenBazaar/multiwallet/zcash/address/address.go:103.87,106.9 2 1 +github.com/OpenBazaar/multiwallet/util/satoshis.go:6.56,8.2 1 0 +github.com/OpenBazaar/multiwallet/util/outpoints.go:9.2,9.27 1 1 +github.com/OpenBazaar/multiwallet/util/outpoints.go:6.30,8.3 1 1 +github.com/OpenBazaar/multiwallet/util/outpoints.go:5.46,6.30 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:96.29,98.3 1 0 +github.com/OpenBazaar/multiwallet/util/fees.go:96.2,96.29 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:92.36,94.3 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:90.2,92.36 2 1 +github.com/OpenBazaar/multiwallet/util/fees.go:86.10,87.24 1 0 +github.com/OpenBazaar/multiwallet/util/fees.go:84.23,85.30 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:82.23,83.26 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:80.21,81.24 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:78.23,79.26 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:76.2,77.18 2 1 +github.com/OpenBazaar/multiwallet/util/fees.go:72.29,74.3 1 0 +github.com/OpenBazaar/multiwallet/util/fees.go:71.2,72.29 2 1 +github.com/OpenBazaar/multiwallet/util/fees.go:67.29,69.3 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:67.2,67.29 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:63.11,64.23 1 0 +github.com/OpenBazaar/multiwallet/util/fees.go:61.24,62.29 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:59.24,60.25 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:57.22,58.23 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:55.24,56.25 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:53.30,54.19 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:52.71,53.30 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:42.122,50.2 1 1 +github.com/OpenBazaar/multiwallet/util/fees.go:100.2,100.27 1 1 +github.com/OpenBazaar/multiwallet/util/currency.go:6.56,8.2 1 0 +github.com/OpenBazaar/multiwallet/util/coin.go:93.2,93.72 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:90.3,91.54 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:87.17,88.12 1 0 +github.com/OpenBazaar/multiwallet/util/coin.go:86.3,87.17 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:83.17,84.12 1 0 +github.com/OpenBazaar/multiwallet/util/coin.go:73.33,83.17 9 1 +github.com/OpenBazaar/multiwallet/util/coin.go:67.187,73.33 5 1 +github.com/OpenBazaar/multiwallet/util/coin.go:64.2,64.10 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:62.3,62.13 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:59.17,60.12 1 0 +github.com/OpenBazaar/multiwallet/util/coin.go:58.3,59.17 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:55.17,56.12 1 0 +github.com/OpenBazaar/multiwallet/util/coin.go:54.3,55.17 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:50.17,51.12 1 0 +github.com/OpenBazaar/multiwallet/util/coin.go:49.3,50.17 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:46.21,48.4 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:45.3,46.21 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:42.18,43.12 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:41.26,42.18 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:39.218,41.26 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:28.130,37.2 2 1 +github.com/OpenBazaar/multiwallet/util/coin.go:26.39,26.81 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:25.39,25.62 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:24.39,24.64 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:23.39,23.59 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:22.39,22.59 1 1 +github.com/OpenBazaar/multiwallet/util/coin.go:21.39,21.58 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:9.81,11.26 2 1 +github.com/OpenBazaar/multiwallet/util/balance.go:58.2,58.24 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:54.9,56.4 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:50.74,52.6 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:49.27,50.74 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:48.9,49.27 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:46.29,48.9 2 1 +github.com/OpenBazaar/multiwallet/util/balance.go:45.2,46.29 2 1 +github.com/OpenBazaar/multiwallet/util/balance.go:40.16,42.3 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:37.2,40.16 4 1 +github.com/OpenBazaar/multiwallet/util/balance.go:34.9,36.3 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:31.72,34.9 2 1 +github.com/OpenBazaar/multiwallet/util/balance.go:28.2,28.31 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:22.11,24.6 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:20.61,22.6 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:19.10,20.61 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:17.25,19.5 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:16.22,17.25 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:15.29,16.22 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:15.2,15.29 1 1 +github.com/OpenBazaar/multiwallet/util/balance.go:11.26,13.3 1 1 +github.com/OpenBazaar/multiwallet/util/address.go:29.2,29.43 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:26.67,28.3 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:26.2,26.67 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:23.70,25.3 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:23.2,23.70 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:20.69,22.3 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:20.2,20.69 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:17.69,19.3 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:17.2,17.69 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:14.23,16.3 1 0 +github.com/OpenBazaar/multiwallet/util/address.go:13.86,14.23 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:96.33,98.2 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:90.34,94.2 3 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:87.2,87.16 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:84.3,85.29 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:80.62,83.4 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:78.8,80.62 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:76.16,78.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:646.49,648.2 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:641.2,643.44 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:638.16,640.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:631.78,638.16 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:628.2,628.14 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:625.3,625.51 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:623.4,623.18 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:619.18,621.13 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:617.24,619.18 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:616.4,616.16 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:612.18,614.13 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:610.21,612.18 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:609.4,609.19 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:605.18,607.13 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:603.27,605.18 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:602.4,602.23 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:598.4,598.23 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:598.23,600.13 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:594.18,596.13 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:592.23,594.18 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:589.38,591.22 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:589.2,589.38 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:584.16,587.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:583.2,584.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:581.3,581.52 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:577.17,579.12 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:575.27,577.17 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:572.72,575.27 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:57.184,76.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:562.40,564.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:561.75,562.40 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:554.3,554.29 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:554.29,557.4 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:550.17,553.4 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:548.8,548.23 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:548.23,550.17 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:546.3,547.27 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:542.17,545.4 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:541.3,542.17 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:536.9,540.4 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:534.26,536.4 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:533.3,534.26 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:530.26,532.4 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:528.16,530.26 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:525.2,528.16 4 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:520.2,520.15 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:520.15,523.3 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:517.3,517.18 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:513.18,515.5 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:508.3,508.20 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:508.20,513.18 4 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:505.10,506.12 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:497.3,505.10 7 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:493.43,494.12 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:493.3,493.43 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:487.18,490.5 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:485.81,487.18 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:484.3,485.81 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:480.17,482.12 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:478.32,480.17 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:478.2,478.32 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:476.3,476.18 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:472.3,472.20 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:472.20,475.4 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:469.10,470.12 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:459.3,469.10 5 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:455.17,458.4 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:451.3,455.17 5 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:446.17,449.4 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:444.3,446.17 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:440.17,442.12 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:439.3,440.17 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:435.17,437.12 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:433.30,435.17 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:431.2,433.30 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:427.16,430.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:426.2,427.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:422.25,424.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:415.115,422.25 6 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:410.25,412.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:404.96,410.25 4 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:394.8,397.3 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:392.16,394.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:391.2,392.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:388.27,390.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:385.66,388.27 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:378.42,382.2 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:371.48,374.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:363.2,371.48 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:359.25,361.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:358.2,359.25 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:354.25,356.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:352.2,354.25 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:347.16,350.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:346.2,347.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:342.16,345.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:340.110,342.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:333.52,335.5 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:332.10,333.52 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:330.35,332.10 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:330.2,330.35 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:323.3,327.47 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:319.17,321.12 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:317.26,319.17 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:311.2,317.26 5 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:306.16,309.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:303.92,306.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:294.8,297.3 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:292.16,294.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:291.2,292.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:288.27,290.3 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:285.68,288.27 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:277.2,280.22 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:272.8,274.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:271.3,271.19 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:268.17,270.4 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:264.16,268.17 4 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:260.40,264.16 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:250.19,252.6 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:249.5,250.19 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:246.6,246.12 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:243.8,243.16 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:240.51,242.9 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:238.41,240.51 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:237.30,238.41 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:234.5,234.30 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:234.30,237.30 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:230.19,233.6 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:228.28,230.19 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:226.21,228.28 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:225.25,226.21 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:224.2,225.25 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:220.16,223.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:219.2,220.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:215.16,218.3 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:214.2,215.16 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:207.73,211.3 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:204.2,207.73 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:201.16,203.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:193.66,201.16 7 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:185.6,185.11 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:182.20,184.7 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:180.68,182.20 2 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:179.28,180.68 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:178.32,179.28 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:178.3,178.32 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:162.33,173.11 3 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:161.52,162.33 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:160.34,161.52 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:159.27,160.34 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:159.2,159.27 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:155.16,157.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:147.75,155.16 8 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:140.29,141.37 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:138.23,139.40 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:136.22,137.10 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:134.6,135.10 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:132.2,134.6 2 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:129.27,131.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:121.35,129.27 3 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:116.33,118.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:115.90,116.33 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:110.101,112.2 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:107.2,107.28 1 1 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:104.16,106.3 1 0 +github.com/OpenBazaar/multiwallet/service/wallet_service.go:100.62,104.16 4 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:97.16,99.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:95.93,97.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:79.2,92.8 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:75.27,77.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:74.2,75.27 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:71.16,73.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:70.2,71.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:66.16,68.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:65.2,66.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:61.16,63.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:60.2,61.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:57.16,59.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:56.2,57.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:53.16,55.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:512.83,514.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:507.2,508.12 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:504.16,506.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:503.2,504.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:491.3,501.46 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:49.181,53.16 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:488.17,490.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:486.31,488.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:486.2,486.31 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:472.3,484.43 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:469.17,471.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:468.3,469.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:463.55,465.10 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:462.28,463.55 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:460.29,462.28 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:460.2,460.29 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:457.16,459.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:445.58,457.16 5 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:440.3,440.85 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:437.9,439.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:435.31,437.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:433.25,435.31 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:433.2,433.25 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:429.35,431.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:429.2,429.35 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:426.35,428.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:420.2,426.35 7 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:417.26,419.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:415.2,417.26 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:412.26,414.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:409.51,412.26 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:405.59,407.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:400.34,403.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:396.2,397.67 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:393.21,395.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:393.2,393.21 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:390.16,392.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:388.88,390.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:384.63,386.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:380.88,382.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:376.2,377.12 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:373.16,375.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:372.2,373.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:369.16,371.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:367.64,369.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:363.2,364.12 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:359.16,361.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:358.2,359.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:355.3,355.50 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:352.17,354.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:350.29,352.17 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:347.78,350.29 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:343.193,345.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:339.208,341.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:335.191,337.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:331.182,333.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:327.95,329.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:322.2,324.20 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:317.27,321.3 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:315.120,317.27 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:311.80,313.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:307.2,308.17 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:303.40,305.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:303.2,303.40 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:297.17,299.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:295.8,297.17 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:292.17,294.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:290.14,292.17 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:285.150,290.14 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:281.69,283.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:277.62,279.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:274.2,274.17 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:272.3,272.21 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:265.4,270.29 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:262.18,264.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:260.32,262.18 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:259.3,260.32 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:256.17,258.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:252.16,256.17 4 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:250.78,252.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:247.2,247.18 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:243.3,245.15 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:239.19,241.25 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:236.32,238.25 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:234.61,235.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:232.62,233.33 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:230.18,231.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:229.3,229.10 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:226.21,228.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:222.26,226.21 4 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:222.2,222.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:219.16,221.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:216.59,219.16 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:210.67,214.2 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:205.60,208.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:201.80,203.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:197.82,199.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:193.78,195.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:190.2,190.13 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:186.65,187.9 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:186.3,186.65 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:183.73,185.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:183.3,183.73 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:180.17,182.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:179.3,180.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:176.17,178.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:174.6,176.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:172.76,174.6 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:169.2,169.13 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:165.73,167.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:165.3,165.73 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:162.65,163.9 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:162.3,162.65 1 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:158.17,160.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:157.3,158.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:154.17,156.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:152.6,154.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:150.80,152.6 2 1 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:139.2,147.23 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:136.8,138.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:134.18,136.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:131.114,134.18 3 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:127.60,129.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:123.61,125.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:119.52,121.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:114.8,116.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:112.50,114.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:111.48,112.50 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:107.52,109.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:102.34,105.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/wallet.go:100.2,100.65 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:248.2,248.22 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:245.32,247.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:244.73,245.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:236.2,240.13 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:231.36,232.58 1 0 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:229.35,230.58 1 0 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:227.26,228.53 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:225.26,226.53 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:223.13,224.42 1 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:221.2,222.19 2 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:216.21,219.3 2 1 +github.com/OpenBazaar/multiwallet/litecoin/txsizes.go:213.113,216.21 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:97.3,97.21 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:94.17,96.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:91.41,94.17 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:85.2,91.41 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:81.3,81.50 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:78.4,79.55 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:75.18,76.13 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:74.4,75.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:71.18,72.13 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:674.2,674.36 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:671.20,673.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:671.2,671.20 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:665.107,667.10 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:664.30,665.107 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:663.32,664.30 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:663.2,663.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:660.16,662.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:658.2,660.16 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:655.34,657.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:654.2,655.34 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:651.16,653.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:650.2,651.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:647.16,649.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:644.95,647.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:641.2,641.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:638.16,640.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:635.2,638.16 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:631.16,633.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:630.2,631.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:620.3,628.28 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:62.35,71.18 9 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:617.30,619.4 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:614.3,617.30 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:611.17,613.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:609.8,611.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:606.3,607.43 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:603.30,605.4 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:600.34,603.30 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:60.3,62.35 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:599.2,600.34 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:596.3,596.33 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:593.17,595.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:591.27,593.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:590.2,591.27 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:584.27,588.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:584.2,584.27 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:580.54,582.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:579.189,580.54 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:574.2,576.25 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:570.41,572.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:57.17,59.4 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:569.2,569.15 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:569.15,570.41 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:565.3,566.26 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:562.17,564.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:560.3,562.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:554.32,556.10 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:553.3,553.29 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:553.29,554.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:548.32,550.10 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:547.29,548.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:544.32,547.29 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:544.2,544.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:540.39,542.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:54.2,54.136 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:54.136,57.17 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:536.2,540.39 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:530.35,532.4 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:528.23,530.35 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:526.2,528.23 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:523.16,525.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:521.2,523.16 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:516.3,517.38 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:513.17,515.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:511.27,513.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:511.2,511.27 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:51.25,53.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:507.3,509.35 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:504.17,506.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:502.25,504.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:500.208,502.25 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:497.2,497.18 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:494.3,495.26 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:491.17,492.12 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:489.25,491.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:488.2,489.25 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:484.16,486.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:481.2,484.16 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:48.2,51.25 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:475.35,477.4 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:473.23,475.35 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:471.2,473.23 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:468.16,470.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:466.2,468.16 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:461.3,462.38 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:458.17,460.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:456.27,458.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:456.2,456.27 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:452.3,454.35 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:45.16,47.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:449.17,451.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:447.25,449.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:444.191,447.25 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:440.2,441.19 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:437.40,439.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:437.2,437.40 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:431.4,432.26 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:428.10,430.5 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:426.18,428.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:425.4,426.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:422.18,424.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:420.9,422.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:419.4,419.33 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:416.18,418.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:411.26,416.18 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:410.31,411.26 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:409.2,410.31 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:404.5,404.29 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:401.19,403.6 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:399.33,401.19 2 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:396.30,399.33 3 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:394.25,396.30 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:393.2,394.25 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:39.2,45.16 5 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:389.3,389.28 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:386.26,388.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:385.77,386.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:385.2,385.77 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:383.3,383.45 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:381.4,381.47 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:378.18,380.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:376.57,378.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:375.88,376.57 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:375.2,375.88 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:371.16,373.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:369.2,371.16 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:366.16,368.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:352.2,366.16 5 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:35.93,37.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:349.16,351.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:342.2,349.16 5 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:338.17,340.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:335.25,338.17 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:332.2,335.25 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:327.3,330.44 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:324.17,326.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:323.3,324.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:320.17,322.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:32.137,35.93 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:317.25,320.17 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:314.2,317.25 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:310.16,312.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:309.2,310.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:306.8,308.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:304.20,306.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:302.178,304.20 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:299.2,299.44 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:296.4,296.29 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:293.18,295.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:286.4,293.18 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:283.18,285.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:282.4,283.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:279.18,281.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:278.4,279.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:275.18,277.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:273.50,275.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:272.26,273.50 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:271.2,272.26 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:267.20,269.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:267.2,267.20 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:264.20,266.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:264.2,264.20 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:261.16,263.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:259.80,261.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:250.3,255.9 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:244.4,247.19 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:240.45,243.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:240.4,240.45 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:237.18,239.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:235.51,237.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:226.3,235.51 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:221.51,223.12 2 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:218.3,221.51 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:214.55,216.4 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:214.3,214.55 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:211.17,213.4 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:209.6,211.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:206.2,209.6 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:202.32,204.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:199.172,202.32 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:196.2,196.16 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:194.3,194.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:191.17,193.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:186.31,191.17 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:186.2,186.31 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:183.37,185.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:182.2,183.37 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:180.3,180.46 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:177.10,179.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:174.88,177.10 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:167.2,174.88 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:162.98,164.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:157.2,162.98 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:152.16,154.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:146.2,152.16 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:143.16,145.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:138.103,143.16 4 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:135.2,135.27 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:133.3,133.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:130.17,132.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:125.42,130.17 3 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:125.2,125.42 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:122.37,124.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:121.2,122.37 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:118.3,119.46 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:115.17,117.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:113.88,115.17 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:110.2,113.88 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:105.16,107.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:104.2,105.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:101.27,103.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/sign.go:100.2,101.27 2 1 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:97.2,100.28 4 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:93.17,95.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:91.14,93.17 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:90.86,91.14 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:87.2,87.19 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:84.9,86.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:77.84,84.9 6 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:74.2,74.19 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:71.9,73.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:65.86,71.9 5 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:51.2,62.11 5 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:48.19,50.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:42.73,48.19 4 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:335.56,337.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:331.2,331.12 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:328.26,330.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:328.2,328.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:325.15,327.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:324.2,325.15 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:321.16,323.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:320.2,321.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:317.9,319.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:316.2,317.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:313.9,315.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:310.2,313.9 4 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:307.9,309.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:306.2,307.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:303.16,305.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:301.122,303.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:298.2,298.12 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:295.26,297.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:295.2,295.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:292.2,292.15 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:292.15,294.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:288.9,290.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:287.2,288.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:284.9,286.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:283.2,284.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:280.9,282.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:279.2,280.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:276.9,278.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:275.2,276.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:272.9,274.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:271.2,272.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:268.16,270.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:266.121,268.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:263.2,263.12 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:260.26,262.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:260.2,260.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:257.15,259.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:255.2,257.15 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:252.16,254.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:251.2,252.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:248.9,250.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:247.2,248.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:244.9,246.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:243.2,244.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:240.9,242.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:239.2,240.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:236.16,238.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:234.122,236.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:231.2,231.12 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:228.26,230.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:228.2,228.26 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:225.15,227.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:223.2,225.15 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:220.16,222.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:219.2,220.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:216.9,218.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:215.2,216.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:212.9,214.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:211.2,212.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:208.9,210.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:207.2,208.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:204.9,206.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:203.2,204.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:200.9,202.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:199.2,200.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:196.9,198.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:195.2,196.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:192.9,194.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:191.2,192.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:188.9,190.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:187.2,188.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:184.16,186.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:182.120,184.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:179.2,179.12 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:176.4,176.36 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:173.11,175.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:172.4,173.11 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:169.11,171.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:167.23,169.11 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:166.25,167.23 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:166.2,166.25 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:163.9,165.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:162.2,163.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:159.9,161.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:158.2,159.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:155.9,157.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:154.2,155.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:150.9,152.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:148.124,150.9 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:145.2,145.83 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:142.16,144.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:139.2,142.16 4 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:136.16,138.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:135.2,136.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:131.33,134.3 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:130.59,131.33 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:125.21,127.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:122.38,125.21 3 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:119.2,119.59 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:115.17,117.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:113.39,115.17 2 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:110.58,113.39 3 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:106.51,108.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:103.2,103.18 1 0 +github.com/OpenBazaar/multiwallet/litecoin/exchange_rates.go:100.28,102.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:99.16,101.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:95.2,99.16 5 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:89.16,91.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:85.98,89.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:791.39,794.2 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:782.2,782.47 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:779.82,781.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:779.8,779.82 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:777.82,779.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:777.8,777.82 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:775.8,775.159 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:775.159,777.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:773.101,775.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:771.99,773.101 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:77.55,81.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:767.70,769.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:760.63,763.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:752.63,756.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:745.2,746.27 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:743.3,743.53 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:740.18,742.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:739.26,740.18 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:738.3,738.60 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:735.18,737.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:734.33,735.18 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:733.3,733.53 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:730.18,732.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:729.26,730.18 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:725.60,728.29 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:719.60,721.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:714.58,716.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:709.49,711.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:703.52,705.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:694.72,697.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:687.59,689.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:682.2,682.12 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:679.16,681.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:676.59,679.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:663.2,670.18 3 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:658.28,661.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:655.101,658.28 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:647.111,650.2 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:64.13,71.2 6 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:632.56,634.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:626.60,628.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:621.58,623.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:616.49,618.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:610.52,612.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:601.72,604.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:594.59,596.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:589.2,589.12 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:586.16,588.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:583.59,586.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:570.2,577.18 3 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:565.28,568.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:562.101,565.28 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:554.111,557.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:539.51,541.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:532.64,536.2 3 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:522.58,524.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:516.47,518.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:510.41,512.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:503.61,506.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:497.48,499.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:490.48,492.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:477.17,478.36 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:474.21,475.40 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:471.23,472.42 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:469.10,470.14 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:467.44,468.24 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:456.2,462.8 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:453.18,454.23 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:451.18,452.27 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:449.2,450.29 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:441.16,443.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:439.94,441.16 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:408.61,410.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:401.45,403.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:393.65,396.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:387.52,389.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:381.52,383.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:374.2,376.18 3 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:370.39,372.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:368.94,370.39 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:358.104,361.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:350.102,354.2 3 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:338.61,340.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:331.45,333.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:33.56,35.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:323.65,326.2 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:317.52,319.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:311.52,313.2 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:304.2,306.18 3 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:300.35,302.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:298.82,300.35 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:288.92,291.2 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:276.2,276.32 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:271.66,274.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:271.2,271.66 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:266.47,268.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:266.2,266.47 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:261.16,263.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:260.2,261.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:253.18,255.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:252.2,253.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:25.52,27.2 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:247.2,247.19 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:247.19,249.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:241.16,243.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:238.64,241.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:233.2,233.14 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:230.43,232.3 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:228.47,230.43 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:220.10,221.63 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:216.11,217.37 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:214.15,215.55 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:212.16,213.47 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:210.26,211.35 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:206.22,209.30 3 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:205.2,205.22 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:203.3,203.65 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:200.32,202.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:199.16,200.32 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:198.2,199.16 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:194.3,194.56 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:191.17,193.4 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:189.41,191.17 2 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:189.2,189.41 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:181.12,182.65 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:179.12,180.57 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:177.12,178.57 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:174.4,176.28 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:169.4,169.23 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:169.23,171.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:163.18,165.5 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:161.35,163.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:159.18,161.35 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:152.79,159.18 2 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:113.2,113.18 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:109.72,111.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:109.2,109.72 1 1 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:105.16,107.3 1 0 +github.com/OpenBazaar/multiwallet/litecoin/address/address.go:104.2,105.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:99.17,100.9 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:94.6,99.17 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:94.2,94.6 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:91.8,93.3 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:89.16,91.3 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:86.87,89.16 3 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:83.2,83.51 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:80.2,80.17 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:80.17,82.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:77.16,79.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:75.89,77.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:72.2,72.32 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:69.16,71.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:68.2,69.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:64.16,66.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:63.2,64.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:59.16,61.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:58.2,59.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:54.16,56.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:53.2,54.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:49.16,51.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:46.127,49.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:42.2,42.16 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:39.39,41.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:31.2,39.39 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:28.16,30.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:26.157,28.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:199.82,201.2 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:196.2,196.12 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:190.19,192.6 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:188.50,190.19 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:187.29,188.50 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:186.46,187.29 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:184.41,186.46 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:181.2,181.47 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:178.8,178.39 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:178.39,180.3 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:176.32,178.3 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:175.106,176.32 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:172.2,172.23 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:169.66,171.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:168.65,169.66 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:164.2,164.68 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:154.3,162.20 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:151.17,153.4 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:149.16,151.17 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:147.86,149.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:144.2,144.13 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:142.3,142.25 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:139.17,140.12 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:137.32,139.17 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:137.2,137.32 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:134.16,136.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:131.51,134.16 3 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:128.2,128.17 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:125.16,127.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:124.2,125.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:121.16,123.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:120.2,121.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:117.39,119.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:116.89,117.39 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:113.2,113.22 1 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:110.16,112.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:108.2,110.16 3 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:105.16,107.3 1 0 +github.com/OpenBazaar/multiwallet/keys/keys.go:104.2,105.16 2 1 +github.com/OpenBazaar/multiwallet/keys/keys.go:102.3,102.13 1 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:97.15,99.3 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:96.80,97.15 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:88.9,90.4 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:84.56,87.12 3 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:82.6,84.56 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:81.71,82.6 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:70.2,75.15 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:67.3,68.56 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:64.17,66.4 1 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:62.33,64.17 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:57.95,62.33 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:40.49,42.2 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:36.40,38.2 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:33.2,33.22 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:30.8,32.3 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:27.41,29.4 1 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:25.53,27.41 2 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:25.2,25.53 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:21.35,24.3 1 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:203.37,205.2 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:199.35,201.2 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:195.36,197.2 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:191.34,193.2 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:19.39,21.35 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:183.54,185.6 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:183.5,183.54 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:179.27,182.6 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:178.47,179.27 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:178.4,178.47 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:175.42,176.13 1 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:174.7,175.42 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:172.34,174.7 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:168.40,172.34 3 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:161.8,163.3 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:156.41,161.8 4 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:151.2,152.12 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:147.43,149.3 1 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:147.2,147.43 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:142.10,144.4 1 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:136.9,142.10 5 0 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:131.65,136.9 4 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:125.3,126.30 2 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:122.16,124.4 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:121.34,122.16 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:117.42,121.34 3 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:112.44,114.2 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:107.2,107.27 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:103.16,104.9 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:102.16,103.16 1 1 +github.com/OpenBazaar/multiwallet/client/rotation_manager.go:100.2,102.16 3 1 +github.com/OpenBazaar/multiwallet/client/pool.go:95.11,96.15 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:93.25,94.10 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:91.6,92.10 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:90.28,91.6 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:87.2,87.16 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:84.46,86.3 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:82.61,84.46 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:77.36,80.2 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:71.2,72.18 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:68.16,70.3 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:58.2,68.16 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:54.25,56.3 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:53.87,54.25 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:48.37,50.2 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:42.34,46.2 3 1 +github.com/OpenBazaar/multiwallet/client/pool.go:393.67,393.86 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:384.46,390.2 5 1 +github.com/OpenBazaar/multiwallet/client/pool.go:374.64,382.2 6 0 +github.com/OpenBazaar/multiwallet/client/pool.go:369.2,370.19 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:364.4,365.14 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:361.18,363.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:36.60,38.2 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:358.4,361.18 4 0 +github.com/OpenBazaar/multiwallet/client/pool.go:355.28,357.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:353.56,355.28 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:350.78,353.56 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:345.2,346.16 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:340.4,341.14 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:337.18,339.5 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:334.56,337.18 3 1 +github.com/OpenBazaar/multiwallet/client/pool.go:331.78,334.56 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:326.2,327.17 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:321.4,322.14 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:318.18,320.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:315.4,318.18 4 0 +github.com/OpenBazaar/multiwallet/client/pool.go:312.28,314.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:310.56,312.28 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:307.92,310.56 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:302.2,303.16 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:298.4,299.14 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:295.18,297.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:292.56,295.18 3 0 +github.com/OpenBazaar/multiwallet/client/pool.go:289.69,292.56 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:284.2,285.18 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:279.4,280.14 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:276.18,278.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:273.56,276.18 3 0 +github.com/OpenBazaar/multiwallet/client/pool.go:270.53,273.56 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:265.2,266.19 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:260.4,261.14 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:257.18,259.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:254.56,257.18 3 0 +github.com/OpenBazaar/multiwallet/client/pool.go:251.59,254.56 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:246.2,247.17 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:241.4,242.14 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:238.18,240.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:235.56,238.18 3 0 +github.com/OpenBazaar/multiwallet/client/pool.go:232.60,235.56 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:227.2,228.18 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:222.4,223.14 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:219.18,221.5 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:216.56,219.18 3 0 +github.com/OpenBazaar/multiwallet/client/pool.go:213.59,216.56 1 0 +github.com/OpenBazaar/multiwallet/client/pool.go:208.55,210.2 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:203.2,204.54 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:198.9,201.4 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:197.4,197.12 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:194.4,194.20 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:194.20,196.5 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:190.4,190.35 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:190.35,193.5 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:186.45,189.5 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:184.42,186.45 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:182.50,184.42 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:180.95,182.50 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:166.22,167.11 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:164.24,165.19 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:162.30,163.25 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:160.7,161.11 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:159.12,160.7 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:152.55,159.12 3 1 +github.com/OpenBazaar/multiwallet/client/pool.go:145.31,148.3 2 1 +github.com/OpenBazaar/multiwallet/client/pool.go:144.47,145.31 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:138.50,142.2 3 1 +github.com/OpenBazaar/multiwallet/client/pool.go:131.53,133.2 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:124.30,128.2 3 1 +github.com/OpenBazaar/multiwallet/client/pool.go:120.2,120.12 1 1 +github.com/OpenBazaar/multiwallet/client/pool.go:116.36,119.3 2 0 +github.com/OpenBazaar/multiwallet/client/pool.go:111.2,116.36 6 1 +github.com/OpenBazaar/multiwallet/client/pool.go:105.62,110.3 4 0 +github.com/OpenBazaar/multiwallet/client/pool.go:101.38,105.62 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:96.86,98.2 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:80.2,93.8 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:76.16,78.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:75.2,76.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:71.27,73.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:70.2,71.27 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:67.16,69.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:66.2,67.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:62.16,64.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:61.2,62.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:58.16,60.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:57.2,58.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:54.16,56.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:50.179,54.16 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:473.82,475.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:468.2,469.12 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:465.16,467.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:464.2,465.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:452.3,462.46 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:449.17,451.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:447.31,449.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:447.2,447.31 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:433.3,445.43 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:430.17,432.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:429.3,430.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:424.55,426.10 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:423.28,424.55 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:421.29,423.28 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:421.2,421.29 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:418.16,420.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:406.57,418.16 5 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:400.26,402.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:398.2,400.26 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:395.26,397.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:392.50,395.26 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:388.58,390.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:383.33,386.2 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:379.2,380.67 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:376.21,378.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:376.2,376.21 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:373.16,375.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:371.87,373.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:367.62,369.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:363.87,365.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:359.2,360.12 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:355.16,357.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:354.2,355.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:351.3,351.50 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:348.17,350.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:346.29,348.17 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:343.73,346.29 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:339.188,341.2 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:335.207,337.2 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:331.190,333.2 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:327.177,329.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:323.94,325.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:318.2,320.20 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:313.27,317.3 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:311.119,313.27 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:307.79,309.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:303.2,304.17 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:300.40,302.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:300.2,300.40 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:295.17,297.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:293.8,295.17 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:290.17,292.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:288.14,290.17 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:283.145,288.14 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:279.68,281.2 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:275.61,277.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:272.2,272.17 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:270.3,270.21 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:263.4,268.29 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:260.10,262.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:258.4,258.23 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:258.23,260.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:255.18,257.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:252.32,255.18 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:251.3,252.32 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:248.17,250.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:244.16,248.17 4 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:242.77,244.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:239.2,239.18 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:235.3,237.15 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:231.18,233.25 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:228.31,230.25 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:226.61,227.26 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:224.62,225.33 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:222.18,223.26 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:221.3,221.10 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:218.21,220.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:214.26,218.21 4 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:214.2,214.26 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:211.16,213.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:208.58,211.16 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:202.66,206.2 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:199.2,199.13 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:196.16,198.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:194.55,196.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:190.75,192.2 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:187.2,187.22 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:184.21,186.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:184.2,184.21 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:181.16,183.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:179.77,181.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:175.73,177.2 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:172.2,172.13 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:169.72,171.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:169.2,169.72 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:166.16,168.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:165.2,166.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:162.16,164.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:160.71,162.16 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:157.2,157.13 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:154.16,156.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:153.2,154.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:150.16,152.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:148.75,150.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:137.2,145.23 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:134.8,136.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:132.18,134.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:129.113,132.18 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:125.59,127.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:121.60,123.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:117.51,119.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:112.8,114.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:110.50,112.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:109.47,110.50 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:105.51,107.2 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/wallet.go:100.33,103.2 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:248.2,248.22 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:245.32,247.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:244.73,245.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:236.2,240.13 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:231.36,232.58 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:229.35,230.58 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:227.26,228.53 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:225.26,226.53 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:223.13,224.42 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:221.2,222.19 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:216.21,219.3 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/txsizes.go:213.113,216.21 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:99.27,101.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:98.2,99.27 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:95.3,95.21 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:92.17,94.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:89.41,92.17 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:83.2,89.41 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:79.3,79.50 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:76.4,77.55 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:73.18,74.13 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:72.4,73.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:69.18,70.13 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:669.2,669.36 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:666.20,668.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:666.2,666.20 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:660.107,662.10 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:659.30,660.107 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:658.32,659.30 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:658.2,658.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:655.16,657.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:653.2,655.16 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:650.34,652.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:649.2,650.34 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:646.16,648.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:645.2,646.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:642.16,644.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:639.94,642.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:636.2,636.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:633.16,635.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:630.2,633.16 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:626.16,628.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:625.2,626.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:615.3,623.28 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:612.30,614.4 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:609.3,612.30 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:606.17,608.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:604.8,606.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:601.3,602.43 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:60.35,69.18 9 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:598.30,600.4 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:595.34,598.30 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:594.2,595.34 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:591.3,591.33 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:588.17,590.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:586.27,588.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:585.2,586.27 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:58.3,60.35 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:579.27,583.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:579.2,579.27 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:575.54,577.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:574.188,575.54 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:569.2,571.25 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:565.41,567.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:564.2,564.15 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:564.15,565.41 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:560.3,561.26 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:557.17,559.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:555.3,557.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:55.17,57.4 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:549.32,551.10 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:548.3,548.29 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:548.29,549.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:543.32,545.10 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:542.29,543.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:539.32,542.29 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:539.2,539.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:535.39,537.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:531.2,535.39 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:525.35,527.4 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:523.23,525.35 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:521.2,523.23 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:52.2,52.136 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:52.136,55.17 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:518.16,520.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:516.2,518.16 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:511.3,512.38 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:508.17,510.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:506.27,508.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:506.2,506.27 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:502.3,504.35 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:499.17,501.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:497.25,499.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:495.207,497.25 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:492.2,492.18 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:49.25,51.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:489.3,490.26 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:486.17,487.12 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:484.25,486.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:483.2,484.25 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:479.16,481.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:476.2,479.16 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:470.35,472.4 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:468.23,470.35 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:466.2,468.23 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:463.16,465.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:461.2,463.16 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:46.2,49.25 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:456.3,457.38 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:453.17,455.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:451.27,453.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:451.2,451.27 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:447.3,449.35 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:444.17,446.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:442.25,444.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:439.190,442.25 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:435.2,436.19 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:432.40,434.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:432.2,432.40 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:43.16,45.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:426.4,427.26 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:423.10,425.5 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:421.18,423.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:420.4,421.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:417.18,419.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:415.9,417.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:414.4,414.33 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:411.18,413.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:406.26,411.18 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:405.31,406.26 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:404.2,405.31 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:399.5,399.29 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:396.19,398.6 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:394.33,396.19 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:391.30,394.33 3 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:389.25,391.30 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:388.2,389.25 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:384.3,384.28 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:381.26,383.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:380.77,381.26 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:380.2,380.77 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:378.3,378.45 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:376.4,376.47 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:373.18,375.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:371.57,373.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:370.88,371.57 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:370.2,370.88 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:37.2,43.16 5 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:366.16,368.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:364.2,366.16 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:361.16,363.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:347.2,361.16 5 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:344.16,346.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:337.2,344.16 5 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:333.17,335.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:330.25,333.17 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:33.89,35.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:327.2,330.25 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:322.3,325.44 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:319.17,321.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:318.3,319.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:315.17,317.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:312.25,315.17 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:309.2,312.25 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:305.16,307.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:304.2,305.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:301.8,303.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:30.136,33.89 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:299.20,301.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:297.177,299.20 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:294.2,294.44 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:291.4,291.29 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:288.18,290.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:281.4,288.18 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:278.18,280.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:277.4,278.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:274.18,276.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:273.4,274.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:270.18,272.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:268.50,270.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:267.26,268.50 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:266.2,267.26 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:262.20,264.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:262.2,262.20 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:259.20,261.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:259.2,259.20 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:256.16,258.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:254.79,256.16 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:245.3,250.9 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:239.4,242.19 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:235.45,238.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:235.4,235.45 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:232.18,234.5 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:230.51,232.18 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:221.3,230.51 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:216.39,218.12 2 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:213.3,216.39 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:209.43,211.4 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:209.3,209.43 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:206.17,208.4 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:204.6,206.17 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:201.2,204.6 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:197.32,199.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:194.172,197.32 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:191.2,191.16 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:189.3,189.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:186.17,188.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:181.31,186.17 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:181.2,181.31 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:178.37,180.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:177.2,178.37 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:175.3,175.46 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:172.10,174.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:169.88,172.10 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:162.2,169.88 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:157.94,159.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:152.2,157.94 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:147.16,149.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:141.2,147.16 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:138.16,140.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:133.102,138.16 4 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:130.2,130.27 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:128.3,128.32 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:125.17,127.4 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:120.42,125.17 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:120.2,120.42 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:117.37,119.3 1 0 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:116.2,117.37 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:111.88,115.3 3 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:108.2,111.88 2 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:103.16,105.3 1 1 +github.com/OpenBazaar/multiwallet/bitcoin/sign.go:102.2,103.16 2 1 diff --git a/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go b/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go index 4c70295b9c..4539888cb4 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go +++ b/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go @@ -74,6 +74,13 @@ func NewMockMultiwalletDatastore() *MockMultiwalletDatastore { &MockTxnStore{txns: make(map[string]*txnStoreEntry)}, &MockWatchedScriptsStore{scripts: make(map[string][]byte)}, }) + db[wallet.Filecoin] = wallet.Datastore(&MockDatastore{ + &MockKeyStore{Keys: make(map[string]*KeyStoreEntry)}, + &MockUtxoStore{utxos: make(map[string]*wallet.Utxo)}, + &MockStxoStore{stxos: make(map[string]*wallet.Stxo)}, + &MockTxnStore{txns: make(map[string]*txnStoreEntry)}, + &MockWatchedScriptsStore{scripts: make(map[string][]byte)}, + }) return &MockMultiwalletDatastore{db: db} } @@ -343,15 +350,15 @@ func (m *MockTxnStore) Put(tx []byte, txid, value string, height int, timestamp return nil } -func (m *MockTxnStore) Get(txid chainhash.Hash) (wallet.Txn, error) { +func (m *MockTxnStore) Get(txid string) (wallet.Txn, error) { m.Lock() defer m.Unlock() - t, ok := m.txns[txid.String()] + t, ok := m.txns[txid] if !ok { return wallet.Txn{}, errors.New("Not found") } return wallet.Txn{ - Txid: txid.String(), + Txid: txid, Value: t.value, Height: int32(t.height), Timestamp: t.timestamp, @@ -378,16 +385,16 @@ func (m *MockTxnStore) GetAll(includeWatchOnly bool) ([]wallet.Txn, error) { return txns, nil } -func (m *MockTxnStore) UpdateHeight(txid chainhash.Hash, height int, timestamp time.Time) error { +func (m *MockTxnStore) UpdateHeight(txid string, height int, timestamp time.Time) error { m.Lock() defer m.Unlock() - txn, ok := m.txns[txid.String()] + txn, ok := m.txns[txid] if !ok { return errors.New("Not found") } txn.height = height txn.timestamp = timestamp - m.txns[txid.String()] = txn + m.txns[txid] = txn return nil } diff --git a/vendor/github.com/OpenBazaar/multiwallet/filecoin/addr.go b/vendor/github.com/OpenBazaar/multiwallet/filecoin/addr.go new file mode 100644 index 0000000000..fa1d87d3a4 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/filecoin/addr.go @@ -0,0 +1,56 @@ +package filecoin + +import ( + "github.com/btcsuite/btcd/chaincfg" + faddr "github.com/filecoin-project/go-address" + "strings" +) + +type FilecoinAddress struct { + addr faddr.Address +} + +func NewFilecoinAddress(addrStr string) (*FilecoinAddress, error) { + addr, err := faddr.NewFromString(addrStr) + if err != nil { + return nil, err + } + return &FilecoinAddress{addr: addr}, nil +} + +// String returns the string encoding of the transaction output +// destination. +// +// Please note that String differs subtly from EncodeAddress: String +// will return the value as a string without any conversion, while +// EncodeAddress may convert destination types (for example, +// converting pubkeys to P2PKH addresses) before encoding as a +// payment address string. +func (f *FilecoinAddress) String() string { + return f.addr.String() +} + +// EncodeAddress returns the string encoding of the payment address +// associated with the Address value. See the comment on String +// for how this method differs from String. +func (f *FilecoinAddress) EncodeAddress() string { + return f.addr.String() +} + +// ScriptAddress returns the raw bytes of the address to be used +// when inserting the address into a txout's script. +func (f *FilecoinAddress) ScriptAddress() []byte { + return nil +} + +// IsForNet returns whether or not the address is associated with the +// passed bitcoin network. +func (f *FilecoinAddress) IsForNet(params *chaincfg.Params) bool { + switch params.Name { + case chaincfg.MainNetParams.Name: + return strings.HasPrefix(f.addr.String(), faddr.MainnetPrefix) + case chaincfg.TestNet3Params.Name: + return strings.HasPrefix(f.addr.String(), faddr.TestnetPrefix) + } + return false +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go b/vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go new file mode 100644 index 0000000000..eb862f88df --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go @@ -0,0 +1,318 @@ +package filecoin + +import ( + "encoding/json" + "fmt" + "github.com/OpenBazaar/multiwallet/cache" + "github.com/OpenBazaar/multiwallet/model" + "github.com/OpenBazaar/multiwallet/service" + "github.com/OpenBazaar/multiwallet/util" + "github.com/OpenBazaar/wallet-interface" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcutil" + "github.com/ipfs/go-cid" + "github.com/op/go-logging" + "math" + "math/big" + "sync" + "time" +) + +var Log = logging.MustGetLogger("Filecoin") + +type FilecoinService struct { + db wallet.Datastore + addr btcutil.Address + client model.APIClient + params *chaincfg.Params + coinType wallet.CoinType + + chainHeight uint32 + bestBlock string + cache cache.Cacher + + listeners []func(wallet.TransactionCallback) + + lock sync.RWMutex + + doneChan chan struct{} +} + +func NewFilecoinService(db wallet.Datastore, addr btcutil.Address, client model.APIClient, params *chaincfg.Params, coinType wallet.CoinType, cache cache.Cacher) (*FilecoinService, error) { + fs := &FilecoinService{ + db: db, + addr: addr, + client: client, + params: params, + coinType: coinType, + cache: cache, + doneChan: make(chan struct{}), + lock: sync.RWMutex{}, + } + marshaledHeight, err := cache.Get(fs.bestHeightKey()) + if err != nil { + Log.Info("cached block height missing: using default") + } else { + var hh service.HashAndHeight + if err := json.Unmarshal(marshaledHeight, &hh); err != nil { + Log.Error("failed unmarshaling cached block height") + return fs, nil + } + fs.bestBlock = hh.Hash + fs.chainHeight = hh.Height + } + return fs, nil +} + +func (fs *FilecoinService) Start() { + Log.Noticef("starting FilecoinService") + go fs.run() +} + +func (fs *FilecoinService) run() { + var ( + txChan = fs.client.TransactionNotify() + blockChan = fs.client.BlockNotify() + ) + + fs.client.ListenAddresses(fs.addr) + + for { + select { + case <-fs.doneChan: + return + case tx := <-txChan: + go fs.ProcessIncomingTransaction(tx) + case block := <-blockChan: + go fs.processIncomingBlock(block) + } + } +} + +func (fs *FilecoinService) Stop() { + close(fs.doneChan) +} + +func (fs *FilecoinService) ChainTip() (uint32, string) { + return fs.chainHeight, fs.bestBlock +} + +func (fs *FilecoinService) AddTransactionListener(callback func(callback wallet.TransactionCallback)) { + fs.listeners = append(fs.listeners, callback) +} + +func (fs *FilecoinService) InvokeTransactionListeners(callback wallet.TransactionCallback) { + for _, l := range fs.listeners { + go l(callback) + } +} + +// This is a transaction fresh off the wire. Let's save it to the db. +func (fs *FilecoinService) ProcessIncomingTransaction(tx model.Transaction) { + Log.Debugf("new incoming %s transaction: %s", fs.coinType.String(), tx.Txid) + + fs.lock.RLock() + chainHeight := int32(fs.chainHeight) + fs.lock.RUnlock() + fs.saveSingleTxToDB(tx, chainHeight) +} + +func (fs *FilecoinService) UpdateState() { + // Start by fetching the chain height from the API + Log.Debugf("updating %s chain state", fs.coinType.String()) + best, err := fs.client.GetBestBlock() + if err == nil { + Log.Debugf("%s chain height: %d", fs.coinType.String(), best.Height) + fs.lock.Lock() + err = fs.saveHashAndHeight(best.Hash, uint32(best.Height)) + if err != nil { + Log.Errorf("updating %s blockchain height: %s", fs.coinType.String(), err.Error()) + } + fs.lock.Unlock() + } else { + Log.Errorf("error querying API for %s chain height: %s", fs.coinType.String(), err.Error()) + } + + go fs.syncTxs() +} + +func (fs *FilecoinService) syncTxs() { + Log.Debugf("querying for %s transactions", fs.coinType.String()) + query := []btcutil.Address{fs.addr} + txs, err := fs.client.GetTransactions(query) + if err != nil { + Log.Errorf("error downloading txs for %s: %s", fs.coinType.String(), err.Error()) + } else { + Log.Debugf("downloaded %d %s transactions", len(txs), fs.coinType.String()) + fs.lock.RLock() + chainHeight := int32(fs.chainHeight) + fs.lock.RUnlock() + for _, u := range txs { + fs.saveSingleTxToDB(u, chainHeight) + } + } +} + +func (fs *FilecoinService) processIncomingBlock(block model.Block) { + Log.Infof("received new %s block at height %d: %s", fs.coinType.String(), block.Height, block.Hash) + fs.lock.RLock() + currentBest := fs.bestBlock + fs.lock.RUnlock() + + fs.lock.Lock() + err := fs.saveHashAndHeight(block.Hash, uint32(block.Height)) + if err != nil { + Log.Errorf("update %s blockchain height: %s", fs.coinType.String(), err.Error()) + } + fs.lock.Unlock() + + // REORG! Rescan all transactions and utxos to see if anything changed + if currentBest != block.PreviousBlockhash && currentBest != block.Hash { + Log.Warningf("%s chain reorg detected: rescanning wallet", fs.coinType.String()) + fs.UpdateState() + return + } + + // Query db for unconfirmed txs and utxos then query API to get current height + txs, err := fs.db.Txns().GetAll(true) + if err != nil { + Log.Errorf("error loading %s txs from db: %s", fs.coinType.String(), err.Error()) + return + } + for _, tx := range txs { + if tx.Height == 0 { + Log.Debugf("broadcasting unconfirmed txid %s", tx.Txid) + go func(txn wallet.Txn) { + ret, err := fs.client.GetTransaction(txn.Txid) + if err != nil { + Log.Errorf("error fetching unconfirmed %s tx: %s", fs.coinType.String(), err.Error()) + return + } + if ret.Confirmations > 0 { + fs.saveSingleTxToDB(*ret, int32(block.Height)) + return + } + // Rebroadcast unconfirmed transactions + _, err = fs.client.Broadcast(tx.Bytes) + if err != nil { + Log.Errorf("broadcasting unconfirmed utxo: %s", err.Error()) + } + }(tx) + } + } +} + +func (fs *FilecoinService) saveSingleTxToDB(u model.Transaction, chainHeight int32) { + hits := 0 + value := new(big.Int) + + height := int32(0) + if u.Confirmations > 0 { + height = chainHeight - (int32(u.Confirmations) - 1) + } + + txHash, err := cid.Decode(u.Txid) + if err != nil { + Log.Errorf("error converting to txHash for %s: %s", fs.coinType.String(), err.Error()) + return + } + var relevant bool + cb := wallet.TransactionCallback{Txid: txHash.String(), Height: height, Timestamp: time.Unix(u.Time, 0)} + for _, in := range u.Inputs { + faddr, err := NewFilecoinAddress(in.Addr) + if err != nil { + Log.Errorf("error parsing address %s: %s", fs.coinType.String(), err.Error()) + continue + } + + v := big.NewInt(int64(math.Round(in.Value * float64(util.SatoshisPerCoin(fs.coinType))))) + cbin := wallet.TransactionInput{ + LinkedAddress: faddr, + Value: *v, + } + cb.Inputs = append(cb.Inputs, cbin) + + if in.Addr == fs.addr.String() { + relevant = true + value.Sub(value, v) + hits++ + } + } + for i, out := range u.Outputs { + if len(out.ScriptPubKey.Addresses) == 0 { + continue + } + faddr, err := NewFilecoinAddress(out.ScriptPubKey.Addresses[0]) + if err != nil { + Log.Errorf("error parsing address %s: %s", fs.coinType.String(), err.Error()) + continue + } + + v := big.NewInt(int64(math.Round(out.Value * float64(util.SatoshisPerCoin(fs.coinType))))) + + cbout := wallet.TransactionOutput{Address: faddr, Value: *v, Index: uint32(i)} + cb.Outputs = append(cb.Outputs, cbout) + + if out.ScriptPubKey.Addresses[0] == fs.addr.String() { + relevant = true + value.Add(value, v) + hits++ + } + } + + if !relevant { + Log.Warningf("abort saving irrelevant txid (%s) to db", u.Txid) + return + } + + cb.Value = *value + saved, err := fs.db.Txns().Get(txHash.String()) + if err != nil { + ts := time.Now() + if u.Confirmations > 0 { + ts = time.Unix(u.BlockTime, 0) + } + err = fs.db.Txns().Put(u.RawBytes, txHash.String(), value.String(), int(height), ts, hits == 0) + if err != nil { + Log.Errorf("putting txid (%s): %s", txHash.String(), err.Error()) + return + } + cb.Timestamp = ts + fs.callbackListeners(cb) + } else if height > 0 { + err := fs.db.Txns().UpdateHeight(txHash.String(), int(height), time.Unix(u.BlockTime, 0)) + if err != nil { + Log.Errorf("updating height for tx (%s): %s", txHash.String(), err.Error()) + return + } + if saved.Height != height { + cb.Timestamp = saved.Timestamp + fs.callbackListeners(cb) + } + } +} + +func (fs *FilecoinService) callbackListeners(cb wallet.TransactionCallback) { + for _, callback := range fs.listeners { + callback(cb) + } +} + +func (fs *FilecoinService) saveHashAndHeight(hash string, height uint32) error { + hh := service.HashAndHeight{ + Height: height, + Hash: hash, + Timestamp: time.Now(), + } + b, err := json.MarshalIndent(&hh, "", " ") + if err != nil { + return err + } + fs.chainHeight = height + fs.bestBlock = hash + return fs.cache.Set(fs.bestHeightKey(), b) +} + +func (fs *FilecoinService) bestHeightKey() string { + return fmt.Sprintf("best-height-%s", fs.coinType.String()) +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go new file mode 100644 index 0000000000..9e399d7b8a --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go @@ -0,0 +1,458 @@ +package filecoin + +import ( + "fmt" + "github.com/OpenBazaar/multiwallet/keys" + "github.com/btcsuite/btcd/btcec" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" + "github.com/filecoin-project/specs-actors/actors/crypto" + "io" + "math/big" + "time" + + "github.com/OpenBazaar/multiwallet/cache" + "github.com/OpenBazaar/multiwallet/client" + "github.com/OpenBazaar/multiwallet/config" + "github.com/OpenBazaar/multiwallet/model" + wi "github.com/OpenBazaar/wallet-interface" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcutil" + hd "github.com/btcsuite/btcutil/hdkeychain" + faddr "github.com/filecoin-project/go-address" + "github.com/op/go-logging" + "github.com/tyler-smith/go-bip39" + "golang.org/x/net/proxy" +) + +type FilecoinWallet struct { + db wi.Datastore + params *chaincfg.Params + client model.APIClient + + mPrivKey *hd.ExtendedKey + mPubKey *hd.ExtendedKey + + addr faddr.Address + key *btcec.PrivateKey + + fs *FilecoinService + + exchangeRates wi.ExchangeRates + log *logging.Logger +} + +var ( + _ = wi.Wallet(&FilecoinWallet{}) + FilecoinCurrencyDefinition = wi.CurrencyDefinition{ + Code: "FIL", + Divisibility: 18, + } +) + +func NewFilecoinWallet(cfg config.CoinConfig, mnemonic string, params *chaincfg.Params, proxy proxy.Dialer, cache cache.Cacher, disableExchangeRates bool) (*FilecoinWallet, error) { + seed := bip39.NewSeed(mnemonic, "") + + mPrivKey, err := hd.NewMaster(seed, params) + if err != nil { + return nil, err + } + mPubKey, err := mPrivKey.Neuter() + if err != nil { + return nil, err + } + + _, external, err := keys.Bip44Derivation(mPrivKey, wi.Filecoin) + if err != nil { + return nil, err + } + + accountHDKey, err := external.Child(0) + if err != nil { + return nil, err + } + + accountECKey, err := accountHDKey.ECPrivKey() + if err != nil { + return nil, err + } + + accountAddr, err := faddr.NewSecp256k1Address(accountECKey.PubKey().SerializeCompressed()) + if err != nil { + return nil, err + } + + c, err := client.NewClientPool(cfg.ClientAPIs, proxy) + if err != nil { + return nil, err + } + + fs, err := NewFilecoinService(cfg.DB, &FilecoinAddress{addr: accountAddr}, c, params, wi.Filecoin, cache) + if err != nil { + return nil, err + } + + return &FilecoinWallet{ + db: cfg.DB, + params: params, + client: c, + addr: accountAddr, + mPrivKey: mPrivKey, + mPubKey: mPubKey, + key: accountECKey, + fs: fs, + log: logging.MustGetLogger("litecoin-wallet"), + }, nil +} + +func (w *FilecoinWallet) Start() { + w.client.Start() + w.fs.Start() +} + +func (w *FilecoinWallet) Params() *chaincfg.Params { + return w.params +} + +func (w *FilecoinWallet) CurrencyCode() string { + if w.params.Name == chaincfg.MainNetParams.Name { + return "fil" + } else { + return "tfil" + } +} + +func (w *FilecoinWallet) IsDust(amount big.Int) bool { + // TODO + return false +} + +func (w *FilecoinWallet) MasterPrivateKey() *hd.ExtendedKey { + return w.mPrivKey +} + +func (w *FilecoinWallet) MasterPublicKey() *hd.ExtendedKey { + return w.mPubKey +} + +func (w *FilecoinWallet) ChildKey(keyBytes []byte, chaincode []byte, isPrivateKey bool) (*hd.ExtendedKey, error) { + parentFP := []byte{0x00, 0x00, 0x00, 0x00} + var id []byte + if isPrivateKey { + id = w.params.HDPrivateKeyID[:] + } else { + id = w.params.HDPublicKeyID[:] + } + hdKey := hd.NewExtendedKey( + id, + keyBytes, + chaincode, + parentFP, + 0, + 0, + isPrivateKey) + return hdKey.Child(0) +} + +func (w *FilecoinWallet) CurrentAddress(purpose wi.KeyPurpose) btcutil.Address { + return &FilecoinAddress{addr: w.addr} +} + +func (w *FilecoinWallet) CreateMultisigSignature(ins []wi.TransactionInput, outs []wi.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]wi.Signature, error) { + return nil, nil +} + +func (w *FilecoinWallet) Multisign(ins []wi.TransactionInput, outs []wi.TransactionOutput, sigs1 []wi.Signature, sigs2 []wi.Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) { + return nil, nil +} + +func (wallet *FilecoinWallet) SweepAddress(utxos []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { + return chainhash.NewHashFromStr("") +} + +func (w *FilecoinWallet) GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btcutil.Address, redeemScript []byte, err error) { + return nil, nil, nil +} + +func (w *FilecoinWallet) NewAddress(purpose wi.KeyPurpose) btcutil.Address { + return &FilecoinAddress{addr: w.addr} +} + +func (w *FilecoinWallet) DecodeAddress(addr string) (btcutil.Address, error) { + a, err := faddr.NewFromString(addr) + if err != nil { + return nil, err + } + return &FilecoinAddress{addr: a}, nil +} + +func (w *FilecoinWallet) ScriptToAddress(script []byte) (btcutil.Address, error) { + return w.DecodeAddress(string(script)) +} + +func (w *FilecoinWallet) AddressToScript(addr btcutil.Address) ([]byte, error) { + return []byte(addr.String()), nil +} + +func (w *FilecoinWallet) HasKey(addr btcutil.Address) bool { + return w.addr.String() == addr.String() +} + +func (w *FilecoinWallet) Balance() (wi.CurrencyValue, wi.CurrencyValue) { + txns, _ := w.db.Txns().GetAll(false) + confirmed, unconfirmed := big.NewInt(0), big.NewInt(0) + for _, tx := range txns { + val, _ := new(big.Int).SetString(tx.Value, 10) + if val.Cmp(big.NewInt(0)) > 0 { + if tx.Height > 0 { + confirmed.Add(confirmed, val) + } else { + unconfirmed.Add(confirmed, val) + } + } else if val.Cmp(big.NewInt(0)) < 0 { + if tx.Height > 0 { + confirmed.Sub(confirmed, val) + } else { + unconfirmed.Sub(confirmed, val) + } + } + } + return wi.CurrencyValue{Value: *confirmed, Currency: FilecoinCurrencyDefinition}, + wi.CurrencyValue{Value: *unconfirmed, Currency: FilecoinCurrencyDefinition} +} + +func (w *FilecoinWallet) Transactions() ([]wi.Txn, error) { + height, _ := w.ChainTip() + txns, err := w.db.Txns().GetAll(false) + if err != nil { + return txns, err + } + for i, tx := range txns { + var confirmations int32 + var status wi.StatusCode + confs := int32(height) - tx.Height + 1 + if tx.Height <= 0 { + confs = tx.Height + } + switch { + case confs < 0: + status = wi.StatusDead + case confs == 0 && time.Since(tx.Timestamp) <= time.Hour*6: + status = wi.StatusUnconfirmed + case confs == 0 && time.Since(tx.Timestamp) > time.Hour*6: + status = wi.StatusDead + case confs > 0 && confs < 24: + status = wi.StatusPending + confirmations = confs + case confs > 23: + status = wi.StatusConfirmed + confirmations = confs + } + tx.Confirmations = int64(confirmations) + tx.Status = status + txns[i] = tx + } + return txns, nil +} + +func (w *FilecoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { + txn, err := w.db.Txns().Get(txid.String()) + return txn, err +} + +func (w *FilecoinWallet) ChainTip() (uint32, string) { + return w.fs.ChainTip() +} + +func (w *FilecoinWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { + return *big.NewInt(0) +} + +func (w *FilecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { + address, err := faddr.NewFromString(addr.String()) + if err != nil { + return nil, err + } + if spendAll { + c, u := w.Balance() + amount = *c.Value.Add(big.NewInt(0), &u.Value) + } + bigAmt, err := types.BigFromString(amount.String()) + if err != nil { + return nil, err + } + m := types.Message{ + To: address, + Value: bigAmt, + From: w.addr, + } + + id := m.Cid() + + cs, err := sigs.Sign(crypto.SigTypeSecp256k1, w.key.Serialize(), id.Bytes()) + if err != nil { + return nil, err + } + + signed := &types.SignedMessage{ + Message: m, + Signature: *cs, + } + + // Broadcast + if err := w.Broadcast(signed); err != nil { + return nil, err + } + + ch, err := chainhash.NewHash(id.Bytes()) + if err != nil { + return nil, err + } + + return ch, nil +} + +func (w *FilecoinWallet) EstimateFee(ins []wi.TransactionInput, outs []wi.TransactionOutput, feePerByte big.Int) big.Int { + return *big.NewInt(1000) // TODO: find right fee +} + +func (w *FilecoinWallet) EstimateSpendFee(amount big.Int, feeLevel wi.FeeLevel) (big.Int, error) { + return *big.NewInt(1000), nil // TODO: find right fee +} + +func (w *FilecoinWallet) AddWatchedAddresses(addrs ...btcutil.Address) error { + var watchedScripts [][]byte + for _, addr := range addrs { + if !w.HasKey(addr) { + script, err := w.AddressToScript(addr) + if err != nil { + return err + } + watchedScripts = append(watchedScripts, script) + } + } + + err := w.db.WatchedScripts().PutAll(watchedScripts) + if err != nil { + return err + } + + w.client.ListenAddresses(addrs...) + return nil +} + +func (w *FilecoinWallet) AddWatchedScript(script []byte) error { + err := w.db.WatchedScripts().Put(script) + if err != nil { + return err + } + addr, err := w.ScriptToAddress(script) + if err != nil { + return err + } + w.client.ListenAddresses(addr) + return nil +} + +func (w *FilecoinWallet) AddTransactionListener(callback func(wi.TransactionCallback)) { + w.fs.AddTransactionListener(callback) +} + +func (w *FilecoinWallet) ReSyncBlockchain(fromTime time.Time) { + go w.fs.UpdateState() +} + +func (w *FilecoinWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { + txn, err := w.db.Txns().Get(txid.String()) + if err != nil { + return 0, 0, err + } + if txn.Height == 0 { + return 0, 0, nil + } + chainTip, _ := w.ChainTip() + return chainTip - uint32(txn.Height) + 1, uint32(txn.Height), nil +} + +func (w *FilecoinWallet) Close() { + w.fs.Stop() + w.client.Close() +} + +func (w *FilecoinWallet) ExchangeRates() wi.ExchangeRates { + return w.exchangeRates +} + +func (w *FilecoinWallet) DumpTables(wr io.Writer) { + fmt.Fprintln(wr, "Transactions-----") + txns, _ := w.db.Txns().GetAll(true) + for _, tx := range txns { + fmt.Fprintf(wr, "Hash: %s, Height: %d, Value: %s, WatchOnly: %t\n", tx.Txid, int(tx.Height), tx.Value, tx.WatchOnly) + } + fmt.Fprintln(wr, "\nUtxos-----") + utxos, _ := w.db.Utxos().GetAll() + for _, u := range utxos { + fmt.Fprintf(wr, "Hash: %s, Index: %d, Height: %d, Value: %s, WatchOnly: %t\n", u.Op.Hash.String(), int(u.Op.Index), int(u.AtHeight), u.Value, u.WatchOnly) + } + fmt.Fprintln(wr, "\nKeys-----") + keys, _ := w.db.Keys().GetAll() + unusedInternal, _ := w.db.Keys().GetUnused(wi.INTERNAL) + unusedExternal, _ := w.db.Keys().GetUnused(wi.EXTERNAL) + internalMap := make(map[int]bool) + externalMap := make(map[int]bool) + for _, k := range unusedInternal { + internalMap[k] = true + } + for _, k := range unusedExternal { + externalMap[k] = true + } + + for _, k := range keys { + var used bool + if k.Purpose == wi.INTERNAL { + used = internalMap[k.Index] + } else { + used = externalMap[k.Index] + } + fmt.Fprintf(wr, "KeyIndex: %d, Purpose: %d, Used: %t\n", k.Index, k.Purpose, used) + } +} + +// Build a client.Transaction so we can ingest it into the wallet service then broadcast +func (w *FilecoinWallet) Broadcast(msg *types.SignedMessage) error { + id := msg.Cid() + ser, err := msg.Serialize() + if err != nil { + return err + } + + cTxn := model.Transaction{ + Txid: id.String(), + Version: int(msg.Message.Version), + Confirmations: 0, + Time: time.Now().Unix(), + RawBytes: ser, + } + output := model.Output{ + ScriptPubKey: model.OutScript{ + Addresses: []string{msg.Message.To.String()}, + }, + } + cTxn.Outputs = append(cTxn.Outputs, output) + _, err = w.client.Broadcast(ser) + if err != nil { + return err + } + w.fs.ProcessIncomingTransaction(cTxn) + return nil +} + +func (w *FilecoinWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { + return nil, nil +} + +// AssociateTransactionWithOrder used for ORDER_PAYMENT message +func (w *FilecoinWallet) AssociateTransactionWithOrder(cb wi.TransactionCallback) { + w.fs.InvokeTransactionListeners(cb) +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/go.mod b/vendor/github.com/OpenBazaar/multiwallet/go.mod new file mode 100644 index 0000000000..f9d7c4a285 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/go.mod @@ -0,0 +1,45 @@ +module github.com/OpenBazaar/multiwallet + +go 1.14 + +require ( + github.com/OpenBazaar/go-ethwallet v0.0.0-20200604192229-31db816d691c + github.com/OpenBazaar/golang-socketio v0.0.0-20200109001351-4147b5f0d294 + github.com/OpenBazaar/openbazaar-go v0.14.3 // indirect + github.com/OpenBazaar/spvwallet v0.0.0-20200112224336-39f04e8d6d34 + github.com/OpenBazaar/wallet-interface v0.0.0-20200511225711-6ec1fd0d9d23 + github.com/btcsuite/btcd v0.20.1-beta + github.com/btcsuite/btcutil v1.0.2 + github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 + github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 + github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 + github.com/cenkalti/backoff v2.2.1+incompatible + github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c + github.com/ethereum/go-ethereum v1.9.15 // indirect + github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef + github.com/filecoin-project/lotus v0.4.0 + github.com/filecoin-project/specs-actors v0.7.1 + github.com/gcash/bchd v0.16.4 + github.com/golang/protobuf v1.4.2 + github.com/google/go-cmp v0.4.1 // indirect + github.com/gorilla/websocket v1.4.2 + github.com/hunterlong/tokenbalance v0.0.12-0.20191105170207-4f98e641e619 // indirect + github.com/jarcoal/httpmock v1.0.5 + github.com/jessevdk/go-flags v1.4.0 + github.com/joho/godotenv v1.3.0 // indirect + github.com/ltcsuite/ltcd v0.20.1-beta + github.com/ltcsuite/ltcutil v1.0.2-beta + github.com/ltcsuite/ltcwallet/wallet/txrules v1.0.0 + github.com/mattn/go-runewidth v0.0.8 // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/nanmu42/etherscan-api v1.1.1 // indirect + github.com/olekukonko/tablewriter v0.0.4 // indirect + github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 + github.com/prometheus/tsdb v0.7.1 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/stretchr/testify v1.6.0 // indirect + github.com/tyler-smith/go-bip39 v1.0.2 + golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0 + golang.org/x/net v0.0.0-20200707034311-ab3426394381 + google.golang.org/grpc v1.30.0 +) diff --git a/vendor/github.com/OpenBazaar/multiwallet/go.sum b/vendor/github.com/OpenBazaar/multiwallet/go.sum new file mode 100644 index 0000000000..5a21446324 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/go.sum @@ -0,0 +1,1880 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= +contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee/go.mod h1:W0GbEAA4uFNYOGG2cJpmFJ04E6SD1NLELPYZB57/7AY= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OpenBazaar/go-ethwallet v0.0.0-20200604192229-31db816d691c h1:+dB9aoL2MH7IN4Tcxa4e6ybEDS48kvImYcKRiH27ITE= +github.com/OpenBazaar/go-ethwallet v0.0.0-20200604192229-31db816d691c/go.mod h1:AQS5qGhP8yd5kv3d+pFDyxEPIsiJr35vwXC1W1ttkdw= +github.com/OpenBazaar/golang-socketio v0.0.0-20200109001351-4147b5f0d294 h1:ic05Fdz58zT1On4uleoZjhlxCIGtiwmU421MksguxSE= +github.com/OpenBazaar/golang-socketio v0.0.0-20200109001351-4147b5f0d294/go.mod h1:sEz//wpQju9ZgIZKKSVf0R5tok3eEqDpKL+Q6WzWXz8= +github.com/OpenBazaar/jsonpb v0.0.0-20171123000858-37d32ddf4eef/go.mod h1:55mCznBcN9WQgrtgaAkv+p2LxeW/tQRdidyyE9D0I5k= +github.com/OpenBazaar/openbazaar-go v0.14.3 h1:8GLYjZp+vZFrsonyj4a8q/JJucgMemN1Ssw/xqzA8LQ= +github.com/OpenBazaar/openbazaar-go v0.14.3/go.mod h1:IPD0UJLYifq0e5ZiJ1oXpKyg1raiRvmU0Mq17sKj/S0= +github.com/OpenBazaar/spvwallet v0.0.0-20200112224336-39f04e8d6d34 h1:xGvs105pXKoIVhYc5SaxbLOzvriX61KYB9oSinjFGUk= +github.com/OpenBazaar/spvwallet v0.0.0-20200112224336-39f04e8d6d34/go.mod h1:SVavvqIp6t5kuJx+PqDsKIQ+avRth92nGg2wVp7mW/s= +github.com/OpenBazaar/wallet-interface v0.0.0-20200511225711-6ec1fd0d9d23 h1:A+/78rkN9VEJNccIcMSdiYfYwZ6AZgenIX41cSN8B08= +github.com/OpenBazaar/wallet-interface v0.0.0-20200511225711-6ec1fd0d9d23/go.mod h1:KiLnq+35bzKd6Bq8EP8iGElNBU/++VxbDVg9zCvKMgU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3oM7gXIttpYDAJXpVNnSCiUMYBLIZ6cb1t+Ip982MRo= +github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= +github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= +github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/benbjohnson/clock v1.0.1/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c= +github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= +github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 h1:2VsfS0sBedcM5KmDzRMT3+b6xobqWveZGvjb+jFez5w= +github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA= +github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 h1:6DxkcoMnCPY4E9cUDPB5tbuuf40SmmMkSQkoE8vCT+s= +github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 h1:nOsAWScwueMVk/VLm/dvQQD7DuanyvAUb6B3P3eT274= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0 h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c h1:4e6Zsb6LFd3kadoMiut2zcd3hCb4zywpJnQa8+NV2Cs= +github.com/cpacia/bchutil v0.0.0-20181003130114-b126f6a35b6c/go.mod h1:k5D13LCXSsMrQyfdW0yGYs4GWUvirqoxHht8qwtqyRY= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f h1:BOaYiTvg8p9vBUXpklC22XSK/mifLF7lG9jtmYYi3Tc= +github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/dchest/siphash v1.2.1 h1:4cLinnzVJDKxTCl9B01807Yiy+W7ZzVHj/KIroQRvT4= +github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= +github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= +github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= +github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y= +github.com/drand/drand v0.9.2-0.20200616080806-a94e9c1636a4/go.mod h1:Bu8QYdU0YdB2ZQZezHxabmOIciddiwLRnyV4nuZ2HQE= +github.com/drand/kyber v1.0.1-0.20200110225416-8de27ed8c0e2/go.mod h1:UpXoA0Upd1N9l4TvRPHr1qAUBBERj6JQ/mnKI3BPEmw= +github.com/drand/kyber v1.0.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= +github.com/drand/kyber v1.1.0/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= +github.com/drand/kyber-bls12381 v0.1.0/go.mod h1:N1emiHpm+jj7kMlxEbu3MUyOiooTgNySln564cgD9mk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/go-sysinfo v1.3.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= +github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= +github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.9.15 h1:wrWl+QrtutRUJ9LZXdUqBoGoo2b1tOCYRDrAOQhCY3A= +github.com/ethereum/go-ethereum v1.9.15/go.mod h1:slT8bPPRhXsyNTwHQxrOnjuTZ1sDXRajW11EkJ84QJ0= +github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY= +github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= +github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= +github.com/filecoin-project/chain-validation v0.0.6-0.20200615191232-6be1a8c6ed09/go.mod h1:HEJn6kOXMNhCNBYNTO/lrEI7wSgqCOR6hN5ecfYUnC8= +github.com/filecoin-project/filecoin-ffi v0.0.0-20200326153646-e899cc1dd072/go.mod h1:PtH9YP0rURHUKHrKeEBeWg/BqIBMQOz8wtlXlVGREBE= +github.com/filecoin-project/filecoin-ffi v0.26.1-0.20200508175440-05b30afeb00d h1:smoOJ2TGTYFsmBaH01WIx4crs8axosy1V9Pi+/bdk5Y= +github.com/filecoin-project/filecoin-ffi v0.26.1-0.20200508175440-05b30afeb00d/go.mod h1:vlQ7sDkbrtM70QMJFDvEyTDywY5SvIjadRCUB+76l90= +github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= +github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= +github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef h1:Wi5E+P1QfHP8IF27eUiTx5vYfqQZwfPxzq3oFEq8w8U= +github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef/go.mod h1:SrA+pWVoUivqKOfC+ckVYbx41hWz++HxJcrlmHNnebU= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2 h1:jamfsxfK0Q9yCMHt8MPWx7Aa/O9k2Lve8eSc6FILYGQ= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= +github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= +github.com/filecoin-project/go-bitfield v0.0.2-0.20200518150651-562fdb554b6e h1:gkG/7G+iKy4He+IiQNeQn+nndFznb/vCoOR8iRQsm60= +github.com/filecoin-project/go-bitfield v0.0.2-0.20200518150651-562fdb554b6e/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= +github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= +github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= +github.com/filecoin-project/go-data-transfer v0.3.0 h1:BwBrrXu9Unh9JjjX4GAc5FfzUNioor/aATIjfc7JTBg= +github.com/filecoin-project/go-data-transfer v0.3.0/go.mod h1:cONglGP4s/d+IUQw5mWZrQK+FQATQxr3AXzi4dRh0l4= +github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5 h1:yvQJCW9mmi9zy+51xA01Ea2X7/dL7r8eKDPuGUjRmbo= +github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= +github.com/filecoin-project/go-fil-markets v0.3.0 h1:7iCGiuTSia4f4DmOn3s96NWUwMNSOI0ZHel/XgeApAQ= +github.com/filecoin-project/go-fil-markets v0.3.0/go.mod h1:UXsXi43AyUQ5ieb4yIaLgk4PVt7TAbl1UCccuNw+7ds= +github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24/go.mod h1:j6zV//WXIIY5kky873Q3iIKt/ViOE8rcijovmpxrXzM= +github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= +github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= +github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-paramfetch v0.0.2-0.20200605171344-fcac609550ca h1:OGykrCr6mSn/ckk2IFbIlkc76nsgEs7tSLhZXQt7+z4= +github.com/filecoin-project/go-paramfetch v0.0.2-0.20200605171344-fcac609550ca/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-statemachine v0.0.0-20200612181802-4eb3d0c68eba h1:GEWb/6KQyNZt4jm8fgVcIFPH0ElAGXfHM59ZSiqPTvY= +github.com/filecoin-project/go-statemachine v0.0.0-20200612181802-4eb3d0c68eba/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIiWBRilQjQ+5IiwdQ= +github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= +github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= +github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= +github.com/filecoin-project/lotus v0.4.0 h1:tr9g3hhv/LrezPlbtOj6MCw1hVkbhpOXiq+Y9QFt34Q= +github.com/filecoin-project/lotus v0.4.0/go.mod h1:RGmcSJ6+0D3vXcBgNk6T7fT9Y5UBZ+Aowse3cTi+yZA= +github.com/filecoin-project/sector-storage v0.0.0-20200615154852-728a47ab99d6/go.mod h1:M59QnAeA/oV+Z8oHFLoNpGMv0LZ8Rll+vHVXX7GirPM= +github.com/filecoin-project/sector-storage v0.0.0-20200618073200-d9de9b7cb4b4 h1:lQC8Fbyn31/H4QxYAYwVV3PYZ9vS61EmjktZc5CaiYs= +github.com/filecoin-project/sector-storage v0.0.0-20200618073200-d9de9b7cb4b4/go.mod h1:M59QnAeA/oV+Z8oHFLoNpGMv0LZ8Rll+vHVXX7GirPM= +github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= +github.com/filecoin-project/specs-actors v0.0.0-20200226200336-94c9b92b2775/go.mod h1:0HAWYrvajFHDgRaKbF0rl+IybVLZL5z4gQ8koCMPhoU= +github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= +github.com/filecoin-project/specs-actors v0.6.0/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= +github.com/filecoin-project/specs-actors v0.6.2-0.20200617175406-de392ca14121/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= +github.com/filecoin-project/specs-actors v0.7.1 h1:/zW++MN4gGIPvG+s0zmSI97k0Z/aaeiREjLC10gQbco= +github.com/filecoin-project/specs-actors v0.7.1/go.mod h1:+z0htZu/wLBDbOLcQTKKUEC2rkUTFzL2KJ/bRAVWkws= +github.com/filecoin-project/specs-storage v0.1.0 h1:PkDgTOT5W5Ao7752onjDl4QSv+sgOVdJbvFjOnD5w94= +github.com/filecoin-project/specs-storage v0.1.0/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= +github.com/filecoin-project/storage-fsm v0.0.0-20200617183754-4380106d3e94/go.mod h1:q1YCutTSMq/yGYvDPHReT37bPfDLHltnwJutzR9kOY0= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc h1:jtW8jbpkO4YirRSyepBOH8E+2HEw6/hKkBvFPwhUN8c= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0= +github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8= +github.com/gcash/bchd v0.14.7/go.mod h1:Gk/O1ktRVW5Kao0RsnVXp3bWxeYQadqawZ1Im9HE78M= +github.com/gcash/bchd v0.15.2/go.mod h1:k9wIjgwnhbrAw+ruIPZ2tHZMzfFNdyUnORZZX7lqXGY= +github.com/gcash/bchd v0.16.4 h1:+aq3sk3MDTLLwfDldvJaQBbpALCiDMH1bT32qIeHYos= +github.com/gcash/bchd v0.16.4/go.mod h1:gR67ljCexTNwbKYN3wjbRHi9lYLp4rMomy1UQ3E1USA= +github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6 h1:3pZvWJ8MSfWstGrb8Hfh4ZpLyZNcXypcGx2Ju4ZibVM= +github.com/gcash/bchlog v0.0.0-20180913005452-b4f036f92fa6/go.mod h1:PpfmXTLfjRp7Tf6v/DCGTRXHz+VFbiRcsoUxi7HvwlQ= +github.com/gcash/bchutil v0.0.0-20190625002603-800e62fe9aff/go.mod h1:zXSP0Fg2L52wpSEDApQDQMiSygnQiK5HDquDl0a5BHg= +github.com/gcash/bchutil v0.0.0-20191012211144-98e73ec336ba/go.mod h1:nUIrcbbtEQdCsRwcp+j/CndDKMQE9Fi8p2F8cIZmIqI= +github.com/gcash/bchutil v0.0.0-20200229194731-128fc9884722 h1:oeBQvSvKXcDbyoUbyeveB99CHJWgQfxiV9gKcPrXfhs= +github.com/gcash/bchutil v0.0.0-20200229194731-128fc9884722/go.mod h1:wB++2ZcHUvGLN1OgO9swBmJK1vmyshJLW9SNS+apXwc= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= +github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/gxed/go-shellwords v1.0.3/go.mod h1:N7paucT91ByIjmVJHhvoarjoQnmsi3Jd3vH7VqgtMxQ= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE= +github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099 h1:vQqOW42RRM5LoM/1K5dK940VipLqpH8lEVGrMz+mNjU= +github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099/go.mod h1:WVPCl0HO/0RAL5+vBH2GMxBomlxBF70MAS78+Lu1//k= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hodgesds/perf-utils v0.0.8/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hunterlong/tokenbalance v0.0.12-0.20191105170207-4f98e641e619 h1:kVdhNuTJN8YZiZx5JlCOuJE4c0VhfC+WCgDGDBPyZxQ= +github.com/hunterlong/tokenbalance v0.0.12-0.20191105170207-4f98e641e619/go.mod h1:np6MtV0Z17TTSmmT3dfGkc0OMD/u/6z+Kflc8IhJBec= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/improbable-eng/grpc-web v0.9.1/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/improbable-eng/grpc-web v0.12.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitswap v0.0.3/go.mod h1:jadAZYsP/tcRMl47ZhFxhaNuDQoXawT8iHMg+iFoQbg= +github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis= +github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= +github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= +github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-bitswap v0.2.8 h1:5tQrbyyRS3DkzvcM5n+bVjdSAHLgvH7D+1LopndhUII= +github.com/ipfs/go-bitswap v0.2.8/go.mod h1:2Yjog0GMdH8+AsxkE0DI9D2mANaUTxbVVav0pPoZoug= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-blockservice v0.0.3/go.mod h1:/NNihwTi6V2Yr6g8wBI+BSwPuURpBRMtYNGrlxZ8KuI= +github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= +github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= +github.com/ipfs/go-blockservice v0.1.3 h1:9XgsPMwwWJSC9uVr2pMDsW2qFTBSkxpGMhmna8mIjPM= +github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4-0.20191112011718-79e75dffeb10/go.mod h1:/BYOuUoxkE+0f6tGzlzMvycuN+5l35VOR4Bpg2sCmds= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 h1:QN88Q0kT2QiDaLxpR/SDsqOBtNIEF/F3n96gSDUimkA= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.0/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= +github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= +github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= +github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= +github.com/ipfs/go-ds-badger2 v0.1.0/go.mod h1:pbR1p817OZbdId9EvLOhKBgUVTM3BMCSTan78lDDVaw= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= +github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ds-measure v0.1.0/go.mod h1:1nDiFrhLlwArTME1Ees2XaBOl49OoCgd2A3f8EchMSY= +github.com/ipfs/go-filestore v1.0.0 h1:QR7ekKH+q2AGiWDc7W2Q0qHuYSRZGUJqUn0GsegEPb0= +github.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPiFOdcuu9SM= +github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y= +github.com/ipfs/go-graphsync v0.0.6-0.20200504202014-9d5f2c26a103 h1:SD+bXod/pOWKJCGj0tG140ht8Us5k+3JBcHw0PVYTho= +github.com/ipfs/go-graphsync v0.0.6-0.20200504202014-9d5f2c26a103/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= +github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= +github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= +github.com/ipfs/go-hamt-ipld v0.1.1-0.20200501020327-d53d20a7063e/go.mod h1:giiPqWYCnRBYpNTsJ/EX1ojldX5kTXrXYckSJQ7ko9M= +github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f h1:mchhWiYYUSoCuE3wDfRCo8cho5kqSoxkgnOtGcnNMZw= +github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f/go.mod h1:phOFBB7W73N9dg1glcb1fQ9HtQFDUpeyJgatW8ns0bw= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= +github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blockstore v1.0.0 h1:pmFp5sFYsYVvMOp9X01AK3s85usVcLvkBTRsN6SnfUA= +github.com/ipfs/go-ipfs-blockstore v1.0.0/go.mod h1:knLVdhVU9L7CC4T+T4nvGdeUIPAXlnd9zmXfp+9MIjU= +github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= +github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= +github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= +github.com/ipfs/go-ipfs-cmds v0.1.0/go.mod h1:TiK4e7/V31tuEb8YWDF8lN3qrnDH+BS7ZqWIeYJlAs8= +github.com/ipfs/go-ipfs-config v0.0.11/go.mod h1:wveA8UT5ywN26oKStByzmz1CO6cXwLKKM6Jn/Hfw08I= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g= +github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.7/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= +github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA= +github.com/ipfs/go-ipfs-http-client v0.0.5/go.mod h1:8EKP9RGUrUex4Ff86WhnKU7seEBOtjdgXlY9XHYvYMw= +github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= +github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= +github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= +github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.1/go.mod h1:RXHr8s4k0NE0TKhnrxqZC9M888QfsBN9rhS5NjfKzY8= +github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5-0.20200204214505-252690b78669/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf h1:PRCy+w3GocY77CBEwTprp6hn7PLiEU1YToKe7B+1FVk= +github.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= +github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= +github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= +github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= +github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= +github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= +github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log/v2 v2.0.1/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.2-0.20200609205458-f8d20c392cb7 h1:LtL/rvdfbKSthZGmAAD9o4KKg6HA6Qn8gXCCdgnj7lw= +github.com/ipfs/go-log/v2 v2.1.2-0.20200609205458-f8d20c392cb7/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA= +github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= +github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= +github.com/ipfs/go-merkledag v0.3.1 h1:3UqWINBEr3/N+r6OwgFXAddDP/8zpQX/8J7IGVOCqRQ= +github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-path v0.0.3/go.mod h1:zIRQUez3LuQIU25zFjC2hpBTHimWx7VK5bjZgRLbbdo= +github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= +github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= +github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN1EJOjc= +github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= +github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= +github.com/ipfs/go-unixfs v0.0.4/go.mod h1:eIo/p9ADu/MFOuyxzwU+Th8D6xoxU//r590vUpWyfz8= +github.com/ipfs/go-unixfs v0.2.1/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k= +github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo= +github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipfs/interface-go-ipfs-core v0.2.3/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s= +github.com/ipfs/iptb v1.4.0/go.mod h1:1rzHpCYtNp87/+hTxG5TfCVn/yMY3dKnLn8tBiMfdmg= +github.com/ipfs/iptb-plugins v0.2.1/go.mod h1:QXMbtIWZ+jRsW8a4h13qAKU7jcM7qaittO8wOsTP0Rs= +github.com/ipld/go-car v0.1.1-0.20200429200904-c222d793c339/go.mod h1:eajxljm6I8o3LitnFeVEmucwZmz7+yLSiKce9yYMefg= +github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae h1:OV9dxl8iPMCOD8Vi/hvFwRh3JWPXqmkYSVxWr9JnEzM= +github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae/go.mod h1:2mvxpu4dKRnuH3mj5u6KW/tmRSCcXvy/KYiJ4nC6h4c= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e h1:ZISbJlM0urTANR9KRfRaqlBmyOj5uUtxs2r4Up9IXsA= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1 h1:K1Ysr7kgIlo7YQkPqdkA6H7BVdIugvuAz7OQUTJxLdE= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= +github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jarcoal/httpmock v1.0.5 h1:cHtVEcTxRSX4J0je7mWPfc9BpDpqzXSJ5HbymZmyHck= +github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c h1:uUx61FiAa1GI6ZmVd2wf2vULeQZIKG66eybjNXKYCz4= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v0.0.0-20181221193153-c0795c8afcf4/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= +github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= +github.com/libp2p/go-conn-security-multistream v0.0.1/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= +github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= +github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= +github.com/libp2p/go-eventbus v0.0.2/go.mod h1:Hr/yGlwxA/stuLnpMiu82lpNKpvRy3EaJxPu40XYOwk= +github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= +github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= +github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.0.2/go.mod h1:Qu8bWqFXiocPloabFGUcVG4kk94fLvfC8mWTDdFC9wE= +github.com/libp2p/go-libp2p v0.0.30/go.mod h1:XWT8FGHlhptAv1+3V/+J5mEpzyui/5bvFsNuWYs611A= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= +github.com/libp2p/go-libp2p v0.3.1/go.mod h1:e6bwxbdYH1HqWTz8faTChKGR0BjPc8p+6SyP8GTTR7Y= +github.com/libp2p/go-libp2p v0.4.0/go.mod h1:9EsEIf9p2UDuwtPd0DwJsAl0qXVxgAnuDGRvHbfATfI= +github.com/libp2p/go-libp2p v0.6.0/go.mod h1:mfKWI7Soz3ABX+XEBR61lGbg+ewyMtJHVt043oWeqwg= +github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= +github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= +github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= +github.com/libp2p/go-libp2p v0.8.2/go.mod h1:NQDA/F/qArMHGe0J7sDScaKjW8Jh4y/ozQqBbYJ+BnA= +github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM= +github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ= +github.com/libp2p/go-libp2p v0.9.4 h1:yighwjFvsF/qQaGtHPZfxcF+ph4ydCNnsKvg712lYRo= +github.com/libp2p/go-libp2p v0.9.4/go.mod h1:NzQcC2o19xgwGqCmjx7DN+4h2F13qPCZ9UJmweYzsnU= +github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= +github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= +github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= +github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= +github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= +github.com/libp2p/go-libp2p-autonat v0.2.3 h1:w46bKK3KTOUWDe5mDYMRjJu1uryqBp8HCNDp/TWMqKw= +github.com/libp2p/go-libp2p-autonat v0.2.3/go.mod h1:2U6bNWCNsAG9LEbwccBDQbjzQ8Krdjge1jLTE9rdoMM= +github.com/libp2p/go-libp2p-autonat-svc v0.1.0/go.mod h1:fqi8Obl/z3R4PFVLm8xFtZ6PBL9MlV/xumymRFkKq5A= +github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-blankhost v0.1.3/go.mod h1:KML1//wiKR8vuuJO0y3LUd1uLv+tlkGTAr3jC0S5cLg= +github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= +github.com/libp2p/go-libp2p-blankhost v0.1.6 h1:CkPp1/zaCrCnBo0AdsQA0O1VkUYoUOtyHOnoa8gKIcE= +github.com/libp2p/go-libp2p-blankhost v0.1.6/go.mod h1:jONCAJqEP+Z8T6EQviGL4JsQcLx1LgTGtVqFNY8EMfQ= +github.com/libp2p/go-libp2p-circuit v0.0.1/go.mod h1:Dqm0s/BiV63j8EEAs8hr1H5HudqvCAeXxDyic59lCwE= +github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-circuit v0.1.1/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-circuit v0.1.3/go.mod h1:Xqh2TjSy8DD5iV2cCOMzdynd6h8OTBGoV1AWbWor3qM= +github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= +github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= +github.com/libp2p/go-libp2p-circuit v0.2.2 h1:87RLabJ9lrhoiSDDZyCJ80ZlI5TLJMwfyoGAaWXzWqA= +github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= +github.com/libp2p/go-libp2p-connmgr v0.1.1/go.mod h1:wZxh8veAmU5qdrfJ0ZBLcU8oJe9L82ciVP/fl1VHjXk= +github.com/libp2p/go-libp2p-connmgr v0.2.3/go.mod h1:Gqjg29zI8CwXX21zRxy6gOg8VYu3zVerJRt2KyktzH4= +github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= +github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= +github.com/libp2p/go-libp2p-core v0.0.6/go.mod h1:0d9xmaYAVY5qmbp/fcgxHT3ZJsLjYeYPMJAUKpaCHrE= +github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= +github.com/libp2p/go-libp2p-core v0.2.3/go.mod h1:GqhyQqyIAPsxFYXHMjfXgMv03lxsvM0mFzuYA9Ib42A= +github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= +github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.2/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= +github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.5.7 h1:QK3xRwFxqd0Xd9bSZL+8yZ8ncZZbl6Zngd/+Y+A6sgQ= +github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= +github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ= +github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI= +github.com/libp2p/go-libp2p-discovery v0.0.5/go.mod h1:YtF20GUxjgoKZ4zmXj8j3Nb2TUSBHFlOCetzYdbZL5I= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= +github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= +github.com/libp2p/go-libp2p-discovery v0.4.0 h1:dK78UhopBk48mlHtRCzbdLm3q/81g77FahEBTjcqQT8= +github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4= +github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= +github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= +github.com/libp2p/go-libp2p-kad-dht v0.2.1/go.mod h1:k7ONOlup7HKzQ68dE6lSnp07cdxdkmnRa+6B4Fh9/w0= +github.com/libp2p/go-libp2p-kad-dht v0.8.1/go.mod h1:u3rbYbp3CSraAHD5s81CJ3hHozKTud/UOXfAgh93Gek= +github.com/libp2p/go-libp2p-kbucket v0.2.1/go.mod h1:/Rtu8tqbJ4WQ2KTCOMJhggMukOLNLNPY1EtEWWLxUvc= +github.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY= +github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= +github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= +github.com/libp2p/go-libp2p-mplex v0.2.3 h1:2zijwaJvpdesST2MXpI5w9wWFRgYtMcpRX7rrw0jmOo= +github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= +github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= +github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= +github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= +github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= +github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= +github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= +github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= +github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= +github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw= +github.com/libp2p/go-libp2p-peerstore v0.2.4 h1:jU9S4jYN30kdzTpDAR7SlHUD+meDUjTODh4waLWF1ws= +github.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= +github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= +github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= +github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= +github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= +github.com/libp2p/go-libp2p-pubsub v0.3.1/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= +github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= +github.com/libp2p/go-libp2p-pubsub v0.3.2/go.mod h1:Uss7/Cfz872KggNb+doCVPHeCDmXB7z500m/R8DaAUk= +github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= +github.com/libp2p/go-libp2p-quic-transport v0.3.7/go.mod h1:Kr4aDtnfHHNeENn5J+sZIVc+t8HpQn9W6BOxhVGHbgI= +github.com/libp2p/go-libp2p-quic-transport v0.5.0 h1:BUN1lgYNUrtv4WLLQ5rQmC9MCJ6uEXusezGvYRNoJXE= +github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= +github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= +github.com/libp2p/go-libp2p-record v0.1.2 h1:M50VKzWnmUrk/M5/Dz99qO9Xh4vs8ijsK+7HkJvRP+0= +github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= +github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= +github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE= +github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= +github.com/libp2p/go-libp2p-secio v0.0.1/go.mod h1:IdG6iQybdcYmbTzxp4J5dwtUEDTOvZrT0opIDVNPrJs= +github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= +github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= +github.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg= +github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= +github.com/libp2p/go-libp2p-swarm v0.0.1/go.mod h1:mh+KZxkbd3lQnveQ3j2q60BM1Cw2mX36XXQqwfPOShs= +github.com/libp2p/go-libp2p-swarm v0.0.6/go.mod h1:s5GZvzg9xXe8sbeESuFpjt8CJPTCa8mhEusweJqyFy8= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-swarm v0.2.1/go.mod h1:x07b4zkMFo2EvgPV2bMTlNmdQc8i+74Jjio7xGvsTgU= +github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= +github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= +github.com/libp2p/go-libp2p-swarm v0.2.4/go.mod h1:/xIpHFPPh3wmSthtxdGbkHZ0OET1h/GGZes8Wku/M5Y= +github.com/libp2p/go-libp2p-swarm v0.2.6 h1:UhMXIa+yCOALQyceENEIStMlbTCzOM6aWo6vw8QW17Q= +github.com/libp2p/go-libp2p-swarm v0.2.6/go.mod h1:F9hrkZjO7dDbcEiYii/fAB1QdpLuU6h1pa4P5VNsEgc= +github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU= +github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= +github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= +github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= +github.com/libp2p/go-libp2p-transport v0.0.4/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= +github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= +github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m+JmZCe5RUXG10UMEx4kWe9Ipj5c= +github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= +github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4= +github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= +github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= +github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= +github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= +github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= +github.com/libp2p/go-libp2p-yamux v0.2.8 h1:0s3ELSLu2O7hWKfX1YjzudBKCP0kZ+m9e2+0veXzkn4= +github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= +github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= +github.com/libp2p/go-mplex v0.0.1/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.1.2 h1:qOg1s+WdGLlpkrczDqmhYzyk3vCfsQ8+RxRTQjOZWwI= +github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= +github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= +github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= +github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= +github.com/libp2p/go-netroute v0.1.2 h1:UHhB35chwgvcRI392znJA3RCBtZ3MpE3ahNCN5MR4Xg= +github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.5 h1:pQkejVhF0xp08D4CQUcw8t+BFJeXowja6RVcb5p++EA= +github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M= +github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= +github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= +github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ= +github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= +github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-tcp-transport v0.0.1/go.mod h1:mnjg0o0O5TmXUaUIanYPUqkW4+u6mK0en8rlpA6BBTs= +github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= +github.com/libp2p/go-tcp-transport v0.2.0 h1:YoThc549fzmNJIh7XjHVtMIFaEDRtIrtWciG5LyYAPo= +github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= +github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= +github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww= +github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-ws-transport v0.1.2/go.mod h1:dsh2Ld8F+XNmzpkaAijmg5Is+e9l6/1tK/6VFOdN69Y= +github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= +github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw= +github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.6/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.7 h1:v40A1eSPJDIZwz2AvrV3cxpTZEGDP11QJbukmEhYyQI= +github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/ltcsuite/ltcd v0.20.1-beta h1:ka9ZwUG7oUPppl+7ptuh5VDxGD7TWEJXu/IOOOz1yfY= +github.com/ltcsuite/ltcd v0.20.1-beta/go.mod h1:ZFQaYdYULIuTQiWqs7AUiHD2XhDFeeHW1IH+UYMdABU= +github.com/ltcsuite/ltcutil v0.0.0-20191227053721-6bec450ea6ad/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= +github.com/ltcsuite/ltcutil v1.0.2-beta h1:IS86frABIvbpw9ilpQ/zt8t30pFog6DD4tBcgbjdj8g= +github.com/ltcsuite/ltcutil v1.0.2-beta/go.mod h1:G1JGpaqtMm0mPtheTryXnDd9a4KAFuGevdQirlJO1Nw= +github.com/ltcsuite/ltcwallet/wallet/txrules v1.0.0 h1:WDrodrBVO5EbaAT5//i2YOg7DH+FnWSm/kjTvMNT/EY= +github.com/ltcsuite/ltcwallet/wallet/txrules v1.0.0/go.mod h1:H/FiHbbfd9+TPn9ao1Ier7rBosT5j2ejIbHvZqHSEVU= +github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= +github.com/lucas-clemente/quic-go v0.15.7/go.mod h1:Myi1OyS0FOjL3not4BxT7KN29bRkcMUV5JVVFLKtDp8= +github.com/lucas-clemente/quic-go v0.16.0 h1:jJw36wfzGJhmOhAOaOC2lS36WgeqXQszH47A7spo1LI= +github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= +github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/marten-seemann/qtls v0.9.1 h1:O0YKQxNVPaiFgMng0suWEOY2Sb4LT2sRn9Qimq3Z1IQ= +github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= +github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee/go.mod h1:Evt/EIne46u9PtQbeTx2NTcqURpr5K4SvKtGmBuDPN8= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= +github.com/multiformats/go-multiaddr v0.2.2 h1:XZLDTszBIJe6m0zF6ITBrEcZR73OPUhCBBS9rYAuUzI= +github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.1.0/go.mod h1:01k2RAqtoXIuPa3DCavAE9/6jc6nM0H3EgZyfUhN2oY= +github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= +github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= +github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.5 h1:QoRKvu0xHN1FCFJcMQLbG/yQE2z441L5urvG3+qyz7g= +github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.2 h1:2pAgScmS1g9XjH7EtAfNhTuyrWYEWcxy0G5Wo85hWDA= +github.com/multiformats/go-multibase v0.0.2/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.7/go.mod h1:XuKXPp8VHcTygube3OWZC+aZrA+H1IhmjoCDtJc7PXM= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI= +github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nanmu42/etherscan-api v1.1.1 h1:Pcx6+iIiERfw7ZeybEOx+ykEQDn1P0Shoxbamk/j620= +github.com/nanmu42/etherscan-api v1.1.1/go.mod h1:JNY1YEQ0cL4Ytlnb3Hf3tjk7rIgprDbludV4xVESLcg= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c h1:1RHs3tNxjXGHeul8z2t6H2N2TlAqpKe5yryJztRx4Jk= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= +github.com/opentracing-contrib/go-grpc v0.0.0-20191001143057-db30781987df/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= +github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289/go.mod h1:FGbBv5OPKjch+jNUJmEQpMZytIdyW0NdBtWFcfSKusc= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150 h1:ZeU+auZj1iNzN8iVhff6M38Mfu73FQiJve/GEXYJBjE= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sercand/kuberesolver v2.1.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ= +github.com/sercand/kuberesolver v2.4.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= +github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil v2.20.5-0.20200531151128-663af789c085+incompatible h1:+gAR1bMhuoQnZMTWFIvp7ukynULPsteLzG+siZKLtD8= +github.com/shirou/gopsutil v2.20.5-0.20200531151128-663af789c085+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a/go.mod h1:LeFCbQYJ3KJlPs/FvPz2dy1tkpxyeNESVyCNNzRXFR0= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho= +github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= +github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-client-go v2.23.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v1.5.1-0.20181102163054-1fc5c315e03c/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5/go.mod h1:c98fKi5B9u8OsKGiWHLRKus6ToQ1Tubeow44ECO1uxY= +github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= +github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= +github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba h1:X4n8JG2e2biEZZXdBKt9HX7DN3bYGFUqljqqy0DqgnY= +github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CHQnYnQUEPydYCwuy8lmTHfGmdw9TKrhWV0xLx8l0oM= +github.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200206220010-03c9665e2a66/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501014322-5f9941ef88e0/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= +github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d h1:Y25auOnuZb/GuJvqMflRSDWBz8/HBRME8fiD+H8zLfs= +github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= +github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDbeKFZInPUrAG+bjuJmUXONGdEFW7XL0SpTY1y4= +github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ= +github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= +github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d/go.mod h1:g7ckxrjiFh8mi1AY7ox23PZD0g6QU/TxW3U3unX7I3A= +github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= +github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zquestz/grab v0.0.0-20190224022517-abcee96e61b1/go.mod h1:bslhAiUxakrA6z6CHmVyvkfpnxx18RJBwVyx2TluJWw= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= +go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg= +go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= +go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= +go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= +go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= +go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0 h1:eIYIE7EC5/Wv5Kbz8bJPaq+TN3kq3W8S+LSm62vM0DY= +golang.org/x/crypto v0.0.0-20200707235045-ab33eee955e0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8= +google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200603215123-a4a8cb9d2cbc h1:17cdygvFw3DEyNMh81Bk687W74d5pcC5qEKQICv9N6g= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200603215123-a4a8cb9d2cbc/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go b/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go index 8991a42701..470986e599 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go @@ -12,7 +12,6 @@ import ( "github.com/btcsuite/btcd/chaincfg" - "github.com/OpenBazaar/spvwallet" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcec" @@ -261,15 +260,15 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } func (w *LitecoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return nil, err } if txn.Height > 0 { - return nil, spvwallet.BumpFeeAlreadyConfirmedError + return nil, util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, spvwallet.BumpFeeTransactionDeadError + return nil, util.BumpFeeTransactionDeadError } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() @@ -302,7 +301,7 @@ func (w *LitecoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { return transactionID, nil } } - return nil, spvwallet.BumpFeeNotFoundError + return nil, util.BumpFeeNotFoundError } func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { @@ -340,7 +339,7 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad txType := P2PKH if redeemScript != nil { txType = P2SH_1of2_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(*redeemScript) + _, err := util.LockTimeFromRedeemScript(*redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_1Sig } @@ -404,7 +403,7 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad timeLocked = true tx.Version = 2 for _, txIn := range tx.TxIn { - locktime, err := spvwallet.LockTimeFromRedeemScript(*redeemScript) + locktime, err := util.LockTimeFromRedeemScript(*redeemScript) if err != nil { return nil, err } @@ -471,7 +470,7 @@ func (w *LitecoinWallet) createMultisigSignature(ins []wi.TransactionInput, outs // Subtract fee txType := P2SH_2of3_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(redeemScript) + _, err := util.LockTimeFromRedeemScript(redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_2Sigs } @@ -526,7 +525,7 @@ func (w *LitecoinWallet) multisign(ins []wi.TransactionInput, outs []wi.Transact // Subtract fee txType := P2SH_2of3_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(redeemScript) + _, err := util.LockTimeFromRedeemScript(redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_2Sigs } diff --git a/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go index 1c264048f9..30ab62b5e8 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go @@ -261,7 +261,7 @@ func (w *LitecoinWallet) Transactions() ([]wi.Txn, error) { } func (w *LitecoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -287,7 +287,7 @@ func (w *LitecoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { return txn, err } -func (w *LitecoinWallet) ChainTip() (uint32, chainhash.Hash) { +func (w *LitecoinWallet) ChainTip() (uint32, string) { return w.ws.ChainTip() } @@ -402,7 +402,7 @@ func (w *LitecoinWallet) ReSyncBlockchain(fromTime time.Time) { } func (w *LitecoinWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/model/mock/interfaces.go b/vendor/github.com/OpenBazaar/multiwallet/model/mock/interfaces.go new file mode 100644 index 0000000000..8872a5bbcd --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/model/mock/interfaces.go @@ -0,0 +1,188 @@ +package mock + +import ( + "encoding/hex" + "errors" + "fmt" + "sync" + + gosocketio "github.com/OpenBazaar/golang-socketio" + "github.com/OpenBazaar/multiwallet/client" + "github.com/OpenBazaar/multiwallet/model" + "github.com/btcsuite/btcutil" +) + +type MockAPIClient struct { + blockChan chan model.Block + txChan chan model.Transaction + + listeningAddrs []btcutil.Address + chainTip int + feePerBlock int + info *model.Info + addrToScript func(btcutil.Address) ([]byte, error) +} + +func NewMockApiClient(addrToScript func(btcutil.Address) ([]byte, error)) model.APIClient { + return &MockAPIClient{ + blockChan: make(chan model.Block), + txChan: make(chan model.Transaction), + chainTip: 0, + addrToScript: addrToScript, + feePerBlock: 1, + info: &MockInfo, + } +} + +func (m *MockAPIClient) Start() error { + return nil +} + +func (m *MockAPIClient) GetInfo() (*model.Info, error) { + return m.info, nil +} + +func (m *MockAPIClient) GetTransaction(txid string) (*model.Transaction, error) { + for _, tx := range MockTransactions { + if tx.Txid == txid { + return &tx, nil + } + } + return nil, errors.New("Not found") +} + +func (m *MockAPIClient) GetRawTransaction(txid string) ([]byte, error) { + if raw, ok := MockRawTransactions[txid]; ok { + return raw, nil + } + return nil, errors.New("Not found") +} + +func (m *MockAPIClient) GetTransactions(addrs []btcutil.Address) ([]model.Transaction, error) { + txs := make([]model.Transaction, len(MockTransactions)) + copy(txs, MockTransactions) + txs[0].Outputs[1].ScriptPubKey.Addresses = []string{addrs[0].String()} + txs[1].Inputs[0].Addr = addrs[0].String() + txs[1].Outputs[1].ScriptPubKey.Addresses = []string{addrs[1].String()} + txs[2].Outputs[1].ScriptPubKey.Addresses = []string{addrs[2].String()} + return txs, nil +} + +func (m *MockAPIClient) GetUtxos(addrs []btcutil.Address) ([]model.Utxo, error) { + utxos := make([]model.Utxo, len(MockUtxos)) + copy(utxos, MockUtxos) + utxos[0].Address = addrs[1].String() + script, _ := m.addrToScript(addrs[1]) + utxos[0].ScriptPubKey = hex.EncodeToString(script) + utxos[1].Address = addrs[2].String() + script, _ = m.addrToScript(addrs[2]) + utxos[1].ScriptPubKey = hex.EncodeToString(script) + return utxos, nil +} + +func (m *MockAPIClient) BlockNotify() <-chan model.Block { + return m.blockChan +} + +func (m *MockAPIClient) TransactionNotify() <-chan model.Transaction { + return m.txChan +} + +func (m *MockAPIClient) ListenAddresses(addrs ...btcutil.Address) { + m.listeningAddrs = append(m.listeningAddrs, addrs...) +} + +func (m *MockAPIClient) Broadcast(tx []byte) (string, error) { + return "a8c685478265f4c14dada651969c45a65e1aeb8cd6791f2f5bb6a1d9952104d9", nil +} + +func (m *MockAPIClient) GetBestBlock() (*model.Block, error) { + return &MockBlocks[m.chainTip], nil +} + +func (m *MockAPIClient) EstimateFee(nBlocks int) (int, error) { + return m.feePerBlock * nBlocks, nil +} + +func (m *MockAPIClient) Close() {} + +func MockWebsocketClientOnClientPool(p *client.ClientPool) *MockSocketClient { + var ( + callbacksMap = make(map[string]func(*gosocketio.Channel, interface{})) + mockSocketClient = &MockSocketClient{ + callbacks: callbacksMap, + listeningAddresses: []string{}, + } + ) + for _, c := range p.Clients() { + c.SocketClient = mockSocketClient + } + return mockSocketClient +} + +func NewMockWebsocketClient() *MockSocketClient { + var ( + callbacksMap = make(map[string]func(*gosocketio.Channel, interface{})) + mockSocketClient = &MockSocketClient{ + callbacks: callbacksMap, + listeningAddresses: []string{}, + } + ) + return mockSocketClient +} + +type MockSocketClient struct { + callbackMutex sync.Mutex + callbacks map[string]func(*gosocketio.Channel, interface{}) + listeningAddresses []string +} + +func (m *MockSocketClient) SendCallback(method string, args ...interface{}) { + if gosocketChan, ok := args[0].(*gosocketio.Channel); ok { + m.callbacks[method](gosocketChan, args[1]) + } else { + m.callbacks[method](nil, args[1]) + } +} + +func (m *MockSocketClient) IsListeningForAddress(addr string) bool { + for _, a := range m.listeningAddresses { + if a == addr { + return true + } + } + return false +} + +func (m *MockSocketClient) On(method string, callback interface{}) error { + c, ok := callback.(func(h *gosocketio.Channel, args interface{})) + if !ok { + return fmt.Errorf("failed casting mock callback: %+v", callback) + } + + m.callbackMutex.Lock() + defer m.callbackMutex.Unlock() + if method == "bitcoind/addresstxid" { + m.callbacks[method] = c + } else if method == "bitcoind/hashblock" { + m.callbacks[method] = c + } + return nil +} + +func (m *MockSocketClient) Emit(method string, args []interface{}) error { + if method == "subscribe" { + subscribeTo, ok := args[0].(string) + if !ok || subscribeTo != "bitcoind/addresstxid" { + return fmt.Errorf("first emit arg is not bitcoind/addresstxid, was: %+v", args[0]) + } + addrs, ok := args[1].([]string) + if !ok { + return fmt.Errorf("second emit arg is not address value, was %+v", args[1]) + } + m.listeningAddresses = append(m.listeningAddresses, addrs...) + } + return nil +} + +func (m *MockSocketClient) Close() {} diff --git a/vendor/github.com/OpenBazaar/multiwallet/model/mock/models.go b/vendor/github.com/OpenBazaar/multiwallet/model/mock/models.go new file mode 100644 index 0000000000..101d7e7a40 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/model/mock/models.go @@ -0,0 +1,283 @@ +package mock + +import "github.com/OpenBazaar/multiwallet/model" + +var MockInfo = model.Info{ + Version: 1, + ProtocolVersion: 9005, + Blocks: 1289596, + TimeOffset: 0, + Connections: 1024, + DifficultyIface: "1.23", + Difficulty: 1.23, + Testnet: true, + RelayFeeIface: "1.00", + RelayFee: 1.00, + Errors: "", + Network: "testnet", +} + +var MockBlocks = []model.Block{ + { + Hash: "000000000000004c68a477283a8db18c1d1c2155b03d9bc23d587ac5e1c4d1af", + Height: 1289594, + PreviousBlockhash: "00000000000003df72ec254d787b216ae913cb82c6ab601c4b3f19fd5d1cf9aa", + Tx: make([]string, 21), + Size: 4705, + Time: 1522349145, + }, + { + Hash: "0000000000000142ffae87224cb67206e93bf934f9fdeba75d02a7050acc6136", + Height: 1289595, + PreviousBlockhash: "000000000000004c68a477283a8db18c1d1c2155b03d9bc23d587ac5e1c4d1af", + Tx: make([]string, 30), + Size: 6623, + Time: 1522349136, + }, + { + Hash: "000000000000033ef24180d5d282d0e6d03b1185e29421fda97e1ba0ffd7c918", + Height: 1289596, + PreviousBlockhash: "0000000000000142ffae87224cb67206e93bf934f9fdeba75d02a7050acc6136", + Tx: make([]string, 5), + Size: 1186, + Time: 1522349156, + }, +} + +var MockTransactions = []model.Transaction{ + { + Txid: "54ebaa07c42216393b9d5816e40dd608593b92c42e2d6525f45bdd36bce8fe4d", + Version: 2, + Locktime: 512378, + Inputs: []model.Input{ + { + Txid: "6d892f04fc097f430d58ab06229c9b6344a130fc1842da5b990e857daed42194", + Vout: 1, + Sequence: 1, + ValueIface: "0.04294455", + Value: 0.04294455, + N: 0, + ScriptSig: model.Script{ + Hex: "4830450221008665481674067564ef562cfd8d1ca8f1506133fb26a2319e4b8dfba3cedfd5de022038f27121c44e6c64b93b94d72620e11b9de35fd864730175db9176ca98f1ec610121022023e49335a0dddb864ff673468a6cc04e282571b1227933fcf3ff9babbcc662", + }, + Addr: "1C74Gbij8Q5h61W58aSKGvXK4rk82T2A3y", + Satoshis: 4294455, + }, + }, + Outputs: []model.Output{ + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "76a914ff3f7d402fbd6d116ba4a02af9784f3ae9b7108a88ac", + }, + Type: "pay-to-pubkey-hash", + Addresses: []string{"1QGdNEDjWnghrjfTBCTDAPZZ3ffoKvGc9B"}, + }, + ValueIface: "0.01398175", + Value: 0.01398175, + N: 0, + }, + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "76a914f99b84270843bdab59a71ce9af15b89bef5087a388ac", + }, + Type: "pay-to-pubkey-hash", + Addresses: []string{"1PkoZDtXT63BnYGd429Vy4DoyGhdDcjQiN"}, // var + }, + ValueIface: "0.02717080", + Value: 0.02717080, + N: 1, + }, + }, + Time: 1520449061, + BlockHash: "0000000000000000003f1fb88ac3dab0e607e87def0e9031f7bea02cb464a04f", + BlockHeight: 1289475, + Confirmations: 15, + }, + { + Txid: "ff2b865c3b73439912eebf4cce9a15b12c7d7bcdd14ae1110a90541426c4e7c5", + Version: 2, + Locktime: 0, + Inputs: []model.Input{ + { + Txid: "54ebaa07c42216393b9d5816e40dd608593b92c42e2d6525f45bdd36bce8fe4d", + Vout: 1, + Sequence: 1, + ValueIface: "0.02717080", + Value: 0.02717080, + N: 0, + ScriptSig: model.Script{ + Hex: "4830450221008665481674067564ef562cfd8d1ca8f1506133fb26a2319e4b8dfba3cedfd5de022038f27121c44e6c64b93b94d72620e11b9de35fd864730175db9176ca98f1ec610121022023e49335a0dddb864ff673468a6cc04e282571b1227933fcf3ff9babbcc662", + }, + Addr: "1PkoZDtXT63BnYGd429Vy4DoyGhdDcjQiN", // var tx0:1 + Satoshis: 2717080, + }, + }, + Outputs: []model.Output{ + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "a9144b18dadba74ad5ef4dbbfea47f9d5aaefe766c6387", + }, + Type: "pay-to-script-hash", + Addresses: []string{"38Y6Nt35hQcEDxyCfCEi62QLGPnr4mhANc"}, + }, + ValueIface: "0.01398175", + Value: 0.01617080, + N: 0, + }, + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "76a914f821d6db9376dc60124de46a8683110877e1f13188ac", + }, + Type: "pay-to-pubkey-hash", + Addresses: []string{"1Pd17mbYsVPcCKLtNdPkngtizTj7zjzqeK"}, // var change + }, + ValueIface: "0.01", + Value: 0.01, + N: 1, + }, + }, + Time: 1520449061, + BlockHash: "0000000000000000003f1fb88ac3dab0e607e87def0e9031f7bea02cb464a04f", + BlockHeight: 1289475, + Confirmations: 10, + }, + { + Txid: "1d4288fa682fa376fbae73dbd74ea04b9ea33011d63315ca9d2d50d081e671d5", + Version: 2, + Locktime: 0, + Inputs: []model.Input{ + { + Txid: "bffb894c27dac82525c1f00a085150be94c70834e8d05ea5e7bb3bd1278d3138", + Vout: 1, + Sequence: 1, + ValueIface: "0.3", + Value: 0.3, + N: 0, + ScriptSig: model.Script{ + Hex: "4830450221008665481674067564ef562cfd8d1ca8f1506133fb26a2319e4b8dfba3cedfd5de022038f27121c44e6c64b93b94d72620e11b9de35fd864730175db9176ca98f1ec610121022023e49335a0dddb864ff673468a6cc04e282571b1227933fcf3ff9babbcc662", + }, + Addr: "1H2ZS69jUZz6CuCtiRCTWXr4AhAWfXc4YT", + Satoshis: 2717080, + }, + }, + Outputs: []model.Output{ + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "76a914e20c0ca5875b1fb0d057e23d032ba88b9dda6f3888ac", + }, + Type: "pay-to-pubkey-hash", + Addresses: []string{"1McE9ZXFhWkFeAqR1hyAm1XaDK8zvyrFPr"}, + }, + ValueIface: "0.2", + Value: 0.2, + N: 0, + }, + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "76a914594963287fe6684872340e9078a78d0accbec26288ac", + }, + Type: "pay-to-pubkey-hash", + Addresses: []string{"199747e2arXMBPiWfTqpBTXz3eFbeJPMqS"}, // var + }, + ValueIface: "0.1", + Value: 0.1, + N: 1, + }, + }, + Time: 1520449061, + BlockHash: "0000000000000000003f1fb88ac3dab0e607e87def0e9031f7bea02cb464a04f", + BlockHeight: 1289475, + Confirmations: 2, + }, + { + Txid: "830bf683ab8eec1a75d891689e2989f846508bc7d500cb026ef671c2d1dce20c", + Version: 2, + Locktime: 516299, + Inputs: []model.Input{ + { + Txid: "b466d034076ab53f4b019d573b6c68cf68c5b9a8cfbf07c8d46208d0fcf37762", + Vout: 0, + Sequence: 4294967294, + ValueIface: "0.01983741", + Value: 0.01983741, + N: 0, + ScriptSig: model.Script{ + Hex: "483045022100baa2b3653d48ccf2838caa549d96a40540c838c4f4a8e7048dbe158ec180b3f602206f1bb8c6d055103ce635db562c31ebd8c30565c5d415458affb9f99407ec06d10121039fea462cb64296e01384cffc16af4b86ab14b6027094399bf5a4b52e5c9ffef3", + }, + Addr: "1LUv9VNMZQR4VknWj1TBa1oDgPq53wP7BK", + Satoshis: 1983741, + }, + }, + Outputs: []model.Output{ + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "76a91491a8a9e0375f10b721743782162a0b4f9fae69a888ac", + }, + Type: "pay-to-pubkey-hash", + Addresses: []string{"1EHB2mSaUXzkM6r6XgVHcutFDZoB9e2mZH"}, + }, + ValueIface: "0.01181823", + Value: 0.01181823, + N: 0, + }, + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "a91457fc729da2a83dc8cd3c1835351c4a813c2ae8ba87", + }, + Type: "pay-to-script-hash", + Addresses: []string{"39iF8cDMhctrPVoPbi2Vb1NnErg6CEB7BZ"}, + }, + ValueIface: "0.00751918", + Value: 0.00751918, + N: 1, + }, + }, + Time: 1520449061, + BlockHash: "0000000000000000003f1fb88ac3dab0e607e87def0e9031f7bea02cb464a04f", + BlockHeight: 1289475, + Confirmations: 2, + }, +} + +var MockRawTransactions = map[string][]byte{} + +var MockUtxos = []model.Utxo{ + { + Address: "1Pd17mbYsVPcCKLtNdPkngtizTj7zjzqeK", // tx1:1 + ScriptPubKey: "76a914f821d6db9376dc60124de46a8683110877e1f13188ac", + Vout: 1, + Satoshis: 1000000, + Confirmations: 10, + Txid: "ff2b865c3b73439912eebf4cce9a15b12c7d7bcdd14ae1110a90541426c4e7c5", + AmountIface: "0.01", + Amount: 0.01, + }, + { + Address: "199747e2arXMBPiWfTqpBTXz3eFbeJPMqS", //tx2:1 + ScriptPubKey: "76a914594963287fe6684872340e9078a78d0accbec26288ac", + Vout: 1, + Satoshis: 10000000, + Confirmations: 2, + Txid: "1d4288fa682fa376fbae73dbd74ea04b9ea33011d63315ca9d2d50d081e671d5", + AmountIface: "0.1", + Amount: 0.1, + }, + { + Address: "39iF8cDMhctrPVoPbi2Vb1NnErg6CEB7BZ", + ScriptPubKey: "a91457fc729da2a83dc8cd3c1835351c4a813c2ae8ba87", + Vout: 1, + Satoshis: 751918, + Confirmations: 2, + Txid: "830bf683ab8eec1a75d891689e2989f846508bc7d500cb026ef671c2d1dce20c", + AmountIface: "0.00751918", + Amount: 0.00751918, + }, +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/multiwallet.go b/vendor/github.com/OpenBazaar/multiwallet/multiwallet.go index 2307e92834..c1513b9069 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/multiwallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/multiwallet.go @@ -2,6 +2,7 @@ package multiwallet import ( "errors" + "github.com/OpenBazaar/multiwallet/filecoin" "strings" "time" @@ -98,6 +99,16 @@ func NewMultiWallet(cfg *config.Config) (MultiWallet, error) { } else { multiwallet[wallet.TestnetEthereum] = w } + case wallet.Filecoin: + w, err = filecoin.NewFilecoinWallet(coin, cfg.Mnemonic, cfg.Params, cfg.Proxy, cfg.Cache, cfg.DisableExchangeRates) + if err != nil { + return nil, err + } + if cfg.Params.Name == chaincfg.MainNetParams.Name { + multiwallet[wallet.Filecoin] = w + } else { + multiwallet[wallet.TestnetFilecoin] = w + } } } return multiwallet, nil diff --git a/vendor/github.com/OpenBazaar/multiwallet/service/wallet_service.go b/vendor/github.com/OpenBazaar/multiwallet/service/wallet_service.go index 3b4d48aae6..8b240d4d97 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/service/wallet_service.go +++ b/vendor/github.com/OpenBazaar/multiwallet/service/wallet_service.go @@ -98,14 +98,10 @@ func (ws *WalletService) Stop() { ws.doneChan <- struct{}{} } -func (ws *WalletService) ChainTip() (uint32, chainhash.Hash) { +func (ws *WalletService) ChainTip() (uint32, string) { ws.lock.RLock() defer ws.lock.RUnlock() - ch, err := chainhash.NewHashFromStr(ws.bestBlock) - if err != nil { - Log.Errorf("producing BestBlock hash: %s", err.Error()) - } - return ws.chainHeight, *ch + return ws.chainHeight, ws.bestBlock } func (ws *WalletService) AddTransactionListener(callback func(callback wallet.TransactionCallback)) { @@ -525,7 +521,7 @@ func (ws *WalletService) saveSingleTxToDB(u model.Transaction, chainHeight int32 cb.Value = *value cb.WatchOnly = (hits == 0) - saved, err := ws.db.Txns().Get(*txHash) + saved, err := ws.db.Txns().Get(txHash.String()) if err != nil || saved.WatchOnly != cb.WatchOnly { ts := time.Now() if u.Confirmations > 0 { @@ -547,15 +543,15 @@ func (ws *WalletService) saveSingleTxToDB(u model.Transaction, chainHeight int32 cb.Timestamp = ts ws.callbackListeners(cb) } else if height > 0 { - err := ws.db.Txns().UpdateHeight(*txHash, int(height), time.Unix(u.BlockTime, 0)) + err := ws.db.Txns().UpdateHeight(txHash.String(), int(height), time.Unix(u.BlockTime, 0)) if err != nil { Log.Errorf("updating height for tx (%s): %s", txHash.String(), err.Error()) return } if saved.Height != height { cb.Timestamp = saved.Timestamp + ws.callbackListeners(cb) } - ws.callbackListeners(cb) } } diff --git a/vendor/github.com/OpenBazaar/multiwallet/test/factory/transaction.go b/vendor/github.com/OpenBazaar/multiwallet/test/factory/transaction.go new file mode 100644 index 0000000000..77304ec7f4 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/test/factory/transaction.go @@ -0,0 +1,50 @@ +package factory + +import "github.com/OpenBazaar/multiwallet/model" + +func NewTransaction() model.Transaction { + return model.Transaction{ + Txid: "1be612e4f2b79af279e0b307337924072b819b3aca09fcb20370dd9492b83428", + Version: 2, + Locktime: 512378, + Inputs: []model.Input{ + { + Txid: "6d892f04fc097f430d58ab06229c9b6344a130fc1842da5b990e857daed42194", + Vout: 1, + Sequence: 1, + ValueIface: "0.04294455", + ScriptSig: model.Script{ + Hex: "4830450221008665481674067564ef562cfd8d1ca8f1506133fb26a2319e4b8dfba3cedfd5de022038f27121c44e6c64b93b94d72620e11b9de35fd864730175db9176ca98f1ec610121022023e49335a0dddb864ff673468a6cc04e282571b1227933fcf3ff9babbcc662", + }, + Addr: "1C74Gbij8Q5h61W58aSKGvXK4rk82T2A3y", + Satoshis: 4294455, + }, + }, + Outputs: []model.Output{ + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "76a914ff3f7d402fbd6d116ba4a02af9784f3ae9b7108a88ac", + }, + Type: "pay-to-pubkey-hash", + Addresses: []string{"1QGdNEDjWnghrjfTBCTDAPZZ3ffoKvGc9B"}, + }, + ValueIface: "0.01398175", + }, + { + ScriptPubKey: model.OutScript{ + Script: model.Script{ + Hex: "a9148a62462d08a977fa89226a56fca7eb01b6fef67c87", + }, + Type: "pay-to-script-hashh", + Addresses: []string{"3EJiuDqsHuAtFqiLGWKVyCfvqoGpWVCCRs"}, + }, + ValueIface: "0.02717080", + }, + }, + Time: 1520449061, + BlockHash: "0000000000000000003f1fb88ac3dab0e607e87def0e9031f7bea02cb464a04f", + BlockHeight: 512476, + Confirmations: 1, + } +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/test/helper.go b/vendor/github.com/OpenBazaar/multiwallet/test/helper.go new file mode 100644 index 0000000000..10386952b4 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/test/helper.go @@ -0,0 +1,85 @@ +package test + +import ( + "testing" + + "github.com/OpenBazaar/multiwallet/model" +) + +func ValidateTransaction(tx, expectedTx model.Transaction, t *testing.T) { + if tx.Txid != expectedTx.Txid { + t.Error("Returned invalid transaction") + } + if tx.Version != expectedTx.Version { + t.Error("Returned invalid transaction") + } + if tx.Locktime != expectedTx.Locktime { + t.Error("Returned invalid transaction") + } + if tx.Time != expectedTx.Time { + t.Error("Returned invalid transaction") + } + if tx.BlockHash != expectedTx.BlockHash { + t.Error("Returned invalid transaction") + } + if tx.BlockHeight != expectedTx.BlockHeight { + t.Error("Returned invalid transaction") + } + if tx.Confirmations != expectedTx.Confirmations { + t.Error("Returned invalid transaction") + } + if len(tx.Inputs) != 1 { + t.Error("Returned incorrect number of inputs") + return + } + if tx.Inputs[0].Txid != expectedTx.Inputs[0].Txid { + t.Error("Returned invalid transaction") + } + if tx.Inputs[0].Value != 0.04294455 { + t.Error("Returned invalid transaction") + } + if tx.Inputs[0].Satoshis != expectedTx.Inputs[0].Satoshis { + t.Error("Returned invalid transaction") + } + if tx.Inputs[0].Addr != expectedTx.Inputs[0].Addr { + t.Error("Returned invalid transaction") + } + if tx.Inputs[0].Sequence != expectedTx.Inputs[0].Sequence { + t.Error("Returned invalid transaction") + } + if tx.Inputs[0].Vout != expectedTx.Inputs[0].Vout { + t.Error("Returned invalid transaction") + } + if tx.Inputs[0].ScriptSig.Hex != expectedTx.Inputs[0].ScriptSig.Hex { + t.Error("Returned invalid transaction") + } + + if len(tx.Outputs) != 2 { + t.Error("Returned incorrect number of outputs") + return + } + if tx.Outputs[0].Value != 0.01398175 { + t.Error("Returned invalid transaction") + } + if tx.Outputs[0].ScriptPubKey.Hex != expectedTx.Outputs[0].ScriptPubKey.Hex { + t.Error("Returned invalid transaction") + } + if tx.Outputs[0].ScriptPubKey.Type != expectedTx.Outputs[0].ScriptPubKey.Type { + t.Error("Returned invalid transaction") + } + if tx.Outputs[0].ScriptPubKey.Addresses[0] != expectedTx.Outputs[0].ScriptPubKey.Addresses[0] { + t.Error("Returned invalid transaction") + } + if tx.Outputs[1].Value != 0.02717080 { + t.Error("Returned invalid transaction") + } + if tx.Outputs[1].ScriptPubKey.Hex != expectedTx.Outputs[1].ScriptPubKey.Hex { + t.Error("Returned invalid transaction") + } + if tx.Outputs[1].ScriptPubKey.Type != expectedTx.Outputs[1].ScriptPubKey.Type { + t.Error("Returned invalid transaction") + } + if tx.Outputs[1].ScriptPubKey.Addresses[0] != expectedTx.Outputs[1].ScriptPubKey.Addresses[0] { + t.Error("Returned invalid transaction") + } +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/util/balance.go b/vendor/github.com/OpenBazaar/multiwallet/util/balance.go index 8202a0ae09..ef2d7ca4c2 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/util/balance.go +++ b/vendor/github.com/OpenBazaar/multiwallet/util/balance.go @@ -2,12 +2,17 @@ package util import ( "bytes" + "errors" "strconv" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/wire" ) +var BumpFeeAlreadyConfirmedError = errors.New("Transaction is confirmed, cannot bump fee") +var BumpFeeTransactionDeadError = errors.New("Cannot bump fee of dead transaction") +var BumpFeeNotFoundError = errors.New("Transaction either doesn't exist or has already been spent") + func CalcBalance(utxos []wi.Utxo, txns []wi.Txn) (confirmed, unconfirmed int64) { var txmap = make(map[string]wi.Txn) for _, tx := range txns { diff --git a/vendor/github.com/OpenBazaar/multiwallet/util/bitconprices.go b/vendor/github.com/OpenBazaar/multiwallet/util/bitconprices.go new file mode 100644 index 0000000000..56298c7d12 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/util/bitconprices.go @@ -0,0 +1,239 @@ +package util + +import ( + "encoding/json" + "errors" + "net" + "net/http" + "reflect" + "strconv" + "sync" + "time" + + "github.com/op/go-logging" + "golang.org/x/net/proxy" +) + +const SatoshiPerBTC int64 = 100000000 + +var log = logging.MustGetLogger("exchangeRates") + +type ExchangeRateProvider struct { + fetchUrl string + cache map[string]float64 + client *http.Client + decoder ExchangeRateDecoder +} + +type ExchangeRateDecoder interface { + decode(dat interface{}, cache map[string]float64) (err error) +} + +// empty structs to tag the different ExchangeRateDecoder implementations +type BitcoinAverageDecoder struct{} +type BitPayDecoder struct{} +type BlockchainInfoDecoder struct{} +type BitcoinChartsDecoder struct{} + +type BitcoinPriceFetcher struct { + sync.Mutex + cache map[string]float64 + providers []*ExchangeRateProvider +} + +func NewBitcoinPriceFetcher(dialer proxy.Dialer) *BitcoinPriceFetcher { + b := BitcoinPriceFetcher{ + cache: make(map[string]float64), + } + dial := net.Dial + if dialer != nil { + dial = dialer.Dial + } + tbTransport := &http.Transport{Dial: dial} + client := &http.Client{Transport: tbTransport, Timeout: time.Minute} + + b.providers = []*ExchangeRateProvider{ + {"https://ticker.openbazaar.org/api", b.cache, client, BitcoinAverageDecoder{}}, + {"https://bitpay.com/api/rates", b.cache, client, BitPayDecoder{}}, + {"https://blockchain.info/ticker", b.cache, client, BlockchainInfoDecoder{}}, + {"https://api.bitcoincharts.com/v1/weighted_prices.json", b.cache, client, BitcoinChartsDecoder{}}, + } + return &b +} + +func (b *BitcoinPriceFetcher) GetExchangeRate(currencyCode string) (float64, error) { + currencyCode = NormalizeCurrencyCode(currencyCode) + + b.Lock() + defer b.Unlock() + price, ok := b.cache[currencyCode] + if !ok { + return 0, errors.New("Currency not tracked") + } + return price, nil +} + +func (b *BitcoinPriceFetcher) GetLatestRate(currencyCode string) (float64, error) { + currencyCode = NormalizeCurrencyCode(currencyCode) + + b.fetchCurrentRates() + b.Lock() + defer b.Unlock() + price, ok := b.cache[currencyCode] + if !ok { + return 0, errors.New("Currency not tracked") + } + return price, nil +} + +func (b *BitcoinPriceFetcher) GetAllRates(cacheOK bool) (map[string]float64, error) { + if !cacheOK { + err := b.fetchCurrentRates() + if err != nil { + return nil, err + } + } + b.Lock() + defer b.Unlock() + copy := make(map[string]float64, len(b.cache)) + for k, v := range b.cache { + copy[k] = v + } + return copy, nil +} + +func (b *BitcoinPriceFetcher) UnitsPerCoin() int64 { + return SatoshiPerBTC +} + +func (b *BitcoinPriceFetcher) fetchCurrentRates() error { + b.Lock() + defer b.Unlock() + for _, provider := range b.providers { + err := provider.fetch() + if err == nil { + return nil + } + } + log.Error("Failed to fetch bitcoin exchange rates") + return errors.New("All exchange rate API queries failed") +} + +func (provider *ExchangeRateProvider) fetch() (err error) { + if len(provider.fetchUrl) == 0 { + err = errors.New("Provider has no fetchUrl") + return err + } + resp, err := provider.client.Get(provider.fetchUrl) + if err != nil { + log.Error("Failed to fetch from "+provider.fetchUrl, err) + return err + } + decoder := json.NewDecoder(resp.Body) + var dataMap interface{} + err = decoder.Decode(&dataMap) + if err != nil { + log.Error("Failed to decode JSON from "+provider.fetchUrl, err) + return err + } + return provider.decoder.decode(dataMap, provider.cache) +} + +func (b *BitcoinPriceFetcher) Run() { + b.fetchCurrentRates() + ticker := time.NewTicker(time.Minute * 15) + for range ticker.C { + b.fetchCurrentRates() + } +} + +// Decoders +func (b BitcoinAverageDecoder) decode(dat interface{}, cache map[string]float64) (err error) { + data, ok := dat.(map[string]interface{}) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed") + } + for k, v := range data { + if k != "timestamp" { + val, ok := v.(map[string]interface{}) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed") + } + price, ok := val["last"].(float64) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed, missing 'last' (float) field") + } + cache[k] = price + } + } + return nil +} + +func (b BitPayDecoder) decode(dat interface{}, cache map[string]float64) (err error) { + data, ok := dat.([]interface{}) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed, not JSON array") + } + + for _, obj := range data { + code := obj.(map[string]interface{}) + k, ok := code["code"].(string) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed, missing 'code' (string) field") + } + price, ok := code["rate"].(float64) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed, missing 'rate' (float) field") + } + cache[k] = price + } + return nil +} + +func (b BlockchainInfoDecoder) decode(dat interface{}, cache map[string]float64) (err error) { + data, ok := dat.(map[string]interface{}) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed, not JSON object") + } + for k, v := range data { + val, ok := v.(map[string]interface{}) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed") + } + price, ok := val["last"].(float64) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed, missing 'last' (float) field") + } + cache[k] = price + } + return nil +} + +func (b BitcoinChartsDecoder) decode(dat interface{}, cache map[string]float64) (err error) { + data, ok := dat.(map[string]interface{}) + if !ok { + return errors.New(reflect.TypeOf(b).Name() + ".decode: Type assertion failed, not JSON object") + } + for k, v := range data { + if k != "timestamp" { + val, ok := v.(map[string]interface{}) + if !ok { + return errors.New("Type assertion failed") + } + p, ok := val["24h"] + if !ok { + continue + } + pr, ok := p.(string) + if !ok { + return errors.New("Type assertion failed") + } + price, err := strconv.ParseFloat(pr, 64) + if err != nil { + return err + } + cache[k] = price + } + } + return nil +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/util/fees.go b/vendor/github.com/OpenBazaar/multiwallet/util/fees.go index add68e4126..a161a6c6b1 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/util/fees.go +++ b/vendor/github.com/OpenBazaar/multiwallet/util/fees.go @@ -45,8 +45,8 @@ func NewFeeProvider(maxFee, priorityFee, normalFee, economicFee, superEconomicFe maxFee: maxFee, priorityFee: priorityFee, normalFee: normalFee, - superEconomicFee: superEconomicFee, economicFee: economicFee, + superEconomicFee: superEconomicFee, exchangeRates: exchangeRates, } } @@ -54,7 +54,7 @@ func NewFeeProvider(maxFee, priorityFee, normalFee, economicFee, superEconomicFe func (fp *FeeProvider) GetFeePerByte(feeLevel wallet.FeeLevel) uint64 { defaultFee := func() uint64 { switch feeLevel { - case wallet.PRIORITY: + case wallet.PRIOIRTY: return fp.priorityFee case wallet.NORMAL: return fp.normalFee @@ -79,12 +79,14 @@ func (fp *FeeProvider) GetFeePerByte(feeLevel wallet.FeeLevel) uint64 { var target FeeTargetInUSDCents switch feeLevel { - case wallet.PRIORITY: + case wallet.PRIOIRTY: target = PriorityTarget case wallet.NORMAL: target = NormalTarget case wallet.ECONOMIC: target = EconomicTarget + case wallet.SUPER_ECONOMIC: + return fp.superEconomicFee case wallet.FEE_BUMP: target = PriorityTarget * 2 default: diff --git a/vendor/github.com/OpenBazaar/multiwallet/util/locktime.go b/vendor/github.com/OpenBazaar/multiwallet/util/locktime.go new file mode 100644 index 0000000000..4816159306 --- /dev/null +++ b/vendor/github.com/OpenBazaar/multiwallet/util/locktime.go @@ -0,0 +1,33 @@ +package util + +import "errors" + +func LockTimeFromRedeemScript(redeemScript []byte) (uint32, error) { + if len(redeemScript) < 113 { + return 0, errors.New("Redeem script invalid length") + } + if redeemScript[106] != 103 { + return 0, errors.New("Invalid redeem script") + } + if redeemScript[107] == 0 { + return 0, nil + } + if 81 <= redeemScript[107] && redeemScript[107] <= 96 { + return uint32((redeemScript[107] - 81) + 1), nil + } + var v []byte + op := redeemScript[107] + if 1 <= op && op <= 75 { + for i := 0; i < int(op); i++ { + v = append(v, []byte{redeemScript[108+i]}...) + } + } else { + return 0, errors.New("Too many bytes pushed for sequence") + } + var result int64 + for i, val := range v { + result |= int64(val) << uint8(8*i) + } + + return uint32(result), nil +} diff --git a/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go b/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go index c3180d6e31..6ae2767c81 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go @@ -13,7 +13,6 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/minio/blake2b-simd" - "github.com/OpenBazaar/spvwallet" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -42,7 +41,7 @@ var ( const ( sigHashMask = 0x1f - branchID = 0xf5b9230b + branchID = 0x2BB40E60 ) func (w *ZCashWallet) buildTx(amount int64, addr btc.Address, feeLevel wi.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { @@ -298,15 +297,15 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } func (w *ZCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return nil, err } if txn.Height > 0 { - return nil, spvwallet.BumpFeeAlreadyConfirmedError + return nil, util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, spvwallet.BumpFeeTransactionDeadError + return nil, util.BumpFeeTransactionDeadError } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() @@ -339,7 +338,7 @@ func (w *ZCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { return transactionID, nil } } - return nil, spvwallet.BumpFeeNotFoundError + return nil, util.BumpFeeNotFoundError } func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { @@ -379,7 +378,7 @@ func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Addre txType := P2PKH if redeemScript != nil { txType = P2SH_1of2_Multisig - _, err := spvwallet.LockTimeFromRedeemScript(*redeemScript) + _, err := util.LockTimeFromRedeemScript(*redeemScript) if err == nil { txType = P2SH_Multisig_Timelock_1Sig } diff --git a/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go index 3cf2a12c07..9bda26d02d 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go @@ -261,7 +261,7 @@ func (w *ZCashWallet) Transactions() ([]wi.Txn, error) { } func (w *ZCashWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(trimTxForDeserialization(txn.Bytes)) @@ -287,7 +287,7 @@ func (w *ZCashWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { return txn, err } -func (w *ZCashWallet) ChainTip() (uint32, chainhash.Hash) { +func (w *ZCashWallet) ChainTip() (uint32, string) { return w.ws.ChainTip() } @@ -401,7 +401,7 @@ func (w *ZCashWallet) ReSyncBlockchain(fromTime time.Time) { } func (w *ZCashWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid) + txn, err := w.db.Txns().Get(txid.String()) if err != nil { return 0, 0, err } From f8c0dc014ca3c5d7a05bf566ebdd289a2732d378 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:58:23 -0400 Subject: [PATCH 02/52] spvwallet fixes --- vendor/github.com/OpenBazaar/spvwallet/fees.go | 14 +++++++------- .../OpenBazaar/spvwallet/sortsignsend.go | 2 +- vendor/github.com/OpenBazaar/spvwallet/txstore.go | 8 ++++---- vendor/github.com/OpenBazaar/spvwallet/wallet.go | 11 +++++------ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/vendor/github.com/OpenBazaar/spvwallet/fees.go b/vendor/github.com/OpenBazaar/spvwallet/fees.go index 8d116e8c6b..46f15bd8f3 100644 --- a/vendor/github.com/OpenBazaar/spvwallet/fees.go +++ b/vendor/github.com/OpenBazaar/spvwallet/fees.go @@ -81,16 +81,16 @@ func (fp *FeeProvider) GetFeePerByte(feeLevel wallet.FeeLevel) uint64 { fees = fp.cache.fees } switch feeLevel { - case wallet.PRIORITY: - return fp.selectFee(fees.Priority, wallet.PRIORITY) + case wallet.PRIOIRTY: + return fp.selectFee(fees.Priority, wallet.PRIOIRTY) case wallet.NORMAL: - return fp.selectFee(fees.Normal, wallet.PRIORITY) + return fp.selectFee(fees.Normal, wallet.PRIOIRTY) case wallet.ECONOMIC: - return fp.selectFee(fees.Economic, wallet.PRIORITY) + return fp.selectFee(fees.Economic, wallet.PRIOIRTY) case wallet.SUPER_ECONOMIC: - return fp.selectFee(fees.SuperEconomic, wallet.PRIORITY) + return fp.selectFee(fees.SuperEconomic, wallet.PRIOIRTY) case wallet.FEE_BUMP: - return fp.selectFee(fees.Priority, wallet.PRIORITY) + return fp.selectFee(fees.Priority, wallet.PRIOIRTY) default: return fp.normalFee } @@ -108,7 +108,7 @@ func (fp *FeeProvider) selectFee(fee uint64, feeLevel wallet.FeeLevel) uint64 { func (fp *FeeProvider) defaultFee(feeLevel wallet.FeeLevel) uint64 { switch feeLevel { - case wallet.PRIORITY: + case wallet.PRIOIRTY: return fp.priorityFee case wallet.NORMAL: return fp.normalFee diff --git a/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go b/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go index 1947afcc3d..52abf54415 100644 --- a/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go +++ b/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go @@ -131,7 +131,7 @@ var BumpFeeTransactionDeadError = errors.New("Cannot bump fee of dead transactio var BumpFeeNotFoundError = errors.New("Transaction either doesn't exist or has already been spent") func (w *SPVWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.txstore.Txns().Get(txid) + txn, err := w.txstore.Txns().Get(txid.String()) if err != nil { return nil, err } diff --git a/vendor/github.com/OpenBazaar/spvwallet/txstore.go b/vendor/github.com/OpenBazaar/spvwallet/txstore.go index 1fde4b6cf9..54f1f60435 100644 --- a/vendor/github.com/OpenBazaar/spvwallet/txstore.go +++ b/vendor/github.com/OpenBazaar/spvwallet/txstore.go @@ -362,7 +362,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32, timestamp time.Time) (ui if hits > 0 || matchesWatchOnly { ts.cbMutex.Lock() ts.txidsMutex.Lock() - txn, err := ts.Txns().Get(tx.TxHash()) + txn, err := ts.Txns().Get(tx.TxHash().String()) shouldCallback := false if err != nil { cb.Value = *big.NewInt(value) @@ -376,7 +376,7 @@ func (ts *TxStore) Ingest(tx *wire.MsgTx, height int32, timestamp time.Time) (ui // Let's check the height before committing so we don't allow rogue peers to send us a lose // tx that resets our height to zero. if err == nil && txn.Height <= 0 { - ts.Txns().UpdateHeight(tx.TxHash(), int(height), txn.Timestamp) + ts.Txns().UpdateHeight(tx.TxHash().String(), int(height), txn.Timestamp) ts.txids[tx.TxHash().String()] = height if height > 0 { val0, _ := new(big.Int).SetString(txn.Value, 10) @@ -409,7 +409,7 @@ func (ts *TxStore) markAsDead(txid chainhash.Hash) error { if err != nil { return err } - err = ts.Txns().UpdateHeight(s.SpendTxid, -1, time.Now()) + err = ts.Txns().UpdateHeight(s.SpendTxid.String(), -1, time.Now()) if err != nil { return err } @@ -448,7 +448,7 @@ func (ts *TxStore) markAsDead(txid chainhash.Hash) error { } } } - ts.Txns().UpdateHeight(txid, -1, time.Now()) + ts.Txns().UpdateHeight(txid.String(), -1, time.Now()) return nil } diff --git a/vendor/github.com/OpenBazaar/spvwallet/wallet.go b/vendor/github.com/OpenBazaar/spvwallet/wallet.go index 25f19e1fae..150fd497fc 100644 --- a/vendor/github.com/OpenBazaar/spvwallet/wallet.go +++ b/vendor/github.com/OpenBazaar/spvwallet/wallet.go @@ -380,7 +380,7 @@ func (w *SPVWallet) Transactions() ([]wallet.Txn, error) { } func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (wallet.Txn, error) { - txn, err := w.txstore.Txns().Get(txid) + txn, err := w.txstore.Txns().Get(txid.String()) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -411,7 +411,7 @@ func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (wallet.Txn, error) { } func (w *SPVWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.txstore.Txns().Get(txid) + txn, err := w.txstore.Txns().Get(txid.String()) if err != nil { return 0, 0, err } @@ -451,13 +451,12 @@ func (w *SPVWallet) AddTransactionListener(callback func(wallet.TransactionCallb w.txstore.listeners = append(w.txstore.listeners, callback) } -func (w *SPVWallet) ChainTip() (uint32, chainhash.Hash) { - var ch chainhash.Hash +func (w *SPVWallet) ChainTip() (uint32, string) { sh, err := w.blockchain.db.GetBestHeader() if err != nil { - return 0, ch + return 0, "" } - return sh.height, sh.header.BlockHash() + return sh.height, sh.header.BlockHash().String() } func (w *SPVWallet) AddWatchedAddresses(addrs ...btc.Address) error { From 1eac8ad045e2719d45a3536a17b7be1e4d834803 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:58:32 -0400 Subject: [PATCH 03/52] wallet-interface fixes --- .../OpenBazaar/wallet-interface/datastore.go | 14 +++- .../OpenBazaar/wallet-interface/wallet.go | 80 ++++++++++++++++++- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/vendor/github.com/OpenBazaar/wallet-interface/datastore.go b/vendor/github.com/OpenBazaar/wallet-interface/datastore.go index 4d91b9e0c6..30af2eefe6 100644 --- a/vendor/github.com/OpenBazaar/wallet-interface/datastore.go +++ b/vendor/github.com/OpenBazaar/wallet-interface/datastore.go @@ -24,12 +24,14 @@ const ( Zcash = 133 BitcoinCash = 145 Ethereum = 60 + Filecoin = 461 TestnetBitcoin = 1000000 TestnetLitecoin = 1000001 TestnetZcash = 1000133 TestnetBitcoinCash = 1000145 TestnetEthereum = 1000060 + TestnetFilecoin = 1000461 ) func (c *CoinType) String() string { @@ -44,6 +46,8 @@ func (c *CoinType) String() string { return "Litecoin" case Ethereum: return "Ethereum" + case Filecoin: + return "Filecoin" case TestnetBitcoin: return "Testnet Bitcoin" case TestnetBitcoinCash: @@ -54,6 +58,8 @@ func (c *CoinType) String() string { return "Testnet Litecoin" case TestnetEthereum: return "Testnet Ethereum" + case TestnetFilecoin: + return "Testnet Filecoin" default: return "" } @@ -71,6 +77,8 @@ func (c *CoinType) CurrencyCode() string { return "LTC" case Ethereum: return "ETH" + case Filecoin: + return "FIL" case TestnetBitcoin: return "TBTC" case TestnetBitcoinCash: @@ -81,6 +89,8 @@ func (c *CoinType) CurrencyCode() string { return "TLTC" case TestnetEthereum: return "TETH" + case TestnetFilecoin: + return "TFIL" default: return "" } @@ -124,13 +134,13 @@ type Txns interface { Put(raw []byte, txid, value string, height int, timestamp time.Time, watchOnly bool) error // Fetch a tx and it's metadata given a hash - Get(txid chainhash.Hash) (Txn, error) + Get(txid string) (Txn, error) // Fetch all transactions from the db GetAll(includeWatchOnly bool) ([]Txn, error) // Update the height of a transaction - UpdateHeight(txid chainhash.Hash, height int, timestamp time.Time) error + UpdateHeight(txid string, height int, timestamp time.Time) error // Delete a transactions from the db Delete(txid *chainhash.Hash) error diff --git a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go index a60985c715..1dab141632 100644 --- a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go +++ b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go @@ -68,6 +68,76 @@ type WalletMustManuallyAssociateTransactionToOrder interface { AssociateTransactionWithOrder(cb TransactionCallback) } +// EscrowWallet is implemented by wallets capable of performing escrow transactions. +type EscrowWallet interface { + // SweepAddress should sweep all the funds from the provided inputs into the provided `address` using the given + // `key`. If `address` is nil, the funds should be swept into an internal address own by this wallet. + // If the `redeemScript` is not nil, this should be treated as a multisig (p2sh) address and signed accordingly. + // + // This method is called by openbazaar-go in the following scenarios: + // 1) The buyer placed a direct order to a vendor who was offline. The buyer sent funds into a 1 of 2 multisig. + // Upon returning online the vendor accepts the order and calls SweepAddress to move the funds into his wallet. + // + // 2) Same as above but the buyer wishes to cancel the order before the vendor comes online. He calls SweepAddress + // to return the funds from the 1 of 2 multisig back into has wallet. + // + // 3) Same as above but rather than accepting the order, the vendor rejects it. When the buyer receives the reject + // message he calls SweepAddress to move the funds back into his wallet. + // + // 4) The timeout has expired on a 2 of 3 multisig. The vendor calls SweepAddress to claim the funds. + SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (*chainhash.Hash, error) + + // GenerateMultisigScript should deterministically create a redeem script and address from the information provided. + // This method should be strictly limited to taking the input data, combining it to produce the redeem script and + // address and that's it. There is no need to interact with the network or make any transactions when this is called. + // + // Openbazaar-go will call this method in the following situations: + // 1) When the buyer places an order he passes in the relevant keys for each party to get back the address where + // the funds should be sent and the redeem script. The redeem script is saved in order (and openbazaar-go database). + // + // 2) The vendor calls this method when he receives and order so as to validate that the address they buyer is sending + // funds to is indeed correctly constructed. If this method fails to return the same values for the vendor as it + // did the buyer, the vendor will reject the order. + // + // 3) The moderator calls this function upon receiving a dispute so that he can validate the payment address for the + // order and make sure neither party is trying to maliciously lie about the details of the dispute to get the moderator + // to release the funds. + // + // Note that according to the order flow, this method is called by the buyer *before* the order is sent to the vendor, + // and before the vendor validates the order. Only after the buyer hears back from the vendor does the buyer send + // funds (either from an external wallet or via the `Spend` method) to the address specified in this method's return. + // + // `threshold` is the number of keys required to release the funds from the address. If `threshold` is two and len(keys) + // is three, this is a two of three multisig. If `timeoutKey` is not nil, then the script should allow the funds to + // be released with a signature from the `timeoutKey` after the `timeout` duration has passed. + // For example: + // OP_IF 2 3 OP_ELSE OP_CHECKSEQUENCEVERIFY OP_CHECKSIG OP_ENDIF + // + // If `timeoutKey` is nil then the a normal multisig without a timeout should be created. + GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btc.Address, redeemScript []byte, err error) + + // CreateMultisigSignature should build a transaction using the given inputs and outputs and sign it with the + // provided key. A list of signatures (one for each input) should be returned. + // + // This method is called by openbazaar-go by each party whenever they decide to release the funds from escrow. + // This method should not actually move any funds or make any transactions, only create necessary signatures to + // do so. The caller will then take the signature and share it with the other parties. Once all parties have shared + // their signatures, the person who wants to release the funds collects them and uses them as an input to the + // `Multisign` method. + CreateMultisigSignature(ins []TransactionInput, outs []TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]Signature, error) + + // Multisign collects all of the signatures generated by the `CreateMultisigSignature` function and builds a final + // transaction that can then be broadcast to the blockchain. The []byte return is the raw transaction. It should be + // broadcasted if `broadcast` is true. If the signatures combine and produce an invalid transaction then an error + // should be returned. + // + // This method is called by openbazaar-go by whichever party to the escrow is trying to release the funds only after + // all needed parties have signed using `CreateMultisigSignature` and have shared their signatures with each other. + Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) +} + + + type walletMustManager interface { // Start is called when the openbazaar-go daemon starts up. At this point in time // the wallet implementation should start syncing and/or updating balances, but @@ -143,7 +213,7 @@ type walletMustManager interface { GetTransaction(txid chainhash.Hash) (Txn, error) // ChainTip returns the best block hash and height of the blockchain. - ChainTip() (uint32, chainhash.Hash) + ChainTip() (uint32, string) // ReSyncBlockchain is called in response to a user action to rescan transactions. API based // wallets should do another scan of their addresses to find anything missing. Full node, or SPV @@ -152,9 +222,7 @@ type walletMustManager interface { // GetConfirmations returns the number of confirmations and the height for a transaction. GetConfirmations(txid chainhash.Hash) (confirms, atHeight uint32, err error) -} -type walletMustKeysmither interface { // ChildKey generate a child key using the given chaincode. Each openbazaar-go node // keeps a master key (an hd secp256k1 key) that it uses in multisig transactions. // Rather than use the key directly (which would result in an on chain privacy leak), @@ -164,6 +232,9 @@ type walletMustKeysmither interface { // function leaves it up the wallet implementation to decide how to derive the child key // so long as it's deterministic and uses the chaincode and the returned key is pseudorandom. ChildKey(keyBytes []byte, chaincode []byte, isPrivateKey bool) (*hd.ExtendedKey, error) +} + +type walletMustKeysmither interface { // HasKey returns whether or not the wallet has the key for the given address. This method // is called by openbazaar-go when validating payouts from multisigs. It makes sure the @@ -220,6 +291,7 @@ type walletMustKeysmither interface { Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) } + type walletMustBanker interface { // GetFeePerByte returns the current fee per byte for the given fee level. There // are three fee levels ― priority, normal, and economic. @@ -283,7 +355,7 @@ type walletCanBumpFee interface { type FeeLevel int const ( - PRIORITY FeeLevel = 0 + PRIOIRTY FeeLevel = 0 NORMAL = 1 ECONOMIC = 2 FEE_BUMP = 3 From e5b1ba5ea30e2ea7b20ed8546208ae9158b6a485 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:58:40 -0400 Subject: [PATCH 04/52] ethwallet fixes --- .../OpenBazaar/go-ethwallet/wallet/wallet.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go index 3698cbfb28..6c9442daef 100644 --- a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go +++ b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go @@ -651,17 +651,12 @@ func (wallet *EthereumWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error } // ChainTip - Get the height and best hash of the blockchain -func (wallet *EthereumWallet) ChainTip() (uint32, chainhash.Hash) { +func (wallet *EthereumWallet) ChainTip() (uint32, string) { num, hash, err := wallet.client.GetLatestBlock() if err != nil { - return 0, *emptyChainHash + return 0, "" } - h, err := util.CreateChainHash(hash.Hex()) - if err != nil { - log.Error(err.Error()) - h = emptyChainHash - } - return num, *h + return num, hash.String() } // GetFeePerByte - Get the current fee per byte @@ -677,7 +672,7 @@ func (wallet *EthereumWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { ret, _ = big.NewFloat(est.Average * 100000000).Int(nil) case wi.ECONOMIC, wi.SUPER_ECONOMIC: ret, _ = big.NewFloat(est.SafeLow * 100000000).Int(nil) - case wi.PRIORITY, wi.FEE_BUMP: + case wi.PRIOIRTY, wi.FEE_BUMP: ret, _ = big.NewFloat(est.Fast * 100000000).Int(nil) } return *ret From 9c23964a46552507098e95e36e6aabeb7b2a0afe Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:58:57 -0400 Subject: [PATCH 05/52] Constants update --- schema/constants.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schema/constants.go b/schema/constants.go index 0c09b7bec5..368fcdd6fc 100644 --- a/schema/constants.go +++ b/schema/constants.go @@ -100,12 +100,14 @@ const ( CoinAPIOpenBazaarLTC = "https://ltc.api.openbazaar.org/api" CoinAPIOpenBazaarZEC = "https://zec.api.openbazaar.org/api" CoinAPIOpenBazaarETH = "https://mainnet.infura.io" + CoinAPIOpenBazaarFIL = "http://localhost:1234" CoinAPIOpenBazaarTBTC = "https://tbtc.api.openbazaar.org/api" CoinAPIOpenBazaarTBCH = "https://tbch.api.openbazaar.org/api" CoinAPIOpenBazaarTLTC = "https://tltc.api.openbazaar.org/api" CoinAPIOpenBazaarTZEC = "https://tzec.api.openbazaar.org/api" CoinAPIOpenBazaarTETH = "https://rinkeby.infura.io" + CoinAPIOpenBazaarTFIL = "http://localhost:1234" ) var ( @@ -114,10 +116,12 @@ var ( CoinPoolLTC = []string{CoinAPIOpenBazaarLTC} CoinPoolZEC = []string{CoinAPIOpenBazaarZEC} CoinPoolETH = []string{CoinAPIOpenBazaarETH} + CoinPoolFIL = []string{CoinAPIOpenBazaarFIL} CoinPoolTBTC = []string{CoinAPIOpenBazaarTBTC} CoinPoolTBCH = []string{CoinAPIOpenBazaarTBCH} CoinPoolTLTC = []string{CoinAPIOpenBazaarTLTC} CoinPoolTZEC = []string{CoinAPIOpenBazaarTZEC} CoinPoolTETH = []string{CoinAPIOpenBazaarTETH} + CoinPoolTFIL = []string{CoinAPIOpenBazaarTFIL} ) From 8ea2f66f62da3170f07b955dd52eeb4c0669df61 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:59:04 -0400 Subject: [PATCH 06/52] coin config update --- schema/configuration.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/schema/configuration.go b/schema/configuration.go index 9bdd5df531..26baa088bd 100644 --- a/schema/configuration.go +++ b/schema/configuration.go @@ -36,6 +36,7 @@ type WalletsConfig struct { LTC *CoinConfig `json:"LTC"` ZEC *CoinConfig `json:"ZEC"` ETH *CoinConfig `json:"ETH"` + FIL *CoinConfig `json:"FIL"` } type CoinConfig struct { @@ -130,6 +131,17 @@ func DefaultWalletsConfig() *WalletsConfig { MaxFee: 200, WalletOptions: EthereumDefaultOptions(), }, + FIL: &CoinConfig{ + Type: WalletTypeAPI, + APIPool: CoinPoolFIL, + APITestnetPool: CoinPoolTFIL, + FeeAPI: "", // intentionally blank + LowFeeDefault: 7, + MediumFeeDefault: 15, + HighFeeDefault: 30, + MaxFee: 200, + WalletOptions: nil, + }, } } From 04ee986791ca8b8bdd8f0e1664f7ba9edeca956c Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:59:16 -0400 Subject: [PATCH 07/52] Database chainhash fix --- repo/db/txns.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/repo/db/txns.go b/repo/db/txns.go index 522e8da283..c8555e1a30 100644 --- a/repo/db/txns.go +++ b/repo/db/txns.go @@ -41,7 +41,7 @@ func (t *TxnsDB) Put(raw []byte, txid, value string, height int, timestamp time. return nil } -func (t *TxnsDB) Get(txid chainhash.Hash) (wallet.Txn, error) { +func (t *TxnsDB) Get(txid string) (wallet.Txn, error) { t.lock.Lock() defer t.lock.Unlock() var txn wallet.Txn @@ -55,7 +55,7 @@ func (t *TxnsDB) Get(txid chainhash.Hash) (wallet.Txn, error) { var timestamp int var value string var watchOnlyInt int - err = stmt.QueryRow(txid.String(), t.coinType.CurrencyCode()).Scan(&raw, &value, &height, ×tamp, &watchOnlyInt) + err = stmt.QueryRow(txid, t.coinType.CurrencyCode()).Scan(&raw, &value, &height, ×tamp, &watchOnlyInt) if err != nil { return txn, err } @@ -64,7 +64,7 @@ func (t *TxnsDB) Get(txid chainhash.Hash) (wallet.Txn, error) { watchOnly = true } txn = wallet.Txn{ - Txid: txid.String(), + Txid: txid, Value: value, Height: int32(height), Timestamp: time.Unix(int64(timestamp), 0), @@ -127,7 +127,7 @@ func (t *TxnsDB) Delete(txid *chainhash.Hash) error { return nil } -func (t *TxnsDB) UpdateHeight(txid chainhash.Hash, height int, timestamp time.Time) error { +func (t *TxnsDB) UpdateHeight(txid string, height int, timestamp time.Time) error { t.lock.Lock() defer t.lock.Unlock() @@ -136,7 +136,7 @@ func (t *TxnsDB) UpdateHeight(txid chainhash.Hash, height int, timestamp time.Ti return fmt.Errorf("prepare txn sql: %s", err.Error()) } defer stmt.Close() - _, err = stmt.Exec(height, int(timestamp.Unix()), txid.String(), t.coinType.CurrencyCode()) + _, err = stmt.Exec(height, int(timestamp.Unix()), txid, t.coinType.CurrencyCode()) if err != nil { return fmt.Errorf("update txns: %s", err.Error()) } From 89eaa9f6d82998a7fea5187cdb35f7c5a2dee043 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:59:24 -0400 Subject: [PATCH 08/52] Filecoin currency definition --- repo/currency_definition.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/repo/currency_definition.go b/repo/currency_definition.go index a12b1d9b75..106ed5560b 100644 --- a/repo/currency_definition.go +++ b/repo/currency_definition.go @@ -72,6 +72,7 @@ var ( "LTC": {Name: "Litecoin", Code: CurrencyCode("LTC"), CurrencyType: Crypto, Divisibility: 8, BlockTime: 150 * time.Second}, "ZEC": {Name: "Zcash", Code: CurrencyCode("ZEC"), CurrencyType: Crypto, Divisibility: 8, BlockTime: DefaultBlockTime}, "ETH": {Name: "Ethereum", Code: CurrencyCode("ETH"), CurrencyType: Crypto, Divisibility: 18, BlockTime: 10 * time.Second}, + "FIL": {Name: "Filecoin", Code: CurrencyCode("FIL"), CurrencyType: Crypto, Divisibility: 18, BlockTime: 10 * time.Second}, } testnetCryptoDefinitions = map[string]CurrencyDefinition{ "TBTC": {Name: "Testnet Bitcoin", Code: CurrencyCode("TBTC"), CurrencyType: Crypto, Divisibility: 8, BlockTime: DefaultBlockTime}, @@ -79,6 +80,7 @@ var ( "TLTC": {Name: "Testnet Litecoin", Code: CurrencyCode("TLTC"), CurrencyType: Crypto, Divisibility: 8, BlockTime: 150 * time.Second}, "TZEC": {Name: "Testnet Zcash", Code: CurrencyCode("TZEC"), CurrencyType: Crypto, Divisibility: 8, BlockTime: DefaultBlockTime}, "TETH": {Name: "Testnet Ethereum", Code: CurrencyCode("TETH"), CurrencyType: Crypto, Divisibility: 18, BlockTime: 10 * time.Second}, + "TFIL": {Name: "Testnet Filecoin", Code: CurrencyCode("TFIL"), CurrencyType: Crypto, Divisibility: 18, BlockTime: 10 * time.Second}, } fiatDefinitions = map[string]CurrencyDefinition{ "AED": {Name: "UAE Dirham", Code: CurrencyCode("AED"), CurrencyType: Fiat, Divisibility: 2}, From 48ad63abf29abf09725536ee026044f128bbea4f Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:59:36 -0400 Subject: [PATCH 09/52] Fix misspelling --- api/jsonapi.go | 10 +++++----- core/spend.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/jsonapi.go b/api/jsonapi.go index f3802a2e60..300e1dbe0a 100644 --- a/api/jsonapi.go +++ b/api/jsonapi.go @@ -3468,7 +3468,7 @@ func (i *jsonAPIHandler) GETEstimateFee(w http.ResponseWriter, r *http.Request) var feeLevel wallet.FeeLevel switch strings.ToUpper(fl) { case "PRIORITY": - feeLevel = wallet.PRIORITY + feeLevel = wallet.PRIOIRTY case "NORMAL": feeLevel = wallet.NORMAL case "ECONOMIC": @@ -3526,7 +3526,7 @@ func (i *jsonAPIHandler) GETFees(w http.ResponseWriter, r *http.Request) { if coinType == "fees" { ret := make(map[string]interface{}) for ct, wal := range i.node.Multiwallet { - priority := wal.GetFeePerByte(wallet.PRIORITY) + priority := wal.GetFeePerByte(wallet.PRIOIRTY) normal := wal.GetFeePerByte(wallet.NORMAL) economic := wal.GetFeePerByte(wallet.ECONOMIC) superEconomic := wal.GetFeePerByte(wallet.SUPER_ECONOMIC) @@ -3555,7 +3555,7 @@ func (i *jsonAPIHandler) GETFees(w http.ResponseWriter, r *http.Request) { ErrorResponse(w, http.StatusBadRequest, "Unknown wallet type") return } - priority := wal.GetFeePerByte(wallet.PRIORITY) + priority := wal.GetFeePerByte(wallet.PRIOIRTY) normal := wal.GetFeePerByte(wallet.NORMAL) economic := wal.GetFeePerByte(wallet.ECONOMIC) superEconomic := wal.GetFeePerByte(wallet.SUPER_ECONOMIC) @@ -3947,7 +3947,7 @@ func (i *jsonAPIHandler) GETWalletStatus(w http.ResponseWriter, r *http.Request) ret := make(map[string]interface{}) for ct, wal := range i.node.Multiwallet { height, hash := wal.ChainTip() - ret[ct.CurrencyCode()] = status{height, hash.String()} + ret[ct.CurrencyCode()] = status{height, hash} } out, err := json.MarshalIndent(ret, "", " ") if err != nil { @@ -3963,7 +3963,7 @@ func (i *jsonAPIHandler) GETWalletStatus(w http.ResponseWriter, r *http.Request) return } height, hash := wal.ChainTip() - st := status{height, hash.String()} + st := status{height, hash} out, err := json.MarshalIndent(st, "", " ") if err != nil { ErrorResponse(w, http.StatusInternalServerError, err.Error()) diff --git a/core/spend.go b/core/spend.go index 38135aedbf..7f3a9b3807 100644 --- a/core/spend.go +++ b/core/spend.go @@ -92,7 +92,7 @@ func (n *OpenBazaarNode) Spend(args *SpendRequest) (*SpendResponse, error) { switch strings.ToUpper(args.FeeLevel) { case "PRIORITY": - feeLevel = wallet.PRIORITY + feeLevel = wallet.PRIOIRTY case "NORMAL": feeLevel = wallet.NORMAL case "ECONOMIC": From 71ff7a75ff5eb6cafa7cb9f47e5d724d4a047adc Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 16 Jul 2020 16:59:48 -0400 Subject: [PATCH 10/52] Add Filecoin API wallet --- wallet/builder.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/wallet/builder.go b/wallet/builder.go index 0e60158b5c..f424d70736 100644 --- a/wallet/builder.go +++ b/wallet/builder.go @@ -3,6 +3,7 @@ package wallet import ( "errors" "fmt" + "github.com/OpenBazaar/multiwallet/filecoin" "net" "net/url" "os" @@ -89,6 +90,7 @@ func NewMultiWallet(cfg *WalletConfig) (multiwallet.MultiWallet, error) { enableAPIWallet[wallet.Litecoin] = cfg.ConfigFile.LTC } enableAPIWallet[wallet.Ethereum] = cfg.ConfigFile.ETH + enableAPIWallet[wallet.Filecoin] = cfg.ConfigFile.FIL var newMultiwallet = make(multiwallet.MultiWallet) for coin, coinConfig := range enableAPIWallet { @@ -178,6 +180,18 @@ func createAPIWallet(coin wallet.CoinType, coinConfigOverrides *schema.CoinConfi return InvalidCoinType, nil, err } return actualCoin, w, nil + case wallet.Filecoin: + if testnet { + actualCoin = wallet.TestnetFilecoin + } else { + actualCoin = wallet.Filecoin + } + //actualCoin = wallet.Filecoin + w, err := filecoin.NewFilecoinWallet(*coinConfig, cfg.Mnemonic, cfg.Params, cfg.Proxy, cache.NewMockCacher(), cfg.DisableExchangeRates) + if err != nil { + return InvalidCoinType, nil, err + } + return actualCoin, w, nil } return InvalidCoinType, nil, fmt.Errorf("unable to create wallet for unknown coin %s", coin.String()) } @@ -297,6 +311,8 @@ func prepareAPICoinConfig(coin wallet.CoinType, override *schema.CoinConfig, wal defaultConfig = defaultConfigSet.LTC case wallet.Zcash: defaultConfig = defaultConfigSet.ZEC + case wallet.Filecoin: + defaultConfig = defaultConfigSet.FIL case wallet.Ethereum: defaultConfig = defaultConfigSet.ETH defaultCoinOptions = schema.EthereumDefaultOptions() From fc969b693884d60f35faa1d9477f248574055fbd Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Tue, 21 Jul 2020 11:22:02 -0400 Subject: [PATCH 11/52] Filecoin server constants --- schema/constants.go | 4 ++-- vendor/github.com/filecoin-project | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 160000 vendor/github.com/filecoin-project diff --git a/schema/constants.go b/schema/constants.go index 368fcdd6fc..5bc589f357 100644 --- a/schema/constants.go +++ b/schema/constants.go @@ -100,14 +100,14 @@ const ( CoinAPIOpenBazaarLTC = "https://ltc.api.openbazaar.org/api" CoinAPIOpenBazaarZEC = "https://zec.api.openbazaar.org/api" CoinAPIOpenBazaarETH = "https://mainnet.infura.io" - CoinAPIOpenBazaarFIL = "http://localhost:1234" + CoinAPIOpenBazaarFIL = "http://localhost:8080/api" CoinAPIOpenBazaarTBTC = "https://tbtc.api.openbazaar.org/api" CoinAPIOpenBazaarTBCH = "https://tbch.api.openbazaar.org/api" CoinAPIOpenBazaarTLTC = "https://tltc.api.openbazaar.org/api" CoinAPIOpenBazaarTZEC = "https://tzec.api.openbazaar.org/api" CoinAPIOpenBazaarTETH = "https://rinkeby.infura.io" - CoinAPIOpenBazaarTFIL = "http://localhost:1234" + CoinAPIOpenBazaarTFIL = "http://localhost:8080/api" ) var ( diff --git a/vendor/github.com/filecoin-project b/vendor/github.com/filecoin-project new file mode 160000 index 0000000000..8b6f2fb2b3 --- /dev/null +++ b/vendor/github.com/filecoin-project @@ -0,0 +1 @@ +Subproject commit 8b6f2fb2b3efffb57f42d57f41532339e3938072 From b60d5a9aa09f0ac71b98c4485214320c1e3e6799 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Tue, 21 Jul 2020 11:23:38 -0400 Subject: [PATCH 12/52] chash fixes --- api/jsonapi.go | 10 +++++----- core/disputes.go | 2 +- core/refunds.go | 2 +- core/spend.go | 6 +++--- core/utils.go | 4 ++-- net/service/handlers.go | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/api/jsonapi.go b/api/jsonapi.go index 300e1dbe0a..92f59c257c 100644 --- a/api/jsonapi.go +++ b/api/jsonapi.go @@ -3371,7 +3371,7 @@ func (i *jsonAPIHandler) POSTBumpFee(w http.ResponseWriter, r *http.Request) { } var wal wallet.Wallet for _, w := range i.node.Multiwallet { - _, err := w.GetTransaction(*txHash) + _, err := w.GetTransaction(txHash.String()) if err == nil { wal = w break @@ -3381,7 +3381,7 @@ func (i *jsonAPIHandler) POSTBumpFee(w http.ResponseWriter, r *http.Request) { ErrorResponse(w, http.StatusBadRequest, "transaction not found in any wallet") return } - newTxid, err := wal.BumpFee(*txHash) + newTxid, err := wal.BumpFee(txHash.String()) if err != nil { if err == spvwallet.BumpFeeAlreadyConfirmedError { ErrorResponse(w, http.StatusBadRequest, err.Error()) @@ -3405,7 +3405,7 @@ func (i *jsonAPIHandler) POSTBumpFee(w http.ResponseWriter, r *http.Request) { return } if err := i.node.Datastore.TxMetadata().Put(repo.Metadata{ - Txid: newTxid.String(), + Txid: newTxid, Address: "", Memo: fmt.Sprintf("Fee bump of %s", txid), OrderId: "", @@ -3429,7 +3429,7 @@ func (i *jsonAPIHandler) POSTBumpFee(w http.ResponseWriter, r *http.Request) { ErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - txn, err := wal.GetTransaction(*newTxid) + txn, err := wal.GetTransaction(newTxid) if err != nil { ErrorResponse(w, http.StatusInternalServerError, err.Error()) return @@ -3439,7 +3439,7 @@ func (i *jsonAPIHandler) POSTBumpFee(w http.ResponseWriter, r *http.Request) { t := repo.NewAPITime(txn.Timestamp) resp := &response{ - Txid: newTxid.String(), + Txid: newTxid, ConfirmedBalance: &repo.CurrencyValue{Currency: defn, Amount: &confirmed.Value}, UnconfirmedBalance: &repo.CurrencyValue{Currency: defn, Amount: &unconfirmed.Value}, Amount: amt0, diff --git a/core/disputes.go b/core/disputes.go index f4324229ec..317715e353 100644 --- a/core/disputes.go +++ b/core/disputes.go @@ -176,7 +176,7 @@ func (n *OpenBazaarNode) verifyEscrowFundsAreDisputeable(contract *pb.RicardianC log.Errorf("Nil NewHashFromStr(%s)", r.Txid) return false } - actualConfirmations, _, err := wal.GetConfirmations(*hash) + actualConfirmations, _, err := wal.GetConfirmations(hash.String()) if err != nil { log.Errorf("Failed GetConfirmations(%s): %s", hash.String(), err.Error()) return false diff --git a/core/refunds.go b/core/refunds.go index 139f1b5046..d6e4270b5f 100644 --- a/core/refunds.go +++ b/core/refunds.go @@ -102,7 +102,7 @@ func (n *OpenBazaarNode) RefundOrder(contract *pb.RicardianContract, records []* return err } txinfo := new(pb.Refund_TransactionInfo) - txinfo.Txid = txid.String() + txinfo.Txid = txid txinfo.BigValue = outValue.String() txinfo.ValueCurrency = contract.BuyerOrder.Payment.AmountCurrency refundMsg.RefundTransaction = txinfo diff --git a/core/spend.go b/core/spend.go index 7f3a9b3807..681f6d05bc 100644 --- a/core/spend.go +++ b/core/spend.go @@ -115,7 +115,7 @@ func (n *OpenBazaarNode) Spend(args *SpendRequest) (*SpendResponse, error) { } } - txn, err := wal.GetTransaction(*txid) + txn, err := wal.GetTransaction(txid) if err != nil { log.Errorf("get txn failed : %v", err.Error()) return nil, fmt.Errorf("failed retrieving new wallet balance: %s", err) @@ -146,7 +146,7 @@ func (n *OpenBazaarNode) Spend(args *SpendRequest) (*SpendResponse, error) { } if err := n.Datastore.TxMetadata().Put(repo.Metadata{ - Txid: txid.String(), + Txid: txid, Address: toAddress, Memo: memo, OrderId: args.OrderID, @@ -163,7 +163,7 @@ func (n *OpenBazaarNode) Spend(args *SpendRequest) (*SpendResponse, error) { } return &SpendResponse{ - Txid: txid.String(), + Txid: txid, ConfirmedBalance: confirmed.Value.String(), UnconfirmedBalance: unconfirmed.Value.String(), Currency: &defn, diff --git a/core/utils.go b/core/utils.go index 3d9de4578b..256bb18713 100644 --- a/core/utils.go +++ b/core/utils.go @@ -52,7 +52,7 @@ func (n *OpenBazaarNode) BuildTransactionRecords(contract *pb.RicardianContract, if err != nil { return paymentRecords, nil, err } - confirmations, height, err := wal.GetConfirmations(*ch) + confirmations, height, err := wal.GetConfirmations(ch.String()) if err != nil { return paymentRecords, nil, err } @@ -93,7 +93,7 @@ func (n *OpenBazaarNode) BuildTransactionRecords(contract *pb.RicardianContract, if err != nil { return paymentRecords, refundRecord, err } - confirmations, height, err := wal.GetConfirmations(*ch) + confirmations, height, err := wal.GetConfirmations(ch.String()) if err != nil { return paymentRecords, refundRecord, nil } diff --git a/net/service/handlers.go b/net/service/handlers.go index fe255bf2c1..4403cc01d4 100644 --- a/net/service/handlers.go +++ b/net/service/handlers.go @@ -1979,7 +1979,7 @@ func (service *OpenBazaarService) handleOrderPayment(peer peer.ID, pmes *pb.Mess } log.Debugf("retrieving %s transaction %s", paymentDetails.Coin, chash.String()) - txn, err := wal.GetTransaction(*chash) + txn, err := wal.GetTransaction(chash.String()) if err != nil { return nil, err } From 3561c8c527d791285f9f3dc817363c484ec907dc Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Tue, 21 Jul 2020 11:25:08 -0400 Subject: [PATCH 13/52] multiwallet updates --- .../go-ethwallet/wallet/erc20_wallet.go | 8 +- .../OpenBazaar/go-ethwallet/wallet/wallet.go | 36 +++--- .../OpenBazaar/multiwallet/bitcoin/sign.go | 48 ++++---- .../OpenBazaar/multiwallet/bitcoin/wallet.go | 23 ++-- .../multiwallet/bitcoincash/sign.go | 50 +++++---- .../multiwallet/bitcoincash/wallet.go | 23 ++-- .../multiwallet/client/blockbook/client.go | 7 +- .../multiwallet/filecoin/service.go | 39 ++++++- .../OpenBazaar/multiwallet/filecoin/wallet.go | 104 +++++++++++------- .../github.com/OpenBazaar/multiwallet/go.mod | 3 +- .../github.com/OpenBazaar/multiwallet/go.sum | 2 + .../OpenBazaar/multiwallet/litecoin/sign.go | 48 ++++---- .../OpenBazaar/multiwallet/litecoin/wallet.go | 23 ++-- .../OpenBazaar/multiwallet/zcash/sign.go | 44 ++++---- .../OpenBazaar/multiwallet/zcash/wallet.go | 23 ++-- .../OpenBazaar/spvwallet/sortsignsend.go | 50 ++++----- .../github.com/OpenBazaar/spvwallet/wallet.go | 8 +- .../OpenBazaar/wallet-interface/wallet.go | 13 +-- 18 files changed, 310 insertions(+), 242 deletions(-) diff --git a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go index d842fa7bb2..0a98f395c7 100644 --- a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go +++ b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/erc20_wallet.go @@ -451,8 +451,8 @@ func (wallet *ERC20Wallet) callListeners(txnCB wi.TransactionCallback) { } // BumpFee - Bump the fee for the given transaction -func (wallet *ERC20Wallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - return chainhash.NewHashFromStr(txid.String()) +func (wallet *ERC20Wallet) BumpFee(txid chainhash.Hash) (string, error) { + return txid.String(), nil } // EstimateFee - Calculates the estimated size of the transaction and returns the total fee for the given feePerByte @@ -476,8 +476,8 @@ func (wallet *ERC20Wallet) EstimateSpendFee(amount int64, feeLevel wi.FeeLevel) } // SweepAddress - Build and broadcast a transaction that sweeps all coins from an address. If it is a p2sh multisig, the redeemScript must be included -func (wallet *ERC20Wallet) SweepAddress(utxos []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { - return chainhash.NewHashFromStr("") +func (wallet *ERC20Wallet) SweepAddress(utxos []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { + return "", nil } // ExchangeRates - return the exchangerates diff --git a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go index 6c9442daef..8bb4a340db 100644 --- a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go +++ b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go @@ -590,8 +590,8 @@ func (wallet *EthereumWallet) Transactions() ([]wi.Txn, error) { } // GetTransaction - Get info on a specific transaction -func (wallet *EthereumWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - tx, _, err := wallet.client.GetTransaction(common.HexToHash(util.EnsureCorrectPrefix(txid.String()))) +func (wallet *EthereumWallet) GetTransaction(txid string) (wi.Txn, error) { + tx, _, err := wallet.client.GetTransaction(common.HexToHash(util.EnsureCorrectPrefix(txid))) if err != nil { return wi.Txn{}, err } @@ -679,7 +679,7 @@ func (wallet *EthereumWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { } // Spend - Send ether to an external wallet -func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (string, error) { var ( hash common.Hash h *chainhash.Hash @@ -700,7 +700,7 @@ func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLev // check if the addr is a multisig addr scripts, err := wallet.db.WatchedScripts().GetAll() if err != nil { - return nil, err + return "", err } isScript := false addrEth := common.HexToAddress(addr.String()) @@ -718,7 +718,7 @@ func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLev if isScript { ethScript, err := DeserializeEthScript(redeemScript) if err != nil { - return nil, err + return "", err } _, scrHash, err := GenScriptHash(ethScript) if err != nil { @@ -729,22 +729,22 @@ func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLev hash, _, err = wallet.callAddTransaction(ethScript, &amount, feeLevel) if err != nil { log.Errorf("error call add txn: %v", err) - return nil, wi.ErrInsufficientFunds + return "", wi.ErrInsufficientFunds } } else { if !wallet.balanceCheck(feeLevel, amount) { - return nil, wi.ErrInsufficientFunds + return "", wi.ErrInsufficientFunds } hash, err = wallet.Transfer(util.EnsureCorrectPrefix(addr.String()), &amount, spendAll, wallet.GetFeePerByte(feeLevel)) } if err != nil { - return nil, err + return "", err } // txn is pending nonce, err = wallet.client.GetTxnNonce(util.EnsureCorrectPrefix(hash.Hex())) if err != nil { - return nil, err + return "", err } } if err == nil { @@ -768,7 +768,7 @@ func (wallet *EthereumWallet) Spend(amount big.Int, addr btcutil.Address, feeLev log.Error(err0.Error()) } } - return h, nil + return h.String(), nil } func (wallet *EthereumWallet) createTxnCallback(txID, orderID string, toAddress btcutil.Address, value big.Int, bTime time.Time, withInput bool, height int64) wi.TransactionCallback { @@ -854,8 +854,8 @@ func (wallet *EthereumWallet) checkTxnRcpt(hash *common.Hash, data []byte) (*com } // BumpFee - Bump the fee for the given transaction -func (wallet *EthereumWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - return util.CreateChainHash(txid.String()) +func (wallet *EthereumWallet) BumpFee(txid string) (string, error) { + return txid, nil } // EstimateFee - Calculates the estimated size of the transaction and returns the total fee for the given feePerByte @@ -903,7 +903,7 @@ func (wallet *EthereumWallet) EstimateSpendFee(amount big.Int, feeLevel wi.FeeLe } // SweepAddress - Build and broadcast a transaction that sweeps all coins from an address. If it is a p2sh multisig, the redeemScript must be included -func (wallet *EthereumWallet) SweepAddress(utxos []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (wallet *EthereumWallet) SweepAddress(utxos []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { outs := []wi.TransactionOutput{} for i, in := range utxos { @@ -918,16 +918,16 @@ func (wallet *EthereumWallet) SweepAddress(utxos []wi.TransactionInput, address sigs, err := wallet.CreateMultisigSignature([]wi.TransactionInput{}, outs, key, *redeemScript, *big.NewInt(1)) if err != nil { - return nil, err + return "", err } data, err := wallet.Multisign([]wi.TransactionInput{}, outs, sigs, []wi.Signature{}, *redeemScript, *big.NewInt(1), false) if err != nil { - return nil, err + return "", err } hash := common.BytesToHash(data) - return util.CreateChainHash(hash.Hex()) + return hash.Hex(), nil } // ExchangeRates - return the exchangerates @@ -1442,11 +1442,11 @@ func (wallet *EthereumWallet) ReSyncBlockchain(fromTime time.Time) { } // GetConfirmations - Return the number of confirmations and the height for a transaction -func (wallet *EthereumWallet) GetConfirmations(txid chainhash.Hash) (confirms, atHeight uint32, err error) { +func (wallet *EthereumWallet) GetConfirmations(txid string) (confirms, atHeight uint32, err error) { // TODO: etherscan api is being used // when mainnet is activated we may need a way to set the // url correctly - done 6 April 2019 - hash := common.HexToHash(util.EnsureCorrectPrefix(txid.String())) + hash := common.HexToHash(util.EnsureCorrectPrefix(txid)) network := etherscan.Rinkby if strings.Contains(wallet.client.url, "mainnet") { network = etherscan.Mainnet diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go index af20e56207..0be6935322 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/sign.go @@ -254,32 +254,36 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } } -func (w *BitcoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *BitcoinWallet) bumpFee(txid string) (string, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { - return nil, err + return "", err } if txn.Height > 0 { - return nil, util.BumpFeeAlreadyConfirmedError + return "", util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, util.BumpFeeTransactionDeadError + return "", util.BumpFeeTransactionDeadError + } + chTxid, err := chainhash.NewHashFromStr(txid) + if err != nil { + return "", err } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() for _, u := range utxos { - if u.Op.Hash.IsEqual(&txid) && u.AtHeight == 0 { + if u.Op.Hash.IsEqual(chTxid) && u.AtHeight == 0 { addr, err := w.ScriptToAddress(u.ScriptPubkey) if err != nil { - return nil, err + return "", err } key, err := w.km.GetKeyForScript(addr.ScriptAddress()) if err != nil { - return nil, err + return "", err } h, err := hex.DecodeString(u.Op.Hash.String()) if err != nil { - return nil, err + return "", err } n := new(big.Int) n, _ = n.SetString(u.Value, 10) @@ -291,15 +295,15 @@ func (w *BitcoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { } transactionID, err := w.sweepAddress([]wi.TransactionInput{in}, nil, key, nil, wi.FEE_BUMP) if err != nil { - return nil, err + return "", err } return transactionID, nil } } - return nil, util.BumpFeeNotFoundError + return "", util.BumpFeeNotFoundError } -func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { var internalAddr btc.Address if address != nil { internalAddr = *address @@ -308,7 +312,7 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add } script, err := txscript.PayToAddrScript(internalAddr) if err != nil { - return nil, err + return "", err } var val int64 @@ -318,11 +322,11 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add val += in.Value.Int64() ch, err := chainhash.NewHashFromStr(hex.EncodeToString(in.OutpointHash)) if err != nil { - return nil, err + return "", err } script, err := txscript.PayToAddrScript(in.LinkedAddress) if err != nil { - return nil, err + return "", err } outpoint := wire.NewOutPoint(ch, in.OutpointIndex) input := wire.NewTxIn(outpoint, []byte{}, [][]byte{}) @@ -365,12 +369,12 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add // Sign tx privKey, err := key.ECPrivKey() if err != nil { - return nil, fmt.Errorf("retrieving private key: %s", err.Error()) + return "", fmt.Errorf("retrieving private key: %s", err.Error()) } pk := privKey.PubKey().SerializeCompressed() addressPub, err := btc.NewAddressPubKey(pk, w.params) if err != nil { - return nil, fmt.Errorf("generating address pub key: %s", err.Error()) + return "", fmt.Errorf("generating address pub key: %s", err.Error()) } getKey := txscript.KeyClosure(func(addr btc.Address) (*btcec.PrivateKey, bool, error) { @@ -400,7 +404,7 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add for _, txIn := range tx.TxIn { locktime, err := util.LockTimeFromRedeemScript(*redeemScript) if err != nil { - return nil, err + return "", err } txIn.Sequence = locktime } @@ -415,13 +419,13 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add tx, i, prevOutScript, txscript.SigHashAll, getKey, getScript, txIn.SignatureScript) if err != nil { - return nil, errors.New("Failed to sign transaction") + return "", errors.New("Failed to sign transaction") } txIn.SignatureScript = script } else { sig, err := txscript.RawTxInWitnessSignature(tx, hashes, i, ins[i].Value.Int64(), *redeemScript, txscript.SigHashAll, privKey) if err != nil { - return nil, err + return "", err } var witness wire.TxWitness if timeLocked { @@ -436,10 +440,10 @@ func (w *BitcoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Add // broadcast if err := w.Broadcast(tx); err != nil { - return nil, err + return "", err } txid := tx.TxHash() - return &txid, nil + return txid.String(), nil } func (w *BitcoinWallet) createMultisigSignature(ins []wi.TransactionInput, outs []wi.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte uint64) ([]wi.Signature, error) { diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go index 2cd9c4d2b9..5a21e8a1ba 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoin/wallet.go @@ -19,7 +19,6 @@ import ( "github.com/OpenBazaar/multiwallet/util" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" btc "github.com/btcsuite/btcutil" @@ -250,8 +249,8 @@ func (w *BitcoinWallet) Transactions() ([]wi.Txn, error) { return txns, nil } -func (w *BitcoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *BitcoinWallet) GetTransaction(txid string) (wi.Txn, error) { + txn, err := w.db.Txns().Get(txid) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -291,7 +290,7 @@ func (w *BitcoinWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *BitcoinWallet) Spend(amount big.Int, addr btc.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *BitcoinWallet) Spend(amount big.Int, addr btc.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (string, error) { var ( tx *wire.MsgTx err error @@ -299,23 +298,23 @@ func (w *BitcoinWallet) Spend(amount big.Int, addr btc.Address, feeLevel wi.FeeL if spendAll { tx, err = w.buildSpendAllTx(addr, feeLevel) if err != nil { - return nil, err + return "", err } } else { tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) if err != nil { - return nil, err + return "", err } } if err := w.Broadcast(tx); err != nil { - return nil, err + return "", err } ch := tx.TxHash() - return &ch, nil + return ch.String(), nil } -func (w *BitcoinWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { +func (w *BitcoinWallet) BumpFee(txid string) (string, error) { return w.bumpFee(txid) } @@ -336,7 +335,7 @@ func (w *BitcoinWallet) EstimateSpendFee(amount big.Int, feeLevel wi.FeeLevel) ( return *big.NewInt(int64(val)), err } -func (w *BitcoinWallet) SweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *BitcoinWallet) SweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { return w.sweepAddress(ins, address, key, redeemScript, feeLevel) } @@ -382,8 +381,8 @@ func (w *BitcoinWallet) ReSyncBlockchain(fromTime time.Time) { go w.ws.UpdateState() } -func (w *BitcoinWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *BitcoinWallet) GetConfirmations(txid string) (uint32, uint32, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go index 7b744f5b9e..d459681c3e 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/sign.go @@ -260,32 +260,36 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } } -func (w *BitcoinCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *BitcoinCashWallet) bumpFee(txid string) (string, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { - return nil, err + return "", err } if txn.Height > 0 { - return nil, util.BumpFeeAlreadyConfirmedError + return "", util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, util.BumpFeeTransactionDeadError + return "", util.BumpFeeTransactionDeadError + } + chTxid, err := chainhash.NewHashFromStr(txid) + if err != nil { + return "", err } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() for _, u := range utxos { - if u.Op.Hash.IsEqual(&txid) && u.AtHeight == 0 { + if u.Op.Hash.IsEqual(chTxid) && u.AtHeight == 0 { addr, err := w.ScriptToAddress(u.ScriptPubkey) if err != nil { - return nil, err + return "", err } key, err := w.km.GetKeyForScript(addr.ScriptAddress()) if err != nil { - return nil, err + return "", err } h, err := hex.DecodeString(u.Op.Hash.String()) if err != nil { - return nil, err + return "", err } n := new(big.Int) n, _ = n.SetString(u.Value, 10) @@ -297,15 +301,15 @@ func (w *BitcoinCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error } transactionID, err := w.sweepAddress([]wi.TransactionInput{in}, nil, key, nil, wi.FEE_BUMP) if err != nil { - return nil, err + return "", err } return transactionID, nil } } - return nil, util.BumpFeeNotFoundError + return "", util.BumpFeeNotFoundError } -func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { var internalAddr btc.Address if address != nil { internalAddr = *address @@ -314,7 +318,7 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc } script, err := bchutil.PayToAddrScript(internalAddr) if err != nil { - return nil, err + return "", err } var val int64 @@ -324,11 +328,11 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc val += in.Value.Int64() ch, err := chainhash.NewHashFromStr(hex.EncodeToString(in.OutpointHash)) if err != nil { - return nil, err + return "", err } script, err := bchutil.PayToAddrScript(in.LinkedAddress) if err != nil { - return nil, err + return "", err } outpoint := wire.NewOutPoint(ch, in.OutpointIndex) input := wire.NewTxIn(outpoint, []byte{}, [][]byte{}) @@ -371,12 +375,12 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc // Sign tx privKey, err := key.ECPrivKey() if err != nil { - return nil, fmt.Errorf("retrieving private key: %s", err.Error()) + return "", fmt.Errorf("retrieving private key: %s", err.Error()) } pk := privKey.PubKey().SerializeCompressed() addressPub, err := btc.NewAddressPubKey(pk, w.params) if err != nil { - return nil, fmt.Errorf("generating address pub key: %s", err.Error()) + return "", fmt.Errorf("generating address pub key: %s", err.Error()) } getKey := txscript.KeyClosure(func(addr btc.Address) (*btcec.PrivateKey, bool, error) { @@ -406,7 +410,7 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc for _, txIn := range tx.TxIn { locktime, err := util.LockTimeFromRedeemScript(*redeemScript) if err != nil { - return nil, err + return "", err } txIn.Sequence = locktime } @@ -420,17 +424,17 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc tx, i, prevOutScript, txscript.SigHashAll, getKey, getScript, txIn.SignatureScript, ins[i].Value.Int64()) if err != nil { - return nil, errors.New("Failed to sign transaction") + return "", errors.New("Failed to sign transaction") } txIn.SignatureScript = script } else { priv, err := key.ECPrivKey() if err != nil { - return nil, err + return "", err } script, err := bchutil.RawTxInSignature(tx, i, *redeemScript, txscript.SigHashAll, priv, ins[i].Value.Int64()) if err != nil { - return nil, err + return "", err } builder := txscript.NewScriptBuilder(). AddData(script). @@ -443,10 +447,10 @@ func (w *BitcoinCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc // broadcast if err := w.Broadcast(tx); err != nil { - return nil, err + return "", err } txid := tx.TxHash() - return &txid, nil + return txid.String(), nil } func (w *BitcoinCashWallet) createMultisigSignature(ins []wi.TransactionInput, outs []wi.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte uint64) ([]wi.Signature, error) { diff --git a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go index efa16a6e34..c2b0ba20e0 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/bitcoincash/wallet.go @@ -13,7 +13,6 @@ import ( wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" hd "github.com/btcsuite/btcutil/hdkeychain" @@ -248,8 +247,8 @@ func (w *BitcoinCashWallet) Transactions() ([]wi.Txn, error) { return txns, nil } -func (w *BitcoinCashWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *BitcoinCashWallet) GetTransaction(txid string) (wi.Txn, error) { + txn, err := w.db.Txns().Get(txid) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -283,7 +282,7 @@ func (w *BitcoinCashWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *BitcoinCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *BitcoinCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (string, error) { var ( tx *wire.MsgTx err error @@ -291,25 +290,25 @@ func (w *BitcoinCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel if spendAll { tx, err = w.buildSpendAllTx(addr, feeLevel) if err != nil { - return nil, err + return "", err } } else { tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) if err != nil { - return nil, err + return "", err } } // Broadcast if err := w.Broadcast(tx); err != nil { - return nil, err + return "", err } ch := tx.TxHash() - return &ch, nil + return ch.String(), nil } -func (w *BitcoinCashWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { +func (w *BitcoinCashWallet) BumpFee(txid string) (string, error) { return w.bumpFee(txid) } @@ -330,7 +329,7 @@ func (w *BitcoinCashWallet) EstimateSpendFee(amount big.Int, feeLevel wi.FeeLeve return *big.NewInt(int64(val)), err } -func (w *BitcoinCashWallet) SweepAddress(ins []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *BitcoinCashWallet) SweepAddress(ins []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { return w.sweepAddress(ins, address, key, redeemScript, feeLevel) } @@ -389,8 +388,8 @@ func (w *BitcoinCashWallet) ReSyncBlockchain(fromTime time.Time) { go w.ws.UpdateState() } -func (w *BitcoinCashWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *BitcoinCashWallet) GetConfirmations(txid string) (uint32, uint32, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go b/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go index 88091c2ded..8a606c2e28 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go +++ b/vendor/github.com/OpenBazaar/multiwallet/client/blockbook/client.go @@ -262,7 +262,7 @@ func (i *BlockBookClient) GetTransaction(txid string) (*model.Transaction, error } type resOut struct { model.Output - Spent bool `json:"spent"` + Spent bool `json:"spent"` Addresses []string `json:"addresses"` } type resTx struct { @@ -292,7 +292,7 @@ func (i *BlockBookClient) GetTransaction(txid string) (*model.Transaction, error tx.Vin[n].Value = f } for n, out := range tx.Vout { - if out.ValueIface == "" || out.ValueIface == nil{ + if out.ValueIface == "" || out.ValueIface == nil { out.ValueIface = "0" } f, err := model.ToFloat(out.ValueIface) @@ -334,6 +334,7 @@ func (i *BlockBookClient) GetTransaction(txid string) (*model.Transaction, error } for n, o := range tx.Vout { newOut := model.Output{ + ValueIface: tx.Vout[n].ValueIface, Value: tx.Vout[n].Value, N: o.N, ScriptPubKey: o.ScriptPubKey, @@ -397,7 +398,7 @@ func (i *BlockBookClient) getTransactions(addr string) ([]model.Transaction, err type resAddr struct { TotalPages int `json:"totalPages"` Transactions []string `json:"transactions"` - Txids []string `json:"txids"` + Txids []string `json:"txids"` } type txOrError struct { Tx *model.Transaction diff --git a/vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go b/vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go index eb862f88df..a89f6fc10d 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go +++ b/vendor/github.com/OpenBazaar/multiwallet/filecoin/service.go @@ -6,13 +6,11 @@ import ( "github.com/OpenBazaar/multiwallet/cache" "github.com/OpenBazaar/multiwallet/model" "github.com/OpenBazaar/multiwallet/service" - "github.com/OpenBazaar/multiwallet/util" "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" "github.com/ipfs/go-cid" "github.com/op/go-logging" - "math" "math/big" "sync" "time" @@ -94,6 +92,8 @@ func (fs *FilecoinService) Stop() { } func (fs *FilecoinService) ChainTip() (uint32, string) { + fs.lock.RLock() + defer fs.lock.RUnlock() return fs.chainHeight, fs.bestBlock } @@ -218,6 +218,13 @@ func (fs *FilecoinService) saveSingleTxToDB(u model.Transaction, chainHeight int } var relevant bool cb := wallet.TransactionCallback{Txid: txHash.String(), Height: height, Timestamp: time.Unix(u.Time, 0)} + + inAddr := "" + if u.Inputs != nil { + inAddr = u.Inputs[0].Addr + } + + outAddr := u.Outputs[0].ScriptPubKey.Addresses[0] for _, in := range u.Inputs { faddr, err := NewFilecoinAddress(in.Addr) if err != nil { @@ -225,7 +232,13 @@ func (fs *FilecoinService) saveSingleTxToDB(u model.Transaction, chainHeight int continue } - v := big.NewInt(int64(math.Round(in.Value * float64(util.SatoshisPerCoin(fs.coinType))))) + var valueString string + if in.ValueIface == nil { + valueString = "0" + } else { + valueString = in.ValueIface.(string) + } + v, _ := new(big.Int).SetString(valueString, 10) cbin := wallet.TransactionInput{ LinkedAddress: faddr, Value: *v, @@ -234,7 +247,6 @@ func (fs *FilecoinService) saveSingleTxToDB(u model.Transaction, chainHeight int if in.Addr == fs.addr.String() { relevant = true - value.Sub(value, v) hits++ } } @@ -248,7 +260,18 @@ func (fs *FilecoinService) saveSingleTxToDB(u model.Transaction, chainHeight int continue } - v := big.NewInt(int64(math.Round(out.Value * float64(util.SatoshisPerCoin(fs.coinType))))) + var valueOutString string + if out.ValueIface == nil { + if out.Value != 0 { + valueBig := new(big.Float).SetFloat64(out.Value).String() + valueOutString = valueBig + } + + valueOutString = "0" + } else { + valueOutString = out.ValueIface.(string) + } + v, _ := new(big.Int).SetString(valueOutString, 10) cbout := wallet.TransactionOutput{Address: faddr, Value: *v, Index: uint32(i)} cb.Outputs = append(cb.Outputs, cbout) @@ -260,6 +283,12 @@ func (fs *FilecoinService) saveSingleTxToDB(u model.Transaction, chainHeight int } } + if inAddr == outAddr { + value = big.NewInt(0) + } else if inAddr == fs.addr.String() { + value = value.Mul(value, big.NewInt(-1)) + } + if !relevant { Log.Warningf("abort saving irrelevant txid (%s) to db", u.Txid) return diff --git a/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go index 9e399d7b8a..623ba28668 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go @@ -6,6 +6,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" + _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/filecoin-project/specs-actors/actors/crypto" "io" "math/big" @@ -17,7 +18,6 @@ import ( "github.com/OpenBazaar/multiwallet/model" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" hd "github.com/btcsuite/btcutil/hdkeychain" faddr "github.com/filecoin-project/go-address" @@ -78,7 +78,7 @@ func NewFilecoinWallet(cfg config.CoinConfig, mnemonic string, params *chaincfg. return nil, err } - accountAddr, err := faddr.NewSecp256k1Address(accountECKey.PubKey().SerializeCompressed()) + accountAddr, err := faddr.NewSecp256k1Address(accountECKey.PubKey().SerializeUncompressed()) if err != nil { return nil, err } @@ -136,6 +136,26 @@ func (w *FilecoinWallet) MasterPublicKey() *hd.ExtendedKey { return w.mPubKey } +func (wallet *FilecoinWallet) BumpFee(txid string) (string, error) { + return txid, nil +} + +func (wallet *FilecoinWallet) CreateMultisigSignature(ins []wi.TransactionInput, outs []wi.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]wi.Signature, error) { + return nil, nil +} + +func (w *FilecoinWallet) GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btcutil.Address, redeemScript []byte, err error) { + return nil, nil, nil +} + +func (wallet *FilecoinWallet) Multisign(ins []wi.TransactionInput, outs []wi.TransactionOutput, sigs1 []wi.Signature, sigs2 []wi.Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) { + return nil, nil +} + +func (wallet *FilecoinWallet) SweepAddress(utxos []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { + return "", nil +} + func (w *FilecoinWallet) ChildKey(keyBytes []byte, chaincode []byte, isPrivateKey bool) (*hd.ExtendedKey, error) { parentFP := []byte{0x00, 0x00, 0x00, 0x00} var id []byte @@ -159,22 +179,6 @@ func (w *FilecoinWallet) CurrentAddress(purpose wi.KeyPurpose) btcutil.Address { return &FilecoinAddress{addr: w.addr} } -func (w *FilecoinWallet) CreateMultisigSignature(ins []wi.TransactionInput, outs []wi.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]wi.Signature, error) { - return nil, nil -} - -func (w *FilecoinWallet) Multisign(ins []wi.TransactionInput, outs []wi.TransactionOutput, sigs1 []wi.Signature, sigs2 []wi.Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) { - return nil, nil -} - -func (wallet *FilecoinWallet) SweepAddress(utxos []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { - return chainhash.NewHashFromStr("") -} - -func (w *FilecoinWallet) GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btcutil.Address, redeemScript []byte, err error) { - return nil, nil, nil -} - func (w *FilecoinWallet) NewAddress(purpose wi.KeyPurpose) btcutil.Address { return &FilecoinAddress{addr: w.addr} } @@ -256,8 +260,8 @@ func (w *FilecoinWallet) Transactions() ([]wi.Txn, error) { return txns, nil } -func (w *FilecoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *FilecoinWallet) GetTransaction(txid string) (wi.Txn, error) { + txn, err := w.db.Txns().Get(txid) return txn, err } @@ -269,10 +273,10 @@ func (w *FilecoinWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(0) } -func (w *FilecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *FilecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (string, error) { address, err := faddr.NewFromString(addr.String()) if err != nil { - return nil, err + return "", err } if spendAll { c, u := w.Balance() @@ -280,19 +284,46 @@ func (w *FilecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi } bigAmt, err := types.BigFromString(amount.String()) if err != nil { - return nil, err + return "", err + } + + txns, err := w.Transactions() + if err != nil { + return "", err + } + + nonce := uint64(1) + for _, tx := range txns { + val, _ := new(big.Int).SetString(tx.Value, 10) + if val.Cmp(big.NewInt(0)) > 0 { + continue + } + + m, err := types.DecodeMessage(tx.Bytes) + if err != nil { + return "", err + } + if m.Nonce > nonce { + nonce = m.Nonce + } + } + if nonce > 0 { + nonce++ } + m := types.Message{ - To: address, - Value: bigAmt, - From: w.addr, + To: address, + Value: bigAmt, + From: w.addr, + GasLimit: 1000, + Nonce: nonce, } id := m.Cid() cs, err := sigs.Sign(crypto.SigTypeSecp256k1, w.key.Serialize(), id.Bytes()) if err != nil { - return nil, err + return "", err } signed := &types.SignedMessage{ @@ -302,15 +333,10 @@ func (w *FilecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi // Broadcast if err := w.Broadcast(signed); err != nil { - return nil, err + return "", err } - ch, err := chainhash.NewHash(id.Bytes()) - if err != nil { - return nil, err - } - - return ch, nil + return id.String(), nil } func (w *FilecoinWallet) EstimateFee(ins []wi.TransactionInput, outs []wi.TransactionOutput, feePerByte big.Int) big.Int { @@ -363,8 +389,8 @@ func (w *FilecoinWallet) ReSyncBlockchain(fromTime time.Time) { go w.fs.UpdateState() } -func (w *FilecoinWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *FilecoinWallet) GetConfirmations(txid string) (uint32, uint32, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { return 0, 0, err } @@ -438,8 +464,10 @@ func (w *FilecoinWallet) Broadcast(msg *types.SignedMessage) error { ScriptPubKey: model.OutScript{ Addresses: []string{msg.Message.To.String()}, }, + ValueIface: msg.Message.Value.String(), } cTxn.Outputs = append(cTxn.Outputs, output) + _, err = w.client.Broadcast(ser) if err != nil { return err @@ -448,10 +476,6 @@ func (w *FilecoinWallet) Broadcast(msg *types.SignedMessage) error { return nil } -func (w *FilecoinWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - return nil, nil -} - // AssociateTransactionWithOrder used for ORDER_PAYMENT message func (w *FilecoinWallet) AssociateTransactionWithOrder(cb wi.TransactionCallback) { w.fs.InvokeTransactionListeners(cb) diff --git a/vendor/github.com/OpenBazaar/multiwallet/go.mod b/vendor/github.com/OpenBazaar/multiwallet/go.mod index f9d7c4a285..a97d5013a1 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/go.mod +++ b/vendor/github.com/OpenBazaar/multiwallet/go.mod @@ -7,7 +7,7 @@ require ( github.com/OpenBazaar/golang-socketio v0.0.0-20200109001351-4147b5f0d294 github.com/OpenBazaar/openbazaar-go v0.14.3 // indirect github.com/OpenBazaar/spvwallet v0.0.0-20200112224336-39f04e8d6d34 - github.com/OpenBazaar/wallet-interface v0.0.0-20200511225711-6ec1fd0d9d23 + github.com/OpenBazaar/wallet-interface v0.0.0-20200720181501-d30f5eb54286 github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcutil v1.0.2 github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 @@ -24,6 +24,7 @@ require ( github.com/google/go-cmp v0.4.1 // indirect github.com/gorilla/websocket v1.4.2 github.com/hunterlong/tokenbalance v0.0.12-0.20191105170207-4f98e641e619 // indirect + github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 github.com/jarcoal/httpmock v1.0.5 github.com/jessevdk/go-flags v1.4.0 github.com/joho/godotenv v1.3.0 // indirect diff --git a/vendor/github.com/OpenBazaar/multiwallet/go.sum b/vendor/github.com/OpenBazaar/multiwallet/go.sum index 5a21446324..ed397e59fd 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/go.sum +++ b/vendor/github.com/OpenBazaar/multiwallet/go.sum @@ -67,6 +67,8 @@ github.com/OpenBazaar/spvwallet v0.0.0-20200112224336-39f04e8d6d34 h1:xGvs105pXK github.com/OpenBazaar/spvwallet v0.0.0-20200112224336-39f04e8d6d34/go.mod h1:SVavvqIp6t5kuJx+PqDsKIQ+avRth92nGg2wVp7mW/s= github.com/OpenBazaar/wallet-interface v0.0.0-20200511225711-6ec1fd0d9d23 h1:A+/78rkN9VEJNccIcMSdiYfYwZ6AZgenIX41cSN8B08= github.com/OpenBazaar/wallet-interface v0.0.0-20200511225711-6ec1fd0d9d23/go.mod h1:KiLnq+35bzKd6Bq8EP8iGElNBU/++VxbDVg9zCvKMgU= +github.com/OpenBazaar/wallet-interface v0.0.0-20200720181501-d30f5eb54286 h1:gHiOKvfKlJwmkX6lfjEuCx13PrMAXdMqjUQzA4eqWSg= +github.com/OpenBazaar/wallet-interface v0.0.0-20200720181501-d30f5eb54286/go.mod h1:KiLnq+35bzKd6Bq8EP8iGElNBU/++VxbDVg9zCvKMgU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= diff --git a/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go b/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go index 470986e599..9c034fd268 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/litecoin/sign.go @@ -259,32 +259,36 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } } -func (w *LitecoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *LitecoinWallet) bumpFee(txid string) (string, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { - return nil, err + return "", err } if txn.Height > 0 { - return nil, util.BumpFeeAlreadyConfirmedError + return "", util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, util.BumpFeeTransactionDeadError + return "", util.BumpFeeTransactionDeadError + } + chTxid, err := chainhash.NewHashFromStr(txid) + if err != nil { + return "", err } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() for _, u := range utxos { - if u.Op.Hash.IsEqual(&txid) && u.AtHeight == 0 { + if u.Op.Hash.IsEqual(chTxid) && u.AtHeight == 0 { addr, err := w.ScriptToAddress(u.ScriptPubkey) if err != nil { - return nil, err + return "", err } key, err := w.km.GetKeyForScript(addr.ScriptAddress()) if err != nil { - return nil, err + return "", err } h, err := hex.DecodeString(u.Op.Hash.String()) if err != nil { - return nil, err + return "", err } n := new(big.Int) n, _ = n.SetString(u.Value, 10) @@ -296,15 +300,15 @@ func (w *LitecoinWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { } transactionID, err := w.sweepAddress([]wi.TransactionInput{in}, nil, key, nil, wi.FEE_BUMP) if err != nil { - return nil, err + return "", err } return transactionID, nil } } - return nil, util.BumpFeeNotFoundError + return "", util.BumpFeeNotFoundError } -func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { var internalAddr btc.Address if address != nil { internalAddr = *address @@ -313,7 +317,7 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad } script, err := laddr.PayToAddrScript(internalAddr) if err != nil { - return nil, err + return "", err } var val int64 @@ -323,11 +327,11 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad val += in.Value.Int64() ch, err := chainhash.NewHashFromStr(hex.EncodeToString(in.OutpointHash)) if err != nil { - return nil, err + return "", err } script, err := laddr.PayToAddrScript(in.LinkedAddress) if err != nil { - return nil, err + return "", err } outpoint := wire.NewOutPoint(ch, in.OutpointIndex) input := wire.NewTxIn(outpoint, []byte{}, [][]byte{}) @@ -370,12 +374,12 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad // Sign tx privKey, err := key.ECPrivKey() if err != nil { - return nil, fmt.Errorf("retrieving private key: %s", err.Error()) + return "", fmt.Errorf("retrieving private key: %s", err.Error()) } pk := privKey.PubKey().SerializeCompressed() addressPub, err := btc.NewAddressPubKey(pk, w.params) if err != nil { - return nil, fmt.Errorf("generating address pub key: %s", err.Error()) + return "", fmt.Errorf("generating address pub key: %s", err.Error()) } getKey := txscript.KeyClosure(func(addr btc.Address) (*btcec.PrivateKey, bool, error) { @@ -405,7 +409,7 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad for _, txIn := range tx.TxIn { locktime, err := util.LockTimeFromRedeemScript(*redeemScript) if err != nil { - return nil, err + return "", err } txIn.Sequence = locktime } @@ -420,13 +424,13 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad tx, i, prevOutScript, txscript.SigHashAll, getKey, getScript, txIn.SignatureScript) if err != nil { - return nil, errors.New("Failed to sign transaction") + return "", errors.New("Failed to sign transaction") } txIn.SignatureScript = script } else { sig, err := txscript.RawTxInWitnessSignature(tx, hashes, i, ins[i].Value.Int64(), *redeemScript, txscript.SigHashAll, privKey) if err != nil { - return nil, err + return "", err } var witness wire.TxWitness if timeLocked { @@ -441,10 +445,10 @@ func (w *LitecoinWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Ad // broadcast if err := w.Broadcast(tx); err != nil { - return nil, err + return "", err } txid := tx.TxHash() - return &txid, nil + return txid.String(), nil } func (w *LitecoinWallet) createMultisigSignature(ins []wi.TransactionInput, outs []wi.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte uint64) ([]wi.Signature, error) { diff --git a/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go index 30ab62b5e8..99604d94c9 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/litecoin/wallet.go @@ -20,7 +20,6 @@ import ( "github.com/OpenBazaar/multiwallet/util" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" hd "github.com/btcsuite/btcutil/hdkeychain" @@ -260,8 +259,8 @@ func (w *LitecoinWallet) Transactions() ([]wi.Txn, error) { return txns, nil } -func (w *LitecoinWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *LitecoinWallet) GetTransaction(txid string) (wi.Txn, error) { + txn, err := w.db.Txns().Get(txid) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -295,7 +294,7 @@ func (w *LitecoinWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *LitecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *LitecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (string, error) { var ( tx *wire.MsgTx err error @@ -303,25 +302,25 @@ func (w *LitecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi if spendAll { tx, err = w.buildSpendAllTx(addr, feeLevel) if err != nil { - return nil, err + return "", err } } else { tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) if err != nil { - return nil, err + return "", err } } // Broadcast if err := w.Broadcast(tx); err != nil { - return nil, err + return "", err } ch := tx.TxHash() - return &ch, nil + return ch.String(), nil } -func (w *LitecoinWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { +func (w *LitecoinWallet) BumpFee(txid string) (string, error) { return w.bumpFee(txid) } @@ -342,7 +341,7 @@ func (w *LitecoinWallet) EstimateSpendFee(amount big.Int, feeLevel wi.FeeLevel) return *big.NewInt(int64(val)), err } -func (w *LitecoinWallet) SweepAddress(ins []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *LitecoinWallet) SweepAddress(ins []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { return w.sweepAddress(ins, address, key, redeemScript, feeLevel) } @@ -401,8 +400,8 @@ func (w *LitecoinWallet) ReSyncBlockchain(fromTime time.Time) { go w.ws.UpdateState() } -func (w *LitecoinWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *LitecoinWallet) GetConfirmations(txid string) (uint32, uint32, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go b/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go index 6ae2767c81..2b73e31870 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go +++ b/vendor/github.com/OpenBazaar/multiwallet/zcash/sign.go @@ -296,32 +296,36 @@ func newUnsignedTransaction(outputs []*wire.TxOut, feePerKb btc.Amount, fetchInp } } -func (w *ZCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *ZCashWallet) bumpFee(txid string) (string, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { - return nil, err + return "", err } if txn.Height > 0 { - return nil, util.BumpFeeAlreadyConfirmedError + return "", util.BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, util.BumpFeeTransactionDeadError + return "", util.BumpFeeTransactionDeadError + } + chTxid, err := chainhash.NewHashFromStr(txid) + if err != nil { + return "", err } // Check utxos for CPFP utxos, _ := w.db.Utxos().GetAll() for _, u := range utxos { - if u.Op.Hash.IsEqual(&txid) && u.AtHeight == 0 { + if u.Op.Hash.IsEqual(chTxid) && u.AtHeight == 0 { addr, err := w.ScriptToAddress(u.ScriptPubkey) if err != nil { - return nil, err + return "", err } key, err := w.km.GetKeyForScript(addr.ScriptAddress()) if err != nil { - return nil, err + return "", err } h, err := hex.DecodeString(u.Op.Hash.String()) if err != nil { - return nil, err + return "", err } n := new(big.Int) n, _ = n.SetString(u.Value, 10) @@ -333,15 +337,15 @@ func (w *ZCashWallet) bumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { } transactionID, err := w.sweepAddress([]wi.TransactionInput{in}, nil, key, nil, wi.FEE_BUMP) if err != nil { - return nil, err + return "", err } return transactionID, nil } } - return nil, util.BumpFeeNotFoundError + return "", util.BumpFeeNotFoundError } -func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { var internalAddr btc.Address if address != nil { internalAddr = *address @@ -350,7 +354,7 @@ func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Addre } script, err := zaddr.PayToAddrScript(internalAddr) if err != nil { - return nil, err + return "", err } var val int64 @@ -362,11 +366,11 @@ func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Addre values = append(values, in.Value.Int64()) ch, err := chainhash.NewHashFromStr(hex.EncodeToString(in.OutpointHash)) if err != nil { - return nil, err + return "", err } script, err := zaddr.PayToAddrScript(in.LinkedAddress) if err != nil { - return nil, err + return "", err } outpoint := wire.NewOutPoint(ch, in.OutpointIndex) input := wire.NewTxIn(outpoint, []byte{}, [][]byte{}) @@ -411,13 +415,13 @@ func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Addre // Sign tx privKey, err := key.ECPrivKey() if err != nil { - return nil, err + return "", err } for i, txIn := range tx.TxIn { sig, err := rawTxInSignature(tx, i, *redeemScript, txscript.SigHashAll, privKey, values[i]) if err != nil { - return nil, errors.New("failed to sign transaction") + return "", errors.New("failed to sign transaction") } builder := txscript.NewScriptBuilder() builder.AddOp(txscript.OP_0) @@ -427,7 +431,7 @@ func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Addre } script, err := builder.Script() if err != nil { - return nil, err + return "", err } txIn.SignatureScript = script } @@ -435,9 +439,9 @@ func (w *ZCashWallet) sweepAddress(ins []wi.TransactionInput, address *btc.Addre // broadcast txid, err := w.Broadcast(tx) if err != nil { - return nil, err + return "", err } - return chainhash.NewHashFromStr(txid) + return txid, nil } func (w *ZCashWallet) createMultisigSignature(ins []wi.TransactionInput, outs []wi.TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte uint64) ([]wi.Signature, error) { diff --git a/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go index 9bda26d02d..e1179f813c 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/zcash/wallet.go @@ -19,7 +19,6 @@ import ( zaddr "github.com/OpenBazaar/multiwallet/zcash/address" wi "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/chaincfg" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" hd "github.com/btcsuite/btcutil/hdkeychain" @@ -260,8 +259,8 @@ func (w *ZCashWallet) Transactions() ([]wi.Txn, error) { return txns, nil } -func (w *ZCashWallet) GetTransaction(txid chainhash.Hash) (wi.Txn, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *ZCashWallet) GetTransaction(txid string) (wi.Txn, error) { + txn, err := w.db.Txns().Get(txid) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(trimTxForDeserialization(txn.Bytes)) @@ -295,7 +294,7 @@ func (w *ZCashWallet) GetFeePerByte(feeLevel wi.FeeLevel) big.Int { return *big.NewInt(int64(w.fp.GetFeePerByte(feeLevel))) } -func (w *ZCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *ZCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.FeeLevel, referenceID string, spendAll bool) (string, error) { var ( tx *wire.MsgTx err error @@ -303,24 +302,24 @@ func (w *ZCashWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi.Fe if spendAll { tx, err = w.buildSpendAllTx(addr, feeLevel) if err != nil { - return nil, err + return "", err } } else { tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) if err != nil { - return nil, err + return "", err } } // Broadcast txid, err := w.Broadcast(tx) if err != nil { - return nil, err + return "", err } - return chainhash.NewHashFromStr(txid) + return txid, nil } -func (w *ZCashWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { +func (w *ZCashWallet) BumpFee(txid string) (string, error) { return w.bumpFee(txid) } @@ -341,7 +340,7 @@ func (w *ZCashWallet) EstimateSpendFee(amount big.Int, feeLevel wi.FeeLevel) (bi return *big.NewInt(int64(val)), err } -func (w *ZCashWallet) SweepAddress(ins []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (*chainhash.Hash, error) { +func (w *ZCashWallet) SweepAddress(ins []wi.TransactionInput, address *btcutil.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wi.FeeLevel) (string, error) { return w.sweepAddress(ins, address, key, redeemScript, feeLevel) } @@ -400,8 +399,8 @@ func (w *ZCashWallet) ReSyncBlockchain(fromTime time.Time) { go w.ws.UpdateState() } -func (w *ZCashWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.db.Txns().Get(txid.String()) +func (w *ZCashWallet) GetConfirmations(txid string) (uint32, uint32, error) { + txn, err := w.db.Txns().Get(txid) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go b/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go index 52abf54415..ed24876528 100644 --- a/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go +++ b/vendor/github.com/OpenBazaar/spvwallet/sortsignsend.go @@ -102,7 +102,7 @@ func (w *SPVWallet) gatherCoins() map[coinset.Coin]*hd.ExtendedKey { return m } -func (w *SPVWallet) Spend(amount big.Int, addr btc.Address, feeLevel wallet.FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) { +func (w *SPVWallet) Spend(amount big.Int, addr btc.Address, feeLevel wallet.FeeLevel, referenceID string, spendAll bool) (string, error) { var ( tx *wire.MsgTx err error @@ -110,36 +110,36 @@ func (w *SPVWallet) Spend(amount big.Int, addr btc.Address, feeLevel wallet.FeeL if spendAll { tx, err = w.buildSpendAllTx(addr, feeLevel) if err != nil { - return nil, err + return "", err } } else { tx, err = w.buildTx(amount.Int64(), addr, feeLevel, nil) if err != nil { - return nil, err + return "", err } } if err := w.Broadcast(tx); err != nil { - return nil, err + return "", err } ch := tx.TxHash() - return &ch, nil + return ch.String(), nil } var BumpFeeAlreadyConfirmedError = errors.New("Transaction is confirmed, cannot bump fee") var BumpFeeTransactionDeadError = errors.New("Cannot bump fee of dead transaction") var BumpFeeNotFoundError = errors.New("Transaction either doesn't exist or has already been spent") -func (w *SPVWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { - txn, err := w.txstore.Txns().Get(txid.String()) +func (w *SPVWallet) BumpFee(txid string) (string, error) { + txn, err := w.txstore.Txns().Get(txid) if err != nil { - return nil, err + return "", err } if txn.Height > 0 { - return nil, BumpFeeAlreadyConfirmedError + return "", BumpFeeAlreadyConfirmedError } if txn.Height < 0 { - return nil, BumpFeeTransactionDeadError + return "", BumpFeeTransactionDeadError } // Check stxos for RBF opportunity /*stxos, _ := w.txstore.Stxos().GetAll() @@ -196,18 +196,18 @@ func (w *SPVWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { // Check utxos for CPFP utxos, _ := w.txstore.Utxos().GetAll() for _, u := range utxos { - if u.Op.Hash.IsEqual(&txid) && u.AtHeight == 0 { + if u.Op.Hash.String() == txid && u.AtHeight == 0 { addr, err := w.ScriptToAddress(u.ScriptPubkey) if err != nil { - return nil, err + return "", err } key, err := w.keyManager.GetKeyForScript(addr.ScriptAddress()) if err != nil { - return nil, err + return "", err } h, err := hex.DecodeString(u.Op.Hash.String()) if err != nil { - return nil, err + return "", err } val0, _ := new(big.Int).SetString(u.Value, 10) in := wallet.TransactionInput{ @@ -218,12 +218,12 @@ func (w *SPVWallet) BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) { } transactionID, err := w.SweepAddress([]wallet.TransactionInput{in}, nil, key, nil, wallet.FEE_BUMP) if err != nil { - return nil, err + return "", err } return transactionID, nil } } - return nil, BumpFeeNotFoundError + return "", BumpFeeNotFoundError } func (w *SPVWallet) EstimateFee(ins []wallet.TransactionInput, outs []wallet.TransactionOutput, feePerByte big.Int) big.Int { @@ -471,7 +471,7 @@ func (w *SPVWallet) Multisign(ins []wallet.TransactionInput, outs []wallet.Trans return buf.Bytes(), nil } -func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wallet.FeeLevel) (*chainhash.Hash, error) { +func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel wallet.FeeLevel) (string, error) { var internalAddr btc.Address if address != nil { internalAddr = *address @@ -480,7 +480,7 @@ func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Add } script, err := txscript.PayToAddrScript(internalAddr) if err != nil { - return nil, err + return "", err } var val int64 @@ -490,11 +490,11 @@ func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Add val += in.Value.Int64() ch, err := chainhash.NewHashFromStr(hex.EncodeToString(in.OutpointHash)) if err != nil { - return nil, err + return "", err } script, err := txscript.PayToAddrScript(in.LinkedAddress) if err != nil { - return nil, err + return "", err } outpoint := wire.NewOutPoint(ch, in.OutpointIndex) input := wire.NewTxIn(outpoint, []byte{}, [][]byte{}) @@ -537,7 +537,7 @@ func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Add // Sign tx privKey, err := key.ECPrivKey() if err != nil { - return nil, err + return "", err } pk := privKey.PubKey().SerializeCompressed() addressPub, err := btc.NewAddressPubKey(pk, w.params) @@ -569,7 +569,7 @@ func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Add for _, txIn := range tx.TxIn { locktime, err := LockTimeFromRedeemScript(*redeemScript) if err != nil { - return nil, err + return "", err } txIn.Sequence = locktime } @@ -584,13 +584,13 @@ func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Add tx, i, prevOutScript, txscript.SigHashAll, getKey, getScript, txIn.SignatureScript) if err != nil { - return nil, errors.New("Failed to sign transaction") + return "", errors.New("Failed to sign transaction") } txIn.SignatureScript = script } else { sig, err := txscript.RawTxInWitnessSignature(tx, hashes, i, ins[i].Value.Int64(), *redeemScript, txscript.SigHashAll, privKey) if err != nil { - return nil, err + return "nil", err } var witness wire.TxWitness if timeLocked { @@ -606,7 +606,7 @@ func (w *SPVWallet) SweepAddress(ins []wallet.TransactionInput, address *btc.Add // broadcast w.Broadcast(tx) txid := tx.TxHash() - return &txid, nil + return txid.String(), nil } func (w *SPVWallet) buildTx(amount int64, addr btc.Address, feeLevel wallet.FeeLevel, optionalOutput *wire.TxOut) (*wire.MsgTx, error) { diff --git a/vendor/github.com/OpenBazaar/spvwallet/wallet.go b/vendor/github.com/OpenBazaar/spvwallet/wallet.go index 150fd497fc..efd804b4e7 100644 --- a/vendor/github.com/OpenBazaar/spvwallet/wallet.go +++ b/vendor/github.com/OpenBazaar/spvwallet/wallet.go @@ -379,8 +379,8 @@ func (w *SPVWallet) Transactions() ([]wallet.Txn, error) { return txns, nil } -func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (wallet.Txn, error) { - txn, err := w.txstore.Txns().Get(txid.String()) +func (w *SPVWallet) GetTransaction(txid string) (wallet.Txn, error) { + txn, err := w.txstore.Txns().Get(txid) if err == nil { tx := wire.NewMsgTx(1) rbuf := bytes.NewReader(txn.Bytes) @@ -410,8 +410,8 @@ func (w *SPVWallet) GetTransaction(txid chainhash.Hash) (wallet.Txn, error) { return txn, err } -func (w *SPVWallet) GetConfirmations(txid chainhash.Hash) (uint32, uint32, error) { - txn, err := w.txstore.Txns().Get(txid.String()) +func (w *SPVWallet) GetConfirmations(txid string) (uint32, uint32, error) { + txn, err := w.txstore.Txns().Get(txid) if err != nil { return 0, 0, err } diff --git a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go index 1dab141632..7ef7124529 100644 --- a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go +++ b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go @@ -5,7 +5,6 @@ import ( "math/big" "time" - "github.com/btcsuite/btcd/chaincfg/chainhash" btc "github.com/btcsuite/btcutil" hd "github.com/btcsuite/btcutil/hdkeychain" ) @@ -85,7 +84,7 @@ type EscrowWallet interface { // message he calls SweepAddress to move the funds back into his wallet. // // 4) The timeout has expired on a 2 of 3 multisig. The vendor calls SweepAddress to claim the funds. - SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (*chainhash.Hash, error) + SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (string, error) // GenerateMultisigScript should deterministically create a redeem script and address from the information provided. // This method should be strictly limited to taking the input data, combining it to produce the redeem script and @@ -210,7 +209,7 @@ type walletMustManager interface { Transactions() ([]Txn, error) // GetTransaction return info on a specific transaction given the txid. - GetTransaction(txid chainhash.Hash) (Txn, error) + GetTransaction(txid string) (Txn, error) // ChainTip returns the best block hash and height of the blockchain. ChainTip() (uint32, string) @@ -221,7 +220,7 @@ type walletMustManager interface { ReSyncBlockchain(fromTime time.Time) // GetConfirmations returns the number of confirmations and the height for a transaction. - GetConfirmations(txid chainhash.Hash) (confirms, atHeight uint32, err error) + GetConfirmations(txid string) (confirms, atHeight uint32, err error) // ChildKey generate a child key using the given chaincode. Each openbazaar-go node // keeps a master key (an hd secp256k1 key) that it uses in multisig transactions. @@ -310,7 +309,7 @@ type walletMustBanker interface { // be swept to the provided payment address. For most coins this entails subtracting the // transaction fee from the total amount being sent rather than adding it on as is normally // the case when spendAll is false. - Spend(amount big.Int, addr btc.Address, feeLevel FeeLevel, referenceID string, spendAll bool) (*chainhash.Hash, error) + Spend(amount big.Int, addr btc.Address, feeLevel FeeLevel, referenceID string, spendAll bool) (string, error) // EstimateFee should return the estimate fee that will be required to make a transaction // spending from the given inputs to the given outputs. FeePerByte is denominated in @@ -341,7 +340,7 @@ type walletMustBanker interface { // message he calls SweepAddress to move the funds back into his wallet. // // 4) The timeout has expired on a 2 of 3 multisig. The vendor calls SweepAddress to claim the funds. - SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (*chainhash.Hash, error) + SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (string, error) } type walletCanBumpFee interface { @@ -349,7 +348,7 @@ type walletCanBumpFee interface { // try to get it confirmed and return the txid of the new transaction (if one exists). // Since this method is only called in response to user action, it is acceptable to // return an error if this functionality is not available in this wallet or on the network. - BumpFee(txid chainhash.Hash) (*chainhash.Hash, error) + BumpFee(txid string) (string, error) } type FeeLevel int From 73cb941c2f65a564c59fbe457d1491a9cf2f81d5 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Tue, 21 Jul 2020 11:25:14 -0400 Subject: [PATCH 14/52] chash fix --- core/completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/completion.go b/core/completion.go index 9439868c99..f1f06f3f13 100644 --- a/core/completion.go +++ b/core/completion.go @@ -334,7 +334,7 @@ func (n *OpenBazaarNode) ReleaseFundsAfterTimeout(contract *pb.RicardianContract return err } - confirms, _, err := wal.GetConfirmations(*hash) + confirms, _, err := wal.GetConfirmations(hash.String()) if err != nil { return err } From 94c7a62c08dd707942121b88ff0688f94d03e4e7 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 23 Jul 2020 14:50:15 -0400 Subject: [PATCH 15/52] Fix dependency issues in vendor --- vendor/github.com/gogo/protobuf/AUTHORS | 15 + vendor/github.com/gogo/protobuf/CONTRIBUTORS | 23 + vendor/github.com/gogo/protobuf/LICENSE | 35 + .../github.com/gogo/protobuf/proto/Makefile | 43 + .../github.com/gogo/protobuf/proto/clone.go | 258 ++ .../gogo/protobuf/proto/custom_gogo.go | 39 + .../github.com/gogo/protobuf/proto/decode.go | 427 +++ .../gogo/protobuf/proto/deprecated.go | 63 + .../github.com/gogo/protobuf/proto/discard.go | 350 ++ .../gogo/protobuf/proto/duration.go | 100 + .../gogo/protobuf/proto/duration_gogo.go | 49 + .../github.com/gogo/protobuf/proto/encode.go | 205 ++ .../gogo/protobuf/proto/encode_gogo.go | 33 + .../github.com/gogo/protobuf/proto/equal.go | 300 ++ .../gogo/protobuf/proto/extensions.go | 605 ++++ .../gogo/protobuf/proto/extensions_gogo.go | 389 +++ vendor/github.com/gogo/protobuf/proto/lib.go | 973 ++++++ .../gogo/protobuf/proto/lib_gogo.go | 50 + .../gogo/protobuf/proto/message_set.go | 181 + .../gogo/protobuf/proto/pointer_reflect.go | 357 ++ .../protobuf/proto/pointer_reflect_gogo.go | 59 + .../gogo/protobuf/proto/pointer_unsafe.go | 308 ++ .../protobuf/proto/pointer_unsafe_gogo.go | 56 + .../gogo/protobuf/proto/properties.go | 610 ++++ .../gogo/protobuf/proto/properties_gogo.go | 36 + .../gogo/protobuf/proto/skip_gogo.go | 119 + .../gogo/protobuf/proto/table_marshal.go | 3009 +++++++++++++++++ .../gogo/protobuf/proto/table_marshal_gogo.go | 388 +++ .../gogo/protobuf/proto/table_merge.go | 676 ++++ .../gogo/protobuf/proto/table_unmarshal.go | 2249 ++++++++++++ .../protobuf/proto/table_unmarshal_gogo.go | 385 +++ vendor/github.com/gogo/protobuf/proto/text.go | 930 +++++ .../gogo/protobuf/proto/text_gogo.go | 57 + .../gogo/protobuf/proto/text_parser.go | 1018 ++++++ .../gogo/protobuf/proto/timestamp.go | 113 + .../gogo/protobuf/proto/timestamp_gogo.go | 49 + .../gogo/protobuf/proto/wrappers.go | 1888 +++++++++++ .../gogo/protobuf/proto/wrappers_gogo.go | 113 + vendor/github.com/ipfs/bbloom/.travis.yml | 32 + vendor/github.com/ipfs/bbloom/README.md | 129 + vendor/github.com/ipfs/bbloom/bbloom.go | 326 ++ vendor/github.com/ipfs/bbloom/go.mod | 3 + vendor/github.com/ipfs/bbloom/package.json | 15 + vendor/github.com/ipfs/bbloom/sipHash.go | 225 ++ vendor/github.com/ipfs/bbloom/words.txt | 140 + .../ipfs/go-block-format/.travis.yml | 32 + .../github.com/ipfs/go-block-format/LICENSE | 21 + .../github.com/ipfs/go-block-format/Makefile | 15 + .../github.com/ipfs/go-block-format/README.md | 35 + .../github.com/ipfs/go-block-format/blocks.go | 82 + .../ipfs/go-block-format/codecov.yml | 3 + vendor/github.com/ipfs/go-block-format/go.mod | 7 + vendor/github.com/ipfs/go-block-format/go.sum | 24 + .../ipfs/go-block-format/package.json | 36 + .../github.com/ipfs/go-blockservice/LICENSE | 21 + .../github.com/ipfs/go-blockservice/README.md | 36 + .../ipfs/go-blockservice/blockservice.go | 368 ++ vendor/github.com/ipfs/go-blockservice/go.mod | 19 + vendor/github.com/ipfs/go-blockservice/go.sum | 363 ++ vendor/github.com/ipfs/go-cid/.gitignore | 1 + vendor/github.com/ipfs/go-cid/.travis.yml | 31 + vendor/github.com/ipfs/go-cid/LICENSE | 21 + vendor/github.com/ipfs/go-cid/Makefile | 16 + vendor/github.com/ipfs/go-cid/README.md | 108 + vendor/github.com/ipfs/go-cid/builder.go | 74 + vendor/github.com/ipfs/go-cid/cid.go | 654 ++++ vendor/github.com/ipfs/go-cid/cid_fuzz.go | 37 + vendor/github.com/ipfs/go-cid/codecov.yml | 3 + vendor/github.com/ipfs/go-cid/deprecated.go | 28 + vendor/github.com/ipfs/go-cid/go.mod | 9 + vendor/github.com/ipfs/go-cid/go.sum | 30 + vendor/github.com/ipfs/go-cid/package.json | 30 + vendor/github.com/ipfs/go-cid/set.go | 65 + vendor/github.com/ipfs/go-cid/varint.go | 40 + .../github.com/ipfs/go-datastore/.gitignore | 1 + vendor/github.com/ipfs/go-datastore/LICENSE | 21 + vendor/github.com/ipfs/go-datastore/Makefile | 9 + vendor/github.com/ipfs/go-datastore/README.md | 47 + .../github.com/ipfs/go-datastore/basic_ds.go | 287 ++ vendor/github.com/ipfs/go-datastore/batch.go | 47 + .../github.com/ipfs/go-datastore/datastore.go | 251 ++ vendor/github.com/ipfs/go-datastore/go.mod | 12 + vendor/github.com/ipfs/go-datastore/go.sum | 16 + vendor/github.com/ipfs/go-datastore/key.go | 309 ++ .../ipfs/go-datastore/keytransform/doc.go | 25 + .../go-datastore/keytransform/interface.go | 13 + .../go-datastore/keytransform/keytransform.go | 260 ++ .../go-datastore/keytransform/transforms.go | 49 + .../ipfs/go-datastore/namespace/doc.go | 24 + .../ipfs/go-datastore/namespace/namespace.go | 26 + .../ipfs/go-datastore/query/filter.go | 102 + .../ipfs/go-datastore/query/order.go | 94 + .../ipfs/go-datastore/query/query.go | 426 +++ .../ipfs/go-datastore/query/query_impl.go | 158 + .../ipfs/go-filestore/LICENSE-APACHE | 5 + .../github.com/ipfs/go-filestore/LICENSE-MIT | 19 + vendor/github.com/ipfs/go-filestore/README.md | 38 + .../github.com/ipfs/go-filestore/filestore.go | 251 ++ .../ipfs/go-filestore/fsrefstore.go | 339 ++ vendor/github.com/ipfs/go-filestore/go.mod | 16 + vendor/github.com/ipfs/go-filestore/go.sum | 387 +++ .../github.com/ipfs/go-filestore/pb/Rules.mk | 8 + .../ipfs/go-filestore/pb/dataobj.pb.go | 375 ++ .../ipfs/go-filestore/pb/dataobj.proto | 9 + vendor/github.com/ipfs/go-filestore/util.go | 291 ++ .../ipfs/go-graphsync/.golangci.yml | 3 + vendor/github.com/ipfs/go-graphsync/COPYRIGHT | 3 + .../ipfs/go-graphsync/LICENSE-APACHE | 13 + .../github.com/ipfs/go-graphsync/LICENSE-MIT | 19 + vendor/github.com/ipfs/go-graphsync/README.md | 234 ++ vendor/github.com/ipfs/go-graphsync/go.mod | 42 + vendor/github.com/ipfs/go-graphsync/go.sum | 711 ++++ .../github.com/ipfs/go-graphsync/graphsync.go | 254 ++ .../github.com/ipfs/go-hamt-ipld/.gitignore | 17 + .../github.com/ipfs/go-hamt-ipld/.travis.yml | 31 + vendor/github.com/ipfs/go-hamt-ipld/LICENSE | 21 + vendor/github.com/ipfs/go-hamt-ipld/Makefile | 14 + vendor/github.com/ipfs/go-hamt-ipld/README.md | 34 + .../github.com/ipfs/go-hamt-ipld/cbor_gen.go | 214 ++ .../github.com/ipfs/go-hamt-ipld/codecov.yml | 3 + vendor/github.com/ipfs/go-hamt-ipld/go.mod | 14 + vendor/github.com/ipfs/go-hamt-ipld/go.sum | 86 + vendor/github.com/ipfs/go-hamt-ipld/hamt.go | 456 +++ vendor/github.com/ipfs/go-hamt-ipld/hash.go | 56 + .../ipfs/go-hamt-ipld/pointer_cbor.go | 133 + vendor/github.com/ipfs/go-hamt-ipld/uhamt.go | 27 + .../ipfs/go-ipfs-blockstore/.travis.yml | 30 + .../ipfs/go-ipfs-blockstore/LICENSE | 21 + .../ipfs/go-ipfs-blockstore/README.md | 47 + .../ipfs/go-ipfs-blockstore/arc_cache.go | 184 + .../ipfs/go-ipfs-blockstore/blockstore.go | 279 ++ .../ipfs/go-ipfs-blockstore/bloom_cache.go | 204 ++ .../ipfs/go-ipfs-blockstore/caching.go | 55 + .../github.com/ipfs/go-ipfs-blockstore/go.mod | 16 + .../github.com/ipfs/go-ipfs-blockstore/go.sum | 95 + .../ipfs/go-ipfs-blockstore/idstore.go | 86 + .../ipfs/go-ipfs-ds-help/.travis.yml | 30 + .../github.com/ipfs/go-ipfs-ds-help/LICENSE | 21 + .../github.com/ipfs/go-ipfs-ds-help/Makefile | 18 + .../github.com/ipfs/go-ipfs-ds-help/README.md | 44 + vendor/github.com/ipfs/go-ipfs-ds-help/go.mod | 10 + vendor/github.com/ipfs/go-ipfs-ds-help/go.sum | 56 + vendor/github.com/ipfs/go-ipfs-ds-help/key.go | 51 + .../go-ipfs-exchange-interface/.travis.yml | 32 + .../ipfs/go-ipfs-exchange-interface/LICENSE | 21 + .../ipfs/go-ipfs-exchange-interface/Makefile | 11 + .../ipfs/go-ipfs-exchange-interface/README.md | 42 + .../ipfs/go-ipfs-exchange-interface/go.mod | 6 + .../ipfs/go-ipfs-exchange-interface/go.sum | 26 + .../go-ipfs-exchange-interface/interface.go | 37 + .../go-ipfs-exchange-interface/package.json | 30 + .../ipfs/go-ipfs-posinfo/.gitignore | 14 + .../ipfs/go-ipfs-posinfo/.travis.yml | 32 + .../github.com/ipfs/go-ipfs-posinfo/LICENSE | 21 + .../github.com/ipfs/go-ipfs-posinfo/Makefile | 18 + .../github.com/ipfs/go-ipfs-posinfo/README.md | 37 + vendor/github.com/ipfs/go-ipfs-posinfo/go.mod | 3 + vendor/github.com/ipfs/go-ipfs-posinfo/go.sum | 28 + .../ipfs/go-ipfs-posinfo/package.json | 24 + .../ipfs/go-ipfs-posinfo/posinfo.go | 23 + .../github.com/ipfs/go-ipfs-util/.gitignore | 1 + .../github.com/ipfs/go-ipfs-util/.travis.yml | 32 + vendor/github.com/ipfs/go-ipfs-util/LICENSE | 21 + vendor/github.com/ipfs/go-ipfs-util/README.md | 45 + vendor/github.com/ipfs/go-ipfs-util/file.go | 12 + vendor/github.com/ipfs/go-ipfs-util/go.mod | 6 + vendor/github.com/ipfs/go-ipfs-util/go.sum | 16 + .../github.com/ipfs/go-ipfs-util/package.json | 28 + vendor/github.com/ipfs/go-ipfs-util/time.go | 22 + vendor/github.com/ipfs/go-ipfs-util/util.go | 158 + .../github.com/ipfs/go-ipld-cbor/.travis.yml | 31 + vendor/github.com/ipfs/go-ipld-cbor/LICENSE | 21 + vendor/github.com/ipfs/go-ipld-cbor/Makefile | 14 + vendor/github.com/ipfs/go-ipld-cbor/README.md | 57 + .../github.com/ipfs/go-ipld-cbor/codecov.yml | 3 + .../ipfs/go-ipld-cbor/encoding/cloner.go | 41 + .../ipfs/go-ipld-cbor/encoding/marshaller.go | 92 + .../go-ipld-cbor/encoding/unmarshaller.go | 88 + vendor/github.com/ipfs/go-ipld-cbor/go.mod | 15 + vendor/github.com/ipfs/go-ipld-cbor/go.sum | 62 + vendor/github.com/ipfs/go-ipld-cbor/node.go | 545 +++ .../github.com/ipfs/go-ipld-cbor/readable.go | 33 + vendor/github.com/ipfs/go-ipld-cbor/refmt.go | 72 + vendor/github.com/ipfs/go-ipld-cbor/store.go | 179 + .../ipfs/go-ipld-format/.travis.yml | 30 + vendor/github.com/ipfs/go-ipld-format/LICENSE | 21 + .../github.com/ipfs/go-ipld-format/Makefile | 15 + .../github.com/ipfs/go-ipld-format/README.md | 38 + .../github.com/ipfs/go-ipld-format/batch.go | 301 ++ .../ipfs/go-ipld-format/codecov.yml | 3 + .../github.com/ipfs/go-ipld-format/coding.go | 62 + .../ipfs/go-ipld-format/daghelpers.go | 118 + .../github.com/ipfs/go-ipld-format/format.go | 90 + vendor/github.com/ipfs/go-ipld-format/go.mod | 10 + vendor/github.com/ipfs/go-ipld-format/go.sum | 30 + .../ipfs/go-ipld-format/merkledag.go | 67 + .../github.com/ipfs/go-ipld-format/navipld.go | 149 + .../github.com/ipfs/go-ipld-format/promise.go | 66 + .../github.com/ipfs/go-ipld-format/walker.go | 436 +++ vendor/github.com/ipfs/go-log/.travis.yml | 31 + vendor/github.com/ipfs/go-log/LICENSE | 21 + vendor/github.com/ipfs/go-log/README.md | 79 + vendor/github.com/ipfs/go-log/context.go | 38 + vendor/github.com/ipfs/go-log/entry.go | 7 + vendor/github.com/ipfs/go-log/go.mod | 10 + vendor/github.com/ipfs/go-log/go.sum | 65 + vendor/github.com/ipfs/go-log/levels.go | 30 + vendor/github.com/ipfs/go-log/log.go | 420 +++ vendor/github.com/ipfs/go-log/loggable.go | 42 + vendor/github.com/ipfs/go-log/metadata.go | 77 + vendor/github.com/ipfs/go-log/oldlog.go | 68 + vendor/github.com/ipfs/go-log/package.json | 41 + vendor/github.com/ipfs/go-log/tracer/LICENSE | 21 + .../github.com/ipfs/go-log/tracer/context.go | 42 + vendor/github.com/ipfs/go-log/tracer/debug.go | 78 + vendor/github.com/ipfs/go-log/tracer/event.go | 62 + .../ipfs/go-log/tracer/propagation.go | 61 + .../ipfs/go-log/tracer/propagation_ot.go | 178 + vendor/github.com/ipfs/go-log/tracer/raw.go | 34 + .../github.com/ipfs/go-log/tracer/recorder.go | 103 + vendor/github.com/ipfs/go-log/tracer/span.go | 274 ++ .../github.com/ipfs/go-log/tracer/tracer.go | 280 ++ vendor/github.com/ipfs/go-log/tracer/util.go | 25 + .../ipfs/go-log/tracer/wire/Makefile | 6 + .../ipfs/go-log/tracer/wire/carrier.go | 40 + .../github.com/ipfs/go-log/tracer/wire/gen.go | 6 + .../ipfs/go-log/tracer/wire/wire.pb.go | 531 +++ .../ipfs/go-log/tracer/wire/wire.proto | 10 + vendor/github.com/ipfs/go-log/v2/LICENSE | 21 + vendor/github.com/ipfs/go-log/v2/README.md | 66 + vendor/github.com/ipfs/go-log/v2/core.go | 120 + vendor/github.com/ipfs/go-log/v2/go.mod | 8 + vendor/github.com/ipfs/go-log/v2/go.sum | 60 + vendor/github.com/ipfs/go-log/v2/levels.go | 30 + vendor/github.com/ipfs/go-log/v2/log.go | 75 + vendor/github.com/ipfs/go-log/v2/package.json | 41 + .../github.com/ipfs/go-log/v2/path_other.go | 11 + .../github.com/ipfs/go-log/v2/path_windows.go | 35 + vendor/github.com/ipfs/go-log/v2/pipe.go | 90 + vendor/github.com/ipfs/go-log/v2/setup.go | 267 ++ .../github.com/ipfs/go-log/writer/option.go | 4 + .../github.com/ipfs/go-log/writer/writer.go | 251 ++ .../ipfs/go-metrics-interface/.gitignore | 24 + .../ipfs/go-metrics-interface/.travis.yml | 32 + .../ipfs/go-metrics-interface/LICENSE | 21 + .../ipfs/go-metrics-interface/context.go | 26 + .../ipfs/go-metrics-interface/ctor.go | 43 + .../ipfs/go-metrics-interface/go.mod | 1 + .../ipfs/go-metrics-interface/interface.go | 45 + .../ipfs/go-metrics-interface/noop.go | 46 + .../ipfs/go-metrics-interface/package.json | 16 + .../github.com/ipfs/go-verifcid/.travis.yml | 32 + vendor/github.com/ipfs/go-verifcid/go.mod | 6 + vendor/github.com/ipfs/go-verifcid/go.sum | 22 + .../github.com/ipfs/go-verifcid/package.json | 28 + .../github.com/ipfs/go-verifcid/validate.go | 62 + .../github.com/ipld/go-ipld-prime/.gitmodules | 39 + .../github.com/ipld/go-ipld-prime/.travis.yml | 25 + .../github.com/ipld/go-ipld-prime/HACKME.md | 120 + .../go-ipld-prime/HACKME_builderBehaviors.md | 61 + vendor/github.com/ipld/go-ipld-prime/LICENSE | 21 + .../github.com/ipld/go-ipld-prime/README.md | 105 + .../go-ipld-prime/codec/dagcbor/common.go | 3 + .../go-ipld-prime/codec/dagcbor/marshal.go | 145 + .../go-ipld-prime/codec/dagcbor/multicodec.go | 46 + .../go-ipld-prime/codec/dagcbor/unmarshal.go | 152 + vendor/github.com/ipld/go-ipld-prime/doc.go | 50 + .../github.com/ipld/go-ipld-prime/errors.go | 86 + .../ipld/go-ipld-prime/fluent/doc.go | 15 + .../go-ipld-prime/fluent/fluentBuilder.go | 179 + .../go-ipld-prime/fluent/fluentRecover.go | 30 + vendor/github.com/ipld/go-ipld-prime/go.mod | 15 + vendor/github.com/ipld/go-ipld-prime/go.sum | 52 + vendor/github.com/ipld/go-ipld-prime/kind.go | 78 + .../github.com/ipld/go-ipld-prime/linking.go | 144 + .../ipld/go-ipld-prime/linking/cid/cidLink.go | 92 + .../go-ipld-prime/linking/cid/multicodec.go | 42 + .../linking/cid/multicodecRegistry.go | 35 + .../github.com/ipld/go-ipld-prime/module.tl | 24 + vendor/github.com/ipld/go-ipld-prime/node.go | 274 ++ .../ipld/go-ipld-prime/node/basic/HACKME.md | 145 + .../ipld/go-ipld-prime/node/basic/any.go | 200 ++ .../ipld/go-ipld-prime/node/basic/bool.go | 144 + .../ipld/go-ipld-prime/node/basic/bytes.go | 144 + .../ipld/go-ipld-prime/node/basic/float.go | 144 + .../ipld/go-ipld-prime/node/basic/int.go | 144 + .../ipld/go-ipld-prime/node/basic/link.go | 145 + .../ipld/go-ipld-prime/node/basic/list.go | 359 ++ .../ipld/go-ipld-prime/node/basic/map.go | 470 +++ .../ipld/go-ipld-prime/node/basic/string.go | 149 + .../ipld/go-ipld-prime/node/basic/style.go | 26 + .../ipld/go-ipld-prime/node/mixins/HACKME.md | 37 + .../go-ipld-prime/node/mixins/boolMixin.go | 97 + .../go-ipld-prime/node/mixins/bytesMixin.go | 97 + .../go-ipld-prime/node/mixins/floatMixin.go | 97 + .../go-ipld-prime/node/mixins/intMixin.go | 97 + .../go-ipld-prime/node/mixins/linkMixin.go | 97 + .../go-ipld-prime/node/mixins/listMixin.go | 88 + .../go-ipld-prime/node/mixins/mapMixin.go | 85 + .../go-ipld-prime/node/mixins/stringMixin.go | 97 + .../go-ipld-prime/node/mixins/tmplMixin.txt | 107 + .../ipld/go-ipld-prime/nodeBuilder.go | 137 + vendor/github.com/ipld/go-ipld-prime/path.go | 193 ++ .../ipld/go-ipld-prime/pathSegment.go | 136 + .../ipld/go-ipld-prime/schema/errors.go | 18 + .../ipld/go-ipld-prime/schema/kind.go | 108 + .../ipld/go-ipld-prime/schema/maybe.go | 9 + .../ipld/go-ipld-prime/schema/tmpBuilders.go | 44 + .../ipld/go-ipld-prime/schema/type.go | 188 + .../ipld/go-ipld-prime/schema/typeMethods.go | 160 + .../ipld/go-ipld-prime/schema/typedNode.go | 73 + .../ipld/go-ipld-prime/schema/typesystem.go | 14 + .../ipld/go-ipld-prime/schema/validate.go | 70 + .../ipld/go-ipld-prime/traversal/common.go | 47 + .../ipld/go-ipld-prime/traversal/doc.go | 57 + .../ipld/go-ipld-prime/traversal/fns.go | 69 + .../ipld/go-ipld-prime/traversal/focus.go | 142 + .../traversal/selector/builder/builder.go | 167 + .../traversal/selector/exploreAll.go | 44 + .../traversal/selector/exploreFields.go | 72 + .../traversal/selector/exploreIndex.go | 63 + .../traversal/selector/exploreRange.go | 87 + .../traversal/selector/exploreRecursive.go | 219 ++ .../selector/exploreRecursiveEdge.go | 47 + .../traversal/selector/exploreUnion.go | 95 + .../traversal/selector/fieldKeys.go | 25 + .../traversal/selector/matcher.go | 46 + .../traversal/selector/selector.go | 119 + .../ipld/go-ipld-prime/traversal/walk.go | 229 ++ vendor/github.com/ipld/go-ipld-prime/unit.go | 125 + .../libp2p/go-buffer-pool/.travis.yml | 30 + .../github.com/libp2p/go-buffer-pool/LICENSE | 21 + .../libp2p/go-buffer-pool/LICENSE-BSD | 29 + .../libp2p/go-buffer-pool/README.md | 53 + .../libp2p/go-buffer-pool/buffer.go | 302 ++ .../libp2p/go-buffer-pool/codecov.yml | 3 + .../github.com/libp2p/go-buffer-pool/go.mod | 3 + .../github.com/libp2p/go-buffer-pool/pool.go | 115 + .../libp2p/go-buffer-pool/writer.go | 119 + .../github.com/libp2p/go-libp2p-core/LICENSE | 4 + .../libp2p/go-libp2p-core/LICENSE-APACHE | 13 + .../libp2p/go-libp2p-core/LICENSE-MIT | 19 + .../libp2p/go-libp2p-core/crypto/ecdsa.go | 177 + .../libp2p/go-libp2p-core/crypto/ed25519.go | 155 + .../libp2p/go-libp2p-core/crypto/key.go | 399 +++ .../go-libp2p-core/crypto/key_not_openssl.go | 80 + .../go-libp2p-core/crypto/key_openssl.go | 94 + .../go-libp2p-core/crypto/openssl_common.go | 119 + .../libp2p/go-libp2p-core/crypto/pb/Makefile | 11 + .../go-libp2p-core/crypto/pb/crypto.pb.go | 625 ++++ .../go-libp2p-core/crypto/pb/crypto.proto | 22 + .../go-libp2p-core/crypto/rsa_common.go | 25 + .../libp2p/go-libp2p-core/crypto/rsa_go.go | 152 + .../go-libp2p-core/crypto/rsa_openssl.go | 68 + .../libp2p/go-libp2p-core/crypto/secp256k1.go | 125 + .../libp2p/go-libp2p-core/peer/addrinfo.go | 98 + .../go-libp2p-core/peer/addrinfo_serde.go | 38 + .../libp2p/go-libp2p-core/peer/pb/Makefile | 11 + .../go-libp2p-core/peer/pb/peer_record.pb.go | 606 ++++ .../go-libp2p-core/peer/pb/peer_record.proto | 29 + .../libp2p/go-libp2p-core/peer/peer.go | 245 ++ .../libp2p/go-libp2p-core/peer/peer_serde.go | 75 + .../libp2p/go-libp2p-core/peer/record.go | 232 ++ .../libp2p/go-libp2p-core/peer/set.go | 71 + .../libp2p/go-libp2p-core/protocol/id.go | 29 + .../libp2p/go-libp2p-core/protocol/switch.go | 81 + .../libp2p/go-libp2p-core/record/envelope.go | 297 ++ .../libp2p/go-libp2p-core/record/pb/Makefile | 11 + .../go-libp2p-core/record/pb/envelope.pb.go | 504 +++ .../go-libp2p-core/record/pb/envelope.proto | 30 + .../libp2p/go-libp2p-core/record/record.go | 102 + .../github.com/libp2p/go-openssl/.gitignore | 1 + vendor/github.com/libp2p/go-openssl/AUTHORS | 24 + vendor/github.com/libp2p/go-openssl/LICENSE | 191 ++ vendor/github.com/libp2p/go-openssl/README.md | 40 + vendor/github.com/libp2p/go-openssl/bio.go | 305 ++ vendor/github.com/libp2p/go-openssl/build.go | 24 + .../libp2p/go-openssl/build_static.go | 24 + vendor/github.com/libp2p/go-openssl/cert.go | 415 +++ .../github.com/libp2p/go-openssl/ciphers.go | 335 ++ .../libp2p/go-openssl/ciphers_gcm.go | 152 + vendor/github.com/libp2p/go-openssl/conn.go | 620 ++++ vendor/github.com/libp2p/go-openssl/ctx.go | 568 ++++ vendor/github.com/libp2p/go-openssl/dh.go | 66 + .../github.com/libp2p/go-openssl/dhparam.go | 64 + vendor/github.com/libp2p/go-openssl/digest.go | 51 + vendor/github.com/libp2p/go-openssl/engine.go | 50 + vendor/github.com/libp2p/go-openssl/fips.go | 39 + vendor/github.com/libp2p/go-openssl/go.mod | 8 + vendor/github.com/libp2p/go-openssl/go.sum | 4 + vendor/github.com/libp2p/go-openssl/hmac.go | 91 + .../github.com/libp2p/go-openssl/hostname.c | 373 ++ .../github.com/libp2p/go-openssl/hostname.go | 132 + vendor/github.com/libp2p/go-openssl/http.go | 61 + vendor/github.com/libp2p/go-openssl/init.go | 117 + .../libp2p/go-openssl/init_posix.go | 68 + .../libp2p/go-openssl/init_windows.go | 57 + vendor/github.com/libp2p/go-openssl/key.go | 518 +++ .../github.com/libp2p/go-openssl/mapping.go | 62 + vendor/github.com/libp2p/go-openssl/md4.go | 89 + vendor/github.com/libp2p/go-openssl/md5.go | 89 + vendor/github.com/libp2p/go-openssl/net.go | 147 + vendor/github.com/libp2p/go-openssl/nid.go | 210 ++ vendor/github.com/libp2p/go-openssl/object.go | 24 + vendor/github.com/libp2p/go-openssl/pem.go | 32 + vendor/github.com/libp2p/go-openssl/sha1.go | 96 + vendor/github.com/libp2p/go-openssl/sha256.go | 89 + vendor/github.com/libp2p/go-openssl/shim.c | 770 +++++ vendor/github.com/libp2p/go-openssl/shim.h | 176 + vendor/github.com/libp2p/go-openssl/sni.c | 23 + vendor/github.com/libp2p/go-openssl/ssl.go | 170 + .../github.com/libp2p/go-openssl/tickets.go | 222 ++ .../libp2p/go-openssl/utils/errors.go | 50 + .../libp2p/go-openssl/utils/future.go | 79 + .../github.com/multiformats/go-base32/LICENSE | 27 + .../multiformats/go-base32/base32.go | 505 +++ .../github.com/multiformats/go-base32/go.mod | 1 + .../multiformats/go-base32/package.json | 15 + .../multiformats/go-multiaddr-dns/.gitignore | 1 + .../multiformats/go-multiaddr-dns/.travis.yml | 30 + .../multiformats/go-multiaddr-dns/LICENSE | 21 + .../multiformats/go-multiaddr-dns/README.md | 57 + .../multiformats/go-multiaddr-dns/dns.go | 29 + .../multiformats/go-multiaddr-dns/go.mod | 5 + .../multiformats/go-multiaddr-dns/go.sum | 20 + .../multiformats/go-multiaddr-dns/resolve.go | 269 ++ .../multiformats/go-multiaddr/.gitignore | 3 + .../multiformats/go-multiaddr/.travis.yml | 31 + .../multiformats/go-multiaddr/LICENSE | 21 + .../multiformats/go-multiaddr/Makefile | 12 + .../multiformats/go-multiaddr/README.md | 117 + .../multiformats/go-multiaddr/codec.go | 204 ++ .../multiformats/go-multiaddr/codecov.yml | 2 + .../multiformats/go-multiaddr/component.go | 183 + .../multiformats/go-multiaddr/doc.go | 36 + .../multiformats/go-multiaddr/filter.go | 179 + .../multiformats/go-multiaddr/go.mod | 8 + .../multiformats/go-multiaddr/go.sum | 20 + .../multiformats/go-multiaddr/interface.go | 62 + .../multiformats/go-multiaddr/multiaddr.go | 186 + .../multiformats/go-multiaddr/package.json | 23 + .../multiformats/go-multiaddr/protocol.go | 119 + .../multiformats/go-multiaddr/protocols.go | 249 ++ .../multiformats/go-multiaddr/transcoders.go | 342 ++ .../multiformats/go-multiaddr/util.go | 180 + .../multiformats/go-multiaddr/varint.go | 27 + .../multiformats/go-multibase/.codecov.yml | 1 + .../multiformats/go-multibase/.gitignore | 3 + .../multiformats/go-multibase/.gitmodules | 3 + .../multiformats/go-multibase/.gxignore | 2 + .../multiformats/go-multibase/.travis.yml | 32 + .../multiformats/go-multibase/LICENSE | 21 + .../multiformats/go-multibase/Makefile | 13 + .../multiformats/go-multibase/README.md | 49 + .../multiformats/go-multibase/base16.go | 21 + .../multiformats/go-multibase/base2.go | 52 + .../multiformats/go-multibase/base32.go | 17 + .../multiformats/go-multibase/encoder.go | 63 + .../multiformats/go-multibase/go.mod | 6 + .../multiformats/go-multibase/go.sum | 4 + .../multiformats/go-multibase/multibase.go | 186 + .../multiformats/go-multibase/package.json | 30 + .../multiformats/go-multihash/.gitignore | 1 + .../multiformats/go-multihash/.gitmodules | 6 + .../multiformats/go-multihash/.travis.yml | 30 + .../multiformats/go-multihash/LICENSE | 21 + .../multiformats/go-multihash/Makefile | 11 + .../multiformats/go-multihash/README.md | 90 + .../multiformats/go-multihash/codecov.yml | 3 + .../multiformats/go-multihash/go.mod | 12 + .../multiformats/go-multihash/go.sum | 22 + .../multiformats/go-multihash/io.go | 98 + .../multiformats/go-multihash/multihash.go | 331 ++ .../multiformats/go-multihash/set.go | 66 + .../multiformats/go-multihash/sum.go | 236 ++ .../multiformats/go-varint/.travis.yml | 30 + .../github.com/multiformats/go-varint/LICENSE | 21 + .../multiformats/go-varint/README.md | 35 + .../multiformats/go-varint/codecov.yml | 2 + .../github.com/multiformats/go-varint/go.mod | 3 + .../multiformats/go-varint/varint.go | 94 + .../whyrusleeping/bencher/LICENSE-MIT | 19 + .../whyrusleeping/bencher/README.md | 25 + .../github.com/whyrusleeping/bencher/go.mod | 9 + .../github.com/whyrusleeping/bencher/go.sum | 14 + .../github.com/whyrusleeping/bencher/main.go | 237 ++ .../whyrusleeping/cbor-gen/Makefile | 8 + .../whyrusleeping/cbor-gen/README.md | 6 + .../whyrusleeping/cbor-gen/cbor_cid.go | 22 + .../github.com/whyrusleeping/cbor-gen/gen.go | 1258 +++++++ .../github.com/whyrusleeping/cbor-gen/go.mod | 11 + .../github.com/whyrusleeping/cbor-gen/go.sum | 48 + .../whyrusleeping/cbor-gen/utils.go | 690 ++++ .../whyrusleeping/cbor-gen/writefile.go | 84 + vendor/go.uber.org/atomic/.codecov.yml | 15 + vendor/go.uber.org/atomic/.gitignore | 12 + vendor/go.uber.org/atomic/.travis.yml | 27 + vendor/go.uber.org/atomic/CHANGELOG.md | 64 + vendor/go.uber.org/atomic/LICENSE.txt | 19 + vendor/go.uber.org/atomic/Makefile | 35 + vendor/go.uber.org/atomic/README.md | 63 + vendor/go.uber.org/atomic/atomic.go | 356 ++ vendor/go.uber.org/atomic/error.go | 55 + vendor/go.uber.org/atomic/go.mod | 10 + vendor/go.uber.org/atomic/go.sum | 22 + vendor/go.uber.org/atomic/string.go | 49 + vendor/go.uber.org/multierr/.codecov.yml | 15 + vendor/go.uber.org/multierr/.gitignore | 4 + vendor/go.uber.org/multierr/.travis.yml | 29 + vendor/go.uber.org/multierr/CHANGELOG.md | 54 + vendor/go.uber.org/multierr/LICENSE.txt | 19 + vendor/go.uber.org/multierr/Makefile | 42 + vendor/go.uber.org/multierr/README.md | 23 + vendor/go.uber.org/multierr/error.go | 449 +++ vendor/go.uber.org/multierr/glide.yaml | 8 + vendor/go.uber.org/multierr/go.mod | 12 + vendor/go.uber.org/multierr/go.sum | 45 + vendor/go.uber.org/multierr/go113.go | 52 + vendor/go.uber.org/zap/.codecov.yml | 17 + vendor/go.uber.org/zap/.gitignore | 32 + vendor/go.uber.org/zap/.readme.tmpl | 109 + vendor/go.uber.org/zap/.travis.yml | 23 + vendor/go.uber.org/zap/CHANGELOG.md | 401 +++ vendor/go.uber.org/zap/CODE_OF_CONDUCT.md | 75 + vendor/go.uber.org/zap/CONTRIBUTING.md | 81 + vendor/go.uber.org/zap/FAQ.md | 155 + vendor/go.uber.org/zap/LICENSE.txt | 19 + vendor/go.uber.org/zap/Makefile | 63 + vendor/go.uber.org/zap/README.md | 134 + vendor/go.uber.org/zap/array.go | 320 ++ vendor/go.uber.org/zap/buffer/buffer.go | 123 + vendor/go.uber.org/zap/buffer/pool.go | 49 + vendor/go.uber.org/zap/checklicense.sh | 17 + vendor/go.uber.org/zap/config.go | 262 ++ vendor/go.uber.org/zap/doc.go | 113 + vendor/go.uber.org/zap/encoder.go | 79 + vendor/go.uber.org/zap/error.go | 80 + vendor/go.uber.org/zap/field.go | 533 +++ vendor/go.uber.org/zap/flag.go | 39 + vendor/go.uber.org/zap/glide.yaml | 34 + vendor/go.uber.org/zap/global.go | 168 + vendor/go.uber.org/zap/global_go112.go | 26 + vendor/go.uber.org/zap/global_prego112.go | 26 + vendor/go.uber.org/zap/go.mod | 12 + vendor/go.uber.org/zap/go.sum | 56 + vendor/go.uber.org/zap/http_handler.go | 81 + .../zap/internal/bufferpool/bufferpool.go | 31 + .../go.uber.org/zap/internal/color/color.go | 44 + vendor/go.uber.org/zap/internal/exit/exit.go | 64 + vendor/go.uber.org/zap/level.go | 132 + vendor/go.uber.org/zap/logger.go | 311 ++ vendor/go.uber.org/zap/options.go | 133 + vendor/go.uber.org/zap/sink.go | 161 + vendor/go.uber.org/zap/stacktrace.go | 126 + vendor/go.uber.org/zap/sugar.go | 304 ++ vendor/go.uber.org/zap/time.go | 27 + vendor/go.uber.org/zap/writer.go | 99 + .../zap/zapcore/console_encoder.go | 147 + vendor/go.uber.org/zap/zapcore/core.go | 113 + vendor/go.uber.org/zap/zapcore/doc.go | 24 + vendor/go.uber.org/zap/zapcore/encoder.go | 401 +++ vendor/go.uber.org/zap/zapcore/entry.go | 258 ++ vendor/go.uber.org/zap/zapcore/error.go | 115 + vendor/go.uber.org/zap/zapcore/field.go | 217 ++ vendor/go.uber.org/zap/zapcore/hook.go | 68 + .../go.uber.org/zap/zapcore/increase_level.go | 66 + .../go.uber.org/zap/zapcore/json_encoder.go | 524 +++ vendor/go.uber.org/zap/zapcore/level.go | 175 + .../go.uber.org/zap/zapcore/level_strings.go | 46 + vendor/go.uber.org/zap/zapcore/marshaler.go | 53 + .../go.uber.org/zap/zapcore/memory_encoder.go | 179 + vendor/go.uber.org/zap/zapcore/sampler.go | 208 ++ vendor/go.uber.org/zap/zapcore/tee.go | 81 + .../go.uber.org/zap/zapcore/write_syncer.go | 123 + 574 files changed, 70201 insertions(+) create mode 100644 vendor/github.com/gogo/protobuf/AUTHORS create mode 100644 vendor/github.com/gogo/protobuf/CONTRIBUTORS create mode 100644 vendor/github.com/gogo/protobuf/LICENSE create mode 100644 vendor/github.com/gogo/protobuf/proto/Makefile create mode 100644 vendor/github.com/gogo/protobuf/proto/clone.go create mode 100644 vendor/github.com/gogo/protobuf/proto/custom_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/decode.go create mode 100644 vendor/github.com/gogo/protobuf/proto/deprecated.go create mode 100644 vendor/github.com/gogo/protobuf/proto/discard.go create mode 100644 vendor/github.com/gogo/protobuf/proto/duration.go create mode 100644 vendor/github.com/gogo/protobuf/proto/duration_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/encode.go create mode 100644 vendor/github.com/gogo/protobuf/proto/encode_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/equal.go create mode 100644 vendor/github.com/gogo/protobuf/proto/extensions.go create mode 100644 vendor/github.com/gogo/protobuf/proto/extensions_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/lib.go create mode 100644 vendor/github.com/gogo/protobuf/proto/lib_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/message_set.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_reflect.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go create mode 100644 vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/properties.go create mode 100644 vendor/github.com/gogo/protobuf/proto/properties_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/skip_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/table_marshal.go create mode 100644 vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/table_merge.go create mode 100644 vendor/github.com/gogo/protobuf/proto/table_unmarshal.go create mode 100644 vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text_parser.go create mode 100644 vendor/github.com/gogo/protobuf/proto/timestamp.go create mode 100644 vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go create mode 100644 vendor/github.com/gogo/protobuf/proto/wrappers.go create mode 100644 vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go create mode 100644 vendor/github.com/ipfs/bbloom/.travis.yml create mode 100644 vendor/github.com/ipfs/bbloom/README.md create mode 100644 vendor/github.com/ipfs/bbloom/bbloom.go create mode 100644 vendor/github.com/ipfs/bbloom/go.mod create mode 100644 vendor/github.com/ipfs/bbloom/package.json create mode 100644 vendor/github.com/ipfs/bbloom/sipHash.go create mode 100644 vendor/github.com/ipfs/bbloom/words.txt create mode 100644 vendor/github.com/ipfs/go-block-format/.travis.yml create mode 100644 vendor/github.com/ipfs/go-block-format/LICENSE create mode 100644 vendor/github.com/ipfs/go-block-format/Makefile create mode 100644 vendor/github.com/ipfs/go-block-format/README.md create mode 100644 vendor/github.com/ipfs/go-block-format/blocks.go create mode 100644 vendor/github.com/ipfs/go-block-format/codecov.yml create mode 100644 vendor/github.com/ipfs/go-block-format/go.mod create mode 100644 vendor/github.com/ipfs/go-block-format/go.sum create mode 100644 vendor/github.com/ipfs/go-block-format/package.json create mode 100644 vendor/github.com/ipfs/go-blockservice/LICENSE create mode 100644 vendor/github.com/ipfs/go-blockservice/README.md create mode 100644 vendor/github.com/ipfs/go-blockservice/blockservice.go create mode 100644 vendor/github.com/ipfs/go-blockservice/go.mod create mode 100644 vendor/github.com/ipfs/go-blockservice/go.sum create mode 100644 vendor/github.com/ipfs/go-cid/.gitignore create mode 100644 vendor/github.com/ipfs/go-cid/.travis.yml create mode 100644 vendor/github.com/ipfs/go-cid/LICENSE create mode 100644 vendor/github.com/ipfs/go-cid/Makefile create mode 100644 vendor/github.com/ipfs/go-cid/README.md create mode 100644 vendor/github.com/ipfs/go-cid/builder.go create mode 100644 vendor/github.com/ipfs/go-cid/cid.go create mode 100644 vendor/github.com/ipfs/go-cid/cid_fuzz.go create mode 100644 vendor/github.com/ipfs/go-cid/codecov.yml create mode 100644 vendor/github.com/ipfs/go-cid/deprecated.go create mode 100644 vendor/github.com/ipfs/go-cid/go.mod create mode 100644 vendor/github.com/ipfs/go-cid/go.sum create mode 100644 vendor/github.com/ipfs/go-cid/package.json create mode 100644 vendor/github.com/ipfs/go-cid/set.go create mode 100644 vendor/github.com/ipfs/go-cid/varint.go create mode 100644 vendor/github.com/ipfs/go-datastore/.gitignore create mode 100644 vendor/github.com/ipfs/go-datastore/LICENSE create mode 100644 vendor/github.com/ipfs/go-datastore/Makefile create mode 100644 vendor/github.com/ipfs/go-datastore/README.md create mode 100644 vendor/github.com/ipfs/go-datastore/basic_ds.go create mode 100644 vendor/github.com/ipfs/go-datastore/batch.go create mode 100644 vendor/github.com/ipfs/go-datastore/datastore.go create mode 100644 vendor/github.com/ipfs/go-datastore/go.mod create mode 100644 vendor/github.com/ipfs/go-datastore/go.sum create mode 100644 vendor/github.com/ipfs/go-datastore/key.go create mode 100644 vendor/github.com/ipfs/go-datastore/keytransform/doc.go create mode 100644 vendor/github.com/ipfs/go-datastore/keytransform/interface.go create mode 100644 vendor/github.com/ipfs/go-datastore/keytransform/keytransform.go create mode 100644 vendor/github.com/ipfs/go-datastore/keytransform/transforms.go create mode 100644 vendor/github.com/ipfs/go-datastore/namespace/doc.go create mode 100644 vendor/github.com/ipfs/go-datastore/namespace/namespace.go create mode 100644 vendor/github.com/ipfs/go-datastore/query/filter.go create mode 100644 vendor/github.com/ipfs/go-datastore/query/order.go create mode 100644 vendor/github.com/ipfs/go-datastore/query/query.go create mode 100644 vendor/github.com/ipfs/go-datastore/query/query_impl.go create mode 100644 vendor/github.com/ipfs/go-filestore/LICENSE-APACHE create mode 100644 vendor/github.com/ipfs/go-filestore/LICENSE-MIT create mode 100644 vendor/github.com/ipfs/go-filestore/README.md create mode 100644 vendor/github.com/ipfs/go-filestore/filestore.go create mode 100644 vendor/github.com/ipfs/go-filestore/fsrefstore.go create mode 100644 vendor/github.com/ipfs/go-filestore/go.mod create mode 100644 vendor/github.com/ipfs/go-filestore/go.sum create mode 100644 vendor/github.com/ipfs/go-filestore/pb/Rules.mk create mode 100644 vendor/github.com/ipfs/go-filestore/pb/dataobj.pb.go create mode 100644 vendor/github.com/ipfs/go-filestore/pb/dataobj.proto create mode 100644 vendor/github.com/ipfs/go-filestore/util.go create mode 100644 vendor/github.com/ipfs/go-graphsync/.golangci.yml create mode 100644 vendor/github.com/ipfs/go-graphsync/COPYRIGHT create mode 100644 vendor/github.com/ipfs/go-graphsync/LICENSE-APACHE create mode 100644 vendor/github.com/ipfs/go-graphsync/LICENSE-MIT create mode 100644 vendor/github.com/ipfs/go-graphsync/README.md create mode 100644 vendor/github.com/ipfs/go-graphsync/go.mod create mode 100644 vendor/github.com/ipfs/go-graphsync/go.sum create mode 100644 vendor/github.com/ipfs/go-graphsync/graphsync.go create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/.gitignore create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/.travis.yml create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/LICENSE create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/Makefile create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/README.md create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/cbor_gen.go create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/codecov.yml create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/go.mod create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/go.sum create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/hamt.go create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/hash.go create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/pointer_cbor.go create mode 100644 vendor/github.com/ipfs/go-hamt-ipld/uhamt.go create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/.travis.yml create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/LICENSE create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/README.md create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/arc_cache.go create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/blockstore.go create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/bloom_cache.go create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/caching.go create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/go.mod create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/go.sum create mode 100644 vendor/github.com/ipfs/go-ipfs-blockstore/idstore.go create mode 100644 vendor/github.com/ipfs/go-ipfs-ds-help/.travis.yml create mode 100644 vendor/github.com/ipfs/go-ipfs-ds-help/LICENSE create mode 100644 vendor/github.com/ipfs/go-ipfs-ds-help/Makefile create mode 100644 vendor/github.com/ipfs/go-ipfs-ds-help/README.md create mode 100644 vendor/github.com/ipfs/go-ipfs-ds-help/go.mod create mode 100644 vendor/github.com/ipfs/go-ipfs-ds-help/go.sum create mode 100644 vendor/github.com/ipfs/go-ipfs-ds-help/key.go create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/.travis.yml create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/LICENSE create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/Makefile create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/README.md create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/go.mod create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/go.sum create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/interface.go create mode 100644 vendor/github.com/ipfs/go-ipfs-exchange-interface/package.json create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/.gitignore create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/.travis.yml create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/LICENSE create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/Makefile create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/README.md create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/go.mod create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/go.sum create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/package.json create mode 100644 vendor/github.com/ipfs/go-ipfs-posinfo/posinfo.go create mode 100644 vendor/github.com/ipfs/go-ipfs-util/.gitignore create mode 100644 vendor/github.com/ipfs/go-ipfs-util/.travis.yml create mode 100644 vendor/github.com/ipfs/go-ipfs-util/LICENSE create mode 100644 vendor/github.com/ipfs/go-ipfs-util/README.md create mode 100644 vendor/github.com/ipfs/go-ipfs-util/file.go create mode 100644 vendor/github.com/ipfs/go-ipfs-util/go.mod create mode 100644 vendor/github.com/ipfs/go-ipfs-util/go.sum create mode 100644 vendor/github.com/ipfs/go-ipfs-util/package.json create mode 100644 vendor/github.com/ipfs/go-ipfs-util/time.go create mode 100644 vendor/github.com/ipfs/go-ipfs-util/util.go create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/.travis.yml create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/LICENSE create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/Makefile create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/README.md create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/codecov.yml create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/encoding/cloner.go create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/encoding/marshaller.go create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/encoding/unmarshaller.go create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/go.mod create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/go.sum create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/node.go create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/readable.go create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/refmt.go create mode 100644 vendor/github.com/ipfs/go-ipld-cbor/store.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/.travis.yml create mode 100644 vendor/github.com/ipfs/go-ipld-format/LICENSE create mode 100644 vendor/github.com/ipfs/go-ipld-format/Makefile create mode 100644 vendor/github.com/ipfs/go-ipld-format/README.md create mode 100644 vendor/github.com/ipfs/go-ipld-format/batch.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/codecov.yml create mode 100644 vendor/github.com/ipfs/go-ipld-format/coding.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/daghelpers.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/format.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/go.mod create mode 100644 vendor/github.com/ipfs/go-ipld-format/go.sum create mode 100644 vendor/github.com/ipfs/go-ipld-format/merkledag.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/navipld.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/promise.go create mode 100644 vendor/github.com/ipfs/go-ipld-format/walker.go create mode 100644 vendor/github.com/ipfs/go-log/.travis.yml create mode 100644 vendor/github.com/ipfs/go-log/LICENSE create mode 100644 vendor/github.com/ipfs/go-log/README.md create mode 100644 vendor/github.com/ipfs/go-log/context.go create mode 100644 vendor/github.com/ipfs/go-log/entry.go create mode 100644 vendor/github.com/ipfs/go-log/go.mod create mode 100644 vendor/github.com/ipfs/go-log/go.sum create mode 100644 vendor/github.com/ipfs/go-log/levels.go create mode 100644 vendor/github.com/ipfs/go-log/log.go create mode 100644 vendor/github.com/ipfs/go-log/loggable.go create mode 100644 vendor/github.com/ipfs/go-log/metadata.go create mode 100644 vendor/github.com/ipfs/go-log/oldlog.go create mode 100644 vendor/github.com/ipfs/go-log/package.json create mode 100644 vendor/github.com/ipfs/go-log/tracer/LICENSE create mode 100644 vendor/github.com/ipfs/go-log/tracer/context.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/debug.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/event.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/propagation.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/propagation_ot.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/raw.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/recorder.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/span.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/tracer.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/util.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/wire/Makefile create mode 100644 vendor/github.com/ipfs/go-log/tracer/wire/carrier.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/wire/gen.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/wire/wire.pb.go create mode 100644 vendor/github.com/ipfs/go-log/tracer/wire/wire.proto create mode 100644 vendor/github.com/ipfs/go-log/v2/LICENSE create mode 100644 vendor/github.com/ipfs/go-log/v2/README.md create mode 100644 vendor/github.com/ipfs/go-log/v2/core.go create mode 100644 vendor/github.com/ipfs/go-log/v2/go.mod create mode 100644 vendor/github.com/ipfs/go-log/v2/go.sum create mode 100644 vendor/github.com/ipfs/go-log/v2/levels.go create mode 100644 vendor/github.com/ipfs/go-log/v2/log.go create mode 100644 vendor/github.com/ipfs/go-log/v2/package.json create mode 100644 vendor/github.com/ipfs/go-log/v2/path_other.go create mode 100644 vendor/github.com/ipfs/go-log/v2/path_windows.go create mode 100644 vendor/github.com/ipfs/go-log/v2/pipe.go create mode 100644 vendor/github.com/ipfs/go-log/v2/setup.go create mode 100644 vendor/github.com/ipfs/go-log/writer/option.go create mode 100644 vendor/github.com/ipfs/go-log/writer/writer.go create mode 100644 vendor/github.com/ipfs/go-metrics-interface/.gitignore create mode 100644 vendor/github.com/ipfs/go-metrics-interface/.travis.yml create mode 100644 vendor/github.com/ipfs/go-metrics-interface/LICENSE create mode 100644 vendor/github.com/ipfs/go-metrics-interface/context.go create mode 100644 vendor/github.com/ipfs/go-metrics-interface/ctor.go create mode 100644 vendor/github.com/ipfs/go-metrics-interface/go.mod create mode 100644 vendor/github.com/ipfs/go-metrics-interface/interface.go create mode 100644 vendor/github.com/ipfs/go-metrics-interface/noop.go create mode 100644 vendor/github.com/ipfs/go-metrics-interface/package.json create mode 100644 vendor/github.com/ipfs/go-verifcid/.travis.yml create mode 100644 vendor/github.com/ipfs/go-verifcid/go.mod create mode 100644 vendor/github.com/ipfs/go-verifcid/go.sum create mode 100644 vendor/github.com/ipfs/go-verifcid/package.json create mode 100644 vendor/github.com/ipfs/go-verifcid/validate.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/.gitmodules create mode 100644 vendor/github.com/ipld/go-ipld-prime/.travis.yml create mode 100644 vendor/github.com/ipld/go-ipld-prime/HACKME.md create mode 100644 vendor/github.com/ipld/go-ipld-prime/HACKME_builderBehaviors.md create mode 100644 vendor/github.com/ipld/go-ipld-prime/LICENSE create mode 100644 vendor/github.com/ipld/go-ipld-prime/README.md create mode 100644 vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/common.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/marshal.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/multicodec.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/unmarshal.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/doc.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/errors.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/fluent/doc.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/fluent/fluentBuilder.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/fluent/fluentRecover.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/go.mod create mode 100644 vendor/github.com/ipld/go-ipld-prime/go.sum create mode 100644 vendor/github.com/ipld/go-ipld-prime/kind.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/linking.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/linking/cid/cidLink.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodec.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodecRegistry.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/module.tl create mode 100644 vendor/github.com/ipld/go-ipld-prime/node.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/HACKME.md create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/any.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/bool.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/bytes.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/float.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/int.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/link.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/list.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/map.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/string.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/basic/style.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/HACKME.md create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/boolMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/bytesMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/floatMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/intMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/linkMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/listMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/mapMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/stringMixin.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/node/mixins/tmplMixin.txt create mode 100644 vendor/github.com/ipld/go-ipld-prime/nodeBuilder.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/path.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/pathSegment.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/errors.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/kind.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/maybe.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/tmpBuilders.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/type.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/typeMethods.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/typedNode.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/typesystem.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/schema/validate.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/common.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/doc.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/fns.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/focus.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/builder/builder.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreAll.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreFields.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreIndex.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRange.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursive.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursiveEdge.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreUnion.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/fieldKeys.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/matcher.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/selector/selector.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/traversal/walk.go create mode 100644 vendor/github.com/ipld/go-ipld-prime/unit.go create mode 100644 vendor/github.com/libp2p/go-buffer-pool/.travis.yml create mode 100644 vendor/github.com/libp2p/go-buffer-pool/LICENSE create mode 100644 vendor/github.com/libp2p/go-buffer-pool/LICENSE-BSD create mode 100644 vendor/github.com/libp2p/go-buffer-pool/README.md create mode 100644 vendor/github.com/libp2p/go-buffer-pool/buffer.go create mode 100644 vendor/github.com/libp2p/go-buffer-pool/codecov.yml create mode 100644 vendor/github.com/libp2p/go-buffer-pool/go.mod create mode 100644 vendor/github.com/libp2p/go-buffer-pool/pool.go create mode 100644 vendor/github.com/libp2p/go-buffer-pool/writer.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/LICENSE create mode 100644 vendor/github.com/libp2p/go-libp2p-core/LICENSE-APACHE create mode 100644 vendor/github.com/libp2p/go-libp2p-core/LICENSE-MIT create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/ecdsa.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/ed25519.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/key.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/key_not_openssl.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/key_openssl.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/openssl_common.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/pb/Makefile create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.pb.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.proto create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_common.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_go.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_openssl.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/crypto/secp256k1.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo_serde.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/pb/Makefile create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.pb.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.proto create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/peer.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/peer_serde.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/record.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/peer/set.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/protocol/id.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/protocol/switch.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/record/envelope.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/record/pb/Makefile create mode 100644 vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.pb.go create mode 100644 vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.proto create mode 100644 vendor/github.com/libp2p/go-libp2p-core/record/record.go create mode 100644 vendor/github.com/libp2p/go-openssl/.gitignore create mode 100644 vendor/github.com/libp2p/go-openssl/AUTHORS create mode 100644 vendor/github.com/libp2p/go-openssl/LICENSE create mode 100644 vendor/github.com/libp2p/go-openssl/README.md create mode 100644 vendor/github.com/libp2p/go-openssl/bio.go create mode 100644 vendor/github.com/libp2p/go-openssl/build.go create mode 100644 vendor/github.com/libp2p/go-openssl/build_static.go create mode 100644 vendor/github.com/libp2p/go-openssl/cert.go create mode 100644 vendor/github.com/libp2p/go-openssl/ciphers.go create mode 100644 vendor/github.com/libp2p/go-openssl/ciphers_gcm.go create mode 100644 vendor/github.com/libp2p/go-openssl/conn.go create mode 100644 vendor/github.com/libp2p/go-openssl/ctx.go create mode 100644 vendor/github.com/libp2p/go-openssl/dh.go create mode 100644 vendor/github.com/libp2p/go-openssl/dhparam.go create mode 100644 vendor/github.com/libp2p/go-openssl/digest.go create mode 100644 vendor/github.com/libp2p/go-openssl/engine.go create mode 100644 vendor/github.com/libp2p/go-openssl/fips.go create mode 100644 vendor/github.com/libp2p/go-openssl/go.mod create mode 100644 vendor/github.com/libp2p/go-openssl/go.sum create mode 100644 vendor/github.com/libp2p/go-openssl/hmac.go create mode 100644 vendor/github.com/libp2p/go-openssl/hostname.c create mode 100644 vendor/github.com/libp2p/go-openssl/hostname.go create mode 100644 vendor/github.com/libp2p/go-openssl/http.go create mode 100644 vendor/github.com/libp2p/go-openssl/init.go create mode 100644 vendor/github.com/libp2p/go-openssl/init_posix.go create mode 100644 vendor/github.com/libp2p/go-openssl/init_windows.go create mode 100644 vendor/github.com/libp2p/go-openssl/key.go create mode 100644 vendor/github.com/libp2p/go-openssl/mapping.go create mode 100644 vendor/github.com/libp2p/go-openssl/md4.go create mode 100644 vendor/github.com/libp2p/go-openssl/md5.go create mode 100644 vendor/github.com/libp2p/go-openssl/net.go create mode 100644 vendor/github.com/libp2p/go-openssl/nid.go create mode 100644 vendor/github.com/libp2p/go-openssl/object.go create mode 100644 vendor/github.com/libp2p/go-openssl/pem.go create mode 100644 vendor/github.com/libp2p/go-openssl/sha1.go create mode 100644 vendor/github.com/libp2p/go-openssl/sha256.go create mode 100644 vendor/github.com/libp2p/go-openssl/shim.c create mode 100644 vendor/github.com/libp2p/go-openssl/shim.h create mode 100644 vendor/github.com/libp2p/go-openssl/sni.c create mode 100644 vendor/github.com/libp2p/go-openssl/ssl.go create mode 100644 vendor/github.com/libp2p/go-openssl/tickets.go create mode 100644 vendor/github.com/libp2p/go-openssl/utils/errors.go create mode 100644 vendor/github.com/libp2p/go-openssl/utils/future.go create mode 100644 vendor/github.com/multiformats/go-base32/LICENSE create mode 100644 vendor/github.com/multiformats/go-base32/base32.go create mode 100644 vendor/github.com/multiformats/go-base32/go.mod create mode 100644 vendor/github.com/multiformats/go-base32/package.json create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/.gitignore create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/.travis.yml create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/LICENSE create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/README.md create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/dns.go create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/go.mod create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/go.sum create mode 100644 vendor/github.com/multiformats/go-multiaddr-dns/resolve.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/.gitignore create mode 100644 vendor/github.com/multiformats/go-multiaddr/.travis.yml create mode 100644 vendor/github.com/multiformats/go-multiaddr/LICENSE create mode 100644 vendor/github.com/multiformats/go-multiaddr/Makefile create mode 100644 vendor/github.com/multiformats/go-multiaddr/README.md create mode 100644 vendor/github.com/multiformats/go-multiaddr/codec.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/codecov.yml create mode 100644 vendor/github.com/multiformats/go-multiaddr/component.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/doc.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/filter.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/go.mod create mode 100644 vendor/github.com/multiformats/go-multiaddr/go.sum create mode 100644 vendor/github.com/multiformats/go-multiaddr/interface.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/multiaddr.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/package.json create mode 100644 vendor/github.com/multiformats/go-multiaddr/protocol.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/protocols.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/transcoders.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/util.go create mode 100644 vendor/github.com/multiformats/go-multiaddr/varint.go create mode 100644 vendor/github.com/multiformats/go-multibase/.codecov.yml create mode 100644 vendor/github.com/multiformats/go-multibase/.gitignore create mode 100644 vendor/github.com/multiformats/go-multibase/.gitmodules create mode 100644 vendor/github.com/multiformats/go-multibase/.gxignore create mode 100644 vendor/github.com/multiformats/go-multibase/.travis.yml create mode 100644 vendor/github.com/multiformats/go-multibase/LICENSE create mode 100644 vendor/github.com/multiformats/go-multibase/Makefile create mode 100644 vendor/github.com/multiformats/go-multibase/README.md create mode 100644 vendor/github.com/multiformats/go-multibase/base16.go create mode 100644 vendor/github.com/multiformats/go-multibase/base2.go create mode 100644 vendor/github.com/multiformats/go-multibase/base32.go create mode 100644 vendor/github.com/multiformats/go-multibase/encoder.go create mode 100644 vendor/github.com/multiformats/go-multibase/go.mod create mode 100644 vendor/github.com/multiformats/go-multibase/go.sum create mode 100644 vendor/github.com/multiformats/go-multibase/multibase.go create mode 100644 vendor/github.com/multiformats/go-multibase/package.json create mode 100644 vendor/github.com/multiformats/go-multihash/.gitignore create mode 100644 vendor/github.com/multiformats/go-multihash/.gitmodules create mode 100644 vendor/github.com/multiformats/go-multihash/.travis.yml create mode 100644 vendor/github.com/multiformats/go-multihash/LICENSE create mode 100644 vendor/github.com/multiformats/go-multihash/Makefile create mode 100644 vendor/github.com/multiformats/go-multihash/README.md create mode 100644 vendor/github.com/multiformats/go-multihash/codecov.yml create mode 100644 vendor/github.com/multiformats/go-multihash/go.mod create mode 100644 vendor/github.com/multiformats/go-multihash/go.sum create mode 100644 vendor/github.com/multiformats/go-multihash/io.go create mode 100644 vendor/github.com/multiformats/go-multihash/multihash.go create mode 100644 vendor/github.com/multiformats/go-multihash/set.go create mode 100644 vendor/github.com/multiformats/go-multihash/sum.go create mode 100644 vendor/github.com/multiformats/go-varint/.travis.yml create mode 100644 vendor/github.com/multiformats/go-varint/LICENSE create mode 100644 vendor/github.com/multiformats/go-varint/README.md create mode 100644 vendor/github.com/multiformats/go-varint/codecov.yml create mode 100644 vendor/github.com/multiformats/go-varint/go.mod create mode 100644 vendor/github.com/multiformats/go-varint/varint.go create mode 100644 vendor/github.com/whyrusleeping/bencher/LICENSE-MIT create mode 100644 vendor/github.com/whyrusleeping/bencher/README.md create mode 100644 vendor/github.com/whyrusleeping/bencher/go.mod create mode 100644 vendor/github.com/whyrusleeping/bencher/go.sum create mode 100644 vendor/github.com/whyrusleeping/bencher/main.go create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/Makefile create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/README.md create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/cbor_cid.go create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/gen.go create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/go.mod create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/go.sum create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/utils.go create mode 100644 vendor/github.com/whyrusleeping/cbor-gen/writefile.go create mode 100644 vendor/go.uber.org/atomic/.codecov.yml create mode 100644 vendor/go.uber.org/atomic/.gitignore create mode 100644 vendor/go.uber.org/atomic/.travis.yml create mode 100644 vendor/go.uber.org/atomic/CHANGELOG.md create mode 100644 vendor/go.uber.org/atomic/LICENSE.txt create mode 100644 vendor/go.uber.org/atomic/Makefile create mode 100644 vendor/go.uber.org/atomic/README.md create mode 100644 vendor/go.uber.org/atomic/atomic.go create mode 100644 vendor/go.uber.org/atomic/error.go create mode 100644 vendor/go.uber.org/atomic/go.mod create mode 100644 vendor/go.uber.org/atomic/go.sum create mode 100644 vendor/go.uber.org/atomic/string.go create mode 100644 vendor/go.uber.org/multierr/.codecov.yml create mode 100644 vendor/go.uber.org/multierr/.gitignore create mode 100644 vendor/go.uber.org/multierr/.travis.yml create mode 100644 vendor/go.uber.org/multierr/CHANGELOG.md create mode 100644 vendor/go.uber.org/multierr/LICENSE.txt create mode 100644 vendor/go.uber.org/multierr/Makefile create mode 100644 vendor/go.uber.org/multierr/README.md create mode 100644 vendor/go.uber.org/multierr/error.go create mode 100644 vendor/go.uber.org/multierr/glide.yaml create mode 100644 vendor/go.uber.org/multierr/go.mod create mode 100644 vendor/go.uber.org/multierr/go.sum create mode 100644 vendor/go.uber.org/multierr/go113.go create mode 100644 vendor/go.uber.org/zap/.codecov.yml create mode 100644 vendor/go.uber.org/zap/.gitignore create mode 100644 vendor/go.uber.org/zap/.readme.tmpl create mode 100644 vendor/go.uber.org/zap/.travis.yml create mode 100644 vendor/go.uber.org/zap/CHANGELOG.md create mode 100644 vendor/go.uber.org/zap/CODE_OF_CONDUCT.md create mode 100644 vendor/go.uber.org/zap/CONTRIBUTING.md create mode 100644 vendor/go.uber.org/zap/FAQ.md create mode 100644 vendor/go.uber.org/zap/LICENSE.txt create mode 100644 vendor/go.uber.org/zap/Makefile create mode 100644 vendor/go.uber.org/zap/README.md create mode 100644 vendor/go.uber.org/zap/array.go create mode 100644 vendor/go.uber.org/zap/buffer/buffer.go create mode 100644 vendor/go.uber.org/zap/buffer/pool.go create mode 100644 vendor/go.uber.org/zap/checklicense.sh create mode 100644 vendor/go.uber.org/zap/config.go create mode 100644 vendor/go.uber.org/zap/doc.go create mode 100644 vendor/go.uber.org/zap/encoder.go create mode 100644 vendor/go.uber.org/zap/error.go create mode 100644 vendor/go.uber.org/zap/field.go create mode 100644 vendor/go.uber.org/zap/flag.go create mode 100644 vendor/go.uber.org/zap/glide.yaml create mode 100644 vendor/go.uber.org/zap/global.go create mode 100644 vendor/go.uber.org/zap/global_go112.go create mode 100644 vendor/go.uber.org/zap/global_prego112.go create mode 100644 vendor/go.uber.org/zap/go.mod create mode 100644 vendor/go.uber.org/zap/go.sum create mode 100644 vendor/go.uber.org/zap/http_handler.go create mode 100644 vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go create mode 100644 vendor/go.uber.org/zap/internal/color/color.go create mode 100644 vendor/go.uber.org/zap/internal/exit/exit.go create mode 100644 vendor/go.uber.org/zap/level.go create mode 100644 vendor/go.uber.org/zap/logger.go create mode 100644 vendor/go.uber.org/zap/options.go create mode 100644 vendor/go.uber.org/zap/sink.go create mode 100644 vendor/go.uber.org/zap/stacktrace.go create mode 100644 vendor/go.uber.org/zap/sugar.go create mode 100644 vendor/go.uber.org/zap/time.go create mode 100644 vendor/go.uber.org/zap/writer.go create mode 100644 vendor/go.uber.org/zap/zapcore/console_encoder.go create mode 100644 vendor/go.uber.org/zap/zapcore/core.go create mode 100644 vendor/go.uber.org/zap/zapcore/doc.go create mode 100644 vendor/go.uber.org/zap/zapcore/encoder.go create mode 100644 vendor/go.uber.org/zap/zapcore/entry.go create mode 100644 vendor/go.uber.org/zap/zapcore/error.go create mode 100644 vendor/go.uber.org/zap/zapcore/field.go create mode 100644 vendor/go.uber.org/zap/zapcore/hook.go create mode 100644 vendor/go.uber.org/zap/zapcore/increase_level.go create mode 100644 vendor/go.uber.org/zap/zapcore/json_encoder.go create mode 100644 vendor/go.uber.org/zap/zapcore/level.go create mode 100644 vendor/go.uber.org/zap/zapcore/level_strings.go create mode 100644 vendor/go.uber.org/zap/zapcore/marshaler.go create mode 100644 vendor/go.uber.org/zap/zapcore/memory_encoder.go create mode 100644 vendor/go.uber.org/zap/zapcore/sampler.go create mode 100644 vendor/go.uber.org/zap/zapcore/tee.go create mode 100644 vendor/go.uber.org/zap/zapcore/write_syncer.go diff --git a/vendor/github.com/gogo/protobuf/AUTHORS b/vendor/github.com/gogo/protobuf/AUTHORS new file mode 100644 index 0000000000..3d97fc7a29 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of GoGo authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS file, which +# lists people. For example, employees are listed in CONTRIBUTORS, +# but not in AUTHORS, because the employer holds the copyright. + +# Names should be added to this file as one of +# Organization's name +# Individual's name +# Individual's name + +# Please keep the list sorted. + +Sendgrid, Inc +Vastech SA (PTY) LTD +Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/CONTRIBUTORS b/vendor/github.com/gogo/protobuf/CONTRIBUTORS new file mode 100644 index 0000000000..1b4f6c208a --- /dev/null +++ b/vendor/github.com/gogo/protobuf/CONTRIBUTORS @@ -0,0 +1,23 @@ +Anton Povarov +Brian Goff +Clayton Coleman +Denis Smirnov +DongYun Kang +Dwayne Schultz +Georg Apitz +Gustav Paul +Johan Brandhorst +John Shahid +John Tuley +Laurent +Patrick Lee +Peter Edge +Roger Johansson +Sam Nguyen +Sergio Arbeo +Stephen J Day +Tamir Duberstein +Todd Eisenberger +Tormod Erevik Lea +Vyacheslav Kim +Walter Schulze diff --git a/vendor/github.com/gogo/protobuf/LICENSE b/vendor/github.com/gogo/protobuf/LICENSE new file mode 100644 index 0000000000..f57de90da8 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/LICENSE @@ -0,0 +1,35 @@ +Copyright (c) 2013, The GoGo Authors. All rights reserved. + +Protocol Buffers for Go with Gadgets + +Go support for Protocol Buffers - Google's data interchange format + +Copyright 2010 The Go Authors. All rights reserved. +https://github.com/golang/protobuf + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/github.com/gogo/protobuf/proto/Makefile b/vendor/github.com/gogo/protobuf/proto/Makefile new file mode 100644 index 0000000000..00d65f3277 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/Makefile @@ -0,0 +1,43 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +install: + go install + +test: install generate-test-pbs + go test + + +generate-test-pbs: + make install + make -C test_proto + make -C proto3_proto + make diff --git a/vendor/github.com/gogo/protobuf/proto/clone.go b/vendor/github.com/gogo/protobuf/proto/clone.go new file mode 100644 index 0000000000..a26b046d94 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/clone.go @@ -0,0 +1,258 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer deep copy and merge. +// TODO: RawMessage. + +package proto + +import ( + "fmt" + "log" + "reflect" + "strings" +) + +// Clone returns a deep copy of a protocol buffer. +func Clone(src Message) Message { + in := reflect.ValueOf(src) + if in.IsNil() { + return src + } + out := reflect.New(in.Type().Elem()) + dst := out.Interface().(Message) + Merge(dst, src) + return dst +} + +// Merger is the interface representing objects that can merge messages of the same type. +type Merger interface { + // Merge merges src into this message. + // Required and optional fields that are set in src will be set to that value in dst. + // Elements of repeated fields will be appended. + // + // Merge may panic if called with a different argument type than the receiver. + Merge(src Message) +} + +// generatedMerger is the custom merge method that generated protos will have. +// We must add this method since a generate Merge method will conflict with +// many existing protos that have a Merge data field already defined. +type generatedMerger interface { + XXX_Merge(src Message) +} + +// Merge merges src into dst. +// Required and optional fields that are set in src will be set to that value in dst. +// Elements of repeated fields will be appended. +// Merge panics if src and dst are not the same type, or if dst is nil. +func Merge(dst, src Message) { + if m, ok := dst.(Merger); ok { + m.Merge(src) + return + } + + in := reflect.ValueOf(src) + out := reflect.ValueOf(dst) + if out.IsNil() { + panic("proto: nil destination") + } + if in.Type() != out.Type() { + panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) + } + if in.IsNil() { + return // Merge from nil src is a noop + } + if m, ok := dst.(generatedMerger); ok { + m.XXX_Merge(src) + return + } + mergeStruct(out.Elem(), in.Elem()) +} + +func mergeStruct(out, in reflect.Value) { + sprop := GetProperties(in.Type()) + for i := 0; i < in.NumField(); i++ { + f := in.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) + } + + if emIn, ok := in.Addr().Interface().(extensionsBytes); ok { + emOut := out.Addr().Interface().(extensionsBytes) + bIn := emIn.GetExtensions() + bOut := emOut.GetExtensions() + *bOut = append(*bOut, *bIn...) + } else if emIn, err := extendable(in.Addr().Interface()); err == nil { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + uf := in.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return + } + uin := uf.Bytes() + if len(uin) > 0 { + out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) + } +} + +// mergeAny performs a merge between two values of the same type. +// viaPtr indicates whether the values were indirected through a pointer (implying proto2). +// prop is set if this is a struct field (it may be nil). +func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { + if in.Type() == protoMessageType { + if !in.IsNil() { + if out.IsNil() { + out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) + } else { + Merge(out.Interface().(Message), in.Interface().(Message)) + } + } + return + } + switch in.Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + if !viaPtr && isProto3Zero(in) { + return + } + out.Set(in) + case reflect.Interface: + // Probably a oneof field; copy non-nil values. + if in.IsNil() { + return + } + // Allocate destination if it is not set, or set to a different type. + // Otherwise we will merge as normal. + if out.IsNil() || out.Elem().Type() != in.Elem().Type() { + out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) + } + mergeAny(out.Elem(), in.Elem(), false, nil) + case reflect.Map: + if in.Len() == 0 { + return + } + if out.IsNil() { + out.Set(reflect.MakeMap(in.Type())) + } + // For maps with value types of *T or []byte we need to deep copy each value. + elemKind := in.Type().Elem().Kind() + for _, key := range in.MapKeys() { + var val reflect.Value + switch elemKind { + case reflect.Ptr: + val = reflect.New(in.Type().Elem().Elem()) + mergeAny(val, in.MapIndex(key), false, nil) + case reflect.Slice: + val = in.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + default: + val = in.MapIndex(key) + } + out.SetMapIndex(key, val) + } + case reflect.Ptr: + if in.IsNil() { + return + } + if out.IsNil() { + out.Set(reflect.New(in.Elem().Type())) + } + mergeAny(out.Elem(), in.Elem(), true, nil) + case reflect.Slice: + if in.IsNil() { + return + } + if in.Type().Elem().Kind() == reflect.Uint8 { + // []byte is a scalar bytes field, not a repeated field. + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value, and should not + // be merged. + if prop != nil && prop.proto3 && in.Len() == 0 { + return + } + + // Make a deep copy. + // Append to []byte{} instead of []byte(nil) so that we never end up + // with a nil result. + out.SetBytes(append([]byte{}, in.Bytes()...)) + return + } + n := in.Len() + if out.IsNil() { + out.Set(reflect.MakeSlice(in.Type(), 0, n)) + } + switch in.Type().Elem().Kind() { + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, + reflect.String, reflect.Uint32, reflect.Uint64: + out.Set(reflect.AppendSlice(out, in)) + default: + for i := 0; i < n; i++ { + x := reflect.Indirect(reflect.New(in.Type().Elem())) + mergeAny(x, in.Index(i), false, nil) + out.Set(reflect.Append(out, x)) + } + } + case reflect.Struct: + mergeStruct(out, in) + default: + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to copy %v", in) + } +} + +func mergeExtension(out, in map[int32]Extension) { + for extNum, eIn := range in { + eOut := Extension{desc: eIn.desc} + if eIn.value != nil { + v := reflect.New(reflect.TypeOf(eIn.value)).Elem() + mergeAny(v, reflect.ValueOf(eIn.value), false, nil) + eOut.value = v.Interface() + } + if eIn.enc != nil { + eOut.enc = make([]byte, len(eIn.enc)) + copy(eOut.enc, eIn.enc) + } + + out[extNum] = eOut + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/custom_gogo.go b/vendor/github.com/gogo/protobuf/proto/custom_gogo.go new file mode 100644 index 0000000000..24552483c6 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/custom_gogo.go @@ -0,0 +1,39 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import "reflect" + +type custom interface { + Marshal() ([]byte, error) + Unmarshal(data []byte) error + Size() int +} + +var customType = reflect.TypeOf((*custom)(nil)).Elem() diff --git a/vendor/github.com/gogo/protobuf/proto/decode.go b/vendor/github.com/gogo/protobuf/proto/decode.go new file mode 100644 index 0000000000..63b0f08bef --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/decode.go @@ -0,0 +1,427 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for decoding protocol buffer data to construct in-memory representations. + */ + +import ( + "errors" + "fmt" + "io" +) + +// errOverflow is returned when an integer is too large to be represented. +var errOverflow = errors.New("proto: integer overflow") + +// ErrInternalBadWireType is returned by generated code when an incorrect +// wire type is encountered. It does not get returned to user code. +var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") + +// DecodeVarint reads a varint-encoded integer from the slice. +// It returns the integer and the number of bytes consumed, or +// zero if there is not enough. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func DecodeVarint(buf []byte) (x uint64, n int) { + for shift := uint(0); shift < 64; shift += 7 { + if n >= len(buf) { + return 0, 0 + } + b := uint64(buf[n]) + n++ + x |= (b & 0x7F) << shift + if (b & 0x80) == 0 { + return x, n + } + } + + // The number is too large to represent in a 64-bit value. + return 0, 0 +} + +func (p *Buffer) decodeVarintSlow() (x uint64, err error) { + i := p.index + l := len(p.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := p.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + p.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = errOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) DecodeVarint() (x uint64, err error) { + i := p.index + buf := p.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + p.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return p.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x = uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + + return 0, errOverflow + +done: + p.index = i + return x, nil +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := p.index + 8 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-8]) + x |= uint64(p.buf[i-7]) << 8 + x |= uint64(p.buf[i-6]) << 16 + x |= uint64(p.buf[i-5]) << 24 + x |= uint64(p.buf[i-4]) << 32 + x |= uint64(p.buf[i-3]) << 40 + x |= uint64(p.buf[i-2]) << 48 + x |= uint64(p.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := p.index + 4 + if i < 0 || i > len(p.buf) { + err = io.ErrUnexpectedEOF + return + } + p.index = i + + x = uint64(p.buf[i-4]) + x |= uint64(p.buf[i-3]) << 8 + x |= uint64(p.buf[i-2]) << 16 + x |= uint64(p.buf[i-1]) << 24 + return +} + +// DecodeZigzag64 reads a zigzag-encoded 64-bit integer +// from the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) DecodeZigzag64() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) + return +} + +// DecodeZigzag32 reads a zigzag-encoded 32-bit integer +// from the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) DecodeZigzag32() (x uint64, err error) { + x, err = p.DecodeVarint() + if err != nil { + return + } + x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31)) + return +} + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := p.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := p.index + nb + if end < p.index || end > len(p.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + // todo: check if can get more uses of alloc=false + buf = p.buf[p.index:end] + p.index += nb + return + } + + buf = make([]byte, nb) + copy(buf, p.buf[p.index:]) + p.index += nb + return +} + +// DecodeStringBytes reads an encoded string from the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) DecodeStringBytes() (s string, err error) { + buf, err := p.DecodeRawBytes(false) + if err != nil { + return + } + return string(buf), nil +} + +// Unmarshaler is the interface representing objects that can +// unmarshal themselves. The argument points to data that may be +// overwritten, so implementations should not keep references to the +// buffer. +// Unmarshal implementations should not clear the receiver. +// Any unmarshaled data should be merged into the receiver. +// Callers of Unmarshal that do not want to retain existing data +// should Reset the receiver before calling Unmarshal. +type Unmarshaler interface { + Unmarshal([]byte) error +} + +// newUnmarshaler is the interface representing objects that can +// unmarshal themselves. The semantics are identical to Unmarshaler. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newUnmarshaler interface { + XXX_Unmarshal([]byte) error +} + +// Unmarshal parses the protocol buffer representation in buf and places the +// decoded result in pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// Unmarshal resets pb before starting to unmarshal, so any +// existing data in pb is always removed. Use UnmarshalMerge +// to preserve and append to existing data. +func Unmarshal(buf []byte, pb Message) error { + pb.Reset() + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } + if u, ok := pb.(Unmarshaler); ok { + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// UnmarshalMerge parses the protocol buffer representation in buf and +// writes the decoded result to pb. If the struct underlying pb does not match +// the data in buf, the results can be unpredictable. +// +// UnmarshalMerge merges into existing data in pb. +// Most code should use Unmarshal instead. +func UnmarshalMerge(buf []byte, pb Message) error { + if u, ok := pb.(newUnmarshaler); ok { + return u.XXX_Unmarshal(buf) + } + if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 + return u.Unmarshal(buf) + } + return NewBuffer(buf).Unmarshal(pb) +} + +// DecodeMessage reads a count-delimited message from the Buffer. +func (p *Buffer) DecodeMessage(pb Message) error { + enc, err := p.DecodeRawBytes(false) + if err != nil { + return err + } + return NewBuffer(enc).Unmarshal(pb) +} + +// DecodeGroup reads a tag-delimited group from the Buffer. +// StartGroup tag is already consumed. This function consumes +// EndGroup tag. +func (p *Buffer) DecodeGroup(pb Message) error { + b := p.buf[p.index:] + x, y := findEndGroup(b) + if x < 0 { + return io.ErrUnexpectedEOF + } + err := Unmarshal(b[:x], pb) + p.index += y + return err +} + +// Unmarshal parses the protocol buffer representation in the +// Buffer and places the decoded result in pb. If the struct +// underlying pb does not match the data in the buffer, the results can be +// unpredictable. +// +// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal. +func (p *Buffer) Unmarshal(pb Message) error { + // If the object can unmarshal itself, let it. + if u, ok := pb.(newUnmarshaler); ok { + err := u.XXX_Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + if u, ok := pb.(Unmarshaler); ok { + // NOTE: The history of proto have unfortunately been inconsistent + // whether Unmarshaler should or should not implicitly clear itself. + // Some implementations do, most do not. + // Thus, calling this here may or may not do what people want. + // + // See https://github.com/golang/protobuf/issues/424 + err := u.Unmarshal(p.buf[p.index:]) + p.index = len(p.buf) + return err + } + + // Slow workaround for messages that aren't Unmarshalers. + // This includes some hand-coded .pb.go files and + // bootstrap protos. + // TODO: fix all of those and then add Unmarshal to + // the Message interface. Then: + // The cast above and code below can be deleted. + // The old unmarshaler can be deleted. + // Clients can call Unmarshal directly (can already do that, actually). + var info InternalMessageInfo + err := info.Unmarshal(pb, p.buf[p.index:]) + p.index = len(p.buf) + return err +} diff --git a/vendor/github.com/gogo/protobuf/proto/deprecated.go b/vendor/github.com/gogo/protobuf/proto/deprecated.go new file mode 100644 index 0000000000..35b882c09a --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/deprecated.go @@ -0,0 +1,63 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2018 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import "errors" + +// Deprecated: do not use. +type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } + +// Deprecated: do not use. +func GetStats() Stats { return Stats{} } + +// Deprecated: do not use. +func MarshalMessageSet(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSet([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func MarshalMessageSetJSON(interface{}) ([]byte, error) { + return nil, errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func UnmarshalMessageSetJSON([]byte, interface{}) error { + return errors.New("proto: not implemented") +} + +// Deprecated: do not use. +func RegisterMessageSetType(Message, int32, string) {} diff --git a/vendor/github.com/gogo/protobuf/proto/discard.go b/vendor/github.com/gogo/protobuf/proto/discard.go new file mode 100644 index 0000000000..fe1bd7d904 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/discard.go @@ -0,0 +1,350 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +type generatedDiscarder interface { + XXX_DiscardUnknown() +} + +// DiscardUnknown recursively discards all unknown fields from this message +// and all embedded messages. +// +// When unmarshaling a message with unrecognized fields, the tags and values +// of such fields are preserved in the Message. This allows a later call to +// marshal to be able to produce a message that continues to have those +// unrecognized fields. To avoid this, DiscardUnknown is used to +// explicitly clear the unknown fields after unmarshaling. +// +// For proto2 messages, the unknown fields of message extensions are only +// discarded from messages that have been accessed via GetExtension. +func DiscardUnknown(m Message) { + if m, ok := m.(generatedDiscarder); ok { + m.XXX_DiscardUnknown() + return + } + // TODO: Dynamically populate a InternalMessageInfo for legacy messages, + // but the master branch has no implementation for InternalMessageInfo, + // so it would be more work to replicate that approach. + discardLegacy(m) +} + +// DiscardUnknown recursively discards all unknown fields. +func (a *InternalMessageInfo) DiscardUnknown(m Message) { + di := atomicLoadDiscardInfo(&a.discard) + if di == nil { + di = getDiscardInfo(reflect.TypeOf(m).Elem()) + atomicStoreDiscardInfo(&a.discard, di) + } + di.discard(toPointer(&m)) +} + +type discardInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []discardFieldInfo + unrecognized field +} + +type discardFieldInfo struct { + field field // Offset of field, guaranteed to be valid + discard func(src pointer) +} + +var ( + discardInfoMap = map[reflect.Type]*discardInfo{} + discardInfoLock sync.Mutex +) + +func getDiscardInfo(t reflect.Type) *discardInfo { + discardInfoLock.Lock() + defer discardInfoLock.Unlock() + di := discardInfoMap[t] + if di == nil { + di = &discardInfo{typ: t} + discardInfoMap[t] = di + } + return di +} + +func (di *discardInfo) discard(src pointer) { + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&di.initialized) == 0 { + di.computeDiscardInfo() + } + + for _, fi := range di.fields { + sfp := src.offset(fi.field) + fi.discard(sfp) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil { + // Ignore lock since DiscardUnknown is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + DiscardUnknown(m) + } + } + } + + if di.unrecognized.IsValid() { + *src.offset(di.unrecognized).toBytes() = nil + } +} + +func (di *discardInfo) computeDiscardInfo() { + di.lock.Lock() + defer di.lock.Unlock() + if di.initialized != 0 { + return + } + t := di.typ + n := t.NumField() + + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + dfi := discardFieldInfo{field: toField(&f)} + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name)) + case isSlice: // E.g., []*pb.T + discardInfo := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sps := src.getPointerSlice() + for _, sp := range sps { + if !sp.isNil() { + discardInfo.discard(sp) + } + } + } + default: // E.g., *pb.T + discardInfo := getDiscardInfo(tf) + dfi.discard = func(src pointer) { + sp := src.getPointer() + if !sp.isNil() { + discardInfo.discard(sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name)) + default: // E.g., map[K]V + if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T) + dfi.discard = func(src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + DiscardUnknown(val.Interface().(Message)) + } + } + } else { + dfi.discard = func(pointer) {} // Noop + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name)) + default: // E.g., interface{} + // TODO: Make this faster? + dfi.discard = func(src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + DiscardUnknown(sv.Interface().(Message)) + } + } + } + } + default: + continue + } + di.fields = append(di.fields, dfi) + } + + di.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + di.unrecognized = toField(&f) + } + + atomic.StoreInt32(&di.initialized, 1) +} + +func discardLegacy(m Message) { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if v.Kind() != reflect.Struct { + return + } + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + vf := v.Field(i) + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) + case isSlice: // E.g., []*pb.T + for j := 0; j < vf.Len(); j++ { + discardLegacy(vf.Index(j).Interface().(Message)) + } + default: // E.g., *pb.T + discardLegacy(vf.Interface().(Message)) + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) + default: // E.g., map[K]V + tv := vf.Type().Elem() + if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) + for _, key := range vf.MapKeys() { + val := vf.MapIndex(key) + discardLegacy(val.Interface().(Message)) + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) + default: // E.g., test_proto.isCommunique_Union interface + if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { + vf = vf.Elem() // E.g., *test_proto.Communique_Msg + if !vf.IsNil() { + vf = vf.Elem() // E.g., test_proto.Communique_Msg + vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value + if vf.Kind() == reflect.Ptr { + discardLegacy(vf.Interface().(Message)) + } + } + } + } + } + } + + if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { + if vf.Type() != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + vf.Set(reflect.ValueOf([]byte(nil))) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, err := extendable(m); err == nil { + // Ignore lock since discardLegacy is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + discardLegacy(m) + } + } + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/duration.go b/vendor/github.com/gogo/protobuf/proto/duration.go new file mode 100644 index 0000000000..93464c91cf --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/duration.go @@ -0,0 +1,100 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// This file implements conversions between google.protobuf.Duration +// and time.Duration. + +import ( + "errors" + "fmt" + "time" +) + +const ( + // Range of a Duration in seconds, as specified in + // google/protobuf/duration.proto. This is about 10,000 years in seconds. + maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) + minSeconds = -maxSeconds +) + +// validateDuration determines whether the Duration is valid according to the +// definition in google/protobuf/duration.proto. A valid Duration +// may still be too large to fit into a time.Duration (the range of Duration +// is about 10,000 years, and the range of time.Duration is about 290). +func validateDuration(d *duration) error { + if d == nil { + return errors.New("duration: nil Duration") + } + if d.Seconds < minSeconds || d.Seconds > maxSeconds { + return fmt.Errorf("duration: %#v: seconds out of range", d) + } + if d.Nanos <= -1e9 || d.Nanos >= 1e9 { + return fmt.Errorf("duration: %#v: nanos out of range", d) + } + // Seconds and Nanos must have the same sign, unless d.Nanos is zero. + if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) { + return fmt.Errorf("duration: %#v: seconds and nanos have different signs", d) + } + return nil +} + +// DurationFromProto converts a Duration to a time.Duration. DurationFromProto +// returns an error if the Duration is invalid or is too large to be +// represented in a time.Duration. +func durationFromProto(p *duration) (time.Duration, error) { + if err := validateDuration(p); err != nil { + return 0, err + } + d := time.Duration(p.Seconds) * time.Second + if int64(d/time.Second) != p.Seconds { + return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) + } + if p.Nanos != 0 { + d += time.Duration(p.Nanos) + if (d < 0) != (p.Nanos < 0) { + return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p) + } + } + return d, nil +} + +// DurationProto converts a time.Duration to a Duration. +func durationProto(d time.Duration) *duration { + nanos := d.Nanoseconds() + secs := nanos / 1e9 + nanos -= secs * 1e9 + return &duration{ + Seconds: secs, + Nanos: int32(nanos), + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/duration_gogo.go b/vendor/github.com/gogo/protobuf/proto/duration_gogo.go new file mode 100644 index 0000000000..e748e1730e --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/duration_gogo.go @@ -0,0 +1,49 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" + "time" +) + +var durationType = reflect.TypeOf((*time.Duration)(nil)).Elem() + +type duration struct { + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` +} + +func (m *duration) Reset() { *m = duration{} } +func (*duration) ProtoMessage() {} +func (*duration) String() string { return "duration" } + +func init() { + RegisterType((*duration)(nil), "gogo.protobuf.proto.duration") +} diff --git a/vendor/github.com/gogo/protobuf/proto/encode.go b/vendor/github.com/gogo/protobuf/proto/encode.go new file mode 100644 index 0000000000..9581ccd304 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/encode.go @@ -0,0 +1,205 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "errors" + "reflect" +) + +var ( + // errRepeatedHasNil is the error returned if Marshal is called with + // a struct with a repeated field containing a nil element. + errRepeatedHasNil = errors.New("proto: repeated field has nil element") + + // errOneofHasNil is the error returned if Marshal is called with + // a struct with a oneof field containing a nil element. + errOneofHasNil = errors.New("proto: oneof field has nil value") + + // ErrNil is the error returned if Marshal is called with nil. + ErrNil = errors.New("proto: Marshal called with nil") + + // ErrTooLarge is the error returned if Marshal is called with a + // message that encodes to >2GB. + ErrTooLarge = errors.New("proto: message encodes to over 2 GB") +) + +// The fundamental encoders that put bytes on the wire. +// Those that take integer types all accept uint64 and are +// therefore of type valueEncoder. + +const maxVarintBytes = 10 // maximum length of a varint + +// EncodeVarint returns the varint encoding of x. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +// Not used by the package itself, but helpful to clients +// wishing to use the same encoding. +func EncodeVarint(x uint64) []byte { + var buf [maxVarintBytes]byte + var n int + for n = 0; x > 127; n++ { + buf[n] = 0x80 | uint8(x&0x7F) + x >>= 7 + } + buf[n] = uint8(x) + n++ + return buf[0:n] +} + +// EncodeVarint writes a varint-encoded integer to the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (p *Buffer) EncodeVarint(x uint64) error { + for x >= 1<<7 { + p.buf = append(p.buf, uint8(x&0x7f|0x80)) + x >>= 7 + } + p.buf = append(p.buf, uint8(x)) + return nil +} + +// SizeVarint returns the varint encoding size of an integer. +func SizeVarint(x uint64) int { + switch { + case x < 1<<7: + return 1 + case x < 1<<14: + return 2 + case x < 1<<21: + return 3 + case x < 1<<28: + return 4 + case x < 1<<35: + return 5 + case x < 1<<42: + return 6 + case x < 1<<49: + return 7 + case x < 1<<56: + return 8 + case x < 1<<63: + return 9 + } + return 10 +} + +// EncodeFixed64 writes a 64-bit integer to the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (p *Buffer) EncodeFixed64(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24), + uint8(x>>32), + uint8(x>>40), + uint8(x>>48), + uint8(x>>56)) + return nil +} + +// EncodeFixed32 writes a 32-bit integer to the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (p *Buffer) EncodeFixed32(x uint64) error { + p.buf = append(p.buf, + uint8(x), + uint8(x>>8), + uint8(x>>16), + uint8(x>>24)) + return nil +} + +// EncodeZigzag64 writes a zigzag-encoded 64-bit integer +// to the Buffer. +// This is the format used for the sint64 protocol buffer type. +func (p *Buffer) EncodeZigzag64(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} + +// EncodeZigzag32 writes a zigzag-encoded 32-bit integer +// to the Buffer. +// This is the format used for the sint32 protocol buffer type. +func (p *Buffer) EncodeZigzag32(x uint64) error { + // use signed number to get arithmetic right shift. + return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) +} + +// EncodeRawBytes writes a count-delimited byte buffer to the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (p *Buffer) EncodeRawBytes(b []byte) error { + p.EncodeVarint(uint64(len(b))) + p.buf = append(p.buf, b...) + return nil +} + +// EncodeStringBytes writes an encoded string to the Buffer. +// This is the format used for the proto2 string type. +func (p *Buffer) EncodeStringBytes(s string) error { + p.EncodeVarint(uint64(len(s))) + p.buf = append(p.buf, s...) + return nil +} + +// Marshaler is the interface representing objects that can marshal themselves. +type Marshaler interface { + Marshal() ([]byte, error) +} + +// EncodeMessage writes the protocol buffer to the Buffer, +// prefixed by a varint-encoded length. +func (p *Buffer) EncodeMessage(pb Message) error { + siz := Size(pb) + sizVar := SizeVarint(uint64(siz)) + p.grow(siz + sizVar) + p.EncodeVarint(uint64(siz)) + return p.Marshal(pb) +} + +// All protocol buffer fields are nillable, but be careful. +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + } + return false +} diff --git a/vendor/github.com/gogo/protobuf/proto/encode_gogo.go b/vendor/github.com/gogo/protobuf/proto/encode_gogo.go new file mode 100644 index 0000000000..0f5fb173e9 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/encode_gogo.go @@ -0,0 +1,33 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +func NewRequiredNotSetError(field string) *RequiredNotSetError { + return &RequiredNotSetError{field} +} diff --git a/vendor/github.com/gogo/protobuf/proto/equal.go b/vendor/github.com/gogo/protobuf/proto/equal.go new file mode 100644 index 0000000000..d4db5a1c14 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/equal.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Protocol buffer comparison. + +package proto + +import ( + "bytes" + "log" + "reflect" + "strings" +) + +/* +Equal returns true iff protocol buffers a and b are equal. +The arguments must both be pointers to protocol buffer structs. + +Equality is defined in this way: + - Two messages are equal iff they are the same type, + corresponding fields are equal, unknown field sets + are equal, and extensions sets are equal. + - Two set scalar fields are equal iff their values are equal. + If the fields are of a floating-point type, remember that + NaN != x for all x, including NaN. If the message is defined + in a proto3 .proto file, fields are not "set"; specifically, + zero length proto3 "bytes" fields are equal (nil == {}). + - Two repeated fields are equal iff their lengths are the same, + and their corresponding elements are equal. Note a "bytes" field, + although represented by []byte, is not a repeated field and the + rule for the scalar fields described above applies. + - Two unset fields are equal. + - Two unknown field sets are equal if their current + encoded state is equal. + - Two extension sets are equal iff they have corresponding + elements that are pairwise equal. + - Two map fields are equal iff their lengths are the same, + and they contain the same set of elements. Zero-length map + fields are equal. + - Every other combination of things are not equal. + +The return value is undefined if a and b are not protocol buffers. +*/ +func Equal(a, b Message) bool { + if a == nil || b == nil { + return a == b + } + v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) + if v1.Type() != v2.Type() { + return false + } + if v1.Kind() == reflect.Ptr { + if v1.IsNil() { + return v2.IsNil() + } + if v2.IsNil() { + return false + } + v1, v2 = v1.Elem(), v2.Elem() + } + if v1.Kind() != reflect.Struct { + return false + } + return equalStruct(v1, v2) +} + +// v1 and v2 are known to have the same type. +func equalStruct(v1, v2 reflect.Value) bool { + sprop := GetProperties(v1.Type()) + for i := 0; i < v1.NumField(); i++ { + f := v1.Type().Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + f1, f2 := v1.Field(i), v2.Field(i) + if f.Type.Kind() == reflect.Ptr { + if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { + // both unset + continue + } else if n1 != n2 { + // set/unset mismatch + return false + } + f1, f2 = f1.Elem(), f2.Elem() + } + if !equalAny(f1, f2, sprop.Prop[i]) { + return false + } + } + + if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_InternalExtensions") + if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { + return false + } + } + + if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { + em2 := v2.FieldByName("XXX_extensions") + if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { + return false + } + } + + uf := v1.FieldByName("XXX_unrecognized") + if !uf.IsValid() { + return true + } + + u1 := uf.Bytes() + u2 := v2.FieldByName("XXX_unrecognized").Bytes() + return bytes.Equal(u1, u2) +} + +// v1 and v2 are known to have the same type. +// prop may be nil. +func equalAny(v1, v2 reflect.Value, prop *Properties) bool { + if v1.Type() == protoMessageType { + m1, _ := v1.Interface().(Message) + m2, _ := v2.Interface().(Message) + return Equal(m1, m2) + } + switch v1.Kind() { + case reflect.Bool: + return v1.Bool() == v2.Bool() + case reflect.Float32, reflect.Float64: + return v1.Float() == v2.Float() + case reflect.Int32, reflect.Int64: + return v1.Int() == v2.Int() + case reflect.Interface: + // Probably a oneof field; compare the inner values. + n1, n2 := v1.IsNil(), v2.IsNil() + if n1 || n2 { + return n1 == n2 + } + e1, e2 := v1.Elem(), v2.Elem() + if e1.Type() != e2.Type() { + return false + } + return equalAny(e1, e2, nil) + case reflect.Map: + if v1.Len() != v2.Len() { + return false + } + for _, key := range v1.MapKeys() { + val2 := v2.MapIndex(key) + if !val2.IsValid() { + // This key was not found in the second map. + return false + } + if !equalAny(v1.MapIndex(key), val2, nil) { + return false + } + } + return true + case reflect.Ptr: + // Maps may have nil values in them, so check for nil. + if v1.IsNil() && v2.IsNil() { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return equalAny(v1.Elem(), v2.Elem(), prop) + case reflect.Slice: + if v1.Type().Elem().Kind() == reflect.Uint8 { + // short circuit: []byte + + // Edge case: if this is in a proto3 message, a zero length + // bytes field is considered the zero value. + if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { + return true + } + if v1.IsNil() != v2.IsNil() { + return false + } + return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) + } + + if v1.Len() != v2.Len() { + return false + } + for i := 0; i < v1.Len(); i++ { + if !equalAny(v1.Index(i), v2.Index(i), prop) { + return false + } + } + return true + case reflect.String: + return v1.Interface().(string) == v2.Interface().(string) + case reflect.Struct: + return equalStruct(v1, v2) + case reflect.Uint32, reflect.Uint64: + return v1.Uint() == v2.Uint() + } + + // unknown type, so not a protocol buffer + log.Printf("proto: don't know how to compare %v", v1) + return false +} + +// base is the struct type that the extensions are based on. +// x1 and x2 are InternalExtensions. +func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { + em1, _ := x1.extensionsRead() + em2, _ := x2.extensionsRead() + return equalExtMap(base, em1, em2) +} + +func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { + if len(em1) != len(em2) { + return false + } + + for extNum, e1 := range em1 { + e2, ok := em2[extNum] + if !ok { + return false + } + + m1, m2 := e1.value, e2.value + + if m1 == nil && m2 == nil { + // Both have only encoded form. + if bytes.Equal(e1.enc, e2.enc) { + continue + } + // The bytes are different, but the extensions might still be + // equal. We need to decode them to compare. + } + + if m1 != nil && m2 != nil { + // Both are unencoded. + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + continue + } + + // At least one is encoded. To do a semantically correct comparison + // we need to unmarshal them first. + var desc *ExtensionDesc + if m := extensionMaps[base]; m != nil { + desc = m[extNum] + } + if desc == nil { + // If both have only encoded form and the bytes are the same, + // it is handled above. We get here when the bytes are different. + // We don't know how to decode it, so just compare them as byte + // slices. + log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) + return false + } + var err error + if m1 == nil { + m1, err = decodeExtension(e1.enc, desc) + } + if m2 == nil && err == nil { + m2, err = decodeExtension(e2.enc, desc) + } + if err != nil { + // The encoded form is invalid. + log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) + return false + } + if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { + return false + } + } + + return true +} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions.go b/vendor/github.com/gogo/protobuf/proto/extensions.go new file mode 100644 index 0000000000..341c6f57f5 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/extensions.go @@ -0,0 +1,605 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Types and routines for supporting protocol buffer extensions. + */ + +import ( + "errors" + "fmt" + "io" + "reflect" + "strconv" + "sync" +) + +// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message. +var ErrMissingExtension = errors.New("proto: missing extension") + +// ExtensionRange represents a range of message extensions for a protocol buffer. +// Used in code generated by the protocol compiler. +type ExtensionRange struct { + Start, End int32 // both inclusive +} + +// extendableProto is an interface implemented by any protocol buffer generated by the current +// proto compiler that may be extended. +type extendableProto interface { + Message + ExtensionRangeArray() []ExtensionRange + extensionsWrite() map[int32]Extension + extensionsRead() (map[int32]Extension, sync.Locker) +} + +// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous +// version of the proto compiler that may be extended. +type extendableProtoV1 interface { + Message + ExtensionRangeArray() []ExtensionRange + ExtensionMap() map[int32]Extension +} + +// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto. +type extensionAdapter struct { + extendableProtoV1 +} + +func (e extensionAdapter) extensionsWrite() map[int32]Extension { + return e.ExtensionMap() +} + +func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + return e.ExtensionMap(), notLocker{} +} + +// notLocker is a sync.Locker whose Lock and Unlock methods are nops. +type notLocker struct{} + +func (n notLocker) Lock() {} +func (n notLocker) Unlock() {} + +// extendable returns the extendableProto interface for the given generated proto message. +// If the proto message has the old extension format, it returns a wrapper that implements +// the extendableProto interface. +func extendable(p interface{}) (extendableProto, error) { + switch p := p.(type) { + case extendableProto: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return p, nil + case extendableProtoV1: + if isNilPtr(p) { + return nil, fmt.Errorf("proto: nil %T is not extendable", p) + } + return extensionAdapter{p}, nil + case extensionsBytes: + return slowExtensionAdapter{p}, nil + } + // Don't allocate a specific error containing %T: + // this is the hot path for Clone and MarshalText. + return nil, errNotExtendable +} + +var errNotExtendable = errors.New("proto: not an extendable proto.Message") + +func isNilPtr(x interface{}) bool { + v := reflect.ValueOf(x) + return v.Kind() == reflect.Ptr && v.IsNil() +} + +// XXX_InternalExtensions is an internal representation of proto extensions. +// +// Each generated message struct type embeds an anonymous XXX_InternalExtensions field, +// thus gaining the unexported 'extensions' method, which can be called only from the proto package. +// +// The methods of XXX_InternalExtensions are not concurrency safe in general, +// but calls to logically read-only methods such as has and get may be executed concurrently. +type XXX_InternalExtensions struct { + // The struct must be indirect so that if a user inadvertently copies a + // generated message and its embedded XXX_InternalExtensions, they + // avoid the mayhem of a copied mutex. + // + // The mutex serializes all logically read-only operations to p.extensionMap. + // It is up to the client to ensure that write operations to p.extensionMap are + // mutually exclusive with other accesses. + p *struct { + mu sync.Mutex + extensionMap map[int32]Extension + } +} + +// extensionsWrite returns the extension map, creating it on first use. +func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension { + if e.p == nil { + e.p = new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }) + e.p.extensionMap = make(map[int32]Extension) + } + return e.p.extensionMap +} + +// extensionsRead returns the extensions map for read-only use. It may be nil. +// The caller must hold the returned mutex's lock when accessing Elements within the map. +func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) { + if e.p == nil { + return nil, nil + } + return e.p.extensionMap, &e.p.mu +} + +// ExtensionDesc represents an extension specification. +// Used in generated code from the protocol compiler. +type ExtensionDesc struct { + ExtendedType Message // nil pointer to the type that is being extended + ExtensionType interface{} // nil pointer to the extension type + Field int32 // field number + Name string // fully-qualified name of extension, for text formatting + Tag string // protobuf tag style + Filename string // name of the file in which the extension is defined +} + +func (ed *ExtensionDesc) repeated() bool { + t := reflect.TypeOf(ed.ExtensionType) + return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 +} + +// Extension represents an extension in a message. +type Extension struct { + // When an extension is stored in a message using SetExtension + // only desc and value are set. When the message is marshaled + // enc will be set to the encoded form of the message. + // + // When a message is unmarshaled and contains extensions, each + // extension will have only enc set. When such an extension is + // accessed using GetExtension (or GetExtensions) desc and value + // will be set. + desc *ExtensionDesc + value interface{} + enc []byte +} + +// SetRawExtension is for testing only. +func SetRawExtension(base Message, id int32, b []byte) { + if ebase, ok := base.(extensionsBytes); ok { + clearExtension(base, id) + ext := ebase.GetExtensions() + *ext = append(*ext, b...) + return + } + epb, err := extendable(base) + if err != nil { + return + } + extmap := epb.extensionsWrite() + extmap[id] = Extension{enc: b} +} + +// isExtensionField returns true iff the given field number is in an extension range. +func isExtensionField(pb extendableProto, field int32) bool { + for _, er := range pb.ExtensionRangeArray() { + if er.Start <= field && field <= er.End { + return true + } + } + return false +} + +// checkExtensionTypes checks that the given extension is valid for pb. +func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { + var pbi interface{} = pb + // Check the extended type. + if ea, ok := pbi.(extensionAdapter); ok { + pbi = ea.extendableProtoV1 + } + if ea, ok := pbi.(slowExtensionAdapter); ok { + pbi = ea.extensionsBytes + } + if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b { + return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) + } + // Check the range. + if !isExtensionField(pb, extension.Field) { + return errors.New("proto: bad extension number; not in declared ranges") + } + return nil +} + +// extPropKey is sufficient to uniquely identify an extension. +type extPropKey struct { + base reflect.Type + field int32 +} + +var extProp = struct { + sync.RWMutex + m map[extPropKey]*Properties +}{ + m: make(map[extPropKey]*Properties), +} + +func extensionProperties(ed *ExtensionDesc) *Properties { + key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field} + + extProp.RLock() + if prop, ok := extProp.m[key]; ok { + extProp.RUnlock() + return prop + } + extProp.RUnlock() + + extProp.Lock() + defer extProp.Unlock() + // Check again. + if prop, ok := extProp.m[key]; ok { + return prop + } + + prop := new(Properties) + prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil) + extProp.m[key] = prop + return prop +} + +// HasExtension returns whether the given extension is present in pb. +func HasExtension(pb Message, extension *ExtensionDesc) bool { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + buf := *ext + o := 0 + for o < len(buf) { + tag, n := DecodeVarint(buf[o:]) + fieldNum := int32(tag >> 3) + if int32(fieldNum) == extension.Field { + return true + } + wireType := int(tag & 0x7) + o += n + l, err := size(buf[o:], wireType) + if err != nil { + return false + } + o += l + } + return false + } + // TODO: Check types, field numbers, etc.? + epb, err := extendable(pb) + if err != nil { + return false + } + extmap, mu := epb.extensionsRead() + if extmap == nil { + return false + } + mu.Lock() + _, ok := extmap[extension.Field] + mu.Unlock() + return ok +} + +// ClearExtension removes the given extension from pb. +func ClearExtension(pb Message, extension *ExtensionDesc) { + clearExtension(pb, extension.Field) +} + +func clearExtension(pb Message, fieldNum int32) { + if epb, ok := pb.(extensionsBytes); ok { + offset := 0 + for offset != -1 { + offset = deleteExtension(epb, fieldNum, offset) + } + return + } + epb, err := extendable(pb) + if err != nil { + return + } + // TODO: Check types, field numbers, etc.? + extmap := epb.extensionsWrite() + delete(extmap, fieldNum) +} + +// GetExtension retrieves a proto2 extended field from pb. +// +// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), +// then GetExtension parses the encoded field and returns a Go value of the specified type. +// If the field is not present, then the default value is returned (if one is specified), +// otherwise ErrMissingExtension is reported. +// +// If the descriptor is not type complete (i.e., ExtensionDesc.ExtensionType is nil), +// then GetExtension returns the raw encoded bytes of the field extension. +func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + return decodeExtensionFromBytes(extension, *ext) + } + + epb, err := extendable(pb) + if err != nil { + return nil, err + } + + if extension.ExtendedType != nil { + // can only check type if this is a complete descriptor + if cerr := checkExtensionTypes(epb, extension); cerr != nil { + return nil, cerr + } + } + + emap, mu := epb.extensionsRead() + if emap == nil { + return defaultExtensionValue(extension) + } + mu.Lock() + defer mu.Unlock() + e, ok := emap[extension.Field] + if !ok { + // defaultExtensionValue returns the default value or + // ErrMissingExtension if there is no default. + return defaultExtensionValue(extension) + } + + if e.value != nil { + // Already decoded. Check the descriptor, though. + if e.desc != extension { + // This shouldn't happen. If it does, it means that + // GetExtension was called twice with two different + // descriptors with the same field number. + return nil, errors.New("proto: descriptor conflict") + } + return e.value, nil + } + + if extension.ExtensionType == nil { + // incomplete descriptor + return e.enc, nil + } + + v, err := decodeExtension(e.enc, extension) + if err != nil { + return nil, err + } + + // Remember the decoded version and drop the encoded version. + // That way it is safe to mutate what we return. + e.value = v + e.desc = extension + e.enc = nil + emap[extension.Field] = e + return e.value, nil +} + +// defaultExtensionValue returns the default value for extension. +// If no default for an extension is defined ErrMissingExtension is returned. +func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { + if extension.ExtensionType == nil { + // incomplete descriptor, so no default + return nil, ErrMissingExtension + } + + t := reflect.TypeOf(extension.ExtensionType) + props := extensionProperties(extension) + + sf, _, err := fieldDefault(t, props) + if err != nil { + return nil, err + } + + if sf == nil || sf.value == nil { + // There is no default value. + return nil, ErrMissingExtension + } + + if t.Kind() != reflect.Ptr { + // We do not need to return a Ptr, we can directly return sf.value. + return sf.value, nil + } + + // We need to return an interface{} that is a pointer to sf.value. + value := reflect.New(t).Elem() + value.Set(reflect.New(value.Type().Elem())) + if sf.kind == reflect.Int32 { + // We may have an int32 or an enum, but the underlying data is int32. + // Since we can't set an int32 into a non int32 reflect.value directly + // set it as a int32. + value.Elem().SetInt(int64(sf.value.(int32))) + } else { + value.Elem().Set(reflect.ValueOf(sf.value)) + } + return value.Interface(), nil +} + +// decodeExtension decodes an extension encoded in b. +func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { + t := reflect.TypeOf(extension.ExtensionType) + unmarshal := typeUnmarshaler(t, extension.Tag) + + // t is a pointer to a struct, pointer to basic type or a slice. + // Allocate space to store the pointer/slice. + value := reflect.New(t).Elem() + + var err error + for { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + wire := int(x) & 7 + + b, err = unmarshal(b, valToPointer(value.Addr()), wire) + if err != nil { + return nil, err + } + + if len(b) == 0 { + break + } + } + return value.Interface(), nil +} + +// GetExtensions returns a slice of the extensions present in pb that are also listed in es. +// The returned slice has the same length as es; missing extensions will appear as nil elements. +func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) { + epb, err := extendable(pb) + if err != nil { + return nil, err + } + extensions = make([]interface{}, len(es)) + for i, e := range es { + extensions[i], err = GetExtension(epb, e) + if err == ErrMissingExtension { + err = nil + } + if err != nil { + return + } + } + return +} + +// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order. +// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing +// just the Field field, which defines the extension's field number. +func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { + epb, err := extendable(pb) + if err != nil { + return nil, err + } + registeredExtensions := RegisteredExtensions(pb) + + emap, mu := epb.extensionsRead() + if emap == nil { + return nil, nil + } + mu.Lock() + defer mu.Unlock() + extensions := make([]*ExtensionDesc, 0, len(emap)) + for extid, e := range emap { + desc := e.desc + if desc == nil { + desc = registeredExtensions[extid] + if desc == nil { + desc = &ExtensionDesc{Field: extid} + } + } + + extensions = append(extensions, desc) + } + return extensions, nil +} + +// SetExtension sets the specified extension of pb to the specified value. +func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { + if epb, ok := pb.(extensionsBytes); ok { + ClearExtension(pb, extension) + newb, err := encodeExtension(extension, value) + if err != nil { + return err + } + bb := epb.GetExtensions() + *bb = append(*bb, newb...) + return nil + } + epb, err := extendable(pb) + if err != nil { + return err + } + if err := checkExtensionTypes(epb, extension); err != nil { + return err + } + typ := reflect.TypeOf(extension.ExtensionType) + if typ != reflect.TypeOf(value) { + return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType) + } + // nil extension values need to be caught early, because the + // encoder can't distinguish an ErrNil due to a nil extension + // from an ErrNil due to a missing field. Extensions are + // always optional, so the encoder would just swallow the error + // and drop all the extensions from the encoded message. + if reflect.ValueOf(value).IsNil() { + return fmt.Errorf("proto: SetExtension called with nil value of type %T", value) + } + + extmap := epb.extensionsWrite() + extmap[extension.Field] = Extension{desc: extension, value: value} + return nil +} + +// ClearAllExtensions clears all extensions from pb. +func ClearAllExtensions(pb Message) { + if epb, doki := pb.(extensionsBytes); doki { + ext := epb.GetExtensions() + *ext = []byte{} + return + } + epb, err := extendable(pb) + if err != nil { + return + } + m := epb.extensionsWrite() + for k := range m { + delete(m, k) + } +} + +// A global registry of extensions. +// The generated code will register the generated descriptors by calling RegisterExtension. + +var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc) + +// RegisterExtension is called from the generated code. +func RegisterExtension(desc *ExtensionDesc) { + st := reflect.TypeOf(desc.ExtendedType).Elem() + m := extensionMaps[st] + if m == nil { + m = make(map[int32]*ExtensionDesc) + extensionMaps[st] = m + } + if _, ok := m[desc.Field]; ok { + panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field))) + } + m[desc.Field] = desc +} + +// RegisteredExtensions returns a map of the registered extensions of a +// protocol buffer struct, indexed by the extension number. +// The argument pb should be a nil pointer to the struct type. +func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc { + return extensionMaps[reflect.TypeOf(pb).Elem()] +} diff --git a/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go b/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go new file mode 100644 index 0000000000..6f1ae120ec --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/extensions_gogo.go @@ -0,0 +1,389 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "bytes" + "errors" + "fmt" + "io" + "reflect" + "sort" + "strings" + "sync" +) + +type extensionsBytes interface { + Message + ExtensionRangeArray() []ExtensionRange + GetExtensions() *[]byte +} + +type slowExtensionAdapter struct { + extensionsBytes +} + +func (s slowExtensionAdapter) extensionsWrite() map[int32]Extension { + panic("Please report a bug to github.com/gogo/protobuf if you see this message: Writing extensions is not supported for extensions stored in a byte slice field.") +} + +func (s slowExtensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) { + b := s.GetExtensions() + m, err := BytesToExtensionsMap(*b) + if err != nil { + panic(err) + } + return m, notLocker{} +} + +func GetBoolExtension(pb Message, extension *ExtensionDesc, ifnotset bool) bool { + if reflect.ValueOf(pb).IsNil() { + return ifnotset + } + value, err := GetExtension(pb, extension) + if err != nil { + return ifnotset + } + if value == nil { + return ifnotset + } + if value.(*bool) == nil { + return ifnotset + } + return *(value.(*bool)) +} + +func (this *Extension) Equal(that *Extension) bool { + if err := this.Encode(); err != nil { + return false + } + if err := that.Encode(); err != nil { + return false + } + return bytes.Equal(this.enc, that.enc) +} + +func (this *Extension) Compare(that *Extension) int { + if err := this.Encode(); err != nil { + return 1 + } + if err := that.Encode(); err != nil { + return -1 + } + return bytes.Compare(this.enc, that.enc) +} + +func SizeOfInternalExtension(m extendableProto) (n int) { + info := getMarshalInfo(reflect.TypeOf(m)) + return info.sizeV1Extensions(m.extensionsWrite()) +} + +type sortableMapElem struct { + field int32 + ext Extension +} + +func newSortableExtensionsFromMap(m map[int32]Extension) sortableExtensions { + s := make(sortableExtensions, 0, len(m)) + for k, v := range m { + s = append(s, &sortableMapElem{field: k, ext: v}) + } + return s +} + +type sortableExtensions []*sortableMapElem + +func (this sortableExtensions) Len() int { return len(this) } + +func (this sortableExtensions) Swap(i, j int) { this[i], this[j] = this[j], this[i] } + +func (this sortableExtensions) Less(i, j int) bool { return this[i].field < this[j].field } + +func (this sortableExtensions) String() string { + sort.Sort(this) + ss := make([]string, len(this)) + for i := range this { + ss[i] = fmt.Sprintf("%d: %v", this[i].field, this[i].ext) + } + return "map[" + strings.Join(ss, ",") + "]" +} + +func StringFromInternalExtension(m extendableProto) string { + return StringFromExtensionsMap(m.extensionsWrite()) +} + +func StringFromExtensionsMap(m map[int32]Extension) string { + return newSortableExtensionsFromMap(m).String() +} + +func StringFromExtensionsBytes(ext []byte) string { + m, err := BytesToExtensionsMap(ext) + if err != nil { + panic(err) + } + return StringFromExtensionsMap(m) +} + +func EncodeInternalExtension(m extendableProto, data []byte) (n int, err error) { + return EncodeExtensionMap(m.extensionsWrite(), data) +} + +func EncodeInternalExtensionBackwards(m extendableProto, data []byte) (n int, err error) { + return EncodeExtensionMapBackwards(m.extensionsWrite(), data) +} + +func EncodeExtensionMap(m map[int32]Extension, data []byte) (n int, err error) { + o := 0 + for _, e := range m { + if err := e.Encode(); err != nil { + return 0, err + } + n := copy(data[o:], e.enc) + if n != len(e.enc) { + return 0, io.ErrShortBuffer + } + o += n + } + return o, nil +} + +func EncodeExtensionMapBackwards(m map[int32]Extension, data []byte) (n int, err error) { + o := 0 + end := len(data) + for _, e := range m { + if err := e.Encode(); err != nil { + return 0, err + } + n := copy(data[end-len(e.enc):], e.enc) + if n != len(e.enc) { + return 0, io.ErrShortBuffer + } + end -= n + o += n + } + return o, nil +} + +func GetRawExtension(m map[int32]Extension, id int32) ([]byte, error) { + e := m[id] + if err := e.Encode(); err != nil { + return nil, err + } + return e.enc, nil +} + +func size(buf []byte, wire int) (int, error) { + switch wire { + case WireVarint: + _, n := DecodeVarint(buf) + return n, nil + case WireFixed64: + return 8, nil + case WireBytes: + v, n := DecodeVarint(buf) + return int(v) + n, nil + case WireFixed32: + return 4, nil + case WireStartGroup: + offset := 0 + for { + u, n := DecodeVarint(buf[offset:]) + fwire := int(u & 0x7) + offset += n + if fwire == WireEndGroup { + return offset, nil + } + s, err := size(buf[offset:], wire) + if err != nil { + return 0, err + } + offset += s + } + } + return 0, fmt.Errorf("proto: can't get size for unknown wire type %d", wire) +} + +func BytesToExtensionsMap(buf []byte) (map[int32]Extension, error) { + m := make(map[int32]Extension) + i := 0 + for i < len(buf) { + tag, n := DecodeVarint(buf[i:]) + if n <= 0 { + return nil, fmt.Errorf("unable to decode varint") + } + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + l, err := size(buf[i+n:], wireType) + if err != nil { + return nil, err + } + end := i + int(l) + n + m[int32(fieldNum)] = Extension{enc: buf[i:end]} + i = end + } + return m, nil +} + +func NewExtension(e []byte) Extension { + ee := Extension{enc: make([]byte, len(e))} + copy(ee.enc, e) + return ee +} + +func AppendExtension(e Message, tag int32, buf []byte) { + if ee, eok := e.(extensionsBytes); eok { + ext := ee.GetExtensions() + *ext = append(*ext, buf...) + return + } + if ee, eok := e.(extendableProto); eok { + m := ee.extensionsWrite() + ext := m[int32(tag)] // may be missing + ext.enc = append(ext.enc, buf...) + m[int32(tag)] = ext + } +} + +func encodeExtension(extension *ExtensionDesc, value interface{}) ([]byte, error) { + u := getMarshalInfo(reflect.TypeOf(extension.ExtendedType)) + ei := u.getExtElemInfo(extension) + v := value + p := toAddrPointer(&v, ei.isptr) + siz := ei.sizer(p, SizeVarint(ei.wiretag)) + buf := make([]byte, 0, siz) + return ei.marshaler(buf, p, ei.wiretag, false) +} + +func decodeExtensionFromBytes(extension *ExtensionDesc, buf []byte) (interface{}, error) { + o := 0 + for o < len(buf) { + tag, n := DecodeVarint((buf)[o:]) + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + if o+n > len(buf) { + return nil, fmt.Errorf("unable to decode extension") + } + l, err := size((buf)[o+n:], wireType) + if err != nil { + return nil, err + } + if int32(fieldNum) == extension.Field { + if o+n+l > len(buf) { + return nil, fmt.Errorf("unable to decode extension") + } + v, err := decodeExtension((buf)[o:o+n+l], extension) + if err != nil { + return nil, err + } + return v, nil + } + o += n + l + } + return defaultExtensionValue(extension) +} + +func (this *Extension) Encode() error { + if this.enc == nil { + var err error + this.enc, err = encodeExtension(this.desc, this.value) + if err != nil { + return err + } + } + return nil +} + +func (this Extension) GoString() string { + if err := this.Encode(); err != nil { + return fmt.Sprintf("error encoding extension: %v", err) + } + return fmt.Sprintf("proto.NewExtension(%#v)", this.enc) +} + +func SetUnsafeExtension(pb Message, fieldNum int32, value interface{}) error { + typ := reflect.TypeOf(pb).Elem() + ext, ok := extensionMaps[typ] + if !ok { + return fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) + } + desc, ok := ext[fieldNum] + if !ok { + return errors.New("proto: bad extension number; not in declared ranges") + } + return SetExtension(pb, desc, value) +} + +func GetUnsafeExtension(pb Message, fieldNum int32) (interface{}, error) { + typ := reflect.TypeOf(pb).Elem() + ext, ok := extensionMaps[typ] + if !ok { + return nil, fmt.Errorf("proto: bad extended type; %s is not extendable", typ.String()) + } + desc, ok := ext[fieldNum] + if !ok { + return nil, fmt.Errorf("unregistered field number %d", fieldNum) + } + return GetExtension(pb, desc) +} + +func NewUnsafeXXX_InternalExtensions(m map[int32]Extension) XXX_InternalExtensions { + x := &XXX_InternalExtensions{ + p: new(struct { + mu sync.Mutex + extensionMap map[int32]Extension + }), + } + x.p.extensionMap = m + return *x +} + +func GetUnsafeExtensionsMap(extendable Message) map[int32]Extension { + pb := extendable.(extendableProto) + return pb.extensionsWrite() +} + +func deleteExtension(pb extensionsBytes, theFieldNum int32, offset int) int { + ext := pb.GetExtensions() + for offset < len(*ext) { + tag, n1 := DecodeVarint((*ext)[offset:]) + fieldNum := int32(tag >> 3) + wireType := int(tag & 0x7) + n2, err := size((*ext)[offset+n1:], wireType) + if err != nil { + panic(err) + } + newOffset := offset + n1 + n2 + if fieldNum == theFieldNum { + *ext = append((*ext)[:offset], (*ext)[newOffset:]...) + return offset + } + offset = newOffset + } + return -1 +} diff --git a/vendor/github.com/gogo/protobuf/proto/lib.go b/vendor/github.com/gogo/protobuf/proto/lib.go new file mode 100644 index 0000000000..80db1c155b --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/lib.go @@ -0,0 +1,973 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* +Package proto converts data structures to and from the wire format of +protocol buffers. It works in concert with the Go source code generated +for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. + - Nested messages, groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Enum types do not get an Enum method. + +The simplest way to describe this is to see an example. +Given file test.proto, containing + + package example; + + enum FOO { X = 17; } + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + oneof union { + int32 number = 6; + string name = 7; + } + } + +The resulting file, test.pb.go, is: + + package example + + import proto "github.com/gogo/protobuf/proto" + import math "math" + + type FOO int32 + const ( + FOO_X FOO = 17 + ) + var FOO_name = map[int32]string{ + 17: "X", + } + var FOO_value = map[string]int32{ + "X": 17, + } + + func (x FOO) Enum() *FOO { + p := new(FOO) + *p = x + return p + } + func (x FOO) String() string { + return proto.EnumName(FOO_name, int32(x)) + } + func (x *FOO) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(FOO_value, data) + if err != nil { + return err + } + *x = FOO(value) + return nil + } + + type Test struct { + Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"` + Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"` + Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"` + Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"` + // Types that are valid to be assigned to Union: + // *Test_Number + // *Test_Name + Union isTest_Union `protobuf_oneof:"union"` + XXX_unrecognized []byte `json:"-"` + } + func (m *Test) Reset() { *m = Test{} } + func (m *Test) String() string { return proto.CompactTextString(m) } + func (*Test) ProtoMessage() {} + + type isTest_Union interface { + isTest_Union() + } + + type Test_Number struct { + Number int32 `protobuf:"varint,6,opt,name=number"` + } + type Test_Name struct { + Name string `protobuf:"bytes,7,opt,name=name"` + } + + func (*Test_Number) isTest_Union() {} + func (*Test_Name) isTest_Union() {} + + func (m *Test) GetUnion() isTest_Union { + if m != nil { + return m.Union + } + return nil + } + const Default_Test_Type int32 = 77 + + func (m *Test) GetLabel() string { + if m != nil && m.Label != nil { + return *m.Label + } + return "" + } + + func (m *Test) GetType() int32 { + if m != nil && m.Type != nil { + return *m.Type + } + return Default_Test_Type + } + + func (m *Test) GetOptionalgroup() *Test_OptionalGroup { + if m != nil { + return m.Optionalgroup + } + return nil + } + + type Test_OptionalGroup struct { + RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"` + } + func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} } + func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) } + + func (m *Test_OptionalGroup) GetRequiredField() string { + if m != nil && m.RequiredField != nil { + return *m.RequiredField + } + return "" + } + + func (m *Test) GetNumber() int32 { + if x, ok := m.GetUnion().(*Test_Number); ok { + return x.Number + } + return 0 + } + + func (m *Test) GetName() string { + if x, ok := m.GetUnion().(*Test_Name); ok { + return x.Name + } + return "" + } + + func init() { + proto.RegisterEnum("example.FOO", FOO_name, FOO_value) + } + +To create and play with a Test object: + + package main + + import ( + "log" + + "github.com/gogo/protobuf/proto" + pb "./example.pb" + ) + + func main() { + test := &pb.Test{ + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &pb.Test_OptionalGroup{ + RequiredField: proto.String("good bye"), + }, + Union: &pb.Test_Name{"fred"}, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &pb.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // Use a type switch to determine which oneof was set. + switch u := test.Union.(type) { + case *pb.Test_Number: // u.Number contains the number. + case *pb.Test_Name: // u.Name contains the string. + } + // etc. + } +*/ +package proto + +import ( + "encoding/json" + "fmt" + "log" + "reflect" + "sort" + "strconv" + "sync" +) + +// RequiredNotSetError is an error type returned by either Marshal or Unmarshal. +// Marshal reports this when a required field is not initialized. +// Unmarshal reports this when a required field is missing from the wire data. +type RequiredNotSetError struct{ field string } + +func (e *RequiredNotSetError) Error() string { + if e.field == "" { + return fmt.Sprintf("proto: required field not set") + } + return fmt.Sprintf("proto: required field %q not set", e.field) +} +func (e *RequiredNotSetError) RequiredNotSet() bool { + return true +} + +type invalidUTF8Error struct{ field string } + +func (e *invalidUTF8Error) Error() string { + if e.field == "" { + return "proto: invalid UTF-8 detected" + } + return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field) +} +func (e *invalidUTF8Error) InvalidUTF8() bool { + return true +} + +// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8. +// This error should not be exposed to the external API as such errors should +// be recreated with the field information. +var errInvalidUTF8 = &invalidUTF8Error{} + +// isNonFatal reports whether the error is either a RequiredNotSet error +// or a InvalidUTF8 error. +func isNonFatal(err error) bool { + if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() { + return true + } + if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() { + return true + } + return false +} + +type nonFatal struct{ E error } + +// Merge merges err into nf and reports whether it was successful. +// Otherwise it returns false for any fatal non-nil errors. +func (nf *nonFatal) Merge(err error) (ok bool) { + if err == nil { + return true // not an error + } + if !isNonFatal(err) { + return false // fatal error + } + if nf.E == nil { + nf.E = err // store first instance of non-fatal error + } + return true +} + +// Message is implemented by generated protocol buffer messages. +type Message interface { + Reset() + String() string + ProtoMessage() +} + +// A Buffer is a buffer manager for marshaling and unmarshaling +// protocol buffers. It may be reused between invocations to +// reduce memory usage. It is not necessary to use a Buffer; +// the global functions Marshal and Unmarshal create a +// temporary Buffer and are fine for most applications. +type Buffer struct { + buf []byte // encode/decode byte stream + index int // read point + + deterministic bool +} + +// NewBuffer allocates a new Buffer and initializes its internal data to +// the contents of the argument slice. +func NewBuffer(e []byte) *Buffer { + return &Buffer{buf: e} +} + +// Reset resets the Buffer, ready for marshaling a new protocol buffer. +func (p *Buffer) Reset() { + p.buf = p.buf[0:0] // for reading/writing + p.index = 0 // for reading +} + +// SetBuf replaces the internal buffer with the slice, +// ready for unmarshaling the contents of the slice. +func (p *Buffer) SetBuf(s []byte) { + p.buf = s + p.index = 0 +} + +// Bytes returns the contents of the Buffer. +func (p *Buffer) Bytes() []byte { return p.buf } + +// SetDeterministic sets whether to use deterministic serialization. +// +// Deterministic serialization guarantees that for a given binary, equal +// messages will always be serialized to the same bytes. This implies: +// +// - Repeated serialization of a message will return the same bytes. +// - Different processes of the same binary (which may be executing on +// different machines) will serialize equal messages to the same bytes. +// +// Note that the deterministic serialization is NOT canonical across +// languages. It is not guaranteed to remain stable over time. It is unstable +// across different builds with schema changes due to unknown fields. +// Users who need canonical serialization (e.g., persistent storage in a +// canonical form, fingerprinting, etc.) should define their own +// canonicalization specification and implement their own serializer rather +// than relying on this API. +// +// If deterministic serialization is requested, map entries will be sorted +// by keys in lexographical order. This is an implementation detail and +// subject to change. +func (p *Buffer) SetDeterministic(deterministic bool) { + p.deterministic = deterministic +} + +/* + * Helper routines for simplifying the creation of optional fields of basic type. + */ + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + return &v +} + +// Int32 is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it. +func Int32(v int32) *int32 { + return &v +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int32 { + p := new(int32) + *p = int32(v) + return p +} + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { + return &v +} + +// Float32 is a helper routine that allocates a new float32 value +// to store v and returns a pointer to it. +func Float32(v float32) *float32 { + return &v +} + +// Float64 is a helper routine that allocates a new float64 value +// to store v and returns a pointer to it. +func Float64(v float64) *float64 { + return &v +} + +// Uint32 is a helper routine that allocates a new uint32 value +// to store v and returns a pointer to it. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 is a helper routine that allocates a new uint64 value +// to store v and returns a pointer to it. +func Uint64(v uint64) *uint64 { + return &v +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + return &v +} + +// EnumName is a helper function to simplify printing protocol buffer enums +// by name. Given an enum map and a value, it returns a useful string. +func EnumName(m map[int32]string, v int32) string { + s, ok := m[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// UnmarshalJSONEnum is a helper function to simplify recovering enum int values +// from their JSON-encoded representation. Given a map from the enum's symbolic +// names to its int values, and a byte buffer containing the JSON-encoded +// value, it returns an int32 that can be cast to the enum type by the caller. +// +// The function can deal with both JSON representations, numeric and symbolic. +func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { + if data[0] == '"' { + // New style: enums are strings. + var repr string + if err := json.Unmarshal(data, &repr); err != nil { + return -1, err + } + val, ok := m[repr] + if !ok { + return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) + } + return val, nil + } + // Old style: enums are ints. + var val int32 + if err := json.Unmarshal(data, &val); err != nil { + return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) + } + return val, nil +} + +// DebugPrint dumps the encoded data in b in a debugging format with a header +// including the string s. Used in testing but made available for general debugging. +func (p *Buffer) DebugPrint(s string, b []byte) { + var u uint64 + + obuf := p.buf + sindex := p.index + p.buf = b + p.index = 0 + depth := 0 + + fmt.Printf("\n--- %s ---\n", s) + +out: + for { + for i := 0; i < depth; i++ { + fmt.Print(" ") + } + + index := p.index + if index == len(p.buf) { + break + } + + op, err := p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: fetching op err %v\n", index, err) + break out + } + tag := op >> 3 + wire := op & 7 + + switch wire { + default: + fmt.Printf("%3d: t=%3d unknown wire=%d\n", + index, tag, wire) + break out + + case WireBytes: + var r []byte + + r, err = p.DecodeRawBytes(false) + if err != nil { + break out + } + fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r)) + if len(r) <= 6 { + for i := 0; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } else { + for i := 0; i < 3; i++ { + fmt.Printf(" %.2x", r[i]) + } + fmt.Printf(" ..") + for i := len(r) - 3; i < len(r); i++ { + fmt.Printf(" %.2x", r[i]) + } + } + fmt.Printf("\n") + + case WireFixed32: + u, err = p.DecodeFixed32() + if err != nil { + fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u) + + case WireFixed64: + u, err = p.DecodeFixed64() + if err != nil { + fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u) + + case WireVarint: + u, err = p.DecodeVarint() + if err != nil { + fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err) + break out + } + fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u) + + case WireStartGroup: + fmt.Printf("%3d: t=%3d start\n", index, tag) + depth++ + + case WireEndGroup: + depth-- + fmt.Printf("%3d: t=%3d end\n", index, tag) + } + } + + if depth != 0 { + fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth) + } + fmt.Printf("\n") + + p.buf = obuf + p.index = sindex +} + +// SetDefaults sets unset protocol buffer fields to their default values. +// It only modifies fields that are both unset and have defined defaults. +// It recursively sets default values in any non-nil sub-messages. +func SetDefaults(pb Message) { + setDefaults(reflect.ValueOf(pb), true, false) +} + +// v is a struct. +func setDefaults(v reflect.Value, recur, zeros bool) { + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + defaultMu.RLock() + dm, ok := defaults[v.Type()] + defaultMu.RUnlock() + if !ok { + dm = buildDefaultMessage(v.Type()) + defaultMu.Lock() + defaults[v.Type()] = dm + defaultMu.Unlock() + } + + for _, sf := range dm.scalars { + f := v.Field(sf.index) + if !f.IsNil() { + // field already set + continue + } + dv := sf.value + if dv == nil && !zeros { + // no explicit default, and don't want to set zeros + continue + } + fptr := f.Addr().Interface() // **T + // TODO: Consider batching the allocations we do here. + switch sf.kind { + case reflect.Bool: + b := new(bool) + if dv != nil { + *b = dv.(bool) + } + *(fptr.(**bool)) = b + case reflect.Float32: + f := new(float32) + if dv != nil { + *f = dv.(float32) + } + *(fptr.(**float32)) = f + case reflect.Float64: + f := new(float64) + if dv != nil { + *f = dv.(float64) + } + *(fptr.(**float64)) = f + case reflect.Int32: + // might be an enum + if ft := f.Type(); ft != int32PtrType { + // enum + f.Set(reflect.New(ft.Elem())) + if dv != nil { + f.Elem().SetInt(int64(dv.(int32))) + } + } else { + // int32 field + i := new(int32) + if dv != nil { + *i = dv.(int32) + } + *(fptr.(**int32)) = i + } + case reflect.Int64: + i := new(int64) + if dv != nil { + *i = dv.(int64) + } + *(fptr.(**int64)) = i + case reflect.String: + s := new(string) + if dv != nil { + *s = dv.(string) + } + *(fptr.(**string)) = s + case reflect.Uint8: + // exceptional case: []byte + var b []byte + if dv != nil { + db := dv.([]byte) + b = make([]byte, len(db)) + copy(b, db) + } else { + b = []byte{} + } + *(fptr.(*[]byte)) = b + case reflect.Uint32: + u := new(uint32) + if dv != nil { + *u = dv.(uint32) + } + *(fptr.(**uint32)) = u + case reflect.Uint64: + u := new(uint64) + if dv != nil { + *u = dv.(uint64) + } + *(fptr.(**uint64)) = u + default: + log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind) + } + } + + for _, ni := range dm.nested { + f := v.Field(ni) + // f is *T or T or []*T or []T + switch f.Kind() { + case reflect.Struct: + setDefaults(f, recur, zeros) + + case reflect.Ptr: + if f.IsNil() { + continue + } + setDefaults(f, recur, zeros) + + case reflect.Slice: + for i := 0; i < f.Len(); i++ { + e := f.Index(i) + if e.Kind() == reflect.Ptr && e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + + case reflect.Map: + for _, k := range f.MapKeys() { + e := f.MapIndex(k) + if e.IsNil() { + continue + } + setDefaults(e, recur, zeros) + } + } + } +} + +var ( + // defaults maps a protocol buffer struct type to a slice of the fields, + // with its scalar fields set to their proto-declared non-zero default values. + defaultMu sync.RWMutex + defaults = make(map[reflect.Type]defaultMessage) + + int32PtrType = reflect.TypeOf((*int32)(nil)) +) + +// defaultMessage represents information about the default values of a message. +type defaultMessage struct { + scalars []scalarField + nested []int // struct field index of nested messages +} + +type scalarField struct { + index int // struct field index + kind reflect.Kind // element type (the T in *T or []T) + value interface{} // the proto-declared default value, or nil +} + +// t is a struct type. +func buildDefaultMessage(t reflect.Type) (dm defaultMessage) { + sprop := GetProperties(t) + for _, prop := range sprop.Prop { + fi, ok := sprop.decoderTags.get(prop.Tag) + if !ok { + // XXX_unrecognized + continue + } + ft := t.Field(fi).Type + + sf, nested, err := fieldDefault(ft, prop) + switch { + case err != nil: + log.Print(err) + case nested: + dm.nested = append(dm.nested, fi) + case sf != nil: + sf.index = fi + dm.scalars = append(dm.scalars, *sf) + } + } + + return dm +} + +// fieldDefault returns the scalarField for field type ft. +// sf will be nil if the field can not have a default. +// nestedMessage will be true if this is a nested message. +// Note that sf.index is not set on return. +func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) { + var canHaveDefault bool + switch ft.Kind() { + case reflect.Struct: + nestedMessage = true // non-nullable + + case reflect.Ptr: + if ft.Elem().Kind() == reflect.Struct { + nestedMessage = true + } else { + canHaveDefault = true // proto2 scalar field + } + + case reflect.Slice: + switch ft.Elem().Kind() { + case reflect.Ptr, reflect.Struct: + nestedMessage = true // repeated message + case reflect.Uint8: + canHaveDefault = true // bytes field + } + + case reflect.Map: + if ft.Elem().Kind() == reflect.Ptr { + nestedMessage = true // map with message values + } + } + + if !canHaveDefault { + if nestedMessage { + return nil, true, nil + } + return nil, false, nil + } + + // We now know that ft is a pointer or slice. + sf = &scalarField{kind: ft.Elem().Kind()} + + // scalar fields without defaults + if !prop.HasDefault { + return sf, false, nil + } + + // a scalar field: either *T or []byte + switch ft.Elem().Kind() { + case reflect.Bool: + x, err := strconv.ParseBool(prop.Default) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Float32: + x, err := strconv.ParseFloat(prop.Default, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err) + } + sf.value = float32(x) + case reflect.Float64: + x, err := strconv.ParseFloat(prop.Default, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.Int32: + x, err := strconv.ParseInt(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err) + } + sf.value = int32(x) + case reflect.Int64: + x, err := strconv.ParseInt(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err) + } + sf.value = x + case reflect.String: + sf.value = prop.Default + case reflect.Uint8: + // []byte (not *uint8) + sf.value = []byte(prop.Default) + case reflect.Uint32: + x, err := strconv.ParseUint(prop.Default, 10, 32) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err) + } + sf.value = uint32(x) + case reflect.Uint64: + x, err := strconv.ParseUint(prop.Default, 10, 64) + if err != nil { + return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err) + } + sf.value = x + default: + return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind()) + } + + return sf, false, nil +} + +// mapKeys returns a sort.Interface to be used for sorting the map keys. +// Map fields may have key types of non-float scalars, strings and enums. +func mapKeys(vs []reflect.Value) sort.Interface { + s := mapKeySorter{vs: vs} + + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. + if len(vs) == 0 { + return s + } + switch vs[0].Kind() { + case reflect.Int32, reflect.Int64: + s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() } + case reflect.Uint32, reflect.Uint64: + s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() } + case reflect.Bool: + s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true + case reflect.String: + s.less = func(a, b reflect.Value) bool { return a.String() < b.String() } + default: + panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind())) + } + + return s +} + +type mapKeySorter struct { + vs []reflect.Value + less func(a, b reflect.Value) bool +} + +func (s mapKeySorter) Len() int { return len(s.vs) } +func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s mapKeySorter) Less(i, j int) bool { + return s.less(s.vs[i], s.vs[j]) +} + +// isProto3Zero reports whether v is a zero proto3 value. +func isProto3Zero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint32, reflect.Uint64: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.String: + return v.String() == "" + } + return false +} + +const ( + // ProtoPackageIsVersion3 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + GoGoProtoPackageIsVersion3 = true + + // ProtoPackageIsVersion2 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + GoGoProtoPackageIsVersion2 = true + + // ProtoPackageIsVersion1 is referenced from generated protocol buffer files + // to assert that that code is compatible with this version of the proto package. + GoGoProtoPackageIsVersion1 = true +) + +// InternalMessageInfo is a type used internally by generated .pb.go files. +// This type is not intended to be used by non-generated code. +// This type is not subject to any compatibility guarantee. +type InternalMessageInfo struct { + marshal *marshalInfo + unmarshal *unmarshalInfo + merge *mergeInfo + discard *discardInfo +} diff --git a/vendor/github.com/gogo/protobuf/proto/lib_gogo.go b/vendor/github.com/gogo/protobuf/proto/lib_gogo.go new file mode 100644 index 0000000000..b3aa39190a --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/lib_gogo.go @@ -0,0 +1,50 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "encoding/json" + "strconv" +) + +type Sizer interface { + Size() int +} + +type ProtoSizer interface { + ProtoSize() int +} + +func MarshalJSONEnum(m map[int32]string, value int32) ([]byte, error) { + s, ok := m[value] + if !ok { + s = strconv.Itoa(int(value)) + } + return json.Marshal(s) +} diff --git a/vendor/github.com/gogo/protobuf/proto/message_set.go b/vendor/github.com/gogo/protobuf/proto/message_set.go new file mode 100644 index 0000000000..f48a756761 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/message_set.go @@ -0,0 +1,181 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Support for message sets. + */ + +import ( + "errors" +) + +// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. +// A message type ID is required for storing a protocol buffer in a message set. +var errNoMessageTypeID = errors.New("proto does not have a message type ID") + +// The first two types (_MessageSet_Item and messageSet) +// model what the protocol compiler produces for the following protocol message: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } +// That is the MessageSet wire format. We can't use a proto to generate these +// because that would introduce a circular dependency between it and this package. + +type _MessageSet_Item struct { + TypeId *int32 `protobuf:"varint,2,req,name=type_id"` + Message []byte `protobuf:"bytes,3,req,name=message"` +} + +type messageSet struct { + Item []*_MessageSet_Item `protobuf:"group,1,rep"` + XXX_unrecognized []byte + // TODO: caching? +} + +// Make sure messageSet is a Message. +var _ Message = (*messageSet)(nil) + +// messageTypeIder is an interface satisfied by a protocol buffer type +// that may be stored in a MessageSet. +type messageTypeIder interface { + MessageTypeId() int32 +} + +func (ms *messageSet) find(pb Message) *_MessageSet_Item { + mti, ok := pb.(messageTypeIder) + if !ok { + return nil + } + id := mti.MessageTypeId() + for _, item := range ms.Item { + if *item.TypeId == id { + return item + } + } + return nil +} + +func (ms *messageSet) Has(pb Message) bool { + return ms.find(pb) != nil +} + +func (ms *messageSet) Unmarshal(pb Message) error { + if item := ms.find(pb); item != nil { + return Unmarshal(item.Message, pb) + } + if _, ok := pb.(messageTypeIder); !ok { + return errNoMessageTypeID + } + return nil // TODO: return error instead? +} + +func (ms *messageSet) Marshal(pb Message) error { + msg, err := Marshal(pb) + if err != nil { + return err + } + if item := ms.find(pb); item != nil { + // reuse existing item + item.Message = msg + return nil + } + + mti, ok := pb.(messageTypeIder) + if !ok { + return errNoMessageTypeID + } + + mtid := mti.MessageTypeId() + ms.Item = append(ms.Item, &_MessageSet_Item{ + TypeId: &mtid, + Message: msg, + }) + return nil +} + +func (ms *messageSet) Reset() { *ms = messageSet{} } +func (ms *messageSet) String() string { return CompactTextString(ms) } +func (*messageSet) ProtoMessage() {} + +// Support for the message_set_wire_format message option. + +func skipVarint(buf []byte) []byte { + i := 0 + for ; buf[i]&0x80 != 0; i++ { + } + return buf[i+1:] +} + +// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format. +// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option. +func unmarshalMessageSet(buf []byte, exts interface{}) error { + var m map[int32]Extension + switch exts := exts.(type) { + case *XXX_InternalExtensions: + m = exts.extensionsWrite() + case map[int32]Extension: + m = exts + default: + return errors.New("proto: not an extension map") + } + + ms := new(messageSet) + if err := Unmarshal(buf, ms); err != nil { + return err + } + for _, item := range ms.Item { + id := *item.TypeId + msg := item.Message + + // Restore wire type and field number varint, plus length varint. + // Be careful to preserve duplicate items. + b := EncodeVarint(uint64(id)<<3 | WireBytes) + if ext, ok := m[id]; ok { + // Existing data; rip off the tag and length varint + // so we join the new data correctly. + // We can assume that ext.enc is set because we are unmarshaling. + o := ext.enc[len(b):] // skip wire type and field number + _, n := DecodeVarint(o) // calculate length of length varint + o = o[n:] // skip length varint + msg = append(o, msg...) // join old data and new data + } + b = append(b, EncodeVarint(uint64(len(msg)))...) + b = append(b, msg...) + + m[id] = Extension{enc: b} + } + return nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go new file mode 100644 index 0000000000..b6cad90834 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go @@ -0,0 +1,357 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build purego appengine js + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "reflect" + "sync" +) + +const unsafeAllowed = false + +// A field identifies a field in a struct, accessible from a pointer. +// In this implementation, a field is identified by the sequence of field indices +// passed to reflect's FieldByIndex. +type field []int + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return f.Index +} + +// invalidField is an invalid field identifier. +var invalidField = field(nil) + +// zeroField is a noop when calling pointer.offset. +var zeroField = field([]int{}) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { return f != nil } + +// The pointer type is for the table-driven decoder. +// The implementation here uses a reflect.Value of pointer type to +// create a generic pointer. In pointer_unsafe.go we use unsafe +// instead of reflect to implement the same (but faster) interface. +type pointer struct { + v reflect.Value +} + +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + return pointer{v: reflect.ValueOf(*i)} +} + +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr bool) pointer { + v := reflect.ValueOf(*i) + u := reflect.New(v.Type()) + u.Elem().Set(v) + return pointer{v: u} +} + +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{v: v} +} + +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + return pointer{v: p.v.Elem().FieldByIndex(f).Addr()} +} + +func (p pointer) isNil() bool { + return p.v.IsNil() +} + +// grow updates the slice s in place to make it one element longer. +// s must be addressable. +// Returns the (addressable) new element. +func grow(s reflect.Value) reflect.Value { + n, m := s.Len(), s.Cap() + if n < m { + s.SetLen(n + 1) + } else { + s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) + } + return s.Index(n) +} + +func (p pointer) toInt64() *int64 { + return p.v.Interface().(*int64) +} +func (p pointer) toInt64Ptr() **int64 { + return p.v.Interface().(**int64) +} +func (p pointer) toInt64Slice() *[]int64 { + return p.v.Interface().(*[]int64) +} + +var int32ptr = reflect.TypeOf((*int32)(nil)) + +func (p pointer) toInt32() *int32 { + return p.v.Convert(int32ptr).Interface().(*int32) +} + +// The toInt32Ptr/Slice methods don't work because of enums. +// Instead, we must use set/get methods for the int32ptr/slice case. +/* + func (p pointer) toInt32Ptr() **int32 { + return p.v.Interface().(**int32) +} + func (p pointer) toInt32Slice() *[]int32 { + return p.v.Interface().(*[]int32) +} +*/ +func (p pointer) getInt32Ptr() *int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().(*int32) + } + // an enum + return p.v.Elem().Convert(int32PtrType).Interface().(*int32) +} +func (p pointer) setInt32Ptr(v int32) { + // Allocate value in a *int32. Possibly convert that to a *enum. + // Then assign it to a **int32 or **enum. + // Note: we can convert *int32 to *enum, but we can't convert + // **int32 to **enum! + p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem())) +} + +// getInt32Slice copies []int32 from p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getInt32Slice() []int32 { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + return p.v.Elem().Interface().([]int32) + } + // an enum + // Allocate a []int32, then assign []enum's values into it. + // Note: we can't convert []enum to []int32. + slice := p.v.Elem() + s := make([]int32, slice.Len()) + for i := 0; i < slice.Len(); i++ { + s[i] = int32(slice.Index(i).Int()) + } + return s +} + +// setInt32Slice copies []int32 into p as a new slice. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setInt32Slice(v []int32) { + if p.v.Type().Elem().Elem() == reflect.TypeOf(int32(0)) { + // raw int32 type + p.v.Elem().Set(reflect.ValueOf(v)) + return + } + // an enum + // Allocate a []enum, then assign []int32's values into it. + // Note: we can't convert []enum to []int32. + slice := reflect.MakeSlice(p.v.Type().Elem(), len(v), cap(v)) + for i, x := range v { + slice.Index(i).SetInt(int64(x)) + } + p.v.Elem().Set(slice) +} +func (p pointer) appendInt32Slice(v int32) { + grow(p.v.Elem()).SetInt(int64(v)) +} + +func (p pointer) toUint64() *uint64 { + return p.v.Interface().(*uint64) +} +func (p pointer) toUint64Ptr() **uint64 { + return p.v.Interface().(**uint64) +} +func (p pointer) toUint64Slice() *[]uint64 { + return p.v.Interface().(*[]uint64) +} +func (p pointer) toUint32() *uint32 { + return p.v.Interface().(*uint32) +} +func (p pointer) toUint32Ptr() **uint32 { + return p.v.Interface().(**uint32) +} +func (p pointer) toUint32Slice() *[]uint32 { + return p.v.Interface().(*[]uint32) +} +func (p pointer) toBool() *bool { + return p.v.Interface().(*bool) +} +func (p pointer) toBoolPtr() **bool { + return p.v.Interface().(**bool) +} +func (p pointer) toBoolSlice() *[]bool { + return p.v.Interface().(*[]bool) +} +func (p pointer) toFloat64() *float64 { + return p.v.Interface().(*float64) +} +func (p pointer) toFloat64Ptr() **float64 { + return p.v.Interface().(**float64) +} +func (p pointer) toFloat64Slice() *[]float64 { + return p.v.Interface().(*[]float64) +} +func (p pointer) toFloat32() *float32 { + return p.v.Interface().(*float32) +} +func (p pointer) toFloat32Ptr() **float32 { + return p.v.Interface().(**float32) +} +func (p pointer) toFloat32Slice() *[]float32 { + return p.v.Interface().(*[]float32) +} +func (p pointer) toString() *string { + return p.v.Interface().(*string) +} +func (p pointer) toStringPtr() **string { + return p.v.Interface().(**string) +} +func (p pointer) toStringSlice() *[]string { + return p.v.Interface().(*[]string) +} +func (p pointer) toBytes() *[]byte { + return p.v.Interface().(*[]byte) +} +func (p pointer) toBytesSlice() *[][]byte { + return p.v.Interface().(*[][]byte) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return p.v.Interface().(*XXX_InternalExtensions) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return p.v.Interface().(*map[int32]Extension) +} +func (p pointer) getPointer() pointer { + return pointer{v: p.v.Elem()} +} +func (p pointer) setPointer(q pointer) { + p.v.Elem().Set(q.v) +} +func (p pointer) appendPointer(q pointer) { + grow(p.v.Elem()).Set(q.v) +} + +// getPointerSlice copies []*T from p as a new []pointer. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) getPointerSlice() []pointer { + if p.v.IsNil() { + return nil + } + n := p.v.Elem().Len() + s := make([]pointer, n) + for i := 0; i < n; i++ { + s[i] = pointer{v: p.v.Elem().Index(i)} + } + return s +} + +// setPointerSlice copies []pointer into p as a new []*T. +// This behavior differs from the implementation in pointer_unsafe.go. +func (p pointer) setPointerSlice(v []pointer) { + if v == nil { + p.v.Elem().Set(reflect.New(p.v.Elem().Type()).Elem()) + return + } + s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) + for _, p := range v { + s = reflect.Append(s, p.v) + } + p.v.Elem().Set(s) +} + +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + if p.v.Elem().IsNil() { + return pointer{v: p.v.Elem()} + } + return pointer{v: p.v.Elem().Elem().Elem().Field(0).Addr()} // *interface -> interface -> *struct -> struct +} + +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + // TODO: check that p.v.Type().Elem() == t? + return p.v +} + +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + atomicLock.Lock() + defer atomicLock.Unlock() + return *p +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomicLock.Lock() + defer atomicLock.Unlock() + *p = v +} + +var atomicLock sync.Mutex diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go new file mode 100644 index 0000000000..7ffd3c29d9 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go @@ -0,0 +1,59 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build purego appengine js + +// This file contains an implementation of proto field accesses using package reflect. +// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can +// be used on App Engine. + +package proto + +import ( + "reflect" +) + +// TODO: untested, so probably incorrect. + +func (p pointer) getRef() pointer { + return pointer{v: p.v.Addr()} +} + +func (p pointer) appendRef(v pointer, typ reflect.Type) { + slice := p.getSlice(typ) + elem := v.asPointerTo(typ).Elem() + newSlice := reflect.Append(slice, elem) + slice.Set(newSlice) +} + +func (p pointer) getSlice(typ reflect.Type) reflect.Value { + sliceTyp := reflect.SliceOf(typ) + slice := p.asPointerTo(sliceTyp) + slice = slice.Elem() + return slice +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go new file mode 100644 index 0000000000..d55a335d94 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go @@ -0,0 +1,308 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build !purego,!appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "sync/atomic" + "unsafe" +) + +const unsafeAllowed = true + +// A field identifies a field in a struct, accessible from a pointer. +// In this implementation, a field is identified by its byte offset from the start of the struct. +type field uintptr + +// toField returns a field equivalent to the given reflect field. +func toField(f *reflect.StructField) field { + return field(f.Offset) +} + +// invalidField is an invalid field identifier. +const invalidField = ^field(0) + +// zeroField is a noop when calling pointer.offset. +const zeroField = field(0) + +// IsValid reports whether the field identifier is valid. +func (f field) IsValid() bool { + return f != invalidField +} + +// The pointer type below is for the new table-driven encoder/decoder. +// The implementation here uses unsafe.Pointer to create a generic pointer. +// In pointer_reflect.go we use reflect instead of unsafe to implement +// the same (but slower) interface. +type pointer struct { + p unsafe.Pointer +} + +// size of pointer +var ptrSize = unsafe.Sizeof(uintptr(0)) + +// toPointer converts an interface of pointer type to a pointer +// that points to the same target. +func toPointer(i *Message) pointer { + // Super-tricky - read pointer out of data word of interface value. + // Saves ~25ns over the equivalent: + // return valToPointer(reflect.ValueOf(*i)) + return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} +} + +// toAddrPointer converts an interface to a pointer that points to +// the interface data. +func toAddrPointer(i *interface{}, isptr bool) pointer { + // Super-tricky - read or get the address of data word of interface value. + if isptr { + // The interface is of pointer type, thus it is a direct interface. + // The data word is the pointer data itself. We take its address. + return pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} + } + // The interface is not of pointer type. The data word is the pointer + // to the data. + return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} +} + +// valToPointer converts v to a pointer. v must be of pointer type. +func valToPointer(v reflect.Value) pointer { + return pointer{p: unsafe.Pointer(v.Pointer())} +} + +// offset converts from a pointer to a structure to a pointer to +// one of its fields. +func (p pointer) offset(f field) pointer { + // For safety, we should panic if !f.IsValid, however calling panic causes + // this to no longer be inlineable, which is a serious performance cost. + /* + if !f.IsValid() { + panic("invalid field") + } + */ + return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} +} + +func (p pointer) isNil() bool { + return p.p == nil +} + +func (p pointer) toInt64() *int64 { + return (*int64)(p.p) +} +func (p pointer) toInt64Ptr() **int64 { + return (**int64)(p.p) +} +func (p pointer) toInt64Slice() *[]int64 { + return (*[]int64)(p.p) +} +func (p pointer) toInt32() *int32 { + return (*int32)(p.p) +} + +// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. +/* + func (p pointer) toInt32Ptr() **int32 { + return (**int32)(p.p) + } + func (p pointer) toInt32Slice() *[]int32 { + return (*[]int32)(p.p) + } +*/ +func (p pointer) getInt32Ptr() *int32 { + return *(**int32)(p.p) +} +func (p pointer) setInt32Ptr(v int32) { + *(**int32)(p.p) = &v +} + +// getInt32Slice loads a []int32 from p. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getInt32Slice() []int32 { + return *(*[]int32)(p.p) +} + +// setInt32Slice stores a []int32 to p. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setInt32Slice(v []int32) { + *(*[]int32)(p.p) = v +} + +// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? +func (p pointer) appendInt32Slice(v int32) { + s := (*[]int32)(p.p) + *s = append(*s, v) +} + +func (p pointer) toUint64() *uint64 { + return (*uint64)(p.p) +} +func (p pointer) toUint64Ptr() **uint64 { + return (**uint64)(p.p) +} +func (p pointer) toUint64Slice() *[]uint64 { + return (*[]uint64)(p.p) +} +func (p pointer) toUint32() *uint32 { + return (*uint32)(p.p) +} +func (p pointer) toUint32Ptr() **uint32 { + return (**uint32)(p.p) +} +func (p pointer) toUint32Slice() *[]uint32 { + return (*[]uint32)(p.p) +} +func (p pointer) toBool() *bool { + return (*bool)(p.p) +} +func (p pointer) toBoolPtr() **bool { + return (**bool)(p.p) +} +func (p pointer) toBoolSlice() *[]bool { + return (*[]bool)(p.p) +} +func (p pointer) toFloat64() *float64 { + return (*float64)(p.p) +} +func (p pointer) toFloat64Ptr() **float64 { + return (**float64)(p.p) +} +func (p pointer) toFloat64Slice() *[]float64 { + return (*[]float64)(p.p) +} +func (p pointer) toFloat32() *float32 { + return (*float32)(p.p) +} +func (p pointer) toFloat32Ptr() **float32 { + return (**float32)(p.p) +} +func (p pointer) toFloat32Slice() *[]float32 { + return (*[]float32)(p.p) +} +func (p pointer) toString() *string { + return (*string)(p.p) +} +func (p pointer) toStringPtr() **string { + return (**string)(p.p) +} +func (p pointer) toStringSlice() *[]string { + return (*[]string)(p.p) +} +func (p pointer) toBytes() *[]byte { + return (*[]byte)(p.p) +} +func (p pointer) toBytesSlice() *[][]byte { + return (*[][]byte)(p.p) +} +func (p pointer) toExtensions() *XXX_InternalExtensions { + return (*XXX_InternalExtensions)(p.p) +} +func (p pointer) toOldExtensions() *map[int32]Extension { + return (*map[int32]Extension)(p.p) +} + +// getPointerSlice loads []*T from p as a []pointer. +// The value returned is aliased with the original slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) getPointerSlice() []pointer { + // Super-tricky - p should point to a []*T where T is a + // message type. We load it as []pointer. + return *(*[]pointer)(p.p) +} + +// setPointerSlice stores []pointer into p as a []*T. +// The value set is aliased with the input slice. +// This behavior differs from the implementation in pointer_reflect.go. +func (p pointer) setPointerSlice(v []pointer) { + // Super-tricky - p should point to a []*T where T is a + // message type. We store it as []pointer. + *(*[]pointer)(p.p) = v +} + +// getPointer loads the pointer at p and returns it. +func (p pointer) getPointer() pointer { + return pointer{p: *(*unsafe.Pointer)(p.p)} +} + +// setPointer stores the pointer q at p. +func (p pointer) setPointer(q pointer) { + *(*unsafe.Pointer)(p.p) = q.p +} + +// append q to the slice pointed to by p. +func (p pointer) appendPointer(q pointer) { + s := (*[]unsafe.Pointer)(p.p) + *s = append(*s, q.p) +} + +// getInterfacePointer returns a pointer that points to the +// interface data of the interface pointed by p. +func (p pointer) getInterfacePointer() pointer { + // Super-tricky - read pointer out of data word of interface value. + return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} +} + +// asPointerTo returns a reflect.Value that is a pointer to an +// object of type t stored at p. +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + return reflect.NewAt(t, p.p) +} + +func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { + return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { + return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { + return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} +func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { + return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} +func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) +} diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go new file mode 100644 index 0000000000..aca8eed02a --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go @@ -0,0 +1,56 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build !purego,!appengine,!js + +// This file contains the implementation of the proto field accesses using package unsafe. + +package proto + +import ( + "reflect" + "unsafe" +) + +func (p pointer) getRef() pointer { + return pointer{p: (unsafe.Pointer)(&p.p)} +} + +func (p pointer) appendRef(v pointer, typ reflect.Type) { + slice := p.getSlice(typ) + elem := v.asPointerTo(typ).Elem() + newSlice := reflect.Append(slice, elem) + slice.Set(newSlice) +} + +func (p pointer) getSlice(typ reflect.Type) reflect.Value { + sliceTyp := reflect.SliceOf(typ) + slice := p.asPointerTo(sliceTyp) + slice = slice.Elem() + return slice +} diff --git a/vendor/github.com/gogo/protobuf/proto/properties.go b/vendor/github.com/gogo/protobuf/proto/properties.go new file mode 100644 index 0000000000..28da1475fb --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/properties.go @@ -0,0 +1,610 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +/* + * Routines for encoding data into the wire format for protocol buffers. + */ + +import ( + "fmt" + "log" + "reflect" + "sort" + "strconv" + "strings" + "sync" +) + +const debug bool = false + +// Constants that identify the encoding of a value on the wire. +const ( + WireVarint = 0 + WireFixed64 = 1 + WireBytes = 2 + WireStartGroup = 3 + WireEndGroup = 4 + WireFixed32 = 5 +) + +// tagMap is an optimization over map[int]int for typical protocol buffer +// use-cases. Encoded protocol buffers are often in tag order with small tag +// numbers. +type tagMap struct { + fastTags []int + slowTags map[int]int +} + +// tagMapFastLimit is the upper bound on the tag number that will be stored in +// the tagMap slice rather than its map. +const tagMapFastLimit = 1024 + +func (p *tagMap) get(t int) (int, bool) { + if t > 0 && t < tagMapFastLimit { + if t >= len(p.fastTags) { + return 0, false + } + fi := p.fastTags[t] + return fi, fi >= 0 + } + fi, ok := p.slowTags[t] + return fi, ok +} + +func (p *tagMap) put(t int, fi int) { + if t > 0 && t < tagMapFastLimit { + for len(p.fastTags) < t+1 { + p.fastTags = append(p.fastTags, -1) + } + p.fastTags[t] = fi + return + } + if p.slowTags == nil { + p.slowTags = make(map[int]int) + } + p.slowTags[t] = fi +} + +// StructProperties represents properties for all the fields of a struct. +// decoderTags and decoderOrigNames should only be used by the decoder. +type StructProperties struct { + Prop []*Properties // properties for each field + reqCount int // required count + decoderTags tagMap // map from proto tag to struct field number + decoderOrigNames map[string]int // map from original name to struct field number + order []int // list of struct field numbers in tag order + + // OneofTypes contains information about the oneof fields in this message. + // It is keyed by the original name of a field. + OneofTypes map[string]*OneofProperties +} + +// OneofProperties represents information about a specific field in a oneof. +type OneofProperties struct { + Type reflect.Type // pointer to generated struct type for this oneof field + Field int // struct field number of the containing oneof in the message + Prop *Properties +} + +// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec. +// See encode.go, (*Buffer).enc_struct. + +func (sp *StructProperties) Len() int { return len(sp.order) } +func (sp *StructProperties) Less(i, j int) bool { + return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag +} +func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] } + +// Properties represents the protocol-specific behavior of a single struct field. +type Properties struct { + Name string // name of the field, for error messages + OrigName string // original name before protocol compiler (always set) + JSONName string // name to use for JSON; determined by protoc + Wire string + WireType int + Tag int + Required bool + Optional bool + Repeated bool + Packed bool // relevant for repeated primitives only + Enum string // set for enum types only + proto3 bool // whether this is known to be a proto3 field + oneof bool // whether this is a oneof field + + Default string // default value + HasDefault bool // whether an explicit default was provided + CustomType string + CastType string + StdTime bool + StdDuration bool + WktPointer bool + + stype reflect.Type // set for struct types only + ctype reflect.Type // set for custom types only + sprop *StructProperties // set for struct types only + + mtype reflect.Type // set for map types only + MapKeyProp *Properties // set for map types only + MapValProp *Properties // set for map types only +} + +// String formats the properties in the protobuf struct field tag style. +func (p *Properties) String() string { + s := p.Wire + s += "," + s += strconv.Itoa(p.Tag) + if p.Required { + s += ",req" + } + if p.Optional { + s += ",opt" + } + if p.Repeated { + s += ",rep" + } + if p.Packed { + s += ",packed" + } + s += ",name=" + p.OrigName + if p.JSONName != p.OrigName { + s += ",json=" + p.JSONName + } + if p.proto3 { + s += ",proto3" + } + if p.oneof { + s += ",oneof" + } + if len(p.Enum) > 0 { + s += ",enum=" + p.Enum + } + if p.HasDefault { + s += ",def=" + p.Default + } + return s +} + +// Parse populates p by parsing a string in the protobuf struct field tag style. +func (p *Properties) Parse(s string) { + // "bytes,49,opt,name=foo,def=hello!" + fields := strings.Split(s, ",") // breaks def=, but handled below. + if len(fields) < 2 { + log.Printf("proto: tag has too few fields: %q", s) + return + } + + p.Wire = fields[0] + switch p.Wire { + case "varint": + p.WireType = WireVarint + case "fixed32": + p.WireType = WireFixed32 + case "fixed64": + p.WireType = WireFixed64 + case "zigzag32": + p.WireType = WireVarint + case "zigzag64": + p.WireType = WireVarint + case "bytes", "group": + p.WireType = WireBytes + // no numeric converter for non-numeric types + default: + log.Printf("proto: tag has unknown wire type: %q", s) + return + } + + var err error + p.Tag, err = strconv.Atoi(fields[1]) + if err != nil { + return + } + +outer: + for i := 2; i < len(fields); i++ { + f := fields[i] + switch { + case f == "req": + p.Required = true + case f == "opt": + p.Optional = true + case f == "rep": + p.Repeated = true + case f == "packed": + p.Packed = true + case strings.HasPrefix(f, "name="): + p.OrigName = f[5:] + case strings.HasPrefix(f, "json="): + p.JSONName = f[5:] + case strings.HasPrefix(f, "enum="): + p.Enum = f[5:] + case f == "proto3": + p.proto3 = true + case f == "oneof": + p.oneof = true + case strings.HasPrefix(f, "def="): + p.HasDefault = true + p.Default = f[4:] // rest of string + if i+1 < len(fields) { + // Commas aren't escaped, and def is always last. + p.Default += "," + strings.Join(fields[i+1:], ",") + break outer + } + case strings.HasPrefix(f, "embedded="): + p.OrigName = strings.Split(f, "=")[1] + case strings.HasPrefix(f, "customtype="): + p.CustomType = strings.Split(f, "=")[1] + case strings.HasPrefix(f, "casttype="): + p.CastType = strings.Split(f, "=")[1] + case f == "stdtime": + p.StdTime = true + case f == "stdduration": + p.StdDuration = true + case f == "wktptr": + p.WktPointer = true + } + } +} + +var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem() + +// setFieldProps initializes the field properties for submessages and maps. +func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, lockGetProp bool) { + isMap := typ.Kind() == reflect.Map + if len(p.CustomType) > 0 && !isMap { + p.ctype = typ + p.setTag(lockGetProp) + return + } + if p.StdTime && !isMap { + p.setTag(lockGetProp) + return + } + if p.StdDuration && !isMap { + p.setTag(lockGetProp) + return + } + if p.WktPointer && !isMap { + p.setTag(lockGetProp) + return + } + switch t1 := typ; t1.Kind() { + case reflect.Struct: + p.stype = typ + case reflect.Ptr: + if t1.Elem().Kind() == reflect.Struct { + p.stype = t1.Elem() + } + case reflect.Slice: + switch t2 := t1.Elem(); t2.Kind() { + case reflect.Ptr: + switch t3 := t2.Elem(); t3.Kind() { + case reflect.Struct: + p.stype = t3 + } + case reflect.Struct: + p.stype = t2 + } + + case reflect.Map: + + p.mtype = t1 + p.MapKeyProp = &Properties{} + p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) + p.MapValProp = &Properties{} + vtype := p.mtype.Elem() + if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { + // The value type is not a message (*T) or bytes ([]byte), + // so we need encoders for the pointer to this type. + vtype = reflect.PtrTo(vtype) + } + + p.MapValProp.CustomType = p.CustomType + p.MapValProp.StdDuration = p.StdDuration + p.MapValProp.StdTime = p.StdTime + p.MapValProp.WktPointer = p.WktPointer + p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) + } + p.setTag(lockGetProp) +} + +func (p *Properties) setTag(lockGetProp bool) { + if p.stype != nil { + if lockGetProp { + p.sprop = GetProperties(p.stype) + } else { + p.sprop = getPropertiesLocked(p.stype) + } + } +} + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() +) + +// Init populates the properties from a protocol buffer struct tag. +func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { + p.init(typ, name, tag, f, true) +} + +func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) { + // "bytes,49,opt,def=hello!" + p.Name = name + p.OrigName = name + if tag == "" { + return + } + p.Parse(tag) + p.setFieldProps(typ, f, lockGetProp) +} + +var ( + propertiesMu sync.RWMutex + propertiesMap = make(map[reflect.Type]*StructProperties) +) + +// GetProperties returns the list of properties for the type represented by t. +// t must represent a generated struct type of a protocol message. +func GetProperties(t reflect.Type) *StructProperties { + if t.Kind() != reflect.Struct { + panic("proto: type must have kind struct") + } + + // Most calls to GetProperties in a long-running program will be + // retrieving details for types we have seen before. + propertiesMu.RLock() + sprop, ok := propertiesMap[t] + propertiesMu.RUnlock() + if ok { + return sprop + } + + propertiesMu.Lock() + sprop = getPropertiesLocked(t) + propertiesMu.Unlock() + return sprop +} + +type ( + oneofFuncsIface interface { + XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{}) + } + oneofWrappersIface interface { + XXX_OneofWrappers() []interface{} + } +) + +// getPropertiesLocked requires that propertiesMu is held. +func getPropertiesLocked(t reflect.Type) *StructProperties { + if prop, ok := propertiesMap[t]; ok { + return prop + } + + prop := new(StructProperties) + // in case of recursive protos, fill this in now. + propertiesMap[t] = prop + + // build properties + prop.Prop = make([]*Properties, t.NumField()) + prop.order = make([]int, t.NumField()) + + isOneofMessage := false + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + p := new(Properties) + name := f.Name + p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false) + + oneof := f.Tag.Get("protobuf_oneof") // special case + if oneof != "" { + isOneofMessage = true + // Oneof fields don't use the traditional protobuf tag. + p.OrigName = oneof + } + prop.Prop[i] = p + prop.order[i] = i + if debug { + print(i, " ", f.Name, " ", t.String(), " ") + if p.Tag > 0 { + print(p.String()) + } + print("\n") + } + } + + // Re-order prop.order. + sort.Sort(prop) + + if isOneofMessage { + var oots []interface{} + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oots = m.XXX_OneofFuncs() + case oneofWrappersIface: + oots = m.XXX_OneofWrappers() + } + if len(oots) > 0 { + // Interpret oneof metadata. + prop.OneofTypes = make(map[string]*OneofProperties) + for _, oot := range oots { + oop := &OneofProperties{ + Type: reflect.ValueOf(oot).Type(), // *T + Prop: new(Properties), + } + sft := oop.Type.Elem().Field(0) + oop.Prop.Name = sft.Name + oop.Prop.Parse(sft.Tag.Get("protobuf")) + // There will be exactly one interface field that + // this new value is assignable to. + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Type.Kind() != reflect.Interface { + continue + } + if !oop.Type.AssignableTo(f.Type) { + continue + } + oop.Field = i + break + } + prop.OneofTypes[oop.Prop.OrigName] = oop + } + } + } + + // build required counts + // build tags + reqCount := 0 + prop.decoderOrigNames = make(map[string]int) + for i, p := range prop.Prop { + if strings.HasPrefix(p.Name, "XXX_") { + // Internal fields should not appear in tags/origNames maps. + // They are handled specially when encoding and decoding. + continue + } + if p.Required { + reqCount++ + } + prop.decoderTags.put(p.Tag, i) + prop.decoderOrigNames[p.OrigName] = i + } + prop.reqCount = reqCount + + return prop +} + +// A global registry of enum types. +// The generated code will register the generated maps by calling RegisterEnum. + +var enumValueMaps = make(map[string]map[string]int32) +var enumStringMaps = make(map[string]map[int32]string) + +// RegisterEnum is called from the generated code to install the enum descriptor +// maps into the global table to aid parsing text format protocol buffers. +func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) { + if _, ok := enumValueMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumValueMaps[typeName] = valueMap + if _, ok := enumStringMaps[typeName]; ok { + panic("proto: duplicate enum registered: " + typeName) + } + enumStringMaps[typeName] = unusedNameMap +} + +// EnumValueMap returns the mapping from names to integers of the +// enum type enumType, or a nil if not found. +func EnumValueMap(enumType string) map[string]int32 { + return enumValueMaps[enumType] +} + +// A registry of all linked message types. +// The string is a fully-qualified proto name ("pkg.Message"). +var ( + protoTypedNils = make(map[string]Message) // a map from proto names to typed nil pointers + protoMapTypes = make(map[string]reflect.Type) // a map from proto names to map types + revProtoTypes = make(map[reflect.Type]string) +) + +// RegisterType is called from generated code and maps from the fully qualified +// proto name to the type (pointer to struct) of the protocol buffer. +func RegisterType(x Message, name string) { + if _, ok := protoTypedNils[name]; ok { + // TODO: Some day, make this a panic. + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + if v := reflect.ValueOf(x); v.Kind() == reflect.Ptr && v.Pointer() == 0 { + // Generated code always calls RegisterType with nil x. + // This check is just for extra safety. + protoTypedNils[name] = x + } else { + protoTypedNils[name] = reflect.Zero(t).Interface().(Message) + } + revProtoTypes[t] = name +} + +// RegisterMapType is called from generated code and maps from the fully qualified +// proto name to the native map type of the proto map definition. +func RegisterMapType(x interface{}, name string) { + if reflect.TypeOf(x).Kind() != reflect.Map { + panic(fmt.Sprintf("RegisterMapType(%T, %q); want map", x, name)) + } + if _, ok := protoMapTypes[name]; ok { + log.Printf("proto: duplicate proto type registered: %s", name) + return + } + t := reflect.TypeOf(x) + protoMapTypes[name] = t + revProtoTypes[t] = name +} + +// MessageName returns the fully-qualified proto name for the given message type. +func MessageName(x Message) string { + type xname interface { + XXX_MessageName() string + } + if m, ok := x.(xname); ok { + return m.XXX_MessageName() + } + return revProtoTypes[reflect.TypeOf(x)] +} + +// MessageType returns the message type (pointer to struct) for a named message. +// The type is not guaranteed to implement proto.Message if the name refers to a +// map entry. +func MessageType(name string) reflect.Type { + if t, ok := protoTypedNils[name]; ok { + return reflect.TypeOf(t) + } + return protoMapTypes[name] +} + +// A registry of all linked proto files. +var ( + protoFiles = make(map[string][]byte) // file name => fileDescriptor +) + +// RegisterFile is called from generated code and maps from the +// full file name of a .proto file to its compressed FileDescriptorProto. +func RegisterFile(filename string, fileDescriptor []byte) { + protoFiles[filename] = fileDescriptor +} + +// FileDescriptor returns the compressed FileDescriptorProto for a .proto file. +func FileDescriptor(filename string) []byte { return protoFiles[filename] } diff --git a/vendor/github.com/gogo/protobuf/proto/properties_gogo.go b/vendor/github.com/gogo/protobuf/proto/properties_gogo.go new file mode 100644 index 0000000000..40ea3dd935 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/properties_gogo.go @@ -0,0 +1,36 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" +) + +var sizerType = reflect.TypeOf((*Sizer)(nil)).Elem() +var protosizerType = reflect.TypeOf((*ProtoSizer)(nil)).Elem() diff --git a/vendor/github.com/gogo/protobuf/proto/skip_gogo.go b/vendor/github.com/gogo/protobuf/proto/skip_gogo.go new file mode 100644 index 0000000000..5a5fd93f7c --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/skip_gogo.go @@ -0,0 +1,119 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "io" +) + +func Skip(data []byte) (n int, err error) { + l := len(data) + index := 0 + for index < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + index++ + if data[index-1] < 0x80 { + break + } + } + return index, nil + case 1: + index += 8 + return index, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + index += length + return index, nil + case 3: + for { + var innerWire uint64 + var start int = index + for shift := uint(0); ; shift += 7 { + if index >= l { + return 0, io.ErrUnexpectedEOF + } + b := data[index] + index++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := Skip(data[start:]) + if err != nil { + return 0, err + } + index = start + next + } + return index, nil + case 4: + return index, nil + case 5: + index += 4 + return index, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} diff --git a/vendor/github.com/gogo/protobuf/proto/table_marshal.go b/vendor/github.com/gogo/protobuf/proto/table_marshal.go new file mode 100644 index 0000000000..f8babdefab --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/table_marshal.go @@ -0,0 +1,3009 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "errors" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// a sizer takes a pointer to a field and the size of its tag, computes the size of +// the encoded data. +type sizer func(pointer, int) int + +// a marshaler takes a byte slice, a pointer to a field, and its tag (in wire format), +// marshals the field to the end of the slice, returns the slice and error (if any). +type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) + +// marshalInfo is the information used for marshaling a message. +type marshalInfo struct { + typ reflect.Type + fields []*marshalFieldInfo + unrecognized field // offset of XXX_unrecognized + extensions field // offset of XXX_InternalExtensions + v1extensions field // offset of XXX_extensions + sizecache field // offset of XXX_sizecache + initialized int32 // 0 -- only typ is set, 1 -- fully initialized + messageset bool // uses message set wire format + hasmarshaler bool // has custom marshaler + sync.RWMutex // protect extElems map, also for initialization + extElems map[int32]*marshalElemInfo // info of extension elements + + hassizer bool // has custom sizer + hasprotosizer bool // has custom protosizer + + bytesExtensions field // offset of XXX_extensions where the field type is []byte +} + +// marshalFieldInfo is the information used for marshaling a field of a message. +type marshalFieldInfo struct { + field field + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isPointer bool + required bool // field is required + name string // name of the field, for error reporting + oneofElems map[reflect.Type]*marshalElemInfo // info of oneof elements +} + +// marshalElemInfo is the information used for marshaling an extension or oneof element. +type marshalElemInfo struct { + wiretag uint64 // tag in wire format + tagsize int // size of tag in wire format + sizer sizer + marshaler marshaler + isptr bool // elem is pointer typed, thus interface of this type is a direct interface (extension only) +} + +var ( + marshalInfoMap = map[reflect.Type]*marshalInfo{} + marshalInfoLock sync.Mutex + + uint8SliceType = reflect.TypeOf(([]uint8)(nil)).Kind() +) + +// getMarshalInfo returns the information to marshal a given type of message. +// The info it returns may not necessarily initialized. +// t is the type of the message (NOT the pointer to it). +func getMarshalInfo(t reflect.Type) *marshalInfo { + marshalInfoLock.Lock() + u, ok := marshalInfoMap[t] + if !ok { + u = &marshalInfo{typ: t} + marshalInfoMap[t] = u + } + marshalInfoLock.Unlock() + return u +} + +// Size is the entry point from generated code, +// and should be ONLY called by generated code. +// It computes the size of encoded data of msg. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Size(msg Message) int { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return 0 + } + return u.size(ptr) +} + +// Marshal is the entry point from generated code, +// and should be ONLY called by generated code. +// It marshals msg to the end of b. +// a is a pointer to a place to store cached marshal info. +func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) { + u := getMessageMarshalInfo(msg, a) + ptr := toPointer(&msg) + if ptr.isNil() { + // We get here if msg is a typed nil ((*SomeMessage)(nil)), + // so it satisfies the interface, and msg == nil wouldn't + // catch it. We don't want crash in this case. + return b, ErrNil + } + return u.marshal(b, ptr, deterministic) +} + +func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo { + // u := a.marshal, but atomically. + // We use an atomic here to ensure memory consistency. + u := atomicLoadMarshalInfo(&a.marshal) + if u == nil { + // Get marshal information from type of message. + t := reflect.ValueOf(msg).Type() + if t.Kind() != reflect.Ptr { + panic(fmt.Sprintf("cannot handle non-pointer message type %v", t)) + } + u = getMarshalInfo(t.Elem()) + // Store it in the cache for later users. + // a.marshal = u, but atomically. + atomicStoreMarshalInfo(&a.marshal, u) + } + return u +} + +// size is the main function to compute the size of the encoded data of a message. +// ptr is the pointer to the message. +func (u *marshalInfo) size(ptr pointer) int { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + // Uses the message's Size method if available + if u.hassizer { + s := ptr.asPointerTo(u.typ).Interface().(Sizer) + return s.Size() + } + // Uses the message's ProtoSize method if available + if u.hasprotosizer { + s := ptr.asPointerTo(u.typ).Interface().(ProtoSizer) + return s.ProtoSize() + } + + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b, _ := m.Marshal() + return len(b) + } + + n := 0 + for _, f := range u.fields { + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + n += f.sizer(ptr.offset(f.field), f.tagsize) + } + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + n += u.sizeMessageSet(e) + } else { + n += u.sizeExtensions(e) + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + n += u.sizeV1Extensions(m) + } + if u.bytesExtensions.IsValid() { + s := *ptr.offset(u.bytesExtensions).toBytes() + n += len(s) + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + n += len(s) + } + + // cache the result for use in marshal + if u.sizecache.IsValid() { + atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n)) + } + return n +} + +// cachedsize gets the size from cache. If there is no cache (i.e. message is not generated), +// fall back to compute the size. +func (u *marshalInfo) cachedsize(ptr pointer) int { + if u.sizecache.IsValid() { + return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32())) + } + return u.size(ptr) +} + +// marshal is the main function to marshal a message. It takes a byte slice and appends +// the encoded data to the end of the slice, returns the slice and error (if any). +// ptr is the pointer to the message. +// If deterministic is true, map is marshaled in deterministic order. +func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) { + if atomic.LoadInt32(&u.initialized) == 0 { + u.computeMarshalInfo() + } + + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if u.hasmarshaler { + m := ptr.asPointerTo(u.typ).Interface().(Marshaler) + b1, err := m.Marshal() + b = append(b, b1...) + return b, err + } + + var err, errLater error + // The old marshaler encodes extensions at beginning. + if u.extensions.IsValid() { + e := ptr.offset(u.extensions).toExtensions() + if u.messageset { + b, err = u.appendMessageSet(b, e, deterministic) + } else { + b, err = u.appendExtensions(b, e, deterministic) + } + if err != nil { + return b, err + } + } + if u.v1extensions.IsValid() { + m := *ptr.offset(u.v1extensions).toOldExtensions() + b, err = u.appendV1Extensions(b, m, deterministic) + if err != nil { + return b, err + } + } + if u.bytesExtensions.IsValid() { + s := *ptr.offset(u.bytesExtensions).toBytes() + b = append(b, s...) + } + for _, f := range u.fields { + if f.required { + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // Required field is not set. + // We record the error but keep going, to give a complete marshaling. + if errLater == nil { + errLater = &RequiredNotSetError{f.name} + } + continue + } + } + if f.isPointer && ptr.offset(f.field).getPointer().isNil() { + // nil pointer always marshals to nothing + continue + } + b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic) + if err != nil { + if err1, ok := err.(*RequiredNotSetError); ok { + // Required field in submessage is not set. + // We record the error but keep going, to give a complete marshaling. + if errLater == nil { + errLater = &RequiredNotSetError{f.name + "." + err1.field} + } + continue + } + if err == errRepeatedHasNil { + err = errors.New("proto: repeated field " + f.name + " has nil element") + } + if err == errInvalidUTF8 { + if errLater == nil { + fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name + errLater = &invalidUTF8Error{fullName} + } + continue + } + return b, err + } + } + if u.unrecognized.IsValid() { + s := *ptr.offset(u.unrecognized).toBytes() + b = append(b, s...) + } + return b, errLater +} + +// computeMarshalInfo initializes the marshal info. +func (u *marshalInfo) computeMarshalInfo() { + u.Lock() + defer u.Unlock() + if u.initialized != 0 { // non-atomic read is ok as it is protected by the lock + return + } + + t := u.typ + u.unrecognized = invalidField + u.extensions = invalidField + u.v1extensions = invalidField + u.bytesExtensions = invalidField + u.sizecache = invalidField + isOneofMessage := false + + if reflect.PtrTo(t).Implements(sizerType) { + u.hassizer = true + } + if reflect.PtrTo(t).Implements(protosizerType) { + u.hasprotosizer = true + } + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + if reflect.PtrTo(t).Implements(marshalerType) { + u.hasmarshaler = true + atomic.StoreInt32(&u.initialized, 1) + return + } + + n := t.NumField() + + // deal with XXX fields first + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Tag.Get("protobuf_oneof") != "" { + isOneofMessage = true + } + if !strings.HasPrefix(f.Name, "XXX_") { + continue + } + switch f.Name { + case "XXX_sizecache": + u.sizecache = toField(&f) + case "XXX_unrecognized": + u.unrecognized = toField(&f) + case "XXX_InternalExtensions": + u.extensions = toField(&f) + u.messageset = f.Tag.Get("protobuf_messageset") == "1" + case "XXX_extensions": + if f.Type.Kind() == reflect.Map { + u.v1extensions = toField(&f) + } else { + u.bytesExtensions = toField(&f) + } + case "XXX_NoUnkeyedLiteral": + // nothing to do + default: + panic("unknown XXX field: " + f.Name) + } + n-- + } + + // get oneof implementers + var oneofImplementers []interface{} + // gogo: isOneofMessage is needed for embedded oneof messages, without a marshaler and unmarshaler + if isOneofMessage { + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oneofImplementers = m.XXX_OneofFuncs() + case oneofWrappersIface: + oneofImplementers = m.XXX_OneofWrappers() + } + } + + // normal fields + fields := make([]marshalFieldInfo, n) // batch allocation + u.fields = make([]*marshalFieldInfo, 0, n) + for i, j := 0, 0; i < t.NumField(); i++ { + f := t.Field(i) + + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + field := &fields[j] + j++ + field.name = f.Name + u.fields = append(u.fields, field) + if f.Tag.Get("protobuf_oneof") != "" { + field.computeOneofFieldInfo(&f, oneofImplementers) + continue + } + if f.Tag.Get("protobuf") == "" { + // field has no tag (not in generated message), ignore it + u.fields = u.fields[:len(u.fields)-1] + j-- + continue + } + field.computeMarshalFieldInfo(&f) + } + + // fields are marshaled in tag order on the wire. + sort.Sort(byTag(u.fields)) + + atomic.StoreInt32(&u.initialized, 1) +} + +// helper for sorting fields by tag +type byTag []*marshalFieldInfo + +func (a byTag) Len() int { return len(a) } +func (a byTag) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag } + +// getExtElemInfo returns the information to marshal an extension element. +// The info it returns is initialized. +func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo { + // get from cache first + u.RLock() + e, ok := u.extElems[desc.Field] + u.RUnlock() + if ok { + return e + } + + t := reflect.TypeOf(desc.ExtensionType) // pointer or slice to basic type or struct + tags := strings.Split(desc.Tag, ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + sizr, marshalr := typeMarshaler(t, tags, false, false) + e = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizr, + marshaler: marshalr, + isptr: t.Kind() == reflect.Ptr, + } + + // update cache + u.Lock() + if u.extElems == nil { + u.extElems = make(map[int32]*marshalElemInfo) + } + u.extElems[desc.Field] = e + u.Unlock() + return e +} + +// computeMarshalFieldInfo fills up the information to marshal a field. +func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { + // parse protobuf tag of the field. + // tag has format of "bytes,49,opt,name=foo,def=hello!" + tags := strings.Split(f.Tag.Get("protobuf"), ",") + if tags[0] == "" { + return + } + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + if tags[2] == "req" { + fi.required = true + } + fi.setTag(f, tag, wt) + fi.setMarshaler(f, tags) +} + +func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { + fi.field = toField(f) + fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. + fi.isPointer = true + fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) + fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) + + ityp := f.Type // interface type + for _, o := range oneofImplementers { + t := reflect.TypeOf(o) + if !t.Implements(ityp) { + continue + } + sf := t.Elem().Field(0) // oneof implementer is a struct with a single field + tags := strings.Split(sf.Tag.Get("protobuf"), ",") + tag, err := strconv.Atoi(tags[1]) + if err != nil { + panic("tag is not an integer") + } + wt := wiretype(tags[0]) + sizr, marshalr := typeMarshaler(sf.Type, tags, false, true) // oneof should not omit any zero value + fi.oneofElems[t.Elem()] = &marshalElemInfo{ + wiretag: uint64(tag)<<3 | wt, + tagsize: SizeVarint(uint64(tag) << 3), + sizer: sizr, + marshaler: marshalr, + } + } +} + +// wiretype returns the wire encoding of the type. +func wiretype(encoding string) uint64 { + switch encoding { + case "fixed32": + return WireFixed32 + case "fixed64": + return WireFixed64 + case "varint", "zigzag32", "zigzag64": + return WireVarint + case "bytes": + return WireBytes + case "group": + return WireStartGroup + } + panic("unknown wire type " + encoding) +} + +// setTag fills up the tag (in wire format) and its size in the info of a field. +func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) { + fi.field = toField(f) + fi.wiretag = uint64(tag)<<3 | wt + fi.tagsize = SizeVarint(uint64(tag) << 3) +} + +// setMarshaler fills up the sizer and marshaler in the info of a field. +func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) { + switch f.Type.Kind() { + case reflect.Map: + // map field + fi.isPointer = true + fi.sizer, fi.marshaler = makeMapMarshaler(f) + return + case reflect.Ptr, reflect.Slice: + fi.isPointer = true + } + fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false) +} + +// typeMarshaler returns the sizer and marshaler of a given field. +// t is the type of the field. +// tags is the generated "protobuf" tag of the field. +// If nozero is true, zero value is not marshaled to the wire. +// If oneof is true, it is a oneof field. +func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) { + encoding := tags[0] + + pointer := false + slice := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + packed := false + proto3 := false + ctype := false + isTime := false + isDuration := false + isWktPointer := false + validateUTF8 := true + for i := 2; i < len(tags); i++ { + if tags[i] == "packed" { + packed = true + } + if tags[i] == "proto3" { + proto3 = true + } + if strings.HasPrefix(tags[i], "customtype=") { + ctype = true + } + if tags[i] == "stdtime" { + isTime = true + } + if tags[i] == "stdduration" { + isDuration = true + } + if tags[i] == "wktptr" { + isWktPointer = true + } + } + validateUTF8 = validateUTF8 && proto3 + if !proto3 && !pointer && !slice { + nozero = false + } + + if ctype { + if reflect.PtrTo(t).Implements(customType) { + if slice { + return makeMessageRefSliceMarshaler(getMarshalInfo(t)) + } + if pointer { + return makeCustomPtrMarshaler(getMarshalInfo(t)) + } + return makeCustomMarshaler(getMarshalInfo(t)) + } else { + panic(fmt.Sprintf("custom type: type: %v, does not implement the proto.custom interface", t)) + } + } + + if isTime { + if pointer { + if slice { + return makeTimePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeTimePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeTimeSliceMarshaler(getMarshalInfo(t)) + } + return makeTimeMarshaler(getMarshalInfo(t)) + } + + if isDuration { + if pointer { + if slice { + return makeDurationPtrSliceMarshaler(getMarshalInfo(t)) + } + return makeDurationPtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeDurationSliceMarshaler(getMarshalInfo(t)) + } + return makeDurationMarshaler(getMarshalInfo(t)) + } + + if isWktPointer { + switch t.Kind() { + case reflect.Float64: + if pointer { + if slice { + return makeStdDoubleValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdDoubleValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdDoubleValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdDoubleValueMarshaler(getMarshalInfo(t)) + case reflect.Float32: + if pointer { + if slice { + return makeStdFloatValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdFloatValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdFloatValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdFloatValueMarshaler(getMarshalInfo(t)) + case reflect.Int64: + if pointer { + if slice { + return makeStdInt64ValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdInt64ValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdInt64ValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdInt64ValueMarshaler(getMarshalInfo(t)) + case reflect.Uint64: + if pointer { + if slice { + return makeStdUInt64ValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdUInt64ValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdUInt64ValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdUInt64ValueMarshaler(getMarshalInfo(t)) + case reflect.Int32: + if pointer { + if slice { + return makeStdInt32ValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdInt32ValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdInt32ValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdInt32ValueMarshaler(getMarshalInfo(t)) + case reflect.Uint32: + if pointer { + if slice { + return makeStdUInt32ValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdUInt32ValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdUInt32ValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdUInt32ValueMarshaler(getMarshalInfo(t)) + case reflect.Bool: + if pointer { + if slice { + return makeStdBoolValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdBoolValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdBoolValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdBoolValueMarshaler(getMarshalInfo(t)) + case reflect.String: + if pointer { + if slice { + return makeStdStringValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdStringValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdStringValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdStringValueMarshaler(getMarshalInfo(t)) + case uint8SliceType: + if pointer { + if slice { + return makeStdBytesValuePtrSliceMarshaler(getMarshalInfo(t)) + } + return makeStdBytesValuePtrMarshaler(getMarshalInfo(t)) + } + if slice { + return makeStdBytesValueSliceMarshaler(getMarshalInfo(t)) + } + return makeStdBytesValueMarshaler(getMarshalInfo(t)) + default: + panic(fmt.Sprintf("unknown wktpointer type %#v", t)) + } + } + + switch t.Kind() { + case reflect.Bool: + if pointer { + return sizeBoolPtr, appendBoolPtr + } + if slice { + if packed { + return sizeBoolPackedSlice, appendBoolPackedSlice + } + return sizeBoolSlice, appendBoolSlice + } + if nozero { + return sizeBoolValueNoZero, appendBoolValueNoZero + } + return sizeBoolValue, appendBoolValue + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixed32Ptr, appendFixed32Ptr + } + if slice { + if packed { + return sizeFixed32PackedSlice, appendFixed32PackedSlice + } + return sizeFixed32Slice, appendFixed32Slice + } + if nozero { + return sizeFixed32ValueNoZero, appendFixed32ValueNoZero + } + return sizeFixed32Value, appendFixed32Value + case "varint": + if pointer { + return sizeVarint32Ptr, appendVarint32Ptr + } + if slice { + if packed { + return sizeVarint32PackedSlice, appendVarint32PackedSlice + } + return sizeVarint32Slice, appendVarint32Slice + } + if nozero { + return sizeVarint32ValueNoZero, appendVarint32ValueNoZero + } + return sizeVarint32Value, appendVarint32Value + } + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return sizeFixedS32Ptr, appendFixedS32Ptr + } + if slice { + if packed { + return sizeFixedS32PackedSlice, appendFixedS32PackedSlice + } + return sizeFixedS32Slice, appendFixedS32Slice + } + if nozero { + return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero + } + return sizeFixedS32Value, appendFixedS32Value + case "varint": + if pointer { + return sizeVarintS32Ptr, appendVarintS32Ptr + } + if slice { + if packed { + return sizeVarintS32PackedSlice, appendVarintS32PackedSlice + } + return sizeVarintS32Slice, appendVarintS32Slice + } + if nozero { + return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero + } + return sizeVarintS32Value, appendVarintS32Value + case "zigzag32": + if pointer { + return sizeZigzag32Ptr, appendZigzag32Ptr + } + if slice { + if packed { + return sizeZigzag32PackedSlice, appendZigzag32PackedSlice + } + return sizeZigzag32Slice, appendZigzag32Slice + } + if nozero { + return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero + } + return sizeZigzag32Value, appendZigzag32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixed64Ptr, appendFixed64Ptr + } + if slice { + if packed { + return sizeFixed64PackedSlice, appendFixed64PackedSlice + } + return sizeFixed64Slice, appendFixed64Slice + } + if nozero { + return sizeFixed64ValueNoZero, appendFixed64ValueNoZero + } + return sizeFixed64Value, appendFixed64Value + case "varint": + if pointer { + return sizeVarint64Ptr, appendVarint64Ptr + } + if slice { + if packed { + return sizeVarint64PackedSlice, appendVarint64PackedSlice + } + return sizeVarint64Slice, appendVarint64Slice + } + if nozero { + return sizeVarint64ValueNoZero, appendVarint64ValueNoZero + } + return sizeVarint64Value, appendVarint64Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return sizeFixedS64Ptr, appendFixedS64Ptr + } + if slice { + if packed { + return sizeFixedS64PackedSlice, appendFixedS64PackedSlice + } + return sizeFixedS64Slice, appendFixedS64Slice + } + if nozero { + return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero + } + return sizeFixedS64Value, appendFixedS64Value + case "varint": + if pointer { + return sizeVarintS64Ptr, appendVarintS64Ptr + } + if slice { + if packed { + return sizeVarintS64PackedSlice, appendVarintS64PackedSlice + } + return sizeVarintS64Slice, appendVarintS64Slice + } + if nozero { + return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero + } + return sizeVarintS64Value, appendVarintS64Value + case "zigzag64": + if pointer { + return sizeZigzag64Ptr, appendZigzag64Ptr + } + if slice { + if packed { + return sizeZigzag64PackedSlice, appendZigzag64PackedSlice + } + return sizeZigzag64Slice, appendZigzag64Slice + } + if nozero { + return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero + } + return sizeZigzag64Value, appendZigzag64Value + } + case reflect.Float32: + if pointer { + return sizeFloat32Ptr, appendFloat32Ptr + } + if slice { + if packed { + return sizeFloat32PackedSlice, appendFloat32PackedSlice + } + return sizeFloat32Slice, appendFloat32Slice + } + if nozero { + return sizeFloat32ValueNoZero, appendFloat32ValueNoZero + } + return sizeFloat32Value, appendFloat32Value + case reflect.Float64: + if pointer { + return sizeFloat64Ptr, appendFloat64Ptr + } + if slice { + if packed { + return sizeFloat64PackedSlice, appendFloat64PackedSlice + } + return sizeFloat64Slice, appendFloat64Slice + } + if nozero { + return sizeFloat64ValueNoZero, appendFloat64ValueNoZero + } + return sizeFloat64Value, appendFloat64Value + case reflect.String: + if validateUTF8 { + if pointer { + return sizeStringPtr, appendUTF8StringPtr + } + if slice { + return sizeStringSlice, appendUTF8StringSlice + } + if nozero { + return sizeStringValueNoZero, appendUTF8StringValueNoZero + } + return sizeStringValue, appendUTF8StringValue + } + if pointer { + return sizeStringPtr, appendStringPtr + } + if slice { + return sizeStringSlice, appendStringSlice + } + if nozero { + return sizeStringValueNoZero, appendStringValueNoZero + } + return sizeStringValue, appendStringValue + case reflect.Slice: + if slice { + return sizeBytesSlice, appendBytesSlice + } + if oneof { + // Oneof bytes field may also have "proto3" tag. + // We want to marshal it as a oneof field. Do this + // check before the proto3 check. + return sizeBytesOneof, appendBytesOneof + } + if proto3 { + return sizeBytes3, appendBytes3 + } + return sizeBytes, appendBytes + case reflect.Struct: + switch encoding { + case "group": + if slice { + return makeGroupSliceMarshaler(getMarshalInfo(t)) + } + return makeGroupMarshaler(getMarshalInfo(t)) + case "bytes": + if pointer { + if slice { + return makeMessageSliceMarshaler(getMarshalInfo(t)) + } + return makeMessageMarshaler(getMarshalInfo(t)) + } else { + if slice { + return makeMessageRefSliceMarshaler(getMarshalInfo(t)) + } + return makeMessageRefMarshaler(getMarshalInfo(t)) + } + } + } + panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding)) +} + +// Below are functions to size/marshal a specific type of a field. +// They are stored in the field's info, and called by function pointers. +// They have type sizer or marshaler. + +func sizeFixed32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixed32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixed32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixed32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixedS32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFixedS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFixedS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + return (4 + tagsize) * len(s) +} +func sizeFixedS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFloat32Value(_ pointer, tagsize int) int { + return 4 + tagsize +} +func sizeFloat32ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat32Ptr() + if p == nil { + return 0 + } + return 4 + tagsize +} +func sizeFloat32Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + return (4 + tagsize) * len(s) +} +func sizeFloat32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return 0 + } + return 4*len(s) + SizeVarint(uint64(4*len(s))) + tagsize +} +func sizeFixed64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixed64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixed64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixed64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFixedS64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFixedS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFixedS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + return (8 + tagsize) * len(s) +} +func sizeFixedS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeFloat64Value(_ pointer, tagsize int) int { + return 8 + tagsize +} +func sizeFloat64ValueNoZero(ptr pointer, tagsize int) int { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toFloat64Ptr() + if p == nil { + return 0 + } + return 8 + tagsize +} +func sizeFloat64Slice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + return (8 + tagsize) * len(s) +} +func sizeFloat64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return 0 + } + return 8*len(s) + SizeVarint(uint64(8*len(s))) + tagsize +} +func sizeVarint32Value(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarint32Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarint32Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarint32PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarint64Value(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + return SizeVarint(v) + tagsize +} +func sizeVarint64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toUint64() + if v == 0 { + return 0 + } + return SizeVarint(v) + tagsize +} +func sizeVarint64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toUint64Ptr() + if p == nil { + return 0 + } + return SizeVarint(*p) + tagsize +} +func sizeVarint64Slice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(v) + tagsize + } + return n +} +func sizeVarint64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeVarintS64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v)) + tagsize +} +func sizeVarintS64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + return SizeVarint(uint64(*p)) + tagsize +} +func sizeVarintS64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + tagsize + } + return n +} +func sizeVarintS64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag32Value(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt32() + if v == 0 { + return 0 + } + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Ptr(ptr pointer, tagsize int) int { + p := ptr.getInt32Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize +} +func sizeZigzag32Slice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + tagsize + } + return n +} +func sizeZigzag32PackedSlice(ptr pointer, tagsize int) int { + s := ptr.getInt32Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeZigzag64Value(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64ValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toInt64() + if v == 0 { + return 0 + } + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Ptr(ptr pointer, tagsize int) int { + p := *ptr.toInt64Ptr() + if p == nil { + return 0 + } + v := *p + return SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize +} +func sizeZigzag64Slice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1)^uint64((int64(v)>>63))) + tagsize + } + return n +} +func sizeZigzag64PackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return 0 + } + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + return n + SizeVarint(uint64(n)) + tagsize +} +func sizeBoolValue(_ pointer, tagsize int) int { + return 1 + tagsize +} +func sizeBoolValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toBool() + if !v { + return 0 + } + return 1 + tagsize +} +func sizeBoolPtr(ptr pointer, tagsize int) int { + p := *ptr.toBoolPtr() + if p == nil { + return 0 + } + return 1 + tagsize +} +func sizeBoolSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + return (1 + tagsize) * len(s) +} +func sizeBoolPackedSlice(ptr pointer, tagsize int) int { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return 0 + } + return len(s) + SizeVarint(uint64(len(s))) + tagsize +} +func sizeStringValue(ptr pointer, tagsize int) int { + v := *ptr.toString() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringValueNoZero(ptr pointer, tagsize int) int { + v := *ptr.toString() + if v == "" { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringPtr(ptr pointer, tagsize int) int { + p := *ptr.toStringPtr() + if p == nil { + return 0 + } + v := *p + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeStringSlice(ptr pointer, tagsize int) int { + s := *ptr.toStringSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} +func sizeBytes(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if v == nil { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytes3(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + if len(v) == 0 { + return 0 + } + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesOneof(ptr pointer, tagsize int) int { + v := *ptr.toBytes() + return len(v) + SizeVarint(uint64(len(v))) + tagsize +} +func sizeBytesSlice(ptr pointer, tagsize int) int { + s := *ptr.toBytesSlice() + n := 0 + for _, v := range s { + n += len(v) + SizeVarint(uint64(len(v))) + tagsize + } + return n +} + +// appendFixed32 appends an encoded fixed32 to b. +func appendFixed32(b []byte, v uint32) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24)) + return b +} + +// appendFixed64 appends an encoded fixed64 to b. +func appendFixed64(b []byte, v uint64) []byte { + b = append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + byte(v>>32), + byte(v>>40), + byte(v>>48), + byte(v>>56)) + return b +} + +// appendVarint appends an encoded varint to b. +func appendVarint(b []byte, v uint64) []byte { + // TODO: make 1-byte (maybe 2-byte) case inline-able, once we + // have non-leaf inliner. + switch { + case v < 1<<7: + b = append(b, byte(v)) + case v < 1<<14: + b = append(b, + byte(v&0x7f|0x80), + byte(v>>7)) + case v < 1<<21: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte(v>>14)) + case v < 1<<28: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte(v>>21)) + case v < 1<<35: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte(v>>28)) + case v < 1<<42: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte(v>>35)) + case v < 1<<49: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte(v>>42)) + case v < 1<<56: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte(v>>49)) + case v < 1<<63: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte(v>>56)) + default: + b = append(b, + byte(v&0x7f|0x80), + byte((v>>7)&0x7f|0x80), + byte((v>>14)&0x7f|0x80), + byte((v>>21)&0x7f|0x80), + byte((v>>28)&0x7f|0x80), + byte((v>>35)&0x7f|0x80), + byte((v>>42)&0x7f|0x80), + byte((v>>49)&0x7f|0x80), + byte((v>>56)&0x7f|0x80), + 1) + } + return b +} + +func appendFixed32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFixed32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, *p) + return b, nil +} +func appendFixed32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixed32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, v) + } + return b, nil +} +func appendFixedS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + return b, nil +} +func appendFixedS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(*p)) + return b, nil +} +func appendFixedS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFixedS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, uint32(v)) + } + return b, nil +} +func appendFloat32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float32bits(*ptr.toFloat32()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, v) + return b, nil +} +func appendFloat32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(*p)) + return b, nil +} +func appendFloat32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFloat32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(4*len(s))) + for _, v := range s { + b = appendFixed32(b, math.Float32bits(v)) + } + return b, nil +} +func appendFixed64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFixed64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, *p) + return b, nil +} +func appendFixed64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixed64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, v) + } + return b, nil +} +func appendFixedS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + return b, nil +} +func appendFixedS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(*p)) + return b, nil +} +func appendFixedS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFixedS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, uint64(v)) + } + return b, nil +} +func appendFloat64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := math.Float64bits(*ptr.toFloat64()) + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, v) + return b, nil +} +func appendFloat64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toFloat64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(*p)) + return b, nil +} +func appendFloat64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendFloat64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toFloat64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(8*len(s))) + for _, v := range s { + b = appendFixed64(b, math.Float64bits(v)) + } + return b, nil +} +func appendVarint32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarint32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarint32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarint64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toUint64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + return b, nil +} +func appendVarint64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toUint64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, *p) + return b, nil +} +func appendVarint64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, v) + } + return b, nil +} +func appendVarint64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toUint64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(v) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, v) + } + return b, nil +} +func appendVarintS64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + return b, nil +} +func appendVarintS64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(*p)) + return b, nil +} +func appendVarintS64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendVarintS64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v)) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v)) + } + return b, nil +} +func appendZigzag32Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt32() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := ptr.getInt32Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + return b, nil +} +func appendZigzag32Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag32PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := ptr.getInt32Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64((uint32(v)<<1)^uint32((int32(v)>>31)))) + } + return b, nil +} +func appendZigzag64Value(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64ValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toInt64() + if v == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Ptr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toInt64Ptr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + v := *p + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + return b, nil +} +func appendZigzag64Slice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendZigzag64PackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toInt64Slice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + // compute size + n := 0 + for _, v := range s { + n += SizeVarint(uint64(v<<1) ^ uint64((int64(v) >> 63))) + } + b = appendVarint(b, uint64(n)) + for _, v := range s { + b = appendVarint(b, uint64(v<<1)^uint64((int64(v)>>63))) + } + return b, nil +} +func appendBoolValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBool() + if !v { + return b, nil + } + b = appendVarint(b, wiretag) + b = append(b, 1) + return b, nil +} + +func appendBoolPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toBoolPtr() + if p == nil { + return b, nil + } + b = appendVarint(b, wiretag) + if *p { + b = append(b, 1) + } else { + b = append(b, 0) + } + return b, nil +} +func appendBoolSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBoolSlice() + if len(s) == 0 { + return b, nil + } + b = appendVarint(b, wiretag&^7|WireBytes) + b = appendVarint(b, uint64(len(s))) + for _, v := range s { + if v { + b = append(b, 1) + } else { + b = append(b, 0) + } + } + return b, nil +} +func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toString() + if v == "" { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + p := *ptr.toStringPtr() + if p == nil { + return b, nil + } + v := *p + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toStringSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} +func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + v := *ptr.toString() + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + v := *ptr.toString() + if v == "" { + return b, nil + } + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + p := *ptr.toStringPtr() + if p == nil { + return b, nil + } + v := *p + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + var invalidUTF8 bool + s := *ptr.toStringSlice() + for _, v := range s { + if !utf8.ValidString(v) { + invalidUTF8 = true + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + if invalidUTF8 { + return b, errInvalidUTF8 + } + return b, nil +} +func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if v == nil { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytes3(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + if len(v) == 0 { + return b, nil + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesOneof(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + v := *ptr.toBytes() + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + return b, nil +} +func appendBytesSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { + s := *ptr.toBytesSlice() + for _, v := range s { + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(v))) + b = append(b, v...) + } + return b, nil +} + +// makeGroupMarshaler returns the sizer and marshaler for a group. +// u is the marshal info of the underlying message. +func makeGroupMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + return u.size(p) + 2*tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + var err error + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, p, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + return b, err + } +} + +// makeGroupSliceMarshaler returns the sizer and marshaler for a group slice. +// u is the marshal info of the underlying message. +func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + n += u.size(v) + 2*tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err error + var nerr nonFatal + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) // start group + b, err = u.marshal(b, v, deterministic) + b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group + if !nerr.Merge(err) { + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, nerr.E + } +} + +// makeMessageMarshaler returns the sizer and marshaler for a message field. +// u is the marshal info of the message. +func makeMessageMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + p := ptr.getPointer() + if p.isNil() { + return 0 + } + siz := u.size(p) + return siz + SizeVarint(uint64(siz)) + tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + p := ptr.getPointer() + if p.isNil() { + return b, nil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(p) + b = appendVarint(b, uint64(siz)) + return u.marshal(b, p, deterministic) + } +} + +// makeMessageSliceMarshaler returns the sizer and marshaler for a message slice. +// u is the marshal info of the message. +func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getPointerSlice() + n := 0 + for _, v := range s { + if v.isNil() { + continue + } + siz := u.size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getPointerSlice() + var err error + var nerr nonFatal + for _, v := range s { + if v.isNil() { + return b, errRepeatedHasNil + } + b = appendVarint(b, wiretag) + siz := u.cachedsize(v) + b = appendVarint(b, uint64(siz)) + b, err = u.marshal(b, v, deterministic) + + if !nerr.Merge(err) { + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + return b, nerr.E + } +} + +// makeMapMarshaler returns the sizer and marshaler for a map field. +// f is the pointer to the reflect data structure of the field. +func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { + // figure out key and value type + t := f.Type + keyType := t.Key() + valType := t.Elem() + tags := strings.Split(f.Tag.Get("protobuf"), ",") + keyTags := strings.Split(f.Tag.Get("protobuf_key"), ",") + valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") + stdOptions := false + for _, t := range tags { + if strings.HasPrefix(t, "customtype=") { + valTags = append(valTags, t) + } + if t == "stdtime" { + valTags = append(valTags, t) + stdOptions = true + } + if t == "stdduration" { + valTags = append(valTags, t) + stdOptions = true + } + if t == "wktptr" { + valTags = append(valTags, t) + } + } + keySizer, keyMarshaler := typeMarshaler(keyType, keyTags, false, false) // don't omit zero value in map + valSizer, valMarshaler := typeMarshaler(valType, valTags, false, false) // don't omit zero value in map + keyWireTag := 1<<3 | wiretype(keyTags[0]) + valWireTag := 2<<3 | wiretype(valTags[0]) + + // We create an interface to get the addresses of the map key and value. + // If value is pointer-typed, the interface is a direct interface, the + // idata itself is the value. Otherwise, the idata is the pointer to the + // value. + // Key cannot be pointer-typed. + valIsPtr := valType.Kind() == reflect.Ptr + + // If value is a message with nested maps, calling + // valSizer in marshal may be quadratic. We should use + // cached version in marshal (but not in size). + // If value is not message type, we don't have size cache, + // but it cannot be nested either. Just use valSizer. + valCachedSizer := valSizer + if valIsPtr && !stdOptions && valType.Elem().Kind() == reflect.Struct { + u := getMarshalInfo(valType.Elem()) + valCachedSizer = func(ptr pointer, tagsize int) int { + // Same as message sizer, but use cache. + p := ptr.getPointer() + if p.isNil() { + return 0 + } + siz := u.cachedsize(p) + return siz + SizeVarint(uint64(siz)) + tagsize + } + } + return func(ptr pointer, tagsize int) int { + m := ptr.asPointerTo(t).Elem() // the map + n := 0 + for _, k := range m.MapKeys() { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, tag uint64, deterministic bool) ([]byte, error) { + m := ptr.asPointerTo(t).Elem() // the map + var err error + keys := m.MapKeys() + if len(keys) > 1 && deterministic { + sort.Sort(mapKeys(keys)) + } + + var nerr nonFatal + for _, k := range keys { + ki := k.Interface() + vi := m.MapIndex(k).Interface() + kaddr := toAddrPointer(&ki, false) // pointer to key + vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value + b = appendVarint(b, tag) + siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) + b = appendVarint(b, uint64(siz)) + b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic) + if !nerr.Merge(err) { + return b, err + } + b, err = valMarshaler(b, vaddr, valWireTag, deterministic) + if err != ErrNil && !nerr.Merge(err) { // allow nil value in map + return b, err + } + } + return b, nerr.E + } +} + +// makeOneOfMarshaler returns the sizer and marshaler for a oneof field. +// fi is the marshal info of the field. +// f is the pointer to the reflect data structure of the field. +func makeOneOfMarshaler(fi *marshalFieldInfo, f *reflect.StructField) (sizer, marshaler) { + // Oneof field is an interface. We need to get the actual data type on the fly. + t := f.Type + return func(ptr pointer, _ int) int { + p := ptr.getInterfacePointer() + if p.isNil() { + return 0 + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + e := fi.oneofElems[telem] + return e.sizer(p, e.tagsize) + }, + func(b []byte, ptr pointer, _ uint64, deterministic bool) ([]byte, error) { + p := ptr.getInterfacePointer() + if p.isNil() { + return b, nil + } + v := ptr.asPointerTo(t).Elem().Elem().Elem() // *interface -> interface -> *struct -> struct + telem := v.Type() + if telem.Field(0).Type.Kind() == reflect.Ptr && p.getPointer().isNil() { + return b, errOneofHasNil + } + e := fi.oneofElems[telem] + return e.marshaler(b, p, e.wiretag, deterministic) + } +} + +// sizeExtensions computes the size of encoded data for a XXX_InternalExtensions field. +func (u *marshalInfo) sizeExtensions(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, ei.tagsize) + } + mu.Unlock() + return n +} + +// appendExtensions marshals a XXX_InternalExtensions field to the end of byte slice b. +func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + var nerr nonFatal + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E + } + + // Sort the keys to provide a deterministic encoding. + // Not sure this is required, but the old code does it. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// message set format is: +// message MessageSet { +// repeated group Item = 1 { +// required int32 type_id = 2; +// required string message = 3; +// }; +// } + +// sizeMessageSet computes the size of encoded data for a XXX_InternalExtensions field +// in message set format (above). +func (u *marshalInfo) sizeMessageSet(ext *XXX_InternalExtensions) int { + m, mu := ext.extensionsRead() + if m == nil { + return 0 + } + mu.Lock() + + n := 0 + for id, e := range m { + n += 2 // start group, end group. tag = 1 (size=1) + n += SizeVarint(uint64(id)) + 1 // type_id, tag = 2 (size=1) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + siz := len(msgWithLen) + n += siz + 1 // message, tag = 3 (size=1) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, 1) // message, tag = 3 (size=1) + } + mu.Unlock() + return n +} + +// appendMessageSet marshals a XXX_InternalExtensions field in message set format (above) +// to the end of byte slice b. +func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, deterministic bool) ([]byte, error) { + m, mu := ext.extensionsRead() + if m == nil { + return b, nil + } + mu.Lock() + defer mu.Unlock() + + var err error + var nerr nonFatal + + // Fast-path for common cases: zero or one extensions. + // Don't bother sorting the keys. + if len(m) <= 1 { + for id, e := range m { + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + if !nerr.Merge(err) { + return b, err + } + b = append(b, 1<<3|WireEndGroup) + } + return b, nerr.E + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + for _, id := range keys { + e := m[int32(id)] + b = append(b, 1<<3|WireStartGroup) + b = append(b, 2<<3|WireVarint) + b = appendVarint(b, uint64(id)) + + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + msgWithLen := skipVarint(e.enc) // skip old tag, but leave the length varint + b = append(b, 3<<3|WireBytes) + b = append(b, msgWithLen...) + b = append(b, 1<<3|WireEndGroup) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) + b = append(b, 1<<3|WireEndGroup) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// sizeV1Extensions computes the size of encoded data for a V1-API extension field. +func (u *marshalInfo) sizeV1Extensions(m map[int32]Extension) int { + if m == nil { + return 0 + } + + n := 0 + for _, e := range m { + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + n += len(e.enc) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + n += ei.sizer(p, ei.tagsize) + } + return n +} + +// appendV1Extensions marshals a V1-API extension field to the end of byte slice b. +func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, deterministic bool) ([]byte, error) { + if m == nil { + return b, nil + } + + // Sort the keys to provide a deterministic encoding. + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, int(k)) + } + sort.Ints(keys) + + var err error + var nerr nonFatal + for _, k := range keys { + e := m[int32(k)] + if e.value == nil || e.desc == nil { + // Extension is only in its encoded form. + b = append(b, e.enc...) + continue + } + + // We don't skip extensions that have an encoded form set, + // because the extension value may have been mutated after + // the last time this function was called. + + ei := u.getExtElemInfo(e.desc) + v := e.value + p := toAddrPointer(&v, ei.isptr) + b, err = ei.marshaler(b, p, ei.wiretag, deterministic) + if !nerr.Merge(err) { + return b, err + } + } + return b, nerr.E +} + +// newMarshaler is the interface representing objects that can marshal themselves. +// +// This exists to support protoc-gen-go generated messages. +// The proto package will stop type-asserting to this interface in the future. +// +// DO NOT DEPEND ON THIS. +type newMarshaler interface { + XXX_Size() int + XXX_Marshal(b []byte, deterministic bool) ([]byte, error) +} + +// Size returns the encoded size of a protocol buffer message. +// This is the main entry point. +func Size(pb Message) int { + if m, ok := pb.(newMarshaler); ok { + return m.XXX_Size() + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + b, _ := m.Marshal() + return len(b) + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return 0 + } + var info InternalMessageInfo + return info.Size(pb) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, returning the data. +// This is the main entry point. +func Marshal(pb Message) ([]byte, error) { + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + b := make([]byte, 0, siz) + return m.XXX_Marshal(b, false) + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + return m.Marshal() + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return nil, ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + b := make([]byte, 0, siz) + return info.Marshal(b, pb, false) +} + +// Marshal takes a protocol buffer message +// and encodes it into the wire format, writing the result to the +// Buffer. +// This is an alternative entry point. It is not necessary to use +// a Buffer for most applications. +func (p *Buffer) Marshal(pb Message) error { + var err error + if p.deterministic { + if _, ok := pb.(Marshaler); ok { + return fmt.Errorf("proto: deterministic not supported by the Marshal method of %T", pb) + } + } + if m, ok := pb.(newMarshaler); ok { + siz := m.XXX_Size() + p.grow(siz) // make sure buf has enough capacity + pp := p.buf[len(p.buf) : len(p.buf) : len(p.buf)+siz] + pp, err = m.XXX_Marshal(pp, p.deterministic) + p.buf = append(p.buf, pp...) + return err + } + if m, ok := pb.(Marshaler); ok { + // If the message can marshal itself, let it do it, for compatibility. + // NOTE: This is not efficient. + var b []byte + b, err = m.Marshal() + p.buf = append(p.buf, b...) + return err + } + // in case somehow we didn't generate the wrapper + if pb == nil { + return ErrNil + } + var info InternalMessageInfo + siz := info.Size(pb) + p.grow(siz) // make sure buf has enough capacity + p.buf, err = info.Marshal(p.buf, pb, p.deterministic) + return err +} + +// grow grows the buffer's capacity, if necessary, to guarantee space for +// another n bytes. After grow(n), at least n bytes can be written to the +// buffer without another allocation. +func (p *Buffer) grow(n int) { + need := len(p.buf) + n + if need <= cap(p.buf) { + return + } + newCap := len(p.buf) * 2 + if newCap < need { + newCap = need + } + p.buf = append(make([]byte, 0, newCap), p.buf...) +} diff --git a/vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go b/vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go new file mode 100644 index 0000000000..997f57c1e1 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/table_marshal_gogo.go @@ -0,0 +1,388 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" + "time" +) + +// makeMessageRefMarshaler differs a bit from makeMessageMarshaler +// It marshal a message T instead of a *T +func makeMessageRefMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + siz := u.size(ptr) + return siz + SizeVarint(uint64(siz)) + tagsize + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + b = appendVarint(b, wiretag) + siz := u.cachedsize(ptr) + b = appendVarint(b, uint64(siz)) + return u.marshal(b, ptr, deterministic) + } +} + +// makeMessageRefSliceMarshaler differs quite a lot from makeMessageSliceMarshaler +// It marshals a slice of messages []T instead of []*T +func makeMessageRefSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + e := elem.Interface() + v := toAddrPointer(&e, false) + siz := u.size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + var err, errreq error + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + e := elem.Interface() + v := toAddrPointer(&e, false) + b = appendVarint(b, wiretag) + siz := u.size(v) + b = appendVarint(b, uint64(siz)) + b, err = u.marshal(b, v, deterministic) + + if err != nil { + if _, ok := err.(*RequiredNotSetError); ok { + // Required field in submessage is not set. + // We record the error but keep going, to give a complete marshaling. + if errreq == nil { + errreq = err + } + continue + } + if err == ErrNil { + err = errRepeatedHasNil + } + return b, err + } + } + + return b, errreq + } +} + +func makeCustomPtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + m := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(custom) + siz := m.Size() + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + m := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(custom) + siz := m.Size() + buf, err := m.Marshal() + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + return b, nil + } +} + +func makeCustomMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + m := ptr.asPointerTo(u.typ).Interface().(custom) + siz := m.Size() + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + m := ptr.asPointerTo(u.typ).Interface().(custom) + siz := m.Size() + buf, err := m.Marshal() + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + return b, nil + } +} + +func makeTimeMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*time.Time) + ts, err := timestampProto(*t) + if err != nil { + return 0 + } + siz := Size(ts) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*time.Time) + ts, err := timestampProto(*t) + if err != nil { + return nil, err + } + buf, err := Marshal(ts) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeTimePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Time) + ts, err := timestampProto(*t) + if err != nil { + return 0 + } + siz := Size(ts) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Time) + ts, err := timestampProto(*t) + if err != nil { + return nil, err + } + buf, err := Marshal(ts) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeTimeSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(time.Time) + ts, err := timestampProto(t) + if err != nil { + return 0 + } + siz := Size(ts) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(time.Time) + ts, err := timestampProto(t) + if err != nil { + return nil, err + } + siz := Size(ts) + buf, err := Marshal(ts) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeTimePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*time.Time) + ts, err := timestampProto(*t) + if err != nil { + return 0 + } + siz := Size(ts) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*time.Time) + ts, err := timestampProto(*t) + if err != nil { + return nil, err + } + siz := Size(ts) + buf, err := Marshal(ts) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeDurationMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + d := ptr.asPointerTo(u.typ).Interface().(*time.Duration) + dur := durationProto(*d) + siz := Size(dur) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + d := ptr.asPointerTo(u.typ).Interface().(*time.Duration) + dur := durationProto(*d) + buf, err := Marshal(dur) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeDurationPtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + d := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Duration) + dur := durationProto(*d) + siz := Size(dur) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + d := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*time.Duration) + dur := durationProto(*d) + buf, err := Marshal(dur) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeDurationSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + d := elem.Interface().(time.Duration) + dur := durationProto(d) + siz := Size(dur) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + d := elem.Interface().(time.Duration) + dur := durationProto(d) + siz := Size(dur) + buf, err := Marshal(dur) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeDurationPtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + d := elem.Interface().(*time.Duration) + dur := durationProto(*d) + siz := Size(dur) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + d := elem.Interface().(*time.Duration) + dur := durationProto(*d) + siz := Size(dur) + buf, err := Marshal(dur) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/table_merge.go b/vendor/github.com/gogo/protobuf/proto/table_merge.go new file mode 100644 index 0000000000..60dcf70d1e --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/table_merge.go @@ -0,0 +1,676 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" +) + +// Merge merges the src message into dst. +// This assumes that dst and src of the same type and are non-nil. +func (a *InternalMessageInfo) Merge(dst, src Message) { + mi := atomicLoadMergeInfo(&a.merge) + if mi == nil { + mi = getMergeInfo(reflect.TypeOf(dst).Elem()) + atomicStoreMergeInfo(&a.merge, mi) + } + mi.merge(toPointer(&dst), toPointer(&src)) +} + +type mergeInfo struct { + typ reflect.Type + + initialized int32 // 0: only typ is valid, 1: everything is valid + lock sync.Mutex + + fields []mergeFieldInfo + unrecognized field // Offset of XXX_unrecognized +} + +type mergeFieldInfo struct { + field field // Offset of field, guaranteed to be valid + + // isPointer reports whether the value in the field is a pointer. + // This is true for the following situations: + // * Pointer to struct + // * Pointer to basic type (proto2 only) + // * Slice (first value in slice header is a pointer) + // * String (first value in string header is a pointer) + isPointer bool + + // basicWidth reports the width of the field assuming that it is directly + // embedded in the struct (as is the case for basic types in proto3). + // The possible values are: + // 0: invalid + // 1: bool + // 4: int32, uint32, float32 + // 8: int64, uint64, float64 + basicWidth int + + // Where dst and src are pointers to the types being merged. + merge func(dst, src pointer) +} + +var ( + mergeInfoMap = map[reflect.Type]*mergeInfo{} + mergeInfoLock sync.Mutex +) + +func getMergeInfo(t reflect.Type) *mergeInfo { + mergeInfoLock.Lock() + defer mergeInfoLock.Unlock() + mi := mergeInfoMap[t] + if mi == nil { + mi = &mergeInfo{typ: t} + mergeInfoMap[t] = mi + } + return mi +} + +// merge merges src into dst assuming they are both of type *mi.typ. +func (mi *mergeInfo) merge(dst, src pointer) { + if dst.isNil() { + panic("proto: nil destination") + } + if src.isNil() { + return // Nothing to do. + } + + if atomic.LoadInt32(&mi.initialized) == 0 { + mi.computeMergeInfo() + } + + for _, fi := range mi.fields { + sfp := src.offset(fi.field) + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string + continue + } + if fi.basicWidth > 0 { + switch { + case fi.basicWidth == 1 && !*sfp.toBool(): + continue + case fi.basicWidth == 4 && *sfp.toUint32() == 0: + continue + case fi.basicWidth == 8 && *sfp.toUint64() == 0: + continue + } + } + } + + dfp := dst.offset(fi.field) + fi.merge(dfp, sfp) + } + + // TODO: Make this faster? + out := dst.asPointerTo(mi.typ).Elem() + in := src.asPointerTo(mi.typ).Elem() + if emIn, err := extendable(in.Addr().Interface()); err == nil { + emOut, _ := extendable(out.Addr().Interface()) + mIn, muIn := emIn.extensionsRead() + if mIn != nil { + mOut := emOut.extensionsWrite() + muIn.Lock() + mergeExtension(mOut, mIn) + muIn.Unlock() + } + } + + if mi.unrecognized.IsValid() { + if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 { + *dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...) + } + } +} + +func (mi *mergeInfo) computeMergeInfo() { + mi.lock.Lock() + defer mi.lock.Unlock() + if mi.initialized != 0 { + return + } + t := mi.typ + n := t.NumField() + + props := GetProperties(t) + for i := 0; i < n; i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + + mfi := mergeFieldInfo{field: toField(&f)} + tf := f.Type + + // As an optimization, we can avoid the merge function call cost + // if we know for sure that the source will have no effect + // by checking if it is the zero value. + if unsafeAllowed { + switch tf.Kind() { + case reflect.Ptr, reflect.Slice, reflect.String: + // As a special case, we assume slices and strings are pointers + // since we know that the first field in the SliceSlice or + // StringHeader is a data pointer. + mfi.isPointer = true + case reflect.Bool: + mfi.basicWidth = 1 + case reflect.Int32, reflect.Uint32, reflect.Float32: + mfi.basicWidth = 4 + case reflect.Int64, reflect.Uint64, reflect.Float64: + mfi.basicWidth = 8 + } + } + + // Unwrap tf to get at its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + tf.Name()) + } + + switch tf.Kind() { + case reflect.Int32: + switch { + case isSlice: // E.g., []int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Slice is not defined (see pointer_reflect.go). + /* + sfsp := src.toInt32Slice() + if *sfsp != nil { + dfsp := dst.toInt32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + */ + sfs := src.getInt32Slice() + if sfs != nil { + dfs := dst.getInt32Slice() + dfs = append(dfs, sfs...) + if dfs == nil { + dfs = []int32{} + } + dst.setInt32Slice(dfs) + } + } + case isPointer: // E.g., *int32 + mfi.merge = func(dst, src pointer) { + // NOTE: toInt32Ptr is not defined (see pointer_reflect.go). + /* + sfpp := src.toInt32Ptr() + if *sfpp != nil { + dfpp := dst.toInt32Ptr() + if *dfpp == nil { + *dfpp = Int32(**sfpp) + } else { + **dfpp = **sfpp + } + } + */ + sfp := src.getInt32Ptr() + if sfp != nil { + dfp := dst.getInt32Ptr() + if dfp == nil { + dst.setInt32Ptr(*sfp) + } else { + *dfp = *sfp + } + } + } + default: // E.g., int32 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt32(); v != 0 { + *dst.toInt32() = v + } + } + } + case reflect.Int64: + switch { + case isSlice: // E.g., []int64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toInt64Slice() + if *sfsp != nil { + dfsp := dst.toInt64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []int64{} + } + } + } + case isPointer: // E.g., *int64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toInt64Ptr() + if *sfpp != nil { + dfpp := dst.toInt64Ptr() + if *dfpp == nil { + *dfpp = Int64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., int64 + mfi.merge = func(dst, src pointer) { + if v := *src.toInt64(); v != 0 { + *dst.toInt64() = v + } + } + } + case reflect.Uint32: + switch { + case isSlice: // E.g., []uint32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint32Slice() + if *sfsp != nil { + dfsp := dst.toUint32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint32{} + } + } + } + case isPointer: // E.g., *uint32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint32Ptr() + if *sfpp != nil { + dfpp := dst.toUint32Ptr() + if *dfpp == nil { + *dfpp = Uint32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint32 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint32(); v != 0 { + *dst.toUint32() = v + } + } + } + case reflect.Uint64: + switch { + case isSlice: // E.g., []uint64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toUint64Slice() + if *sfsp != nil { + dfsp := dst.toUint64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []uint64{} + } + } + } + case isPointer: // E.g., *uint64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toUint64Ptr() + if *sfpp != nil { + dfpp := dst.toUint64Ptr() + if *dfpp == nil { + *dfpp = Uint64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., uint64 + mfi.merge = func(dst, src pointer) { + if v := *src.toUint64(); v != 0 { + *dst.toUint64() = v + } + } + } + case reflect.Float32: + switch { + case isSlice: // E.g., []float32 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat32Slice() + if *sfsp != nil { + dfsp := dst.toFloat32Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float32{} + } + } + } + case isPointer: // E.g., *float32 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat32Ptr() + if *sfpp != nil { + dfpp := dst.toFloat32Ptr() + if *dfpp == nil { + *dfpp = Float32(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float32 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat32(); v != 0 { + *dst.toFloat32() = v + } + } + } + case reflect.Float64: + switch { + case isSlice: // E.g., []float64 + mfi.merge = func(dst, src pointer) { + sfsp := src.toFloat64Slice() + if *sfsp != nil { + dfsp := dst.toFloat64Slice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []float64{} + } + } + } + case isPointer: // E.g., *float64 + mfi.merge = func(dst, src pointer) { + sfpp := src.toFloat64Ptr() + if *sfpp != nil { + dfpp := dst.toFloat64Ptr() + if *dfpp == nil { + *dfpp = Float64(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., float64 + mfi.merge = func(dst, src pointer) { + if v := *src.toFloat64(); v != 0 { + *dst.toFloat64() = v + } + } + } + case reflect.Bool: + switch { + case isSlice: // E.g., []bool + mfi.merge = func(dst, src pointer) { + sfsp := src.toBoolSlice() + if *sfsp != nil { + dfsp := dst.toBoolSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []bool{} + } + } + } + case isPointer: // E.g., *bool + mfi.merge = func(dst, src pointer) { + sfpp := src.toBoolPtr() + if *sfpp != nil { + dfpp := dst.toBoolPtr() + if *dfpp == nil { + *dfpp = Bool(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., bool + mfi.merge = func(dst, src pointer) { + if v := *src.toBool(); v { + *dst.toBool() = v + } + } + } + case reflect.String: + switch { + case isSlice: // E.g., []string + mfi.merge = func(dst, src pointer) { + sfsp := src.toStringSlice() + if *sfsp != nil { + dfsp := dst.toStringSlice() + *dfsp = append(*dfsp, *sfsp...) + if *dfsp == nil { + *dfsp = []string{} + } + } + } + case isPointer: // E.g., *string + mfi.merge = func(dst, src pointer) { + sfpp := src.toStringPtr() + if *sfpp != nil { + dfpp := dst.toStringPtr() + if *dfpp == nil { + *dfpp = String(**sfpp) + } else { + **dfpp = **sfpp + } + } + } + default: // E.g., string + mfi.merge = func(dst, src pointer) { + if v := *src.toString(); v != "" { + *dst.toString() = v + } + } + } + case reflect.Slice: + isProto3 := props.Prop[i].proto3 + switch { + case isPointer: + panic("bad pointer in byte slice case in " + tf.Name()) + case tf.Elem().Kind() != reflect.Uint8: + panic("bad element kind in byte slice case in " + tf.Name()) + case isSlice: // E.g., [][]byte + mfi.merge = func(dst, src pointer) { + sbsp := src.toBytesSlice() + if *sbsp != nil { + dbsp := dst.toBytesSlice() + for _, sb := range *sbsp { + if sb == nil { + *dbsp = append(*dbsp, nil) + } else { + *dbsp = append(*dbsp, append([]byte{}, sb...)) + } + } + if *dbsp == nil { + *dbsp = [][]byte{} + } + } + } + default: // E.g., []byte + mfi.merge = func(dst, src pointer) { + sbp := src.toBytes() + if *sbp != nil { + dbp := dst.toBytes() + if !isProto3 || len(*sbp) > 0 { + *dbp = append([]byte{}, *sbp...) + } + } + } + } + case reflect.Struct: + switch { + case isSlice && !isPointer: // E.g. []pb.T + mergeInfo := getMergeInfo(tf) + zero := reflect.Zero(tf) + mfi.merge = func(dst, src pointer) { + // TODO: Make this faster? + dstsp := dst.asPointerTo(f.Type) + dsts := dstsp.Elem() + srcs := src.asPointerTo(f.Type).Elem() + for i := 0; i < srcs.Len(); i++ { + dsts = reflect.Append(dsts, zero) + srcElement := srcs.Index(i).Addr() + dstElement := dsts.Index(dsts.Len() - 1).Addr() + mergeInfo.merge(valToPointer(dstElement), valToPointer(srcElement)) + } + if dsts.IsNil() { + dsts = reflect.MakeSlice(f.Type, 0, 0) + } + dstsp.Elem().Set(dsts) + } + case !isPointer: + mergeInfo := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + mergeInfo.merge(dst, src) + } + case isSlice: // E.g., []*pb.T + mergeInfo := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sps := src.getPointerSlice() + if sps != nil { + dps := dst.getPointerSlice() + for _, sp := range sps { + var dp pointer + if !sp.isNil() { + dp = valToPointer(reflect.New(tf)) + mergeInfo.merge(dp, sp) + } + dps = append(dps, dp) + } + if dps == nil { + dps = []pointer{} + } + dst.setPointerSlice(dps) + } + } + default: // E.g., *pb.T + mergeInfo := getMergeInfo(tf) + mfi.merge = func(dst, src pointer) { + sp := src.getPointer() + if !sp.isNil() { + dp := dst.getPointer() + if dp.isNil() { + dp = valToPointer(reflect.New(tf)) + dst.setPointer(dp) + } + mergeInfo.merge(dp, sp) + } + } + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic("bad pointer or slice in map case in " + tf.Name()) + default: // E.g., map[K]V + mfi.merge = func(dst, src pointer) { + sm := src.asPointerTo(tf).Elem() + if sm.Len() == 0 { + return + } + dm := dst.asPointerTo(tf).Elem() + if dm.IsNil() { + dm.Set(reflect.MakeMap(tf)) + } + + switch tf.Elem().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(Clone(val.Interface().(Message))) + dm.SetMapIndex(key, val) + } + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) + dm.SetMapIndex(key, val) + } + default: // Basic type (e.g., string) + for _, key := range sm.MapKeys() { + val := sm.MapIndex(key) + dm.SetMapIndex(key, val) + } + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic("bad pointer or slice in interface case in " + tf.Name()) + default: // E.g., interface{} + // TODO: Make this faster? + mfi.merge = func(dst, src pointer) { + su := src.asPointerTo(tf).Elem() + if !su.IsNil() { + du := dst.asPointerTo(tf).Elem() + typ := su.Elem().Type() + if du.IsNil() || du.Elem().Type() != typ { + du.Set(reflect.New(typ.Elem())) // Initialize interface if empty + } + sv := su.Elem().Elem().Field(0) + if sv.Kind() == reflect.Ptr && sv.IsNil() { + return + } + dv := du.Elem().Elem().Field(0) + if dv.Kind() == reflect.Ptr && dv.IsNil() { + dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty + } + switch sv.Type().Kind() { + case reflect.Ptr: // Proto struct (e.g., *T) + Merge(dv.Interface().(Message), sv.Interface().(Message)) + case reflect.Slice: // E.g. Bytes type (e.g., []byte) + dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...))) + default: // Basic type (e.g., string) + dv.Set(sv) + } + } + } + } + default: + panic(fmt.Sprintf("merger not found for type:%s", tf)) + } + mi.fields = append(mi.fields, mfi) + } + + mi.unrecognized = invalidField + if f, ok := t.FieldByName("XXX_unrecognized"); ok { + if f.Type != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + mi.unrecognized = toField(&f) + } + + atomic.StoreInt32(&mi.initialized, 1) +} diff --git a/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go b/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go new file mode 100644 index 0000000000..937229386a --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go @@ -0,0 +1,2249 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "errors" + "fmt" + "io" + "math" + "reflect" + "strconv" + "strings" + "sync" + "sync/atomic" + "unicode/utf8" +) + +// Unmarshal is the entry point from the generated .pb.go files. +// This function is not intended to be used by non-generated code. +// This function is not subject to any compatibility guarantee. +// msg contains a pointer to a protocol buffer struct. +// b is the data to be unmarshaled into the protocol buffer. +// a is a pointer to a place to store cached unmarshal information. +func (a *InternalMessageInfo) Unmarshal(msg Message, b []byte) error { + // Load the unmarshal information for this message type. + // The atomic load ensures memory consistency. + u := atomicLoadUnmarshalInfo(&a.unmarshal) + if u == nil { + // Slow path: find unmarshal info for msg, update a with it. + u = getUnmarshalInfo(reflect.TypeOf(msg).Elem()) + atomicStoreUnmarshalInfo(&a.unmarshal, u) + } + // Then do the unmarshaling. + err := u.unmarshal(toPointer(&msg), b) + return err +} + +type unmarshalInfo struct { + typ reflect.Type // type of the protobuf struct + + // 0 = only typ field is initialized + // 1 = completely initialized + initialized int32 + lock sync.Mutex // prevents double initialization + dense []unmarshalFieldInfo // fields indexed by tag # + sparse map[uint64]unmarshalFieldInfo // fields indexed by tag # + reqFields []string // names of required fields + reqMask uint64 // 1< 0 { + // Read tag and wire type. + // Special case 1 and 2 byte varints. + var x uint64 + if b[0] < 128 { + x = uint64(b[0]) + b = b[1:] + } else if len(b) >= 2 && b[1] < 128 { + x = uint64(b[0]&0x7f) + uint64(b[1])<<7 + b = b[2:] + } else { + var n int + x, n = decodeVarint(b) + if n == 0 { + return io.ErrUnexpectedEOF + } + b = b[n:] + } + tag := x >> 3 + wire := int(x) & 7 + + // Dispatch on the tag to one of the unmarshal* functions below. + var f unmarshalFieldInfo + if tag < uint64(len(u.dense)) { + f = u.dense[tag] + } else { + f = u.sparse[tag] + } + if fn := f.unmarshal; fn != nil { + var err error + b, err = fn(b, m.offset(f.field), wire) + if err == nil { + reqMask |= f.reqMask + continue + } + if r, ok := err.(*RequiredNotSetError); ok { + // Remember this error, but keep parsing. We need to produce + // a full parse even if a required field is missing. + if errLater == nil { + errLater = r + } + reqMask |= f.reqMask + continue + } + if err != errInternalBadWireType { + if err == errInvalidUTF8 { + if errLater == nil { + fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name + errLater = &invalidUTF8Error{fullName} + } + continue + } + return err + } + // Fragments with bad wire type are treated as unknown fields. + } + + // Unknown tag. + if !u.unrecognized.IsValid() { + // Don't keep unrecognized data; just skip it. + var err error + b, err = skipField(b, wire) + if err != nil { + return err + } + continue + } + // Keep unrecognized data around. + // maybe in extensions, maybe in the unrecognized field. + z := m.offset(u.unrecognized).toBytes() + var emap map[int32]Extension + var e Extension + for _, r := range u.extensionRanges { + if uint64(r.Start) <= tag && tag <= uint64(r.End) { + if u.extensions.IsValid() { + mp := m.offset(u.extensions).toExtensions() + emap = mp.extensionsWrite() + e = emap[int32(tag)] + z = &e.enc + break + } + if u.oldExtensions.IsValid() { + p := m.offset(u.oldExtensions).toOldExtensions() + emap = *p + if emap == nil { + emap = map[int32]Extension{} + *p = emap + } + e = emap[int32(tag)] + z = &e.enc + break + } + if u.bytesExtensions.IsValid() { + z = m.offset(u.bytesExtensions).toBytes() + break + } + panic("no extensions field available") + } + } + // Use wire type to skip data. + var err error + b0 := b + b, err = skipField(b, wire) + if err != nil { + return err + } + *z = encodeVarint(*z, tag<<3|uint64(wire)) + *z = append(*z, b0[:len(b0)-len(b)]...) + + if emap != nil { + emap[int32(tag)] = e + } + } + if reqMask != u.reqMask && errLater == nil { + // A required field of this message is missing. + for _, n := range u.reqFields { + if reqMask&1 == 0 { + errLater = &RequiredNotSetError{n} + } + reqMask >>= 1 + } + } + return errLater +} + +// computeUnmarshalInfo fills in u with information for use +// in unmarshaling protocol buffers of type u.typ. +func (u *unmarshalInfo) computeUnmarshalInfo() { + u.lock.Lock() + defer u.lock.Unlock() + if u.initialized != 0 { + return + } + t := u.typ + n := t.NumField() + + // Set up the "not found" value for the unrecognized byte buffer. + // This is the default for proto3. + u.unrecognized = invalidField + u.extensions = invalidField + u.oldExtensions = invalidField + u.bytesExtensions = invalidField + + // List of the generated type and offset for each oneof field. + type oneofField struct { + ityp reflect.Type // interface type of oneof field + field field // offset in containing message + } + var oneofFields []oneofField + + for i := 0; i < n; i++ { + f := t.Field(i) + if f.Name == "XXX_unrecognized" { + // The byte slice used to hold unrecognized input is special. + if f.Type != reflect.TypeOf(([]byte)(nil)) { + panic("bad type for XXX_unrecognized field: " + f.Type.Name()) + } + u.unrecognized = toField(&f) + continue + } + if f.Name == "XXX_InternalExtensions" { + // Ditto here. + if f.Type != reflect.TypeOf(XXX_InternalExtensions{}) { + panic("bad type for XXX_InternalExtensions field: " + f.Type.Name()) + } + u.extensions = toField(&f) + if f.Tag.Get("protobuf_messageset") == "1" { + u.isMessageSet = true + } + continue + } + if f.Name == "XXX_extensions" { + // An older form of the extensions field. + if f.Type == reflect.TypeOf((map[int32]Extension)(nil)) { + u.oldExtensions = toField(&f) + continue + } else if f.Type == reflect.TypeOf(([]byte)(nil)) { + u.bytesExtensions = toField(&f) + continue + } + panic("bad type for XXX_extensions field: " + f.Type.Name()) + } + if f.Name == "XXX_NoUnkeyedLiteral" || f.Name == "XXX_sizecache" { + continue + } + + oneof := f.Tag.Get("protobuf_oneof") + if oneof != "" { + oneofFields = append(oneofFields, oneofField{f.Type, toField(&f)}) + // The rest of oneof processing happens below. + continue + } + + tags := f.Tag.Get("protobuf") + tagArray := strings.Split(tags, ",") + if len(tagArray) < 2 { + panic("protobuf tag not enough fields in " + t.Name() + "." + f.Name + ": " + tags) + } + tag, err := strconv.Atoi(tagArray[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tagArray[1]) + } + + name := "" + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + } + + // Extract unmarshaling function from the field (its type and tags). + unmarshal := fieldUnmarshaler(&f) + + // Required field? + var reqMask uint64 + if tagArray[2] == "req" { + bit := len(u.reqFields) + u.reqFields = append(u.reqFields, name) + reqMask = uint64(1) << uint(bit) + // TODO: if we have more than 64 required fields, we end up + // not verifying that all required fields are present. + // Fix this, perhaps using a count of required fields? + } + + // Store the info in the correct slot in the message. + u.setTag(tag, toField(&f), unmarshal, reqMask, name) + } + + // Find any types associated with oneof fields. + // gogo: len(oneofFields) > 0 is needed for embedded oneof messages, without a marshaler and unmarshaler + if len(oneofFields) > 0 { + var oneofImplementers []interface{} + switch m := reflect.Zero(reflect.PtrTo(t)).Interface().(type) { + case oneofFuncsIface: + _, _, _, oneofImplementers = m.XXX_OneofFuncs() + case oneofWrappersIface: + oneofImplementers = m.XXX_OneofWrappers() + } + for _, v := range oneofImplementers { + tptr := reflect.TypeOf(v) // *Msg_X + typ := tptr.Elem() // Msg_X + + f := typ.Field(0) // oneof implementers have one field + baseUnmarshal := fieldUnmarshaler(&f) + tags := strings.Split(f.Tag.Get("protobuf"), ",") + fieldNum, err := strconv.Atoi(tags[1]) + if err != nil { + panic("protobuf tag field not an integer: " + tags[1]) + } + var name string + for _, tag := range tags { + if strings.HasPrefix(tag, "name=") { + name = strings.TrimPrefix(tag, "name=") + break + } + } + + // Find the oneof field that this struct implements. + // Might take O(n^2) to process all of the oneofs, but who cares. + for _, of := range oneofFields { + if tptr.Implements(of.ityp) { + // We have found the corresponding interface for this struct. + // That lets us know where this struct should be stored + // when we encounter it during unmarshaling. + unmarshal := makeUnmarshalOneof(typ, of.ityp, baseUnmarshal) + u.setTag(fieldNum, of.field, unmarshal, 0, name) + } + } + + } + } + + // Get extension ranges, if any. + fn := reflect.Zero(reflect.PtrTo(t)).MethodByName("ExtensionRangeArray") + if fn.IsValid() { + if !u.extensions.IsValid() && !u.oldExtensions.IsValid() && !u.bytesExtensions.IsValid() { + panic("a message with extensions, but no extensions field in " + t.Name()) + } + u.extensionRanges = fn.Call(nil)[0].Interface().([]ExtensionRange) + } + + // Explicitly disallow tag 0. This will ensure we flag an error + // when decoding a buffer of all zeros. Without this code, we + // would decode and skip an all-zero buffer of even length. + // [0 0] is [tag=0/wiretype=varint varint-encoded-0]. + u.setTag(0, zeroField, func(b []byte, f pointer, w int) ([]byte, error) { + return nil, fmt.Errorf("proto: %s: illegal tag 0 (wire type %d)", t, w) + }, 0, "") + + // Set mask for required field check. + u.reqMask = uint64(1)<= 0 && (tag < 16 || tag < 2*n) { // TODO: what are the right numbers here? + for len(u.dense) <= tag { + u.dense = append(u.dense, unmarshalFieldInfo{}) + } + u.dense[tag] = i + return + } + if u.sparse == nil { + u.sparse = map[uint64]unmarshalFieldInfo{} + } + u.sparse[uint64(tag)] = i +} + +// fieldUnmarshaler returns an unmarshaler for the given field. +func fieldUnmarshaler(f *reflect.StructField) unmarshaler { + if f.Type.Kind() == reflect.Map { + return makeUnmarshalMap(f) + } + return typeUnmarshaler(f.Type, f.Tag.Get("protobuf")) +} + +// typeUnmarshaler returns an unmarshaler for the given field type / field tag pair. +func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { + tagArray := strings.Split(tags, ",") + encoding := tagArray[0] + name := "unknown" + ctype := false + isTime := false + isDuration := false + isWktPointer := false + proto3 := false + validateUTF8 := true + for _, tag := range tagArray[3:] { + if strings.HasPrefix(tag, "name=") { + name = tag[5:] + } + if tag == "proto3" { + proto3 = true + } + if strings.HasPrefix(tag, "customtype=") { + ctype = true + } + if tag == "stdtime" { + isTime = true + } + if tag == "stdduration" { + isDuration = true + } + if tag == "wktptr" { + isWktPointer = true + } + } + validateUTF8 = validateUTF8 && proto3 + + // Figure out packaging (pointer, slice, or both) + slice := false + pointer := false + if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 { + slice = true + t = t.Elem() + } + if t.Kind() == reflect.Ptr { + pointer = true + t = t.Elem() + } + + if ctype { + if reflect.PtrTo(t).Implements(customType) { + if slice { + return makeUnmarshalCustomSlice(getUnmarshalInfo(t), name) + } + if pointer { + return makeUnmarshalCustomPtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalCustom(getUnmarshalInfo(t), name) + } else { + panic(fmt.Sprintf("custom type: type: %v, does not implement the proto.custom interface", t)) + } + } + + if isTime { + if pointer { + if slice { + return makeUnmarshalTimePtrSlice(getUnmarshalInfo(t), name) + } + return makeUnmarshalTimePtr(getUnmarshalInfo(t), name) + } + if slice { + return makeUnmarshalTimeSlice(getUnmarshalInfo(t), name) + } + return makeUnmarshalTime(getUnmarshalInfo(t), name) + } + + if isDuration { + if pointer { + if slice { + return makeUnmarshalDurationPtrSlice(getUnmarshalInfo(t), name) + } + return makeUnmarshalDurationPtr(getUnmarshalInfo(t), name) + } + if slice { + return makeUnmarshalDurationSlice(getUnmarshalInfo(t), name) + } + return makeUnmarshalDuration(getUnmarshalInfo(t), name) + } + + if isWktPointer { + switch t.Kind() { + case reflect.Float64: + if pointer { + if slice { + return makeStdDoubleValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdDoubleValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdDoubleValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdDoubleValueUnmarshaler(getUnmarshalInfo(t), name) + case reflect.Float32: + if pointer { + if slice { + return makeStdFloatValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdFloatValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdFloatValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdFloatValueUnmarshaler(getUnmarshalInfo(t), name) + case reflect.Int64: + if pointer { + if slice { + return makeStdInt64ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdInt64ValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdInt64ValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdInt64ValueUnmarshaler(getUnmarshalInfo(t), name) + case reflect.Uint64: + if pointer { + if slice { + return makeStdUInt64ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdUInt64ValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdUInt64ValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdUInt64ValueUnmarshaler(getUnmarshalInfo(t), name) + case reflect.Int32: + if pointer { + if slice { + return makeStdInt32ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdInt32ValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdInt32ValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdInt32ValueUnmarshaler(getUnmarshalInfo(t), name) + case reflect.Uint32: + if pointer { + if slice { + return makeStdUInt32ValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdUInt32ValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdUInt32ValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdUInt32ValueUnmarshaler(getUnmarshalInfo(t), name) + case reflect.Bool: + if pointer { + if slice { + return makeStdBoolValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdBoolValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdBoolValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdBoolValueUnmarshaler(getUnmarshalInfo(t), name) + case reflect.String: + if pointer { + if slice { + return makeStdStringValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdStringValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdStringValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdStringValueUnmarshaler(getUnmarshalInfo(t), name) + case uint8SliceType: + if pointer { + if slice { + return makeStdBytesValuePtrSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdBytesValuePtrUnmarshaler(getUnmarshalInfo(t), name) + } + if slice { + return makeStdBytesValueSliceUnmarshaler(getUnmarshalInfo(t), name) + } + return makeStdBytesValueUnmarshaler(getUnmarshalInfo(t), name) + default: + panic(fmt.Sprintf("unknown wktpointer type %#v", t)) + } + } + + // We'll never have both pointer and slice for basic types. + if pointer && slice && t.Kind() != reflect.Struct { + panic("both pointer and slice for basic type in " + t.Name()) + } + + switch t.Kind() { + case reflect.Bool: + if pointer { + return unmarshalBoolPtr + } + if slice { + return unmarshalBoolSlice + } + return unmarshalBoolValue + case reflect.Int32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixedS32Ptr + } + if slice { + return unmarshalFixedS32Slice + } + return unmarshalFixedS32Value + case "varint": + // this could be int32 or enum + if pointer { + return unmarshalInt32Ptr + } + if slice { + return unmarshalInt32Slice + } + return unmarshalInt32Value + case "zigzag32": + if pointer { + return unmarshalSint32Ptr + } + if slice { + return unmarshalSint32Slice + } + return unmarshalSint32Value + } + case reflect.Int64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixedS64Ptr + } + if slice { + return unmarshalFixedS64Slice + } + return unmarshalFixedS64Value + case "varint": + if pointer { + return unmarshalInt64Ptr + } + if slice { + return unmarshalInt64Slice + } + return unmarshalInt64Value + case "zigzag64": + if pointer { + return unmarshalSint64Ptr + } + if slice { + return unmarshalSint64Slice + } + return unmarshalSint64Value + } + case reflect.Uint32: + switch encoding { + case "fixed32": + if pointer { + return unmarshalFixed32Ptr + } + if slice { + return unmarshalFixed32Slice + } + return unmarshalFixed32Value + case "varint": + if pointer { + return unmarshalUint32Ptr + } + if slice { + return unmarshalUint32Slice + } + return unmarshalUint32Value + } + case reflect.Uint64: + switch encoding { + case "fixed64": + if pointer { + return unmarshalFixed64Ptr + } + if slice { + return unmarshalFixed64Slice + } + return unmarshalFixed64Value + case "varint": + if pointer { + return unmarshalUint64Ptr + } + if slice { + return unmarshalUint64Slice + } + return unmarshalUint64Value + } + case reflect.Float32: + if pointer { + return unmarshalFloat32Ptr + } + if slice { + return unmarshalFloat32Slice + } + return unmarshalFloat32Value + case reflect.Float64: + if pointer { + return unmarshalFloat64Ptr + } + if slice { + return unmarshalFloat64Slice + } + return unmarshalFloat64Value + case reflect.Map: + panic("map type in typeUnmarshaler in " + t.Name()) + case reflect.Slice: + if pointer { + panic("bad pointer in slice case in " + t.Name()) + } + if slice { + return unmarshalBytesSlice + } + return unmarshalBytesValue + case reflect.String: + if validateUTF8 { + if pointer { + return unmarshalUTF8StringPtr + } + if slice { + return unmarshalUTF8StringSlice + } + return unmarshalUTF8StringValue + } + if pointer { + return unmarshalStringPtr + } + if slice { + return unmarshalStringSlice + } + return unmarshalStringValue + case reflect.Struct: + // message or group field + if !pointer { + switch encoding { + case "bytes": + if slice { + return makeUnmarshalMessageSlice(getUnmarshalInfo(t), name) + } + return makeUnmarshalMessage(getUnmarshalInfo(t), name) + } + } + switch encoding { + case "bytes": + if slice { + return makeUnmarshalMessageSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalMessagePtr(getUnmarshalInfo(t), name) + case "group": + if slice { + return makeUnmarshalGroupSlicePtr(getUnmarshalInfo(t), name) + } + return makeUnmarshalGroupPtr(getUnmarshalInfo(t), name) + } + } + panic(fmt.Sprintf("unmarshaler not found type:%s encoding:%s", t, encoding)) +} + +// Below are all the unmarshalers for individual fields of various types. + +func unmarshalInt64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64() = v + return b, nil +} + +func unmarshalInt64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalInt64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x) + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalSint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64() = v + return b, nil +} + +func unmarshalSint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + *f.toInt64Ptr() = &v + return b, nil +} + +func unmarshalSint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int64(x>>1) ^ int64(x)<<63>>63 + s := f.toInt64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalUint64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64() = v + return b, nil +} + +func unmarshalUint64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + *f.toUint64Ptr() = &v + return b, nil +} + +func unmarshalUint64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint64(x) + s := f.toUint64Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalInt32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + *f.toInt32() = v + return b, nil +} + +func unmarshalInt32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalInt32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x) + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalSint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + *f.toInt32() = v + return b, nil +} + +func unmarshalSint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.setInt32Ptr(v) + return b, nil +} + +func unmarshalSint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := int32(x>>1) ^ int32(x)<<31>>31 + f.appendInt32Slice(v) + return b, nil +} + +func unmarshalUint32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32() = v + return b, nil +} + +func unmarshalUint32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + *f.toUint32Ptr() = &v + return b, nil +} + +func unmarshalUint32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + v := uint32(x) + s := f.toUint32Slice() + *s = append(*s, v) + return b, nil +} + +func unmarshalFixed64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64() = v + return b[8:], nil +} + +func unmarshalFixed64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + *f.toUint64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixed64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + s := f.toUint64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixedS64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64() = v + return b[8:], nil +} + +func unmarshalFixedS64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + *f.toInt64Ptr() = &v + return b[8:], nil +} + +func unmarshalFixedS64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := int64(b[0]) | int64(b[1])<<8 | int64(b[2])<<16 | int64(b[3])<<24 | int64(b[4])<<32 | int64(b[5])<<40 | int64(b[6])<<48 | int64(b[7])<<56 + s := f.toInt64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFixed32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32() = v + return b[4:], nil +} + +func unmarshalFixed32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + *f.toUint32Ptr() = &v + return b[4:], nil +} + +func unmarshalFixed32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 + s := f.toUint32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalFixedS32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + *f.toInt32() = v + return b[4:], nil +} + +func unmarshalFixedS32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.setInt32Ptr(v) + return b[4:], nil +} + +func unmarshalFixedS32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := int32(b[0]) | int32(b[1])<<8 | int32(b[2])<<16 | int32(b[3])<<24 + f.appendInt32Slice(v) + return b[4:], nil +} + +func unmarshalBoolValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + // Note: any length varint is allowed, even though any sane + // encoder will use one byte. + // See https://github.com/golang/protobuf/issues/76 + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + // TODO: check if x>1? Tests seem to indicate no. + v := x != 0 + *f.toBool() = v + return b[n:], nil +} + +func unmarshalBoolPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + *f.toBoolPtr() = &v + return b[n:], nil +} + +func unmarshalBoolSlice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + x, n = decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + b = b[n:] + } + return res, nil + } + if w != WireVarint { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + v := x != 0 + s := f.toBoolSlice() + *s = append(*s, v) + return b[n:], nil +} + +func unmarshalFloat64Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64() = v + return b[8:], nil +} + +func unmarshalFloat64Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + *f.toFloat64Ptr() = &v + return b[8:], nil +} + +func unmarshalFloat64Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + b = b[8:] + } + return res, nil + } + if w != WireFixed64 { + return b, errInternalBadWireType + } + if len(b) < 8 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float64frombits(uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56) + s := f.toFloat64Slice() + *s = append(*s, v) + return b[8:], nil +} + +func unmarshalFloat32Value(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32() = v + return b[4:], nil +} + +func unmarshalFloat32Ptr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + *f.toFloat32Ptr() = &v + return b[4:], nil +} + +func unmarshalFloat32Slice(b []byte, f pointer, w int) ([]byte, error) { + if w == WireBytes { // packed + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + res := b[x:] + b = b[:x] + for len(b) > 0 { + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + b = b[4:] + } + return res, nil + } + if w != WireFixed32 { + return b, errInternalBadWireType + } + if len(b) < 4 { + return nil, io.ErrUnexpectedEOF + } + v := math.Float32frombits(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24) + s := f.toFloat32Slice() + *s = append(*s, v) + return b[4:], nil +} + +func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toString() = v + return b[x:], nil +} + +func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toStringPtr() = &v + return b[x:], nil +} + +func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + s := f.toStringSlice() + *s = append(*s, v) + return b[x:], nil +} + +func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toString() = v + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + *f.toStringPtr() = &v + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := string(b[:x]) + s := f.toStringSlice() + *s = append(*s, v) + if !utf8.ValidString(v) { + return b[x:], errInvalidUTF8 + } + return b[x:], nil +} + +var emptyBuf [0]byte + +func unmarshalBytesValue(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // The use of append here is a trick which avoids the zeroing + // that would be required if we used a make/copy pair. + // We append to emptyBuf instead of nil because we want + // a non-nil result even when the length is 0. + v := append(emptyBuf[:], b[:x]...) + *f.toBytes() = v + return b[x:], nil +} + +func unmarshalBytesSlice(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := append(emptyBuf[:], b[:x]...) + s := f.toBytesSlice() + *s = append(*s, v) + return b[x:], nil +} + +func makeUnmarshalMessagePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // First read the message field to see if something is there. + // The semantics of multiple submessages are weird. Instead of + // the last one winning (as it is for all other fields), multiple + // submessages are merged. + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[x:], err + } +} + +func makeUnmarshalMessageSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return b, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[x:], err + } +} + +func makeUnmarshalGroupPtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[y:], err + } +} + +func makeUnmarshalGroupSlicePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireStartGroup { + return b, errInternalBadWireType + } + x, y := findEndGroup(b) + if x < 0 { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendPointer(v) + return b[y:], err + } +} + +func makeUnmarshalMap(f *reflect.StructField) unmarshaler { + t := f.Type + kt := t.Key() + vt := t.Elem() + tagArray := strings.Split(f.Tag.Get("protobuf"), ",") + valTags := strings.Split(f.Tag.Get("protobuf_val"), ",") + for _, t := range tagArray { + if strings.HasPrefix(t, "customtype=") { + valTags = append(valTags, t) + } + if t == "stdtime" { + valTags = append(valTags, t) + } + if t == "stdduration" { + valTags = append(valTags, t) + } + if t == "wktptr" { + valTags = append(valTags, t) + } + } + unmarshalKey := typeUnmarshaler(kt, f.Tag.Get("protobuf_key")) + unmarshalVal := typeUnmarshaler(vt, strings.Join(valTags, ",")) + return func(b []byte, f pointer, w int) ([]byte, error) { + // The map entry is a submessage. Figure out how big it is. + if w != WireBytes { + return nil, fmt.Errorf("proto: bad wiretype for map field: got %d want %d", w, WireBytes) + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + r := b[x:] // unused data to return + b = b[:x] // data for map entry + + // Note: we could use #keys * #values ~= 200 functions + // to do map decoding without reflection. Probably not worth it. + // Maps will be somewhat slow. Oh well. + + // Read key and value from data. + var nerr nonFatal + k := reflect.New(kt) + v := reflect.New(vt) + for len(b) > 0 { + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + wire := int(x) & 7 + b = b[n:] + + var err error + switch x >> 3 { + case 1: + b, err = unmarshalKey(b, valToPointer(k), wire) + case 2: + b, err = unmarshalVal(b, valToPointer(v), wire) + default: + err = errInternalBadWireType // skip unknown tag + } + + if nerr.Merge(err) { + continue + } + if err != errInternalBadWireType { + return nil, err + } + + // Skip past unknown fields. + b, err = skipField(b, wire) + if err != nil { + return nil, err + } + } + + // Get map, allocate if needed. + m := f.asPointerTo(t).Elem() // an addressable map[K]T + if m.IsNil() { + m.Set(reflect.MakeMap(t)) + } + + // Insert into map. + m.SetMapIndex(k.Elem(), v.Elem()) + + return r, nerr.E + } +} + +// makeUnmarshalOneof makes an unmarshaler for oneof fields. +// for: +// message Msg { +// oneof F { +// int64 X = 1; +// float64 Y = 2; +// } +// } +// typ is the type of the concrete entry for a oneof case (e.g. Msg_X). +// ityp is the interface type of the oneof field (e.g. isMsg_F). +// unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64). +// Note that this function will be called once for each case in the oneof. +func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshaler { + sf := typ.Field(0) + field0 := toField(&sf) + return func(b []byte, f pointer, w int) ([]byte, error) { + // Allocate holder for value. + v := reflect.New(typ) + + // Unmarshal data into holder. + // We unmarshal into the first field of the holder object. + var err error + var nerr nonFatal + b, err = unmarshal(b, valToPointer(v).offset(field0), w) + if !nerr.Merge(err) { + return nil, err + } + + // Write pointer to holder into target field. + f.asPointerTo(ityp).Elem().Set(v) + + return b, nerr.E + } +} + +// Error used by decode internally. +var errInternalBadWireType = errors.New("proto: internal error: bad wiretype") + +// skipField skips past a field of type wire and returns the remaining bytes. +func skipField(b []byte, wire int) ([]byte, error) { + switch wire { + case WireVarint: + _, k := decodeVarint(b) + if k == 0 { + return b, io.ErrUnexpectedEOF + } + b = b[k:] + case WireFixed32: + if len(b) < 4 { + return b, io.ErrUnexpectedEOF + } + b = b[4:] + case WireFixed64: + if len(b) < 8 { + return b, io.ErrUnexpectedEOF + } + b = b[8:] + case WireBytes: + m, k := decodeVarint(b) + if k == 0 || uint64(len(b)-k) < m { + return b, io.ErrUnexpectedEOF + } + b = b[uint64(k)+m:] + case WireStartGroup: + _, i := findEndGroup(b) + if i == -1 { + return b, io.ErrUnexpectedEOF + } + b = b[i:] + default: + return b, fmt.Errorf("proto: can't skip unknown wire type %d", wire) + } + return b, nil +} + +// findEndGroup finds the index of the next EndGroup tag. +// Groups may be nested, so the "next" EndGroup tag is the first +// unpaired EndGroup. +// findEndGroup returns the indexes of the start and end of the EndGroup tag. +// Returns (-1,-1) if it can't find one. +func findEndGroup(b []byte) (int, int) { + depth := 1 + i := 0 + for { + x, n := decodeVarint(b[i:]) + if n == 0 { + return -1, -1 + } + j := i + i += n + switch x & 7 { + case WireVarint: + _, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + case WireFixed32: + if len(b)-4 < i { + return -1, -1 + } + i += 4 + case WireFixed64: + if len(b)-8 < i { + return -1, -1 + } + i += 8 + case WireBytes: + m, k := decodeVarint(b[i:]) + if k == 0 { + return -1, -1 + } + i += k + if uint64(len(b)-i) < m { + return -1, -1 + } + i += int(m) + case WireStartGroup: + depth++ + case WireEndGroup: + depth-- + if depth == 0 { + return j, i + } + default: + return -1, -1 + } + } +} + +// encodeVarint appends a varint-encoded integer to b and returns the result. +func encodeVarint(b []byte, x uint64) []byte { + for x >= 1<<7 { + b = append(b, byte(x&0x7f|0x80)) + x >>= 7 + } + return append(b, byte(x)) +} + +// decodeVarint reads a varint-encoded integer from b. +// Returns the decoded integer and the number of bytes read. +// If there is an error, it returns 0,0. +func decodeVarint(b []byte) (uint64, int) { + var x, y uint64 + if len(b) == 0 { + goto bad + } + x = uint64(b[0]) + if x < 0x80 { + return x, 1 + } + x -= 0x80 + + if len(b) <= 1 { + goto bad + } + y = uint64(b[1]) + x += y << 7 + if y < 0x80 { + return x, 2 + } + x -= 0x80 << 7 + + if len(b) <= 2 { + goto bad + } + y = uint64(b[2]) + x += y << 14 + if y < 0x80 { + return x, 3 + } + x -= 0x80 << 14 + + if len(b) <= 3 { + goto bad + } + y = uint64(b[3]) + x += y << 21 + if y < 0x80 { + return x, 4 + } + x -= 0x80 << 21 + + if len(b) <= 4 { + goto bad + } + y = uint64(b[4]) + x += y << 28 + if y < 0x80 { + return x, 5 + } + x -= 0x80 << 28 + + if len(b) <= 5 { + goto bad + } + y = uint64(b[5]) + x += y << 35 + if y < 0x80 { + return x, 6 + } + x -= 0x80 << 35 + + if len(b) <= 6 { + goto bad + } + y = uint64(b[6]) + x += y << 42 + if y < 0x80 { + return x, 7 + } + x -= 0x80 << 42 + + if len(b) <= 7 { + goto bad + } + y = uint64(b[7]) + x += y << 49 + if y < 0x80 { + return x, 8 + } + x -= 0x80 << 49 + + if len(b) <= 8 { + goto bad + } + y = uint64(b[8]) + x += y << 56 + if y < 0x80 { + return x, 9 + } + x -= 0x80 << 56 + + if len(b) <= 9 { + goto bad + } + y = uint64(b[9]) + x += y << 63 + if y < 2 { + return x, 10 + } + +bad: + return 0, 0 +} diff --git a/vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go b/vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go new file mode 100644 index 0000000000..00d6c7ad93 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/table_unmarshal_gogo.go @@ -0,0 +1,385 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "io" + "reflect" +) + +func makeUnmarshalMessage(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + // First read the message field to see if something is there. + // The semantics of multiple submessages are weird. Instead of + // the last one winning (as it is for all other fields), multiple + // submessages are merged. + v := f // gogo: changed from v := f.getPointer() + if v.isNil() { + v = valToPointer(reflect.New(sub.typ)) + f.setPointer(v) + } + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + return b[x:], err + } +} + +func makeUnmarshalMessageSlice(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + v := valToPointer(reflect.New(sub.typ)) + err := sub.unmarshal(v, b[:x]) + if err != nil { + if r, ok := err.(*RequiredNotSetError); ok { + r.field = name + "." + r.field + } else { + return nil, err + } + } + f.appendRef(v, sub.typ) // gogo: changed from f.appendPointer(v) + return b[x:], err + } +} + +func makeUnmarshalCustomPtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.New(sub.typ)) + m := s.Interface().(custom) + if err := m.Unmarshal(b[:x]); err != nil { + return nil, err + } + return b[x:], nil + } +} + +func makeUnmarshalCustomSlice(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := reflect.New(sub.typ) + c := m.Interface().(custom) + if err := c.Unmarshal(b[:x]); err != nil { + return nil, err + } + v := valToPointer(m) + f.appendRef(v, sub.typ) + return b[x:], nil + } +} + +func makeUnmarshalCustom(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + + m := f.asPointerTo(sub.typ).Interface().(custom) + if err := m.Unmarshal(b[:x]); err != nil { + return nil, err + } + return b[x:], nil + } +} + +func makeUnmarshalTime(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := ×tamp{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + t, err := timestampFromProto(m) + if err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(t)) + return b[x:], nil + } +} + +func makeUnmarshalTimePtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := ×tamp{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + t, err := timestampFromProto(m) + if err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&t)) + return b[x:], nil + } +} + +func makeUnmarshalTimePtrSlice(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := ×tamp{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + t, err := timestampFromProto(m) + if err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&t)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeUnmarshalTimeSlice(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := ×tamp{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + t, err := timestampFromProto(m) + if err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(t)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeUnmarshalDurationPtr(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &duration{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + d, err := durationFromProto(m) + if err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&d)) + return b[x:], nil + } +} + +func makeUnmarshalDuration(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &duration{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + d, err := durationFromProto(m) + if err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(d)) + return b[x:], nil + } +} + +func makeUnmarshalDurationPtrSlice(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &duration{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + d, err := durationFromProto(m) + if err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&d)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeUnmarshalDurationSlice(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &duration{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + d, err := durationFromProto(m) + if err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(d)) + slice.Set(newSlice) + return b[x:], nil + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/text.go b/vendor/github.com/gogo/protobuf/proto/text.go new file mode 100644 index 0000000000..87416afe95 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text.go @@ -0,0 +1,930 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for writing the text protocol buffer format. + +import ( + "bufio" + "bytes" + "encoding" + "errors" + "fmt" + "io" + "log" + "math" + "reflect" + "sort" + "strings" + "sync" + "time" +) + +var ( + newline = []byte("\n") + spaces = []byte(" ") + endBraceNewline = []byte("}\n") + backslashN = []byte{'\\', 'n'} + backslashR = []byte{'\\', 'r'} + backslashT = []byte{'\\', 't'} + backslashDQ = []byte{'\\', '"'} + backslashBS = []byte{'\\', '\\'} + posInf = []byte("inf") + negInf = []byte("-inf") + nan = []byte("nan") +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +// textWriter is an io.Writer that tracks its indentation level. +type textWriter struct { + ind int + complete bool // if the current position is a complete line + compact bool // whether to write out as a one-liner + w writer +} + +func (w *textWriter) WriteString(s string) (n int, err error) { + if !strings.Contains(s, "\n") { + if !w.compact && w.complete { + w.writeIndent() + } + w.complete = false + return io.WriteString(w.w, s) + } + // WriteString is typically called without newlines, so this + // codepath and its copy are rare. We copy to avoid + // duplicating all of Write's logic here. + return w.Write([]byte(s)) +} + +func (w *textWriter) Write(p []byte) (n int, err error) { + newlines := bytes.Count(p, newline) + if newlines == 0 { + if !w.compact && w.complete { + w.writeIndent() + } + n, err = w.w.Write(p) + w.complete = false + return n, err + } + + frags := bytes.SplitN(p, newline, newlines+1) + if w.compact { + for i, frag := range frags { + if i > 0 { + if err := w.w.WriteByte(' '); err != nil { + return n, err + } + n++ + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + } + return n, nil + } + + for i, frag := range frags { + if w.complete { + w.writeIndent() + } + nn, err := w.w.Write(frag) + n += nn + if err != nil { + return n, err + } + if i+1 < len(frags) { + if err := w.w.WriteByte('\n'); err != nil { + return n, err + } + n++ + } + } + w.complete = len(frags[len(frags)-1]) == 0 + return n, nil +} + +func (w *textWriter) WriteByte(c byte) error { + if w.compact && c == '\n' { + c = ' ' + } + if !w.compact && w.complete { + w.writeIndent() + } + err := w.w.WriteByte(c) + w.complete = c == '\n' + return err +} + +func (w *textWriter) indent() { w.ind++ } + +func (w *textWriter) unindent() { + if w.ind == 0 { + log.Print("proto: textWriter unindented too far") + return + } + w.ind-- +} + +func writeName(w *textWriter, props *Properties) error { + if _, err := w.WriteString(props.OrigName); err != nil { + return err + } + if props.Wire != "group" { + return w.WriteByte(':') + } + return nil +} + +func requiresQuotes(u string) bool { + // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. + for _, ch := range u { + switch { + case ch == '.' || ch == '/' || ch == '_': + continue + case '0' <= ch && ch <= '9': + continue + case 'A' <= ch && ch <= 'Z': + continue + case 'a' <= ch && ch <= 'z': + continue + default: + return true + } + } + return false +} + +// isAny reports whether sv is a google.protobuf.Any message +func isAny(sv reflect.Value) bool { + type wkt interface { + XXX_WellKnownType() string + } + t, ok := sv.Addr().Interface().(wkt) + return ok && t.XXX_WellKnownType() == "Any" +} + +// writeProto3Any writes an expanded google.protobuf.Any message. +// +// It returns (false, nil) if sv value can't be unmarshaled (e.g. because +// required messages are not linked in). +// +// It returns (true, error) when sv was written in expanded format or an error +// was encountered. +func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) { + turl := sv.FieldByName("TypeUrl") + val := sv.FieldByName("Value") + if !turl.IsValid() || !val.IsValid() { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + b, ok := val.Interface().([]byte) + if !ok { + return true, errors.New("proto: invalid google.protobuf.Any message") + } + + parts := strings.Split(turl.String(), "/") + mt := MessageType(parts[len(parts)-1]) + if mt == nil { + return false, nil + } + m := reflect.New(mt.Elem()) + if err := Unmarshal(b, m.Interface().(Message)); err != nil { + return false, nil + } + w.Write([]byte("[")) + u := turl.String() + if requiresQuotes(u) { + writeString(w, u) + } else { + w.Write([]byte(u)) + } + if w.compact { + w.Write([]byte("]:<")) + } else { + w.Write([]byte("]: <\n")) + w.ind++ + } + if err := tm.writeStruct(w, m.Elem()); err != nil { + return true, err + } + if w.compact { + w.Write([]byte("> ")) + } else { + w.ind-- + w.Write([]byte(">\n")) + } + return true, nil +} + +func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { + if tm.ExpandAny && isAny(sv) { + if canExpand, err := tm.writeProto3Any(w, sv); canExpand { + return err + } + } + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < sv.NumField(); i++ { + fv := sv.Field(i) + props := sprops.Prop[i] + name := st.Field(i).Name + + if name == "XXX_NoUnkeyedLiteral" { + continue + } + + if strings.HasPrefix(name, "XXX_") { + // There are two XXX_ fields: + // XXX_unrecognized []byte + // XXX_extensions map[int32]proto.Extension + // The first is handled here; + // the second is handled at the bottom of this function. + if name == "XXX_unrecognized" && !fv.IsNil() { + if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Field not filled in. This could be an optional field or + // a required field that wasn't filled in. Either way, there + // isn't anything we can show for it. + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + // Repeated field that is empty, or a bytes field that is unused. + continue + } + + if props.Repeated && fv.Kind() == reflect.Slice { + // Repeated field. + for j := 0; j < fv.Len(); j++ { + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + v := fv.Index(j) + if v.Kind() == reflect.Ptr && v.IsNil() { + // A nil message in a repeated field is not valid, + // but we can handle that more gracefully than panicking. + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + continue + } + if len(props.Enum) > 0 { + if err := tm.writeEnum(w, v, props); err != nil { + return err + } + } else if err := tm.writeAny(w, v, props); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if fv.Kind() == reflect.Map { + // Map fields are rendered as a repeated struct with key/value fields. + keys := fv.MapKeys() + sort.Sort(mapKeys(keys)) + for _, key := range keys { + val := fv.MapIndex(key) + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + // open struct + if err := w.WriteByte('<'); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + // key + if _, err := w.WriteString("key:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, key, props.MapKeyProp); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + // nil values aren't legal, but we can avoid panicking because of them. + if val.Kind() != reflect.Ptr || !val.IsNil() { + // value + if _, err := w.WriteString("value:"); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, val, props.MapValProp); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + // close struct + w.unindent() + if err := w.WriteByte('>'); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + continue + } + if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 { + // empty bytes field + continue + } + if props.proto3 && fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice { + // proto3 non-repeated scalar field; skip if zero value + if isProto3Zero(fv) { + continue + } + } + + if fv.Kind() == reflect.Interface { + // Check if it is a oneof. + if st.Field(i).Tag.Get("protobuf_oneof") != "" { + // fv is nil, or holds a pointer to generated struct. + // That generated struct has exactly one field, + // which has a protobuf struct tag. + if fv.IsNil() { + continue + } + inner := fv.Elem().Elem() // interface -> *T -> T + tag := inner.Type().Field(0).Tag.Get("protobuf") + props = new(Properties) // Overwrite the outer props var, but not its pointee. + props.Parse(tag) + // Write the value in the oneof, not the oneof itself. + fv = inner.Field(0) + + // Special case to cope with malformed messages gracefully: + // If the value in the oneof is a nil pointer, don't panic + // in writeAny. + if fv.Kind() == reflect.Ptr && fv.IsNil() { + // Use errors.New so writeAny won't render quotes. + msg := errors.New("/* nil */") + fv = reflect.ValueOf(&msg).Elem() + } + } + } + + if err := writeName(w, props); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + + if len(props.Enum) > 0 { + if err := tm.writeEnum(w, fv, props); err != nil { + return err + } + } else if err := tm.writeAny(w, fv, props); err != nil { + return err + } + + if err := w.WriteByte('\n'); err != nil { + return err + } + } + + // Extensions (the XXX_extensions field). + pv := sv + if pv.CanAddr() { + pv = sv.Addr() + } else { + pv = reflect.New(sv.Type()) + pv.Elem().Set(sv) + } + if _, err := extendable(pv.Interface()); err == nil { + if err := tm.writeExtensions(w, pv); err != nil { + return err + } + } + + return nil +} + +var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() + +// writeAny writes an arbitrary field. +func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error { + v = reflect.Indirect(v) + + if props != nil { + if len(props.CustomType) > 0 { + custom, ok := v.Interface().(Marshaler) + if ok { + data, err := custom.Marshal() + if err != nil { + return err + } + if err := writeString(w, string(data)); err != nil { + return err + } + return nil + } + } else if len(props.CastType) > 0 { + if _, ok := v.Interface().(interface { + String() string + }); ok { + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + _, err := fmt.Fprintf(w, "%d", v.Interface()) + return err + } + } + } else if props.StdTime { + t, ok := v.Interface().(time.Time) + if !ok { + return fmt.Errorf("stdtime is not time.Time, but %T", v.Interface()) + } + tproto, err := timestampProto(t) + if err != nil { + return err + } + propsCopy := *props // Make a copy so that this is goroutine-safe + propsCopy.StdTime = false + err = tm.writeAny(w, reflect.ValueOf(tproto), &propsCopy) + return err + } else if props.StdDuration { + d, ok := v.Interface().(time.Duration) + if !ok { + return fmt.Errorf("stdtime is not time.Duration, but %T", v.Interface()) + } + dproto := durationProto(d) + propsCopy := *props // Make a copy so that this is goroutine-safe + propsCopy.StdDuration = false + err := tm.writeAny(w, reflect.ValueOf(dproto), &propsCopy) + return err + } + } + + // Floats have special cases. + if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 { + x := v.Float() + var b []byte + switch { + case math.IsInf(x, 1): + b = posInf + case math.IsInf(x, -1): + b = negInf + case math.IsNaN(x): + b = nan + } + if b != nil { + _, err := w.Write(b) + return err + } + // Other values are handled below. + } + + // We don't attempt to serialise every possible value type; only those + // that can occur in protocol buffers. + switch v.Kind() { + case reflect.Slice: + // Should only be a []byte; repeated fields are handled in writeStruct. + if err := writeString(w, string(v.Bytes())); err != nil { + return err + } + case reflect.String: + if err := writeString(w, v.String()); err != nil { + return err + } + case reflect.Struct: + // Required/optional group/message. + var bra, ket byte = '<', '>' + if props != nil && props.Wire == "group" { + bra, ket = '{', '}' + } + if err := w.WriteByte(bra); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte('\n'); err != nil { + return err + } + } + w.indent() + if v.CanAddr() { + // Calling v.Interface on a struct causes the reflect package to + // copy the entire struct. This is racy with the new Marshaler + // since we atomically update the XXX_sizecache. + // + // Thus, we retrieve a pointer to the struct if possible to avoid + // a race since v.Interface on the pointer doesn't copy the struct. + // + // If v is not addressable, then we are not worried about a race + // since it implies that the binary Marshaler cannot possibly be + // mutating this value. + v = v.Addr() + } + if v.Type().Implements(textMarshalerType) { + text, err := v.Interface().(encoding.TextMarshaler).MarshalText() + if err != nil { + return err + } + if _, err = w.Write(text); err != nil { + return err + } + } else { + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if err := tm.writeStruct(w, v); err != nil { + return err + } + } + w.unindent() + if err := w.WriteByte(ket); err != nil { + return err + } + default: + _, err := fmt.Fprint(w, v.Interface()) + return err + } + return nil +} + +// equivalent to C's isprint. +func isprint(c byte) bool { + return c >= 0x20 && c < 0x7f +} + +// writeString writes a string in the protocol buffer text format. +// It is similar to strconv.Quote except we don't use Go escape sequences, +// we treat the string as a byte sequence, and we use octal escapes. +// These differences are to maintain interoperability with the other +// languages' implementations of the text format. +func writeString(w *textWriter, s string) error { + // use WriteByte here to get any needed indent + if err := w.WriteByte('"'); err != nil { + return err + } + // Loop over the bytes, not the runes. + for i := 0; i < len(s); i++ { + var err error + // Divergence from C++: we don't escape apostrophes. + // There's no need to escape them, and the C++ parser + // copes with a naked apostrophe. + switch c := s[i]; c { + case '\n': + _, err = w.w.Write(backslashN) + case '\r': + _, err = w.w.Write(backslashR) + case '\t': + _, err = w.w.Write(backslashT) + case '"': + _, err = w.w.Write(backslashDQ) + case '\\': + _, err = w.w.Write(backslashBS) + default: + if isprint(c) { + err = w.w.WriteByte(c) + } else { + _, err = fmt.Fprintf(w.w, "\\%03o", c) + } + } + if err != nil { + return err + } + } + return w.WriteByte('"') +} + +func writeUnknownStruct(w *textWriter, data []byte) (err error) { + if !w.compact { + if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil { + return err + } + } + b := NewBuffer(data) + for b.index < len(b.buf) { + x, err := b.DecodeVarint() + if err != nil { + _, ferr := fmt.Fprintf(w, "/* %v */\n", err) + return ferr + } + wire, tag := x&7, x>>3 + if wire == WireEndGroup { + w.unindent() + if _, werr := w.Write(endBraceNewline); werr != nil { + return werr + } + continue + } + if _, ferr := fmt.Fprint(w, tag); ferr != nil { + return ferr + } + if wire != WireStartGroup { + if err = w.WriteByte(':'); err != nil { + return err + } + } + if !w.compact || wire == WireStartGroup { + if err = w.WriteByte(' '); err != nil { + return err + } + } + switch wire { + case WireBytes: + buf, e := b.DecodeRawBytes(false) + if e == nil { + _, err = fmt.Fprintf(w, "%q", buf) + } else { + _, err = fmt.Fprintf(w, "/* %v */", e) + } + case WireFixed32: + x, err = b.DecodeFixed32() + err = writeUnknownInt(w, x, err) + case WireFixed64: + x, err = b.DecodeFixed64() + err = writeUnknownInt(w, x, err) + case WireStartGroup: + err = w.WriteByte('{') + w.indent() + case WireVarint: + x, err = b.DecodeVarint() + err = writeUnknownInt(w, x, err) + default: + _, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire) + } + if err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + } + return nil +} + +func writeUnknownInt(w *textWriter, x uint64, err error) error { + if err == nil { + _, err = fmt.Fprint(w, x) + } else { + _, err = fmt.Fprintf(w, "/* %v */", err) + } + return err +} + +type int32Slice []int32 + +func (s int32Slice) Len() int { return len(s) } +func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] } +func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// writeExtensions writes all the extensions in pv. +// pv is assumed to be a pointer to a protocol message struct that is extendable. +func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error { + emap := extensionMaps[pv.Type().Elem()] + e := pv.Interface().(Message) + + var m map[int32]Extension + var mu sync.Locker + if em, ok := e.(extensionsBytes); ok { + eb := em.GetExtensions() + var err error + m, err = BytesToExtensionsMap(*eb) + if err != nil { + return err + } + mu = notLocker{} + } else if _, ok := e.(extendableProto); ok { + ep, _ := extendable(e) + m, mu = ep.extensionsRead() + if m == nil { + return nil + } + } + + // Order the extensions by ID. + // This isn't strictly necessary, but it will give us + // canonical output, which will also make testing easier. + + mu.Lock() + ids := make([]int32, 0, len(m)) + for id := range m { + ids = append(ids, id) + } + sort.Sort(int32Slice(ids)) + mu.Unlock() + + for _, extNum := range ids { + ext := m[extNum] + var desc *ExtensionDesc + if emap != nil { + desc = emap[extNum] + } + if desc == nil { + // Unknown extension. + if err := writeUnknownStruct(w, ext.enc); err != nil { + return err + } + continue + } + + pb, err := GetExtension(e, desc) + if err != nil { + return fmt.Errorf("failed getting extension: %v", err) + } + + // Repeated extensions will appear as a slice. + if !desc.repeated() { + if err := tm.writeExtension(w, desc.Name, pb); err != nil { + return err + } + } else { + v := reflect.ValueOf(pb) + for i := 0; i < v.Len(); i++ { + if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil { + return err + } + } + } + } + return nil +} + +func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error { + if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil { + return err + } + if !w.compact { + if err := w.WriteByte(' '); err != nil { + return err + } + } + if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil { + return err + } + if err := w.WriteByte('\n'); err != nil { + return err + } + return nil +} + +func (w *textWriter) writeIndent() { + if !w.complete { + return + } + remain := w.ind * 2 + for remain > 0 { + n := remain + if n > len(spaces) { + n = len(spaces) + } + w.w.Write(spaces[:n]) + remain -= n + } + w.complete = false +} + +// TextMarshaler is a configurable text format marshaler. +type TextMarshaler struct { + Compact bool // use compact text format (one line). + ExpandAny bool // expand google.protobuf.Any messages of known types +} + +// Marshal writes a given protocol buffer in text format. +// The only errors returned are from w. +func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error { + val := reflect.ValueOf(pb) + if pb == nil || val.IsNil() { + w.Write([]byte("")) + return nil + } + var bw *bufio.Writer + ww, ok := w.(writer) + if !ok { + bw = bufio.NewWriter(w) + ww = bw + } + aw := &textWriter{ + w: ww, + complete: true, + compact: tm.Compact, + } + + if etm, ok := pb.(encoding.TextMarshaler); ok { + text, err := etm.MarshalText() + if err != nil { + return err + } + if _, err = aw.Write(text); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil + } + // Dereference the received pointer so we don't have outer < and >. + v := reflect.Indirect(val) + if err := tm.writeStruct(aw, v); err != nil { + return err + } + if bw != nil { + return bw.Flush() + } + return nil +} + +// Text is the same as Marshal, but returns the string directly. +func (tm *TextMarshaler) Text(pb Message) string { + var buf bytes.Buffer + tm.Marshal(&buf, pb) + return buf.String() +} + +var ( + defaultTextMarshaler = TextMarshaler{} + compactTextMarshaler = TextMarshaler{Compact: true} +) + +// TODO: consider removing some of the Marshal functions below. + +// MarshalText writes a given protocol buffer in text format. +// The only errors returned are from w. +func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) } + +// MarshalTextString is the same as MarshalText, but returns the string directly. +func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } + +// CompactText writes a given protocol buffer in compact text format (one line). +func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) } + +// CompactTextString is the same as CompactText, but returns the string directly. +func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } diff --git a/vendor/github.com/gogo/protobuf/proto/text_gogo.go b/vendor/github.com/gogo/protobuf/proto/text_gogo.go new file mode 100644 index 0000000000..1d6c6aa0e4 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_gogo.go @@ -0,0 +1,57 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "fmt" + "reflect" +) + +func (tm *TextMarshaler) writeEnum(w *textWriter, v reflect.Value, props *Properties) error { + m, ok := enumStringMaps[props.Enum] + if !ok { + if err := tm.writeAny(w, v, props); err != nil { + return err + } + } + key := int32(0) + if v.Kind() == reflect.Ptr { + key = int32(v.Elem().Int()) + } else { + key = int32(v.Int()) + } + s, ok := m[key] + if !ok { + if err := tm.writeAny(w, v, props); err != nil { + return err + } + } + _, err := fmt.Fprint(w, s) + return err +} diff --git a/vendor/github.com/gogo/protobuf/proto/text_parser.go b/vendor/github.com/gogo/protobuf/proto/text_parser.go new file mode 100644 index 0000000000..1ce0be2fa9 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_parser.go @@ -0,0 +1,1018 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// Functions for parsing the Text protocol buffer format. +// TODO: message sets. + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +// Error string emitted when deserializing Any and fields are already set +const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set" + +type ParseError struct { + Message string + Line int // 1-based line number + Offset int // 0-based byte offset from start of input +} + +func (p *ParseError) Error() string { + if p.Line == 1 { + // show offset only for first line + return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message) + } + return fmt.Sprintf("line %d: %v", p.Line, p.Message) +} + +type token struct { + value string + err *ParseError + line int // line number + offset int // byte number from start of input, not start of line + unquoted string // the unquoted version of value, if it was a quoted string +} + +func (t *token) String() string { + if t.err == nil { + return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset) + } + return fmt.Sprintf("parse error: %v", t.err) +} + +type textParser struct { + s string // remaining input + done bool // whether the parsing is finished (success or error) + backed bool // whether back() was called + offset, line int + cur token +} + +func newTextParser(s string) *textParser { + p := new(textParser) + p.s = s + p.line = 1 + p.cur.line = 1 + return p +} + +func (p *textParser) errorf(format string, a ...interface{}) *ParseError { + pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} + p.cur.err = pe + p.done = true + return pe +} + +// Numbers and identifiers are matched by [-+._A-Za-z0-9] +func isIdentOrNumberChar(c byte) bool { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': + return true + case '0' <= c && c <= '9': + return true + } + switch c { + case '-', '+', '.', '_': + return true + } + return false +} + +func isWhitespace(c byte) bool { + switch c { + case ' ', '\t', '\n', '\r': + return true + } + return false +} + +func isQuote(c byte) bool { + switch c { + case '"', '\'': + return true + } + return false +} + +func (p *textParser) skipWhitespace() { + i := 0 + for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { + if p.s[i] == '#' { + // comment; skip to end of line or input + for i < len(p.s) && p.s[i] != '\n' { + i++ + } + if i == len(p.s) { + break + } + } + if p.s[i] == '\n' { + p.line++ + } + i++ + } + p.offset += i + p.s = p.s[i:len(p.s)] + if len(p.s) == 0 { + p.done = true + } +} + +func (p *textParser) advance() { + // Skip whitespace + p.skipWhitespace() + if p.done { + return + } + + // Start of non-whitespace + p.cur.err = nil + p.cur.offset, p.cur.line = p.offset, p.line + p.cur.unquoted = "" + switch p.s[0] { + case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': + // Single symbol + p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] + case '"', '\'': + // Quoted string + i := 1 + for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { + if p.s[i] == '\\' && i+1 < len(p.s) { + // skip escaped char + i++ + } + i++ + } + if i >= len(p.s) || p.s[i] != p.s[0] { + p.errorf("unmatched quote") + return + } + unq, err := unquoteC(p.s[1:i], rune(p.s[0])) + if err != nil { + p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) + return + } + p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] + p.cur.unquoted = unq + default: + i := 0 + for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { + i++ + } + if i == 0 { + p.errorf("unexpected byte %#x", p.s[0]) + return + } + p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] + } + p.offset += len(p.cur.value) +} + +var ( + errBadUTF8 = errors.New("proto: bad UTF-8") +) + +func unquoteC(s string, quote rune) (string, error) { + // This is based on C++'s tokenizer.cc. + // Despite its name, this is *not* parsing C syntax. + // For instance, "\0" is an invalid quoted string. + + // Avoid allocation in trivial cases. + simple := true + for _, r := range s { + if r == '\\' || r == quote { + simple = false + break + } + } + if simple { + return s, nil + } + + buf := make([]byte, 0, 3*len(s)/2) + for len(s) > 0 { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", errBadUTF8 + } + s = s[n:] + if r != '\\' { + if r < utf8.RuneSelf { + buf = append(buf, byte(r)) + } else { + buf = append(buf, string(r)...) + } + continue + } + + ch, tail, err := unescape(s) + if err != nil { + return "", err + } + buf = append(buf, ch...) + s = tail + } + return string(buf), nil +} + +func unescape(s string) (ch string, tail string, err error) { + r, n := utf8.DecodeRuneInString(s) + if r == utf8.RuneError && n == 1 { + return "", "", errBadUTF8 + } + s = s[n:] + switch r { + case 'a': + return "\a", s, nil + case 'b': + return "\b", s, nil + case 'f': + return "\f", s, nil + case 'n': + return "\n", s, nil + case 'r': + return "\r", s, nil + case 't': + return "\t", s, nil + case 'v': + return "\v", s, nil + case '?': + return "?", s, nil // trigraph workaround + case '\'', '"', '\\': + return string(r), s, nil + case '0', '1', '2', '3', '4', '5', '6', '7': + if len(s) < 2 { + return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) + } + ss := string(r) + s[:2] + s = s[2:] + i, err := strconv.ParseUint(ss, 8, 8) + if err != nil { + return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) + } + return string([]byte{byte(i)}), s, nil + case 'x', 'X', 'u', 'U': + var n int + switch r { + case 'x', 'X': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + if len(s) < n { + return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) + } + ss := s[:n] + s = s[n:] + i, err := strconv.ParseUint(ss, 16, 64) + if err != nil { + return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) + } + if r == 'x' || r == 'X' { + return string([]byte{byte(i)}), s, nil + } + if i > utf8.MaxRune { + return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) + } + return string(i), s, nil + } + return "", "", fmt.Errorf(`unknown escape \%c`, r) +} + +// Back off the parser by one token. Can only be done between calls to next(). +// It makes the next advance() a no-op. +func (p *textParser) back() { p.backed = true } + +// Advances the parser and returns the new current token. +func (p *textParser) next() *token { + if p.backed || p.done { + p.backed = false + return &p.cur + } + p.advance() + if p.done { + p.cur.value = "" + } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { + // Look for multiple quoted strings separated by whitespace, + // and concatenate them. + cat := p.cur + for { + p.skipWhitespace() + if p.done || !isQuote(p.s[0]) { + break + } + p.advance() + if p.cur.err != nil { + return &p.cur + } + cat.value += " " + p.cur.value + cat.unquoted += p.cur.unquoted + } + p.done = false // parser may have seen EOF, but we want to return cat + p.cur = cat + } + return &p.cur +} + +func (p *textParser) consumeToken(s string) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != s { + p.back() + return p.errorf("expected %q, found %q", s, tok.value) + } + return nil +} + +// Return a RequiredNotSetError indicating which required field was not set. +func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError { + st := sv.Type() + sprops := GetProperties(st) + for i := 0; i < st.NumField(); i++ { + if !isNil(sv.Field(i)) { + continue + } + + props := sprops.Prop[i] + if props.Required { + return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)} + } + } + return &RequiredNotSetError{fmt.Sprintf("%v.", st)} // should not happen +} + +// Returns the index in the struct for the named field, as well as the parsed tag properties. +func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) { + i, ok := sprops.decoderOrigNames[name] + if ok { + return i, sprops.Prop[i], true + } + return -1, nil, false +} + +// Consume a ':' from the input stream (if the next token is a colon), +// returning an error if a colon is needed but not present. +func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ":" { + // Colon is optional when the field is a group or message. + needColon := true + switch props.Wire { + case "group": + needColon = false + case "bytes": + // A "bytes" field is either a message, a string, or a repeated field; + // those three become *T, *string and []T respectively, so we can check for + // this field being a pointer to a non-string. + if typ.Kind() == reflect.Ptr { + // *T or *string + if typ.Elem().Kind() == reflect.String { + break + } + } else if typ.Kind() == reflect.Slice { + // []T or []*T + if typ.Elem().Kind() != reflect.Ptr { + break + } + } else if typ.Kind() == reflect.String { + // The proto3 exception is for a string field, + // which requires a colon. + break + } + needColon = false + } + if needColon { + return p.errorf("expected ':', found %q", tok.value) + } + p.back() + } + return nil +} + +func (p *textParser) readStruct(sv reflect.Value, terminator string) error { + st := sv.Type() + sprops := GetProperties(st) + reqCount := sprops.reqCount + var reqFieldErr error + fieldSet := make(map[string]bool) + // A struct is a sequence of "name: value", terminated by one of + // '>' or '}', or the end of the input. A name may also be + // "[extension]" or "[type/url]". + // + // The whole struct can also be an expanded Any message, like: + // [type/url] < ... struct contents ... > + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + if tok.value == "[" { + // Looks like an extension or an Any. + // + // TODO: Check whether we need to handle + // namespace rooted names (e.g. ".something.Foo"). + extName, err := p.consumeExtName() + if err != nil { + return err + } + + if s := strings.LastIndex(extName, "/"); s >= 0 { + // If it contains a slash, it's an Any type URL. + messageName := extName[s+1:] + mt := MessageType(messageName) + if mt == nil { + return p.errorf("unrecognized message %q in google.protobuf.Any", messageName) + } + tok = p.next() + if tok.err != nil { + return tok.err + } + // consume an optional colon + if tok.value == ":" { + tok = p.next() + if tok.err != nil { + return tok.err + } + } + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + v := reflect.New(mt.Elem()) + if pe := p.readStruct(v.Elem(), terminator); pe != nil { + return pe + } + b, err := Marshal(v.Interface().(Message)) + if err != nil { + return p.errorf("failed to marshal message of type %q: %v", messageName, err) + } + if fieldSet["type_url"] { + return p.errorf(anyRepeatedlyUnpacked, "type_url") + } + if fieldSet["value"] { + return p.errorf(anyRepeatedlyUnpacked, "value") + } + sv.FieldByName("TypeUrl").SetString(extName) + sv.FieldByName("Value").SetBytes(b) + fieldSet["type_url"] = true + fieldSet["value"] = true + continue + } + + var desc *ExtensionDesc + // This could be faster, but it's functional. + // TODO: Do something smarter than a linear scan. + for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) { + if d.Name == extName { + desc = d + break + } + } + if desc == nil { + return p.errorf("unrecognized extension %q", extName) + } + + props := &Properties{} + props.Parse(desc.Tag) + + typ := reflect.TypeOf(desc.ExtensionType) + if err := p.checkForColon(props, typ); err != nil { + return err + } + + rep := desc.repeated() + + // Read the extension structure, and set it in + // the value we're constructing. + var ext reflect.Value + if !rep { + ext = reflect.New(typ).Elem() + } else { + ext = reflect.New(typ.Elem()).Elem() + } + if err := p.readAny(ext, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + ep := sv.Addr().Interface().(Message) + if !rep { + SetExtension(ep, desc, ext.Interface()) + } else { + old, err := GetExtension(ep, desc) + var sl reflect.Value + if err == nil { + sl = reflect.ValueOf(old) // existing slice + } else { + sl = reflect.MakeSlice(typ, 0, 1) + } + sl = reflect.Append(sl, ext) + SetExtension(ep, desc, sl.Interface()) + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + continue + } + + // This is a normal, non-extension field. + name := tok.value + var dst reflect.Value + fi, props, ok := structFieldByName(sprops, name) + if ok { + dst = sv.Field(fi) + } else if oop, ok := sprops.OneofTypes[name]; ok { + // It is a oneof. + props = oop.Prop + nv := reflect.New(oop.Type.Elem()) + dst = nv.Elem().Field(0) + field := sv.Field(oop.Field) + if !field.IsNil() { + return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name) + } + field.Set(nv) + } + if !dst.IsValid() { + return p.errorf("unknown field name %q in %v", name, st) + } + + if dst.Kind() == reflect.Map { + // Consume any colon. + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Construct the map if it doesn't already exist. + if dst.IsNil() { + dst.Set(reflect.MakeMap(dst.Type())) + } + key := reflect.New(dst.Type().Key()).Elem() + val := reflect.New(dst.Type().Elem()).Elem() + + // The map entry should be this sequence of tokens: + // < key : KEY value : VALUE > + // However, implementations may omit key or value, and technically + // we should support them in any order. See b/28924776 for a time + // this went wrong. + + tok := p.next() + var terminator string + switch tok.value { + case "<": + terminator = ">" + case "{": + terminator = "}" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + for { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == terminator { + break + } + switch tok.value { + case "key": + if err := p.consumeToken(":"); err != nil { + return err + } + if err := p.readAny(key, props.MapKeyProp); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + case "value": + if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil { + return err + } + if err := p.readAny(val, props.MapValProp); err != nil { + return err + } + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + default: + p.back() + return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) + } + } + + dst.SetMapIndex(key, val) + continue + } + + // Check that it's not already set if it's not a repeated field. + if !props.Repeated && fieldSet[name] { + return p.errorf("non-repeated field %q was repeated", name) + } + + if err := p.checkForColon(props, dst.Type()); err != nil { + return err + } + + // Parse into the field. + fieldSet[name] = true + if err := p.readAny(dst, props); err != nil { + if _, ok := err.(*RequiredNotSetError); !ok { + return err + } + reqFieldErr = err + } + if props.Required { + reqCount-- + } + + if err := p.consumeOptionalSeparator(); err != nil { + return err + } + + } + + if reqCount > 0 { + return p.missingRequiredFieldError(sv) + } + return reqFieldErr +} + +// consumeExtName consumes extension name or expanded Any type URL and the +// following ']'. It returns the name or URL consumed. +func (p *textParser) consumeExtName() (string, error) { + tok := p.next() + if tok.err != nil { + return "", tok.err + } + + // If extension name or type url is quoted, it's a single token. + if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { + name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) + if err != nil { + return "", err + } + return name, p.consumeToken("]") + } + + // Consume everything up to "]" + var parts []string + for tok.value != "]" { + parts = append(parts, tok.value) + tok = p.next() + if tok.err != nil { + return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) + } + if p.done && tok.value != "]" { + return "", p.errorf("unclosed type_url or extension name") + } + } + return strings.Join(parts, ""), nil +} + +// consumeOptionalSeparator consumes an optional semicolon or comma. +// It is used in readStruct to provide backward compatibility. +func (p *textParser) consumeOptionalSeparator() error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value != ";" && tok.value != "," { + p.back() + } + return nil +} + +func (p *textParser) readAny(v reflect.Value, props *Properties) error { + tok := p.next() + if tok.err != nil { + return tok.err + } + if tok.value == "" { + return p.errorf("unexpected EOF") + } + if len(props.CustomType) > 0 { + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + tc := reflect.TypeOf(new(Marshaler)) + ok := t.Elem().Implements(tc.Elem()) + if ok { + fv := v + flen := fv.Len() + if flen == fv.Cap() { + nav := reflect.MakeSlice(v.Type(), flen, 2*flen+1) + reflect.Copy(nav, fv) + fv.Set(nav) + } + fv.SetLen(flen + 1) + + // Read one. + p.back() + return p.readAny(fv.Index(flen), props) + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + custom := reflect.New(props.ctype.Elem()).Interface().(Unmarshaler) + err := custom.Unmarshal([]byte(tok.unquoted)) + if err != nil { + return p.errorf("%v %v: %v", err, v.Type(), tok.value) + } + v.Set(reflect.ValueOf(custom)) + } else { + custom := reflect.New(reflect.TypeOf(v.Interface())).Interface().(Unmarshaler) + err := custom.Unmarshal([]byte(tok.unquoted)) + if err != nil { + return p.errorf("%v %v: %v", err, v.Type(), tok.value) + } + v.Set(reflect.Indirect(reflect.ValueOf(custom))) + } + return nil + } + if props.StdTime { + fv := v + p.back() + props.StdTime = false + tproto := ×tamp{} + err := p.readAny(reflect.ValueOf(tproto).Elem(), props) + props.StdTime = true + if err != nil { + return err + } + tim, err := timestampFromProto(tproto) + if err != nil { + return err + } + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + if t.Elem().Kind() == reflect.Ptr { + ts := fv.Interface().([]*time.Time) + ts = append(ts, &tim) + fv.Set(reflect.ValueOf(ts)) + return nil + } else { + ts := fv.Interface().([]time.Time) + ts = append(ts, tim) + fv.Set(reflect.ValueOf(ts)) + return nil + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + v.Set(reflect.ValueOf(&tim)) + } else { + v.Set(reflect.Indirect(reflect.ValueOf(&tim))) + } + return nil + } + if props.StdDuration { + fv := v + p.back() + props.StdDuration = false + dproto := &duration{} + err := p.readAny(reflect.ValueOf(dproto).Elem(), props) + props.StdDuration = true + if err != nil { + return err + } + dur, err := durationFromProto(dproto) + if err != nil { + return err + } + if props.Repeated { + t := reflect.TypeOf(v.Interface()) + if t.Kind() == reflect.Slice { + if t.Elem().Kind() == reflect.Ptr { + ds := fv.Interface().([]*time.Duration) + ds = append(ds, &dur) + fv.Set(reflect.ValueOf(ds)) + return nil + } else { + ds := fv.Interface().([]time.Duration) + ds = append(ds, dur) + fv.Set(reflect.ValueOf(ds)) + return nil + } + } + } + if reflect.TypeOf(v.Interface()).Kind() == reflect.Ptr { + v.Set(reflect.ValueOf(&dur)) + } else { + v.Set(reflect.Indirect(reflect.ValueOf(&dur))) + } + return nil + } + switch fv := v; fv.Kind() { + case reflect.Slice: + at := v.Type() + if at.Elem().Kind() == reflect.Uint8 { + // Special case for []byte + if tok.value[0] != '"' && tok.value[0] != '\'' { + // Deliberately written out here, as the error after + // this switch statement would write "invalid []byte: ...", + // which is not as user-friendly. + return p.errorf("invalid string: %v", tok.value) + } + bytes := []byte(tok.unquoted) + fv.Set(reflect.ValueOf(bytes)) + return nil + } + // Repeated field. + if tok.value == "[" { + // Repeated field with list notation, like [1,2,3]. + for { + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + err := p.readAny(fv.Index(fv.Len()-1), props) + if err != nil { + return err + } + ntok := p.next() + if ntok.err != nil { + return ntok.err + } + if ntok.value == "]" { + break + } + if ntok.value != "," { + return p.errorf("Expected ']' or ',' found %q", ntok.value) + } + } + return nil + } + // One value of the repeated field. + p.back() + fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem())) + return p.readAny(fv.Index(fv.Len()-1), props) + case reflect.Bool: + // true/1/t/True or false/f/0/False. + switch tok.value { + case "true", "1", "t", "True": + fv.SetBool(true) + return nil + case "false", "0", "f", "False": + fv.SetBool(false) + return nil + } + case reflect.Float32, reflect.Float64: + v := tok.value + // Ignore 'f' for compatibility with output generated by C++, but don't + // remove 'f' when the value is "-inf" or "inf". + if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" { + v = v[:len(v)-1] + } + if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil { + fv.SetFloat(f) + return nil + } + case reflect.Int8: + if x, err := strconv.ParseInt(tok.value, 0, 8); err == nil { + fv.SetInt(x) + return nil + } + case reflect.Int16: + if x, err := strconv.ParseInt(tok.value, 0, 16); err == nil { + fv.SetInt(x) + return nil + } + case reflect.Int32: + if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { + fv.SetInt(x) + return nil + } + + if len(props.Enum) == 0 { + break + } + m, ok := enumValueMaps[props.Enum] + if !ok { + break + } + x, ok := m[tok.value] + if !ok { + break + } + fv.SetInt(int64(x)) + return nil + case reflect.Int64: + if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { + fv.SetInt(x) + return nil + } + + case reflect.Ptr: + // A basic field (indirected through pointer), or a repeated message/group + p.back() + fv.Set(reflect.New(fv.Type().Elem())) + return p.readAny(fv.Elem(), props) + case reflect.String: + if tok.value[0] == '"' || tok.value[0] == '\'' { + fv.SetString(tok.unquoted) + return nil + } + case reflect.Struct: + var terminator string + switch tok.value { + case "{": + terminator = "}" + case "<": + terminator = ">" + default: + return p.errorf("expected '{' or '<', found %q", tok.value) + } + // TODO: Handle nested messages which implement encoding.TextUnmarshaler. + return p.readStruct(fv, terminator) + case reflect.Uint8: + if x, err := strconv.ParseUint(tok.value, 0, 8); err == nil { + fv.SetUint(x) + return nil + } + case reflect.Uint16: + if x, err := strconv.ParseUint(tok.value, 0, 16); err == nil { + fv.SetUint(x) + return nil + } + case reflect.Uint32: + if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { + fv.SetUint(uint64(x)) + return nil + } + case reflect.Uint64: + if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { + fv.SetUint(x) + return nil + } + } + return p.errorf("invalid %v: %v", v.Type(), tok.value) +} + +// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb +// before starting to unmarshal, so any existing data in pb is always removed. +// If a required field is not set and no other error occurs, +// UnmarshalText returns *RequiredNotSetError. +func UnmarshalText(s string, pb Message) error { + if um, ok := pb.(encoding.TextUnmarshaler); ok { + return um.UnmarshalText([]byte(s)) + } + pb.Reset() + v := reflect.ValueOf(pb) + return newTextParser(s).readStruct(v.Elem(), "") +} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp.go b/vendor/github.com/gogo/protobuf/proto/timestamp.go new file mode 100644 index 0000000000..9324f6542b --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/timestamp.go @@ -0,0 +1,113 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +// This file implements operations on google.protobuf.Timestamp. + +import ( + "errors" + "fmt" + "time" +) + +const ( + // Seconds field of the earliest valid Timestamp. + // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + minValidSeconds = -62135596800 + // Seconds field just after the latest valid Timestamp. + // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). + maxValidSeconds = 253402300800 +) + +// validateTimestamp determines whether a Timestamp is valid. +// A valid timestamp represents a time in the range +// [0001-01-01, 10000-01-01) and has a Nanos field +// in the range [0, 1e9). +// +// If the Timestamp is valid, validateTimestamp returns nil. +// Otherwise, it returns an error that describes +// the problem. +// +// Every valid Timestamp can be represented by a time.Time, but the converse is not true. +func validateTimestamp(ts *timestamp) error { + if ts == nil { + return errors.New("timestamp: nil Timestamp") + } + if ts.Seconds < minValidSeconds { + return fmt.Errorf("timestamp: %#v before 0001-01-01", ts) + } + if ts.Seconds >= maxValidSeconds { + return fmt.Errorf("timestamp: %#v after 10000-01-01", ts) + } + if ts.Nanos < 0 || ts.Nanos >= 1e9 { + return fmt.Errorf("timestamp: %#v: nanos not in range [0, 1e9)", ts) + } + return nil +} + +// TimestampFromProto converts a google.protobuf.Timestamp proto to a time.Time. +// It returns an error if the argument is invalid. +// +// Unlike most Go functions, if Timestamp returns an error, the first return value +// is not the zero time.Time. Instead, it is the value obtained from the +// time.Unix function when passed the contents of the Timestamp, in the UTC +// locale. This may or may not be a meaningful time; many invalid Timestamps +// do map to valid time.Times. +// +// A nil Timestamp returns an error. The first return value in that case is +// undefined. +func timestampFromProto(ts *timestamp) (time.Time, error) { + // Don't return the zero value on error, because corresponds to a valid + // timestamp. Instead return whatever time.Unix gives us. + var t time.Time + if ts == nil { + t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp + } else { + t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() + } + return t, validateTimestamp(ts) +} + +// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. +// It returns an error if the resulting Timestamp is invalid. +func timestampProto(t time.Time) (*timestamp, error) { + seconds := t.Unix() + nanos := int32(t.Sub(time.Unix(seconds, 0))) + ts := ×tamp{ + Seconds: seconds, + Nanos: nanos, + } + if err := validateTimestamp(ts); err != nil { + return nil, err + } + return ts, nil +} diff --git a/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go b/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go new file mode 100644 index 0000000000..38439fa990 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/timestamp_gogo.go @@ -0,0 +1,49 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2016, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "reflect" + "time" +) + +var timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + +type timestamp struct { + Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` + Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` +} + +func (m *timestamp) Reset() { *m = timestamp{} } +func (*timestamp) ProtoMessage() {} +func (*timestamp) String() string { return "timestamp" } + +func init() { + RegisterType((*timestamp)(nil), "gogo.protobuf.proto.timestamp") +} diff --git a/vendor/github.com/gogo/protobuf/proto/wrappers.go b/vendor/github.com/gogo/protobuf/proto/wrappers.go new file mode 100644 index 0000000000..b175d1b642 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/wrappers.go @@ -0,0 +1,1888 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "io" + "reflect" +) + +func makeStdDoubleValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*float64) + v := &float64Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*float64) + v := &float64Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdDoubleValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float64) + v := &float64Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float64) + v := &float64Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdDoubleValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(float64) + v := &float64Value{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(float64) + v := &float64Value{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdDoubleValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*float64) + v := &float64Value{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*float64) + v := &float64Value{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdDoubleValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdDoubleValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdDoubleValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdDoubleValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdFloatValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*float32) + v := &float32Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*float32) + v := &float32Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdFloatValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float32) + v := &float32Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*float32) + v := &float32Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdFloatValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(float32) + v := &float32Value{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(float32) + v := &float32Value{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdFloatValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*float32) + v := &float32Value{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*float32) + v := &float32Value{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdFloatValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdFloatValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdFloatValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdFloatValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &float32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdInt64ValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*int64) + v := &int64Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*int64) + v := &int64Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdInt64ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int64) + v := &int64Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int64) + v := &int64Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdInt64ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(int64) + v := &int64Value{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(int64) + v := &int64Value{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdInt64ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*int64) + v := &int64Value{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*int64) + v := &int64Value{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdInt64ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdInt64ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdInt64ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdInt64ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdUInt64ValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*uint64) + v := &uint64Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*uint64) + v := &uint64Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdUInt64ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint64) + v := &uint64Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint64) + v := &uint64Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdUInt64ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(uint64) + v := &uint64Value{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(uint64) + v := &uint64Value{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdUInt64ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*uint64) + v := &uint64Value{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*uint64) + v := &uint64Value{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdUInt64ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdUInt64ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdUInt64ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdUInt64ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint64Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdInt32ValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*int32) + v := &int32Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*int32) + v := &int32Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdInt32ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int32) + v := &int32Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*int32) + v := &int32Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdInt32ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(int32) + v := &int32Value{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(int32) + v := &int32Value{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdInt32ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*int32) + v := &int32Value{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*int32) + v := &int32Value{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdInt32ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdInt32ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdInt32ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdInt32ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &int32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdUInt32ValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*uint32) + v := &uint32Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*uint32) + v := &uint32Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdUInt32ValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint32) + v := &uint32Value{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*uint32) + v := &uint32Value{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdUInt32ValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(uint32) + v := &uint32Value{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(uint32) + v := &uint32Value{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdUInt32ValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*uint32) + v := &uint32Value{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*uint32) + v := &uint32Value{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdUInt32ValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdUInt32ValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdUInt32ValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdUInt32ValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &uint32Value{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdBoolValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*bool) + v := &boolValue{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*bool) + v := &boolValue{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdBoolValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*bool) + v := &boolValue{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*bool) + v := &boolValue{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdBoolValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(bool) + v := &boolValue{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(bool) + v := &boolValue{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdBoolValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*bool) + v := &boolValue{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*bool) + v := &boolValue{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdBoolValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &boolValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdBoolValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &boolValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdBoolValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &boolValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdBoolValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &boolValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdStringValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*string) + v := &stringValue{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*string) + v := &stringValue{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdStringValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*string) + v := &stringValue{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*string) + v := &stringValue{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdStringValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(string) + v := &stringValue{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(string) + v := &stringValue{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdStringValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*string) + v := &stringValue{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*string) + v := &stringValue{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdStringValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &stringValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdStringValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &stringValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdStringValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &stringValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdStringValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &stringValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdBytesValueMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + t := ptr.asPointerTo(u.typ).Interface().(*[]byte) + v := &bytesValue{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + t := ptr.asPointerTo(u.typ).Interface().(*[]byte) + v := &bytesValue{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdBytesValuePtrMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + if ptr.isNil() { + return 0 + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*[]byte) + v := &bytesValue{*t} + siz := Size(v) + return tagsize + SizeVarint(uint64(siz)) + siz + }, func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + if ptr.isNil() { + return b, nil + } + t := ptr.asPointerTo(reflect.PtrTo(u.typ)).Elem().Interface().(*[]byte) + v := &bytesValue{*t} + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(len(buf))) + b = append(b, buf...) + return b, nil + } +} + +func makeStdBytesValueSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(u.typ) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().([]byte) + v := &bytesValue{t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(u.typ) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().([]byte) + v := &bytesValue{t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdBytesValuePtrSliceMarshaler(u *marshalInfo) (sizer, marshaler) { + return func(ptr pointer, tagsize int) int { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + n := 0 + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*[]byte) + v := &bytesValue{*t} + siz := Size(v) + n += siz + SizeVarint(uint64(siz)) + tagsize + } + return n + }, + func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { + s := ptr.getSlice(reflect.PtrTo(u.typ)) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + t := elem.Interface().(*[]byte) + v := &bytesValue{*t} + siz := Size(v) + buf, err := Marshal(v) + if err != nil { + return nil, err + } + b = appendVarint(b, wiretag) + b = appendVarint(b, uint64(siz)) + b = append(b, buf...) + } + + return b, nil + } +} + +func makeStdBytesValueUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &bytesValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(sub.typ).Elem() + s.Set(reflect.ValueOf(m.Value)) + return b[x:], nil + } +} + +func makeStdBytesValuePtrUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &bytesValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + s := f.asPointerTo(reflect.PtrTo(sub.typ)).Elem() + s.Set(reflect.ValueOf(&m.Value)) + return b[x:], nil + } +} + +func makeStdBytesValuePtrSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &bytesValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(reflect.PtrTo(sub.typ)) + newSlice := reflect.Append(slice, reflect.ValueOf(&m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} + +func makeStdBytesValueSliceUnmarshaler(sub *unmarshalInfo, name string) unmarshaler { + return func(b []byte, f pointer, w int) ([]byte, error) { + if w != WireBytes { + return nil, errInternalBadWireType + } + x, n := decodeVarint(b) + if n == 0 { + return nil, io.ErrUnexpectedEOF + } + b = b[n:] + if x > uint64(len(b)) { + return nil, io.ErrUnexpectedEOF + } + m := &bytesValue{} + if err := Unmarshal(b[:x], m); err != nil { + return nil, err + } + slice := f.getSlice(sub.typ) + newSlice := reflect.Append(slice, reflect.ValueOf(m.Value)) + slice.Set(newSlice) + return b[x:], nil + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go b/vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go new file mode 100644 index 0000000000..c1cf7bf85e --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/wrappers_gogo.go @@ -0,0 +1,113 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2018, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +type float64Value struct { + Value float64 `protobuf:"fixed64,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *float64Value) Reset() { *m = float64Value{} } +func (*float64Value) ProtoMessage() {} +func (*float64Value) String() string { return "float64" } + +type float32Value struct { + Value float32 `protobuf:"fixed32,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *float32Value) Reset() { *m = float32Value{} } +func (*float32Value) ProtoMessage() {} +func (*float32Value) String() string { return "float32" } + +type int64Value struct { + Value int64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *int64Value) Reset() { *m = int64Value{} } +func (*int64Value) ProtoMessage() {} +func (*int64Value) String() string { return "int64" } + +type uint64Value struct { + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *uint64Value) Reset() { *m = uint64Value{} } +func (*uint64Value) ProtoMessage() {} +func (*uint64Value) String() string { return "uint64" } + +type int32Value struct { + Value int32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *int32Value) Reset() { *m = int32Value{} } +func (*int32Value) ProtoMessage() {} +func (*int32Value) String() string { return "int32" } + +type uint32Value struct { + Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *uint32Value) Reset() { *m = uint32Value{} } +func (*uint32Value) ProtoMessage() {} +func (*uint32Value) String() string { return "uint32" } + +type boolValue struct { + Value bool `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *boolValue) Reset() { *m = boolValue{} } +func (*boolValue) ProtoMessage() {} +func (*boolValue) String() string { return "bool" } + +type stringValue struct { + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *stringValue) Reset() { *m = stringValue{} } +func (*stringValue) ProtoMessage() {} +func (*stringValue) String() string { return "string" } + +type bytesValue struct { + Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *bytesValue) Reset() { *m = bytesValue{} } +func (*bytesValue) ProtoMessage() {} +func (*bytesValue) String() string { return "[]byte" } + +func init() { + RegisterType((*float64Value)(nil), "gogo.protobuf.proto.DoubleValue") + RegisterType((*float32Value)(nil), "gogo.protobuf.proto.FloatValue") + RegisterType((*int64Value)(nil), "gogo.protobuf.proto.Int64Value") + RegisterType((*uint64Value)(nil), "gogo.protobuf.proto.UInt64Value") + RegisterType((*int32Value)(nil), "gogo.protobuf.proto.Int32Value") + RegisterType((*uint32Value)(nil), "gogo.protobuf.proto.UInt32Value") + RegisterType((*boolValue)(nil), "gogo.protobuf.proto.BoolValue") + RegisterType((*stringValue)(nil), "gogo.protobuf.proto.StringValue") + RegisterType((*bytesValue)(nil), "gogo.protobuf.proto.BytesValue") +} diff --git a/vendor/github.com/ipfs/bbloom/.travis.yml b/vendor/github.com/ipfs/bbloom/.travis.yml new file mode 100644 index 0000000000..4cfe98c242 --- /dev/null +++ b/vendor/github.com/ipfs/bbloom/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/bbloom/README.md b/vendor/github.com/ipfs/bbloom/README.md new file mode 100644 index 0000000000..46e5ec75eb --- /dev/null +++ b/vendor/github.com/ipfs/bbloom/README.md @@ -0,0 +1,129 @@ +## bbloom: a bitset Bloom filter for go/golang +=== + +package implements a fast bloom filter with real 'bitset' and JSONMarshal/JSONUnmarshal to store/reload the Bloom filter. + +NOTE: the package uses unsafe.Pointer to set and read the bits from the bitset. If you're uncomfortable with using the unsafe package, please consider using my bloom filter package at github.com/AndreasBriese/bloom + +=== + +changelog 11/2015: new thread safe methods AddTS(), HasTS(), AddIfNotHasTS() following a suggestion from Srdjan Marinovic (github @a-little-srdjan), who used this to code a bloomfilter cache. + +This bloom filter was developed to strengthen a website-log database and was tested and optimized for this log-entry mask: "2014/%02i/%02i %02i:%02i:%02i /info.html". +Nonetheless bbloom should work with any other form of entries. + +~~Hash function is a modified Berkeley DB sdbm hash (to optimize for smaller strings). sdbm http://www.cse.yorku.ca/~oz/hash.html~~ + +Found sipHash (SipHash-2-4, a fast short-input PRF created by Jean-Philippe Aumasson and Daniel J. Bernstein.) to be about as fast. sipHash had been ported by Dimtry Chestnyk to Go (github.com/dchest/siphash ) + +Minimum hashset size is: 512 ([4]uint64; will be set automatically). + +###install + +```sh +go get github.com/AndreasBriese/bbloom +``` + +###test ++ change to folder ../bbloom ++ create wordlist in file "words.txt" (you might use `python permut.py`) ++ run 'go test -bench=.' within the folder + +```go +go test -bench=. +``` + +~~If you've installed the GOCONVEY TDD-framework http://goconvey.co/ you can run the tests automatically.~~ + +using go's testing framework now (have in mind that the op timing is related to 65536 operations of Add, Has, AddIfNotHas respectively) + +### usage + +after installation add + +```go +import ( + ... + "github.com/AndreasBriese/bbloom" + ... + ) +``` + +at your header. In the program use + +```go +// create a bloom filter for 65536 items and 1 % wrong-positive ratio +bf := bbloom.New(float64(1<<16), float64(0.01)) + +// or +// create a bloom filter with 650000 for 65536 items and 7 locs per hash explicitly +// bf = bbloom.New(float64(650000), float64(7)) +// or +bf = bbloom.New(650000.0, 7.0) + +// add one item +bf.Add([]byte("butter")) + +// Number of elements added is exposed now +// Note: ElemNum will not be included in JSON export (for compatability to older version) +nOfElementsInFilter := bf.ElemNum + +// check if item is in the filter +isIn := bf.Has([]byte("butter")) // should be true +isNotIn := bf.Has([]byte("Butter")) // should be false + +// 'add only if item is new' to the bloomfilter +added := bf.AddIfNotHas([]byte("butter")) // should be false because 'butter' is already in the set +added = bf.AddIfNotHas([]byte("buTTer")) // should be true because 'buTTer' is new + +// thread safe versions for concurrent use: AddTS, HasTS, AddIfNotHasTS +// add one item +bf.AddTS([]byte("peanutbutter")) +// check if item is in the filter +isIn = bf.HasTS([]byte("peanutbutter")) // should be true +isNotIn = bf.HasTS([]byte("peanutButter")) // should be false +// 'add only if item is new' to the bloomfilter +added = bf.AddIfNotHasTS([]byte("butter")) // should be false because 'peanutbutter' is already in the set +added = bf.AddIfNotHasTS([]byte("peanutbuTTer")) // should be true because 'penutbuTTer' is new + +// convert to JSON ([]byte) +Json := bf.JSONMarshal() + +// bloomfilters Mutex is exposed for external un-/locking +// i.e. mutex lock while doing JSON conversion +bf.Mtx.Lock() +Json = bf.JSONMarshal() +bf.Mtx.Unlock() + +// restore a bloom filter from storage +bfNew, _ := bbloom.JSONUnmarshal(Json) + +isInNew := bfNew.Has([]byte("butter")) // should be true +isNotInNew := bfNew.Has([]byte("Butter")) // should be false + +``` + +to work with the bloom filter. + +### why 'fast'? + +It's about 3 times faster than William Fitzgeralds bitset bloom filter https://github.com/willf/bloom . And it is about so fast as my []bool set variant for Boom filters (see https://github.com/AndreasBriese/bloom ) but having a 8times smaller memory footprint: + + + Bloom filter (filter size 524288, 7 hashlocs) + github.com/AndreasBriese/bbloom 'Add' 65536 items (10 repetitions): 6595800 ns (100 ns/op) + github.com/AndreasBriese/bbloom 'Has' 65536 items (10 repetitions): 5986600 ns (91 ns/op) + github.com/AndreasBriese/bloom 'Add' 65536 items (10 repetitions): 6304684 ns (96 ns/op) + github.com/AndreasBriese/bloom 'Has' 65536 items (10 repetitions): 6568663 ns (100 ns/op) + + github.com/willf/bloom 'Add' 65536 items (10 repetitions): 24367224 ns (371 ns/op) + github.com/willf/bloom 'Test' 65536 items (10 repetitions): 21881142 ns (333 ns/op) + github.com/dataence/bloom/standard 'Add' 65536 items (10 repetitions): 23041644 ns (351 ns/op) + github.com/dataence/bloom/standard 'Check' 65536 items (10 repetitions): 19153133 ns (292 ns/op) + github.com/cabello/bloom 'Add' 65536 items (10 repetitions): 131921507 ns (2012 ns/op) + github.com/cabello/bloom 'Contains' 65536 items (10 repetitions): 131108962 ns (2000 ns/op) + +(on MBPro15 OSX10.8.5 i7 4Core 2.4Ghz) + + +With 32bit bloom filters (bloom32) using modified sdbm, bloom32 does hashing with only 2 bit shifts, one xor and one substraction per byte. smdb is about as fast as fnv64a but gives less collisions with the dataset (see mask above). bloom.New(float64(10 * 1<<16),float64(7)) populated with 1<<16 random items from the dataset (see above) and tested against the rest results in less than 0.05% collisions. diff --git a/vendor/github.com/ipfs/bbloom/bbloom.go b/vendor/github.com/ipfs/bbloom/bbloom.go new file mode 100644 index 0000000000..36f12e0dea --- /dev/null +++ b/vendor/github.com/ipfs/bbloom/bbloom.go @@ -0,0 +1,326 @@ +// The MIT License (MIT) +// Copyright (c) 2014 Andreas Briese, eduToolbox@Bri-C GmbH, Sarstedt + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package bbloom + +import ( + "encoding/binary" + "encoding/json" + "errors" + "log" + "math" + "math/bits" + "sync" +) + +func getSize(ui64 uint64) (size uint64, exponent uint64) { + if ui64 < uint64(512) { + ui64 = uint64(512) + } + size = uint64(1) + for size < ui64 { + size <<= 1 + exponent++ + } + return size, exponent +} + +func calcSizeByWrongPositives(numEntries, wrongs float64) (uint64, uint64) { + size := -1 * numEntries * math.Log(wrongs) / math.Pow(float64(0.69314718056), 2) + locs := math.Ceil(float64(0.69314718056) * size / numEntries) + return uint64(size), uint64(locs) +} + +var ErrUsage = errors.New("usage: New(float64(number_of_entries), float64(number_of_hashlocations)) i.e. New(float64(1000), float64(3)) or New(float64(number_of_entries), float64(ratio_of_false_positives)) i.e. New(float64(1000), float64(0.03))") +var ErrInvalidParms = errors.New("One of parameters was outside of allowed range") + +// New +// returns a new bloomfilter +func New(params ...float64) (bloomfilter *Bloom, err error) { + var entries, locs uint64 + if len(params) == 2 { + if params[0] < 0 || params[1] < 0 { + return nil, ErrInvalidParms + } + if params[1] < 1 { + entries, locs = calcSizeByWrongPositives(math.Max(params[0], 1), params[1]) + } else { + entries, locs = uint64(params[0]), uint64(params[1]) + } + } else { + return nil, ErrUsage + } + size, exponent := getSize(uint64(entries)) + bloomfilter = &Bloom{ + sizeExp: exponent, + size: size - 1, + setLocs: locs, + shift: 64 - exponent, + bitset: make([]uint64, size>>6), + } + return bloomfilter, nil +} + +// NewWithBoolset +// takes a []byte slice and number of locs per entry +// returns the bloomfilter with a bitset populated according to the input []byte +func NewWithBoolset(bs []byte, locs uint64) (bloomfilter *Bloom) { + bloomfilter, err := New(float64(len(bs)<<3), float64(locs)) + if err != nil { + panic(err) // Should never happen + } + for i := range bloomfilter.bitset { + bloomfilter.bitset[i] = binary.BigEndian.Uint64((bs)[i<<3:]) + } + return bloomfilter +} + +// bloomJSONImExport +// Im/Export structure used by JSONMarshal / JSONUnmarshal +type bloomJSONImExport struct { + FilterSet []byte + SetLocs uint64 +} + +// +// Bloom filter +type Bloom struct { + Mtx sync.RWMutex + bitset []uint64 + sizeExp uint64 + size uint64 + setLocs uint64 + shift uint64 + + content uint64 +} + +// ElementsAdded returns the number of elements added to the bloom filter. +func (bl *Bloom) ElementsAdded() uint64 { + return bl.content +} + +// <--- http://www.cse.yorku.ca/~oz/hash.html +// modified Berkeley DB Hash (32bit) +// hash is casted to l, h = 16bit fragments +// func (bl Bloom) absdbm(b *[]byte) (l, h uint64) { +// hash := uint64(len(*b)) +// for _, c := range *b { +// hash = uint64(c) + (hash << 6) + (hash << bl.sizeExp) - hash +// } +// h = hash >> bl.shift +// l = hash << bl.shift >> bl.shift +// return l, h +// } + +// Update: found sipHash of Jean-Philippe Aumasson & Daniel J. Bernstein to be even faster than absdbm() +// https://131002.net/siphash/ +// siphash was implemented for Go by Dmitry Chestnykh https://github.com/dchest/siphash + +// Add +// set the bit(s) for entry; Adds an entry to the Bloom filter +func (bl *Bloom) Add(entry []byte) { + bl.content++ + l, h := bl.sipHash(entry) + for i := uint64(0); i < (*bl).setLocs; i++ { + bl.set((h + i*l) & (*bl).size) + } +} + +// AddTS +// Thread safe: Mutex.Lock the bloomfilter for the time of processing the entry +func (bl *Bloom) AddTS(entry []byte) { + bl.Mtx.Lock() + bl.Add(entry) + bl.Mtx.Unlock() +} + +// Has +// check if bit(s) for entry is/are set +// returns true if the entry was added to the Bloom Filter +func (bl *Bloom) Has(entry []byte) bool { + l, h := bl.sipHash(entry) + res := true + for i := uint64(0); i < bl.setLocs; i++ { + res = res && bl.isSet((h+i*l)&bl.size) + // Branching here (early escape) is not worth it + // This is my conclusion from benchmarks + // (prevents loop unrolling) + // if !res { + // return false + // } + } + return res +} + +// HasTS +// Thread safe: Mutex.Lock the bloomfilter for the time of processing the entry +func (bl *Bloom) HasTS(entry []byte) bool { + bl.Mtx.RLock() + has := bl.Has(entry[:]) + bl.Mtx.RUnlock() + return has +} + +// AddIfNotHas +// Only Add entry if it's not present in the bloomfilter +// returns true if entry was added +// returns false if entry was allready registered in the bloomfilter +func (bl *Bloom) AddIfNotHas(entry []byte) (added bool) { + l, h := bl.sipHash(entry) + contained := true + for i := uint64(0); i < bl.setLocs; i++ { + prev := bl.getSet((h + i*l) & bl.size) + contained = contained && prev + } + if !contained { + bl.content++ + } + return !contained +} + +// AddIfNotHasTS +// Tread safe: Only Add entry if it's not present in the bloomfilter +// returns true if entry was added +// returns false if entry was allready registered in the bloomfilter +func (bl *Bloom) AddIfNotHasTS(entry []byte) (added bool) { + bl.Mtx.Lock() + added = bl.AddIfNotHas(entry[:]) + bl.Mtx.Unlock() + return added +} + +// Clear +// resets the Bloom filter +func (bl *Bloom) Clear() { + bs := bl.bitset // important performance optimization. + for i := range bs { + bs[i] = 0 + } + bl.content = 0 +} + +// ClearTS clears the bloom filter (thread safe). +func (bl *Bloom) ClearTS() { + bl.Mtx.Lock() + bl.Clear() + bl.Mtx.Unlock() +} + +func (bl *Bloom) set(idx uint64) { + bl.bitset[idx>>6] |= 1 << (idx % 64) +} + +func (bl *Bloom) getSet(idx uint64) bool { + cur := bl.bitset[idx>>6] + bit := uint64(1 << (idx % 64)) + bl.bitset[idx>>6] = cur | bit + return (cur & bit) > 0 +} + +func (bl *Bloom) isSet(idx uint64) bool { + return bl.bitset[idx>>6]&(1<<(idx%64)) > 0 +} + +func (bl *Bloom) marshal() bloomJSONImExport { + bloomImEx := bloomJSONImExport{} + bloomImEx.SetLocs = uint64(bl.setLocs) + bloomImEx.FilterSet = make([]byte, len(bl.bitset)<<3) + for i, w := range bl.bitset { + binary.BigEndian.PutUint64(bloomImEx.FilterSet[i<<3:], w) + } + return bloomImEx +} + +// JSONMarshal +// returns JSON-object (type bloomJSONImExport) as []byte +func (bl *Bloom) JSONMarshal() []byte { + data, err := json.Marshal(bl.marshal()) + if err != nil { + log.Fatal("json.Marshal failed: ", err) + } + return data +} + +// JSONMarshalTS is a thread-safe version of JSONMarshal +func (bl *Bloom) JSONMarshalTS() []byte { + bl.Mtx.RLock() + export := bl.marshal() + bl.Mtx.RUnlock() + data, err := json.Marshal(export) + if err != nil { + log.Fatal("json.Marshal failed: ", err) + } + return data +} + +// JSONUnmarshal +// takes JSON-Object (type bloomJSONImExport) as []bytes +// returns bloom32 / bloom64 object +func JSONUnmarshal(dbData []byte) (*Bloom, error) { + bloomImEx := bloomJSONImExport{} + err := json.Unmarshal(dbData, &bloomImEx) + if err != nil { + return nil, err + } + bf := NewWithBoolset(bloomImEx.FilterSet, bloomImEx.SetLocs) + return bf, nil +} + +// FillRatio returns the fraction of bits set. +func (bl *Bloom) FillRatio() float64 { + count := uint64(0) + for _, b := range bl.bitset { + count += uint64(bits.OnesCount64(b)) + } + return float64(count) / float64(bl.size+1) +} + +// FillRatioTS is a thread-save version of FillRatio +func (bl *Bloom) FillRatioTS() float64 { + bl.Mtx.RLock() + fr := bl.FillRatio() + bl.Mtx.RUnlock() + return fr +} + +// // alternative hashFn +// func (bl Bloom) fnv64a(b *[]byte) (l, h uint64) { +// h64 := fnv.New64a() +// h64.Write(*b) +// hash := h64.Sum64() +// h = hash >> 32 +// l = hash << 32 >> 32 +// return l, h +// } +// +// // <-- http://partow.net/programming/hashfunctions/index.html +// // citation: An algorithm proposed by Donald E. Knuth in The Art Of Computer Programming Volume 3, +// // under the topic of sorting and search chapter 6.4. +// // modified to fit with boolset-length +// func (bl Bloom) DEKHash(b *[]byte) (l, h uint64) { +// hash := uint64(len(*b)) +// for _, c := range *b { +// hash = ((hash << 5) ^ (hash >> bl.shift)) ^ uint64(c) +// } +// h = hash >> bl.shift +// l = hash << bl.sizeExp >> bl.sizeExp +// return l, h +// } diff --git a/vendor/github.com/ipfs/bbloom/go.mod b/vendor/github.com/ipfs/bbloom/go.mod new file mode 100644 index 0000000000..d215f4f103 --- /dev/null +++ b/vendor/github.com/ipfs/bbloom/go.mod @@ -0,0 +1,3 @@ +module github.com/ipfs/bbloom + +go 1.12 diff --git a/vendor/github.com/ipfs/bbloom/package.json b/vendor/github.com/ipfs/bbloom/package.json new file mode 100644 index 0000000000..3d42cf9c85 --- /dev/null +++ b/vendor/github.com/ipfs/bbloom/package.json @@ -0,0 +1,15 @@ +{ + "author": "AndreasBriese", + "bugs": { + "url": "https://github.com/ipfs/bbloom" + }, + "gx": { + "dvcsimport": "github.com/ipfs/bbloom" + }, + "gxVersion": "0.7.0", + "language": "go", + "license": "MIT", + "name": "bbloom", + "version": "0.1.2" +} + diff --git a/vendor/github.com/ipfs/bbloom/sipHash.go b/vendor/github.com/ipfs/bbloom/sipHash.go new file mode 100644 index 0000000000..4f2755ca9e --- /dev/null +++ b/vendor/github.com/ipfs/bbloom/sipHash.go @@ -0,0 +1,225 @@ +// Written in 2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ +// +// Package siphash implements SipHash-2-4, a fast short-input PRF +// created by Jean-Philippe Aumasson and Daniel J. Bernstein. + +package bbloom + +// Hash returns the 64-bit SipHash-2-4 of the given byte slice with two 64-bit +// parts of 128-bit key: k0 and k1. +func (bl *Bloom) sipHash(p []byte) (l, h uint64) { + // Initialization. + v0 := uint64(8317987320269560794) // k0 ^ 0x736f6d6570736575 + v1 := uint64(7237128889637516672) // k1 ^ 0x646f72616e646f6d + v2 := uint64(7816392314733513934) // k0 ^ 0x6c7967656e657261 + v3 := uint64(8387220255325274014) // k1 ^ 0x7465646279746573 + t := uint64(len(p)) << 56 + + // Compression. + for len(p) >= 8 { + + m := uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | + uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 + + v3 ^= m + + // Round 1. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + // Round 2. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + v0 ^= m + p = p[8:] + } + + // Compress last block. + switch len(p) { + case 7: + t |= uint64(p[6]) << 48 + fallthrough + case 6: + t |= uint64(p[5]) << 40 + fallthrough + case 5: + t |= uint64(p[4]) << 32 + fallthrough + case 4: + t |= uint64(p[3]) << 24 + fallthrough + case 3: + t |= uint64(p[2]) << 16 + fallthrough + case 2: + t |= uint64(p[1]) << 8 + fallthrough + case 1: + t |= uint64(p[0]) + } + + v3 ^= t + + // Round 1. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + // Round 2. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + v0 ^= t + + // Finalization. + v2 ^= 0xff + + // Round 1. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + // Round 2. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + // Round 3. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + // Round 4. + v0 += v1 + v1 = v1<<13 | v1>>51 + v1 ^= v0 + v0 = v0<<32 | v0>>32 + + v2 += v3 + v3 = v3<<16 | v3>>48 + v3 ^= v2 + + v0 += v3 + v3 = v3<<21 | v3>>43 + v3 ^= v0 + + v2 += v1 + v1 = v1<<17 | v1>>47 + v1 ^= v2 + v2 = v2<<32 | v2>>32 + + // return v0 ^ v1 ^ v2 ^ v3 + + hash := v0 ^ v1 ^ v2 ^ v3 + h = hash >> bl.shift + l = hash << bl.shift >> bl.shift + return l, h + +} diff --git a/vendor/github.com/ipfs/bbloom/words.txt b/vendor/github.com/ipfs/bbloom/words.txt new file mode 100644 index 0000000000..ad86a31ac5 --- /dev/null +++ b/vendor/github.com/ipfs/bbloom/words.txt @@ -0,0 +1,140 @@ +2014/01/01 00:00:00 /info.html +2014/01/01 00:00:00 /info.html +2014/01/01 00:00:01 /info.html +2014/01/01 00:00:02 /info.html +2014/01/01 00:00:03 /info.html +2014/01/01 00:00:04 /info.html +2014/01/01 00:00:05 /info.html +2014/01/01 00:00:06 /info.html +2014/01/01 00:00:07 /info.html +2014/01/01 00:00:08 /info.html +2014/01/01 00:00:09 /info.html +2014/01/01 00:00:10 /info.html +2014/01/01 00:00:11 /info.html +2014/01/01 00:00:12 /info.html +2014/01/01 00:00:13 /info.html +2014/01/01 00:00:14 /info.html +2014/01/01 00:00:15 /info.html +2014/01/01 00:00:16 /info.html +2014/01/01 00:00:17 /info.html +2014/01/01 00:00:18 /info.html +2014/01/01 00:00:19 /info.html +2014/01/01 00:00:20 /info.html +2014/01/01 00:00:21 /info.html +2014/01/01 00:00:22 /info.html +2014/01/01 00:00:23 /info.html +2014/01/01 00:00:24 /info.html +2014/01/01 00:00:25 /info.html +2014/01/01 00:00:26 /info.html +2014/01/01 00:00:27 /info.html +2014/01/01 00:00:28 /info.html +2014/01/01 00:00:29 /info.html +2014/01/01 00:00:30 /info.html +2014/01/01 00:00:31 /info.html +2014/01/01 00:00:32 /info.html +2014/01/01 00:00:33 /info.html +2014/01/01 00:00:34 /info.html +2014/01/01 00:00:35 /info.html +2014/01/01 00:00:36 /info.html +2014/01/01 00:00:37 /info.html +2014/01/01 00:00:38 /info.html +2014/01/01 00:00:39 /info.html +2014/01/01 00:00:40 /info.html +2014/01/01 00:00:41 /info.html +2014/01/01 00:00:42 /info.html +2014/01/01 00:00:43 /info.html +2014/01/01 00:00:44 /info.html +2014/01/01 00:00:45 /info.html +2014/01/01 00:00:46 /info.html +2014/01/01 00:00:47 /info.html +2014/01/01 00:00:48 /info.html +2014/01/01 00:00:49 /info.html +2014/01/01 00:00:50 /info.html +2014/01/01 00:00:51 /info.html +2014/01/01 00:00:52 /info.html +2014/01/01 00:00:53 /info.html +2014/01/01 00:00:54 /info.html +2014/01/01 00:00:55 /info.html +2014/01/01 00:00:56 /info.html +2014/01/01 00:00:57 /info.html +2014/01/01 00:00:58 /info.html +2014/01/01 00:00:59 /info.html +2014/01/01 00:01:00 /info.html +2014/01/01 00:01:01 /info.html +2014/01/01 00:01:02 /info.html +2014/01/01 00:01:03 /info.html +2014/01/01 00:01:04 /info.html +2014/01/01 00:01:05 /info.html +2014/01/01 00:01:06 /info.html +2014/01/01 00:01:07 /info.html +2014/01/01 00:01:08 /info.html +2014/01/01 00:01:09 /info.html +2014/01/01 00:01:10 /info.html +2014/01/01 00:01:11 /info.html +2014/01/01 00:01:12 /info.html +2014/01/01 00:01:13 /info.html +2014/01/01 00:01:14 /info.html +2014/01/01 00:01:15 /info.html +2014/01/01 00:01:16 /info.html +2014/01/01 00:01:17 /info.html +2014/01/01 00:01:18 /info.html +2014/01/01 00:01:19 /info.html +2014/01/01 00:01:20 /info.html +2014/01/01 00:01:21 /info.html +2014/01/01 00:01:22 /info.html +2014/01/01 00:01:23 /info.html +2014/01/01 00:01:24 /info.html +2014/01/01 00:01:25 /info.html +2014/01/01 00:01:26 /info.html +2014/01/01 00:01:27 /info.html +2014/01/01 00:01:28 /info.html +2014/01/01 00:01:29 /info.html +2014/01/01 00:01:30 /info.html +2014/01/01 00:01:31 /info.html +2014/01/01 00:01:32 /info.html +2014/01/01 00:01:33 /info.html +2014/01/01 00:01:34 /info.html +2014/01/01 00:01:35 /info.html +2014/01/01 00:01:36 /info.html +2014/01/01 00:01:37 /info.html +2014/01/01 00:01:38 /info.html +2014/01/01 00:01:39 /info.html +2014/01/01 00:01:40 /info.html +2014/01/01 00:01:41 /info.html +2014/01/01 00:01:42 /info.html +2014/01/01 00:01:43 /info.html +2014/01/01 00:01:44 /info.html +2014/01/01 00:01:45 /info.html +2014/01/01 00:01:46 /info.html +2014/01/01 00:01:47 /info.html +2014/01/01 00:01:48 /info.html +2014/01/01 00:01:49 /info.html +2014/01/01 00:01:50 /info.html +2014/01/01 00:01:51 /info.html +2014/01/01 00:01:52 /info.html +2014/01/01 00:01:53 /info.html +2014/01/01 00:01:54 /info.html +2014/01/01 00:01:55 /info.html +2014/01/01 00:01:56 /info.html +2014/01/01 00:01:57 /info.html +2014/01/01 00:01:58 /info.html +2014/01/01 00:01:59 /info.html +2014/01/01 00:02:00 /info.html +2014/01/01 00:02:01 /info.html +2014/01/01 00:02:02 /info.html +2014/01/01 00:02:03 /info.html +2014/01/01 00:02:04 /info.html +2014/01/01 00:02:05 /info.html +2014/01/01 00:02:06 /info.html +2014/01/01 00:02:07 /info.html +2014/01/01 00:02:08 /info.html +2014/01/01 00:02:09 /info.html +2014/01/01 00:02:10 /info.html +2014/01/01 00:02:11 /info.html +2014/01/01 00:02:12 /info.html +2014/01/01 00:02:13 /info.html +2014/01/01 00:02:14 /info.html +2014/01/01 00:02:15 /info.html +2014/01/01 00:02:16 /info.html +2014/01/01 00:02:17 /info.html +2014/01/01 00:02:18 /info.html diff --git a/vendor/github.com/ipfs/go-block-format/.travis.yml b/vendor/github.com/ipfs/go-block-format/.travis.yml new file mode 100644 index 0000000000..4cfe98c242 --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-block-format/LICENSE b/vendor/github.com/ipfs/go-block-format/LICENSE new file mode 100644 index 0000000000..8001ebee6a --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2017 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-block-format/Makefile b/vendor/github.com/ipfs/go-block-format/Makefile new file mode 100644 index 0000000000..7811c099ea --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/Makefile @@ -0,0 +1,15 @@ +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go + +covertools: + go get github.com/mattn/goveralls + go get golang.org/x/tools/cmd/cover + +deps: gx covertools + gx --verbose install --global + gx-go rewrite + +publish: + gx-go rewrite --undo + diff --git a/vendor/github.com/ipfs/go-block-format/README.md b/vendor/github.com/ipfs/go-block-format/README.md new file mode 100644 index 0000000000..67cd1fcd1a --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/README.md @@ -0,0 +1,35 @@ +go-block-format +================== + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![Coverage Status](https://codecov.io/gh/ipfs/go-block-format/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-block-format/branch/master) +[![Travis CI](https://travis-ci.org/ipfs/go-block-format.svg?branch=master)](https://travis-ci.org/ipfs/go-block-format) + +> go-block-format is a set of interfaces that a type needs to implement in order to be a CID addressable block of data. + + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [API](#api) +- [Contribute](#contribute) +- [License](#license) + +## Install + +```sh +make install +``` + +## Contribute + +PRs are welcome! + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Juan Batiz-Benet diff --git a/vendor/github.com/ipfs/go-block-format/blocks.go b/vendor/github.com/ipfs/go-block-format/blocks.go new file mode 100644 index 0000000000..3d3894b3f3 --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/blocks.go @@ -0,0 +1,82 @@ +// Package blocks contains the lowest level of IPLD data structures. +// A block is raw data accompanied by a CID. The CID contains the multihash +// corresponding to the block. +package blocks + +import ( + "errors" + "fmt" + + cid "github.com/ipfs/go-cid" + u "github.com/ipfs/go-ipfs-util" + mh "github.com/multiformats/go-multihash" +) + +// ErrWrongHash is returned when the Cid of a block is not the expected +// according to the contents. It is currently used only when debugging. +var ErrWrongHash = errors.New("data did not match given hash") + +// Block provides abstraction for blocks implementations. +type Block interface { + RawData() []byte + Cid() cid.Cid + String() string + Loggable() map[string]interface{} +} + +// A BasicBlock is a singular block of data in ipfs. It implements the Block +// interface. +type BasicBlock struct { + cid cid.Cid + data []byte +} + +// NewBlock creates a Block object from opaque data. It will hash the data. +func NewBlock(data []byte) *BasicBlock { + // TODO: fix assumptions + return &BasicBlock{data: data, cid: cid.NewCidV0(u.Hash(data))} +} + +// NewBlockWithCid creates a new block when the hash of the data +// is already known, this is used to save time in situations where +// we are able to be confident that the data is correct. +func NewBlockWithCid(data []byte, c cid.Cid) (*BasicBlock, error) { + if u.Debug { + chkc, err := c.Prefix().Sum(data) + if err != nil { + return nil, err + } + + if !chkc.Equals(c) { + return nil, ErrWrongHash + } + } + return &BasicBlock{data: data, cid: c}, nil +} + +// Multihash returns the hash contained in the block CID. +func (b *BasicBlock) Multihash() mh.Multihash { + return b.cid.Hash() +} + +// RawData returns the block raw contents as a byte slice. +func (b *BasicBlock) RawData() []byte { + return b.data +} + +// Cid returns the content identifier of the block. +func (b *BasicBlock) Cid() cid.Cid { + return b.cid +} + +// String provides a human-readable representation of the block CID. +func (b *BasicBlock) String() string { + return fmt.Sprintf("[Block %s]", b.Cid()) +} + +// Loggable returns a go-log loggable item. +func (b *BasicBlock) Loggable() map[string]interface{} { + return map[string]interface{}{ + "block": b.Cid().String(), + } +} diff --git a/vendor/github.com/ipfs/go-block-format/codecov.yml b/vendor/github.com/ipfs/go-block-format/codecov.yml new file mode 100644 index 0000000000..5f88a9ea27 --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/codecov.yml @@ -0,0 +1,3 @@ +coverage: + range: "50...100" +comment: off diff --git a/vendor/github.com/ipfs/go-block-format/go.mod b/vendor/github.com/ipfs/go-block-format/go.mod new file mode 100644 index 0000000000..f6ab8eabd8 --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/go.mod @@ -0,0 +1,7 @@ +module github.com/ipfs/go-block-format + +require ( + github.com/ipfs/go-cid v0.0.1 + github.com/ipfs/go-ipfs-util v0.0.1 + github.com/multiformats/go-multihash v0.0.1 +) diff --git a/vendor/github.com/ipfs/go-block-format/go.sum b/vendor/github.com/ipfs/go-block-format/go.sum new file mode 100644 index 0000000000..3fb22960b3 --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/go.sum @@ -0,0 +1,24 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/ipfs/go-block-format/package.json b/vendor/github.com/ipfs/go-block-format/package.json new file mode 100644 index 0000000000..970ac559b1 --- /dev/null +++ b/vendor/github.com/ipfs/go-block-format/package.json @@ -0,0 +1,36 @@ +{ + "author": "stebalien", + "bugs": { + "url": "https://github.com/ipfs/go-block-format" + }, + "gx": { + "dvcsimport": "github.com/ipfs/go-block-format" + }, + "gxDependencies": [ + { + "author": "whyrusleeping", + "hash": "QmTbxNB1NwDesLmKTscr4udL2tVP7MaxvXnD1D9yX7g3PN", + "name": "go-cid", + "version": "0.9.3" + }, + { + "author": "multiformats", + "hash": "QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW", + "name": "go-multihash", + "version": "1.0.9" + }, + { + "author": "whyrusleeping", + "hash": "QmNohiVssaPw3KVLZik59DBVGTSm2dGvYT9eoXt5DQ36Yz", + "name": "go-ipfs-util", + "version": "1.2.9" + } + ], + "gxVersion": "0.11.0", + "language": "go", + "license": "", + "name": "go-block-format", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "0.2.2" +} + diff --git a/vendor/github.com/ipfs/go-blockservice/LICENSE b/vendor/github.com/ipfs/go-blockservice/LICENSE new file mode 100644 index 0000000000..7d5dcac4d2 --- /dev/null +++ b/vendor/github.com/ipfs/go-blockservice/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2018 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-blockservice/README.md b/vendor/github.com/ipfs/go-blockservice/README.md new file mode 100644 index 0000000000..d36c5cc779 --- /dev/null +++ b/vendor/github.com/ipfs/go-blockservice/README.md @@ -0,0 +1,36 @@ +go-blockservice +================== + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![Coverage Status](https://codecov.io/gh/ipfs/go-block-format/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-block-format/branch/master) +[![Build Status](https://circleci.com/gh/ipfs/go-blockservice.svg?style=svg)](https://circleci.com/gh/ipfs/go-blockservice) + +> go-blockservice provides a seamless interface to both local and remote storage backends. + +## Lead Maintainer + +[Steven Allen](https://github.com/Stebalien) + +## Table of Contents + +- [TODO](#todo) +- [Contribute](#contribute) +- [License](#license) + +## TODO + +The interfaces here really would like to be merged with the blockstore interfaces. +The 'dagservice' constructor currently takes a blockservice, but it would be really nice +if it could just take a blockstore, and have this package implement a blockstore. + +## Contribute + +PRs are welcome! + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Juan Batiz-Benet diff --git a/vendor/github.com/ipfs/go-blockservice/blockservice.go b/vendor/github.com/ipfs/go-blockservice/blockservice.go new file mode 100644 index 0000000000..ba0ab41830 --- /dev/null +++ b/vendor/github.com/ipfs/go-blockservice/blockservice.go @@ -0,0 +1,368 @@ +// package blockservice implements a BlockService interface that provides +// a single GetBlock/AddBlock interface that seamlessly retrieves data either +// locally or from a remote peer through the exchange. +package blockservice + +import ( + "context" + "errors" + "io" + "sync" + + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + blockstore "github.com/ipfs/go-ipfs-blockstore" + exchange "github.com/ipfs/go-ipfs-exchange-interface" + logging "github.com/ipfs/go-log" + "github.com/ipfs/go-verifcid" +) + +var log = logging.Logger("blockservice") + +var ErrNotFound = errors.New("blockservice: key not found") + +// BlockGetter is the common interface shared between blockservice sessions and +// the blockservice. +type BlockGetter interface { + // GetBlock gets the requested block. + GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) + + // GetBlocks does a batch request for the given cids, returning blocks as + // they are found, in no particular order. + // + // It may not be able to find all requested blocks (or the context may + // be canceled). In that case, it will close the channel early. It is up + // to the consumer to detect this situation and keep track which blocks + // it has received and which it hasn't. + GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block +} + +// BlockService is a hybrid block datastore. It stores data in a local +// datastore and may retrieve data from a remote Exchange. +// It uses an internal `datastore.Datastore` instance to store values. +type BlockService interface { + io.Closer + BlockGetter + + // Blockstore returns a reference to the underlying blockstore + Blockstore() blockstore.Blockstore + + // Exchange returns a reference to the underlying exchange (usually bitswap) + Exchange() exchange.Interface + + // AddBlock puts a given block to the underlying datastore + AddBlock(o blocks.Block) error + + // AddBlocks adds a slice of blocks at the same time using batching + // capabilities of the underlying datastore whenever possible. + AddBlocks(bs []blocks.Block) error + + // DeleteBlock deletes the given block from the blockservice. + DeleteBlock(o cid.Cid) error +} + +type blockService struct { + blockstore blockstore.Blockstore + exchange exchange.Interface + // If checkFirst is true then first check that a block doesn't + // already exist to avoid republishing the block on the exchange. + checkFirst bool +} + +// NewBlockService creates a BlockService with given datastore instance. +func New(bs blockstore.Blockstore, rem exchange.Interface) BlockService { + if rem == nil { + log.Debug("blockservice running in local (offline) mode.") + } + + return &blockService{ + blockstore: bs, + exchange: rem, + checkFirst: true, + } +} + +// NewWriteThrough ceates a BlockService that guarantees writes will go +// through to the blockstore and are not skipped by cache checks. +func NewWriteThrough(bs blockstore.Blockstore, rem exchange.Interface) BlockService { + if rem == nil { + log.Debug("blockservice running in local (offline) mode.") + } + + return &blockService{ + blockstore: bs, + exchange: rem, + checkFirst: false, + } +} + +// Blockstore returns the blockstore behind this blockservice. +func (s *blockService) Blockstore() blockstore.Blockstore { + return s.blockstore +} + +// Exchange returns the exchange behind this blockservice. +func (s *blockService) Exchange() exchange.Interface { + return s.exchange +} + +// NewSession creates a new session that allows for +// controlled exchange of wantlists to decrease the bandwidth overhead. +// If the current exchange is a SessionExchange, a new exchange +// session will be created. Otherwise, the current exchange will be used +// directly. +func NewSession(ctx context.Context, bs BlockService) *Session { + exch := bs.Exchange() + if sessEx, ok := exch.(exchange.SessionExchange); ok { + return &Session{ + sessCtx: ctx, + ses: nil, + sessEx: sessEx, + bs: bs.Blockstore(), + } + } + return &Session{ + ses: exch, + sessCtx: ctx, + bs: bs.Blockstore(), + } +} + +// AddBlock adds a particular block to the service, Putting it into the datastore. +// TODO pass a context into this if the remote.HasBlock is going to remain here. +func (s *blockService) AddBlock(o blocks.Block) error { + c := o.Cid() + // hash security + err := verifcid.ValidateCid(c) + if err != nil { + return err + } + if s.checkFirst { + if has, err := s.blockstore.Has(c); has || err != nil { + return err + } + } + + if err := s.blockstore.Put(o); err != nil { + return err + } + + log.Event(context.TODO(), "BlockService.BlockAdded", c) + + if s.exchange != nil { + if err := s.exchange.HasBlock(o); err != nil { + log.Errorf("HasBlock: %s", err.Error()) + } + } + + return nil +} + +func (s *blockService) AddBlocks(bs []blocks.Block) error { + // hash security + for _, b := range bs { + err := verifcid.ValidateCid(b.Cid()) + if err != nil { + return err + } + } + var toput []blocks.Block + if s.checkFirst { + toput = make([]blocks.Block, 0, len(bs)) + for _, b := range bs { + has, err := s.blockstore.Has(b.Cid()) + if err != nil { + return err + } + if !has { + toput = append(toput, b) + } + } + } else { + toput = bs + } + + if len(toput) == 0 { + return nil + } + + err := s.blockstore.PutMany(toput) + if err != nil { + return err + } + + if s.exchange != nil { + for _, o := range toput { + log.Event(context.TODO(), "BlockService.BlockAdded", o.Cid()) + if err := s.exchange.HasBlock(o); err != nil { + log.Errorf("HasBlock: %s", err.Error()) + } + } + } + return nil +} + +// GetBlock retrieves a particular block from the service, +// Getting it from the datastore using the key (hash). +func (s *blockService) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + log.Debugf("BlockService GetBlock: '%s'", c) + + var f func() exchange.Fetcher + if s.exchange != nil { + f = s.getExchange + } + + return getBlock(ctx, c, s.blockstore, f) // hash security +} + +func (s *blockService) getExchange() exchange.Fetcher { + return s.exchange +} + +func getBlock(ctx context.Context, c cid.Cid, bs blockstore.Blockstore, fget func() exchange.Fetcher) (blocks.Block, error) { + err := verifcid.ValidateCid(c) // hash security + if err != nil { + return nil, err + } + + block, err := bs.Get(c) + if err == nil { + return block, nil + } + + if err == blockstore.ErrNotFound && fget != nil { + f := fget() // Don't load the exchange until we have to + + // TODO be careful checking ErrNotFound. If the underlying + // implementation changes, this will break. + log.Debug("Blockservice: Searching bitswap") + blk, err := f.GetBlock(ctx, c) + if err != nil { + if err == blockstore.ErrNotFound { + return nil, ErrNotFound + } + return nil, err + } + log.Event(ctx, "BlockService.BlockFetched", c) + return blk, nil + } + + log.Debug("Blockservice GetBlock: Not found") + if err == blockstore.ErrNotFound { + return nil, ErrNotFound + } + + return nil, err +} + +// GetBlocks gets a list of blocks asynchronously and returns through +// the returned channel. +// NB: No guarantees are made about order. +func (s *blockService) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block { + var f func() exchange.Fetcher + if s.exchange != nil { + f = s.getExchange + } + + return getBlocks(ctx, ks, s.blockstore, f) // hash security +} + +func getBlocks(ctx context.Context, ks []cid.Cid, bs blockstore.Blockstore, fget func() exchange.Fetcher) <-chan blocks.Block { + out := make(chan blocks.Block) + + go func() { + defer close(out) + + k := 0 + for _, c := range ks { + // hash security + if err := verifcid.ValidateCid(c); err == nil { + ks[k] = c + k++ + } else { + log.Errorf("unsafe CID (%s) passed to blockService.GetBlocks: %s", c, err) + } + } + ks = ks[:k] + + var misses []cid.Cid + for _, c := range ks { + hit, err := bs.Get(c) + if err != nil { + misses = append(misses, c) + continue + } + select { + case out <- hit: + case <-ctx.Done(): + return + } + } + + if len(misses) == 0 || fget == nil { + return + } + + f := fget() // don't load exchange unless we have to + rblocks, err := f.GetBlocks(ctx, misses) + if err != nil { + log.Debugf("Error with GetBlocks: %s", err) + return + } + + for b := range rblocks { + log.Event(ctx, "BlockService.BlockFetched", b.Cid()) + select { + case out <- b: + case <-ctx.Done(): + return + } + } + }() + return out +} + +// DeleteBlock deletes a block in the blockservice from the datastore +func (s *blockService) DeleteBlock(c cid.Cid) error { + err := s.blockstore.DeleteBlock(c) + if err == nil { + log.Event(context.TODO(), "BlockService.BlockDeleted", c) + } + return err +} + +func (s *blockService) Close() error { + log.Debug("blockservice is shutting down...") + return s.exchange.Close() +} + +// Session is a helper type to provide higher level access to bitswap sessions +type Session struct { + bs blockstore.Blockstore + ses exchange.Fetcher + sessEx exchange.SessionExchange + sessCtx context.Context + lk sync.Mutex +} + +func (s *Session) getSession() exchange.Fetcher { + s.lk.Lock() + defer s.lk.Unlock() + if s.ses == nil { + s.ses = s.sessEx.NewSession(s.sessCtx) + } + + return s.ses +} + +// GetBlock gets a block in the context of a request session +func (s *Session) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { + return getBlock(ctx, c, s.bs, s.getSession) // hash security +} + +// GetBlocks gets blocks in the context of a request session +func (s *Session) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block { + return getBlocks(ctx, ks, s.bs, s.getSession) // hash security +} + +var _ BlockGetter = (*Session)(nil) diff --git a/vendor/github.com/ipfs/go-blockservice/go.mod b/vendor/github.com/ipfs/go-blockservice/go.mod new file mode 100644 index 0000000000..b966f19f0f --- /dev/null +++ b/vendor/github.com/ipfs/go-blockservice/go.mod @@ -0,0 +1,19 @@ +module github.com/ipfs/go-blockservice + +go 1.13 + +require ( + github.com/ipfs/go-bitswap v0.1.8 + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.5 + github.com/ipfs/go-datastore v0.4.4 + github.com/ipfs/go-ipfs-blockstore v0.1.4 + github.com/ipfs/go-ipfs-blocksutil v0.0.1 + github.com/ipfs/go-ipfs-delay v0.0.1 + github.com/ipfs/go-ipfs-exchange-interface v0.0.1 + github.com/ipfs/go-ipfs-exchange-offline v0.0.1 + github.com/ipfs/go-ipfs-routing v0.1.0 + github.com/ipfs/go-ipfs-util v0.0.1 + github.com/ipfs/go-log v0.0.1 + github.com/ipfs/go-verifcid v0.0.1 +) diff --git a/vendor/github.com/ipfs/go-blockservice/go.sum b/vendor/github.com/ipfs/go-blockservice/go.sum new file mode 100644 index 0000000000..0fc7ec2783 --- /dev/null +++ b/vendor/github.com/ipfs/go-blockservice/go.sum @@ -0,0 +1,363 @@ +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 h1:qkOC5Gd33k54tobS36cXdAzJbeHaduLtnLQQwNoIi78= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c h1:aEbSeNALREWXk0G7UdNhR3ayBV7tZ4M2PNmnrCAph6Q= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50 h1:4i3KsuVA0o0KoBxAC5x+MY7RbteiMK1V7gf/G08NGIQ= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ipfs/bbloom v0.0.1 h1:s7KkiBPfxCeDVo47KySjK0ACPc5GJRUxFpdyWEuDjhw= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitswap v0.1.8 h1:38X1mKXkiU6Nzw4TOSWD8eTVY5eX3slQunv3QEWfXKg= +github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-datastore v0.0.1 h1:AW/KZCScnBWlSb5JbnEnLKFWXL224LBEh/9KXXOrUms= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5 h1:q3OfiOZV5rlsK1H5V8benjeUApRfMGs4Mrhmr6NriQo= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1 h1:F4k0TkTAZGLFzBOrVKDAvch6JZtuN4NHkfdcEZL50aI= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ipfs-blockstore v0.0.1 h1:O9n3PbmTYZoNhkgkEyrXTznbmktIXif62xLX+8dPHzc= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blockstore v0.1.4 h1:2SGI6U1B44aODevza8Rde3+dY30Pb+lbcObe1LETxOQ= +github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1 h1:QBg+Ts2zgeemK/dB0saiF/ykzRGgfoFMT90Rzo0OnVU= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-ds-help v0.1.1 h1:IW/bXGeaAZV2VH0Kuok+Ohva/zHkHmeLFBxC1k7mNPc= +github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-pq v0.0.1 h1:zgUotX8dcAB/w/HidJh1zzc1yFq6Vm8J7T2F4itj/RU= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-peertaskqueue v0.1.1 h1:+gPjbI+V3NktXZOqJA1kzbms2pYmhjgQQal0MzZrOAY= +github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec h1:DQqZhhDvrTrEQ3Qod5yfavcA064e53xlQ+xajiorXgM= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-buffer-pool v0.0.1 h1:9Rrn/H46cXjaA2HQ5Y8lyhOS1NhTkZ4yuEs2r3Eechg= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security-multistream v0.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-libp2p v0.1.1 h1:52sB0TJuDk2nYMcMfHOKaPoaayDZjaYVCq6Vk1ejUTk= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-blankhost v0.1.1 h1:X919sCh+KLqJcNRApj43xCSiQRYqOSI88Fdf55ngf78= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-core v0.0.1 h1:HSTZtFIq/W5Ue43Zw+uWZyy2Vl5WtF0zDjKN8/DT/1I= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2 h1:86uOwW+O6Uc7NbaK4diuLZo2/Ikvqw2rgyV03VcSbLE= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3 h1:+IonUYY0nJZLb5Fdv6a6DOjtGP1L8Bb3faamiI2q5FY= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= +github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-nat v0.0.4 h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0 h1:MKh7pRNPHSh1fLPj8u/M/s/napdmeNpoi9BRy9lPN0E= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-record v0.1.0 h1:wHwBGbFzymoIl69BpgwIu0O6ta3TXGcMPvHUAcodzRc= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-secio v0.1.0 h1:NNP5KLxuP97sE5Bu3iuwOWyT/dKEGMN5zSLMWdB7GTQ= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-swarm v0.1.0 h1:HrFk2p0awrGEgch9JXK/qp/hfjqQfgNxpLWnCiWPg5s= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-testing v0.0.2 h1:p9ySW7MFvGGs83hAAe0MPGnjy/tPjl5KyxpMkojdZ+g= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3 h1:bdij4bKaaND7tCsaXVjRfYkMpvoOeKj9AVQGJllA6jM= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4 h1:Qev57UR47GcLPXWjrunv5aLIQGO4n9mhI/8/EIrEEFc= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-yamux v0.2.0 h1:TSPZ5cMMz/wdoYsye/wU1TE4G3LDGMoeEN0xgnCKU/I= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1 h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-maddr-filter v0.0.4 h1:hx8HIuuwk34KePddrp2mM5ivgPkZ09JH4AvsALRbFUs= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-msgio v0.0.2 h1:ivPvEKHxmVkTClHzg6RXTYHqaJQ0V9cDbq+6lKb3UV0= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.3 h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1 h1:Ce6e2Pyu+b5MC1k3eeFtAax0pW4gc6MosYSLV05UeLw= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0 h1:IGhowvEqyMFknOar4FWCKSWE0zL36UFKQtiRQD60/8o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-yamux v1.2.2 h1:s6J6o7+ajoQMjHe7BEnq+EynOj5D2EoG8CuQgL3F2vg= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0 h1:U41/2erhAKcmSI14xh/ZTUdBPOzDOIfS93ibzUSl8KM= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multiaddr v0.0.1 h1:/QUV3VBMDI6pi6xfiw7lr6xhDWWvQKn9udPn68kLSdY= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4 h1:WgMSI84/eRLdbptXMkMWDXPjPq7SPLIgGUVm2eroyU4= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2 h1:/Bbsgsy3R6e3jf2qBahzNHzww6usYaZ0NhNH3sqdFS8= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-fmt v0.0.1 h1:5YjeOIzbX8OTKVaN72aOzGIYW7PnrZrnkDyOfAWRSMA= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-net v0.0.1 h1:76O59E3FavvHqNg7jvzWzsPSW5JSi/ek0E4eiDVbg9g= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7 h1:C2F/nMkR/9sfUTpvR3QrjBuTdvMUC/cFajkphs1YLQo= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a h1:+KkCgOMgnKSgenxTBoiwkMqTiouMIy/3o8RLdmSbGoY= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae h1:xiXzMMEQdQcric9hXtr1QU98MHunKK7OTtsoU6bYWs4= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/ipfs/go-cid/.gitignore b/vendor/github.com/ipfs/go-cid/.gitignore new file mode 100644 index 0000000000..aaea8ed0a7 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/.gitignore @@ -0,0 +1 @@ +cid-fuzz.zip diff --git a/vendor/github.com/ipfs/go-cid/.travis.yml b/vendor/github.com/ipfs/go-cid/.travis.yml new file mode 100644 index 0000000000..923835bc58 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/.travis.yml @@ -0,0 +1,31 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-cid/LICENSE b/vendor/github.com/ipfs/go-cid/LICENSE new file mode 100644 index 0000000000..0e323020a6 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-cid/Makefile b/vendor/github.com/ipfs/go-cid/Makefile new file mode 100644 index 0000000000..e6bdd2c9bd --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/Makefile @@ -0,0 +1,16 @@ +all: deps + +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go + +covertools: + go get github.com/mattn/goveralls + go get golang.org/x/tools/cmd/cover + +deps: gx covertools + gx --verbose install --global + gx-go rewrite + +publish: + gx-go rewrite --undo diff --git a/vendor/github.com/ipfs/go-cid/README.md b/vendor/github.com/ipfs/go-cid/README.md new file mode 100644 index 0000000000..4f54343a97 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/README.md @@ -0,0 +1,108 @@ +go-cid +================== + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/ipfs/go-cid?status.svg)](https://godoc.org/github.com/ipfs/go-cid) +[![Coverage Status](https://coveralls.io/repos/github/ipfs/go-cid/badge.svg?branch=master)](https://coveralls.io/github/ipfs/go-cid?branch=master) +[![Travis CI](https://travis-ci.org/ipfs/go-cid.svg?branch=master)](https://travis-ci.org/ipfs/go-cid) + +> A package to handle content IDs in Go. + +This is an implementation in Go of the [CID spec](https://github.com/ipld/cid). +It is used in `go-ipfs` and related packages to refer to a typed hunk of data. + +## Lead Maintainer + +[Eric Myhre](https://github.com/warpfork) + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [API](#api) +- [Contribute](#contribute) +- [License](#license) + +## Install + +`go-cid` is a standard Go module which can be installed with: + +```sh +go get github.com/ipfs/go-cid +``` + +## Usage + +### Running tests + +Run tests with `go test` from the directory root + +```sh +go test +``` + +### Examples + +#### Parsing string input from users + +```go +// Create a cid from a marshaled string +c, err := cid.Decode("bafzbeigai3eoy2ccc7ybwjfz5r3rdxqrinwi4rwytly24tdbh6yk7zslrm") +if err != nil {...} + +fmt.Println("Got CID: ", c) +``` + +#### Creating a CID from scratch + +```go +// Create a cid manually by specifying the 'prefix' parameters +pref := cid.Prefix{ + Version: 1, + Codec: cid.Raw, + MhType: mh.SHA2_256, + MhLength: -1, // default length +} + +// And then feed it some data +c, err := pref.Sum([]byte("Hello World!")) +if err != nil {...} + +fmt.Println("Created CID: ", c) +``` + +#### Check if two CIDs match + +```go +// To test if two cid's are equivalent, be sure to use the 'Equals' method: +if c1.Equals(c2) { + fmt.Println("These two refer to the same exact data!") +} +``` + +#### Check if some data matches a given CID + +```go +// To check if some data matches a given cid, +// Get your CIDs prefix, and use that to sum the data in question: +other, err := c.Prefix().Sum(mydata) +if err != nil {...} + +if !c.Equals(other) { + fmt.Println("This data is different.") +} + +``` + +## Contribute + +PRs are welcome! + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Jeromy Johnson diff --git a/vendor/github.com/ipfs/go-cid/builder.go b/vendor/github.com/ipfs/go-cid/builder.go new file mode 100644 index 0000000000..3d2fc77cbd --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/builder.go @@ -0,0 +1,74 @@ +package cid + +import ( + mh "github.com/multiformats/go-multihash" +) + +type Builder interface { + Sum(data []byte) (Cid, error) + GetCodec() uint64 + WithCodec(uint64) Builder +} + +type V0Builder struct{} + +type V1Builder struct { + Codec uint64 + MhType uint64 + MhLength int // MhLength <= 0 means the default length +} + +func (p Prefix) GetCodec() uint64 { + return p.Codec +} + +func (p Prefix) WithCodec(c uint64) Builder { + if c == p.Codec { + return p + } + p.Codec = c + if c != DagProtobuf { + p.Version = 1 + } + return p +} + +func (p V0Builder) Sum(data []byte) (Cid, error) { + hash, err := mh.Sum(data, mh.SHA2_256, -1) + if err != nil { + return Undef, err + } + return Cid{string(hash)}, nil +} + +func (p V0Builder) GetCodec() uint64 { + return DagProtobuf +} + +func (p V0Builder) WithCodec(c uint64) Builder { + if c == DagProtobuf { + return p + } + return V1Builder{Codec: c, MhType: mh.SHA2_256} +} + +func (p V1Builder) Sum(data []byte) (Cid, error) { + mhLen := p.MhLength + if mhLen <= 0 { + mhLen = -1 + } + hash, err := mh.Sum(data, p.MhType, mhLen) + if err != nil { + return Undef, err + } + return NewCidV1(p.Codec, hash), nil +} + +func (p V1Builder) GetCodec() uint64 { + return p.Codec +} + +func (p V1Builder) WithCodec(c uint64) Builder { + p.Codec = c + return p +} diff --git a/vendor/github.com/ipfs/go-cid/cid.go b/vendor/github.com/ipfs/go-cid/cid.go new file mode 100644 index 0000000000..09f49f5beb --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/cid.go @@ -0,0 +1,654 @@ +// Package cid implements the Content-IDentifiers specification +// (https://github.com/ipld/cid) in Go. CIDs are +// self-describing content-addressed identifiers useful for +// distributed information systems. CIDs are used in the IPFS +// (https://ipfs.io) project ecosystem. +// +// CIDs have two major versions. A CIDv0 corresponds to a multihash of type +// DagProtobuf, is deprecated and exists for compatibility reasons. Usually, +// CIDv1 should be used. +// +// A CIDv1 has four parts: +// +// ::= +// +// As shown above, the CID implementation relies heavily on Multiformats, +// particularly Multibase +// (https://github.com/multiformats/go-multibase), Multicodec +// (https://github.com/multiformats/multicodec) and Multihash +// implementations (https://github.com/multiformats/go-multihash). +package cid + +import ( + "bytes" + "encoding" + "encoding/json" + "errors" + "fmt" + "io" + "strings" + + mbase "github.com/multiformats/go-multibase" + mh "github.com/multiformats/go-multihash" + varint "github.com/multiformats/go-varint" +) + +// UnsupportedVersionString just holds an error message +const UnsupportedVersionString = "" + +var ( + // ErrCidTooShort means that the cid passed to decode was not long + // enough to be a valid Cid + ErrCidTooShort = errors.New("cid too short") + + // ErrInvalidEncoding means that selected encoding is not supported + // by this Cid version + ErrInvalidEncoding = errors.New("invalid base encoding") +) + +// These are multicodec-packed content types. The should match +// the codes described in the authoritative document: +// https://github.com/multiformats/multicodec/blob/master/table.csv +const ( + Raw = 0x55 + + DagProtobuf = 0x70 + DagCBOR = 0x71 + Libp2pKey = 0x72 + + GitRaw = 0x78 + + EthBlock = 0x90 + EthBlockList = 0x91 + EthTxTrie = 0x92 + EthTx = 0x93 + EthTxReceiptTrie = 0x94 + EthTxReceipt = 0x95 + EthStateTrie = 0x96 + EthAccountSnapshot = 0x97 + EthStorageTrie = 0x98 + BitcoinBlock = 0xb0 + BitcoinTx = 0xb1 + ZcashBlock = 0xc0 + ZcashTx = 0xc1 + DecredBlock = 0xe0 + DecredTx = 0xe1 + DashBlock = 0xf0 + DashTx = 0xf1 +) + +// Codecs maps the name of a codec to its type +var Codecs = map[string]uint64{ + "v0": DagProtobuf, + "raw": Raw, + "protobuf": DagProtobuf, + "cbor": DagCBOR, + "libp2p-key": Libp2pKey, + "git-raw": GitRaw, + "eth-block": EthBlock, + "eth-block-list": EthBlockList, + "eth-tx-trie": EthTxTrie, + "eth-tx": EthTx, + "eth-tx-receipt-trie": EthTxReceiptTrie, + "eth-tx-receipt": EthTxReceipt, + "eth-state-trie": EthStateTrie, + "eth-account-snapshot": EthAccountSnapshot, + "eth-storage-trie": EthStorageTrie, + "bitcoin-block": BitcoinBlock, + "bitcoin-tx": BitcoinTx, + "zcash-block": ZcashBlock, + "zcash-tx": ZcashTx, + "decred-block": DecredBlock, + "decred-tx": DecredTx, + "dash-block": DashBlock, + "dash-tx": DashTx, +} + +// CodecToStr maps the numeric codec to its name +var CodecToStr = map[uint64]string{ + Raw: "raw", + DagProtobuf: "protobuf", + DagCBOR: "cbor", + GitRaw: "git-raw", + EthBlock: "eth-block", + EthBlockList: "eth-block-list", + EthTxTrie: "eth-tx-trie", + EthTx: "eth-tx", + EthTxReceiptTrie: "eth-tx-receipt-trie", + EthTxReceipt: "eth-tx-receipt", + EthStateTrie: "eth-state-trie", + EthAccountSnapshot: "eth-account-snapshot", + EthStorageTrie: "eth-storage-trie", + BitcoinBlock: "bitcoin-block", + BitcoinTx: "bitcoin-tx", + ZcashBlock: "zcash-block", + ZcashTx: "zcash-tx", + DecredBlock: "decred-block", + DecredTx: "decred-tx", + DashBlock: "dash-block", + DashTx: "dash-tx", +} + +// tryNewCidV0 tries to convert a multihash into a CIDv0 CID and returns an +// error on failure. +func tryNewCidV0(mhash mh.Multihash) (Cid, error) { + // Need to make sure hash is valid for CidV0 otherwise we will + // incorrectly detect it as CidV1 in the Version() method + dec, err := mh.Decode(mhash) + if err != nil { + return Undef, err + } + if dec.Code != mh.SHA2_256 || dec.Length != 32 { + return Undef, fmt.Errorf("invalid hash for cidv0 %d-%d", dec.Code, dec.Length) + } + return Cid{string(mhash)}, nil +} + +// NewCidV0 returns a Cid-wrapped multihash. +// They exist to allow IPFS to work with Cids while keeping +// compatibility with the plain-multihash format used used in IPFS. +// NewCidV1 should be used preferentially. +// +// Panics if the multihash isn't sha2-256. +func NewCidV0(mhash mh.Multihash) Cid { + c, err := tryNewCidV0(mhash) + if err != nil { + panic(err) + } + return c +} + +// NewCidV1 returns a new Cid using the given multicodec-packed +// content type. +// +// Panics if the multihash is invalid. +func NewCidV1(codecType uint64, mhash mh.Multihash) Cid { + hashlen := len(mhash) + // two 8 bytes (max) numbers plus hash + buf := make([]byte, 1+varint.UvarintSize(codecType)+hashlen) + n := varint.PutUvarint(buf, 1) + n += varint.PutUvarint(buf[n:], codecType) + cn := copy(buf[n:], mhash) + if cn != hashlen { + panic("copy hash length is inconsistent") + } + + return Cid{string(buf[:n+hashlen])} +} + +var _ encoding.BinaryMarshaler = Cid{} +var _ encoding.BinaryUnmarshaler = (*Cid)(nil) +var _ encoding.TextMarshaler = Cid{} +var _ encoding.TextUnmarshaler = (*Cid)(nil) + +// Cid represents a self-describing content addressed +// identifier. It is formed by a Version, a Codec (which indicates +// a multicodec-packed content type) and a Multihash. +type Cid struct{ str string } + +// Undef can be used to represent a nil or undefined Cid, using Cid{} +// directly is also acceptable. +var Undef = Cid{} + +// Defined returns true if a Cid is defined +// Calling any other methods on an undefined Cid will result in +// undefined behavior. +func (c Cid) Defined() bool { + return c.str != "" +} + +// Parse is a short-hand function to perform Decode, Cast etc... on +// a generic interface{} type. +func Parse(v interface{}) (Cid, error) { + switch v2 := v.(type) { + case string: + if strings.Contains(v2, "/ipfs/") { + return Decode(strings.Split(v2, "/ipfs/")[1]) + } + return Decode(v2) + case []byte: + return Cast(v2) + case mh.Multihash: + return tryNewCidV0(v2) + case Cid: + return v2, nil + default: + return Undef, fmt.Errorf("can't parse %+v as Cid", v2) + } +} + +// Decode parses a Cid-encoded string and returns a Cid object. +// For CidV1, a Cid-encoded string is primarily a multibase string: +// +// +// +// The base-encoded string represents a: +// +// +// +// Decode will also detect and parse CidV0 strings. Strings +// starting with "Qm" are considered CidV0 and treated directly +// as B58-encoded multihashes. +func Decode(v string) (Cid, error) { + if len(v) < 2 { + return Undef, ErrCidTooShort + } + + if len(v) == 46 && v[:2] == "Qm" { + hash, err := mh.FromB58String(v) + if err != nil { + return Undef, err + } + + return tryNewCidV0(hash) + } + + _, data, err := mbase.Decode(v) + if err != nil { + return Undef, err + } + + return Cast(data) +} + +// Extract the encoding from a Cid. If Decode on the same string did +// not return an error neither will this function. +func ExtractEncoding(v string) (mbase.Encoding, error) { + if len(v) < 2 { + return -1, ErrCidTooShort + } + + if len(v) == 46 && v[:2] == "Qm" { + return mbase.Base58BTC, nil + } + + encoding := mbase.Encoding(v[0]) + + // check encoding is valid + _, err := mbase.NewEncoder(encoding) + if err != nil { + return -1, err + } + + return encoding, nil +} + +// Cast takes a Cid data slice, parses it and returns a Cid. +// For CidV1, the data buffer is in the form: +// +// +// +// CidV0 are also supported. In particular, data buffers starting +// with length 34 bytes, which starts with bytes [18,32...] are considered +// binary multihashes. +// +// Please use decode when parsing a regular Cid string, as Cast does not +// expect multibase-encoded data. Cast accepts the output of Cid.Bytes(). +func Cast(data []byte) (Cid, error) { + nr, c, err := CidFromBytes(data) + if err != nil { + return Undef, err + } + + if nr != len(data) { + return Undef, fmt.Errorf("trailing bytes in data buffer passed to cid Cast") + } + + return c, nil +} + +// UnmarshalBinary is equivalent to Cast(). It implements the +// encoding.BinaryUnmarshaler interface. +func (c *Cid) UnmarshalBinary(data []byte) error { + casted, err := Cast(data) + if err != nil { + return err + } + c.str = casted.str + return nil +} + +// UnmarshalText is equivalent to Decode(). It implements the +// encoding.TextUnmarshaler interface. +func (c *Cid) UnmarshalText(text []byte) error { + decodedCid, err := Decode(string(text)) + if err != nil { + return err + } + c.str = decodedCid.str + return nil +} + +// Version returns the Cid version. +func (c Cid) Version() uint64 { + if len(c.str) == 34 && c.str[0] == 18 && c.str[1] == 32 { + return 0 + } + return 1 +} + +// Type returns the multicodec-packed content type of a Cid. +func (c Cid) Type() uint64 { + if c.Version() == 0 { + return DagProtobuf + } + _, n, _ := uvarint(c.str) + codec, _, _ := uvarint(c.str[n:]) + return codec +} + +// String returns the default string representation of a +// Cid. Currently, Base32 is used for CIDV1 as the encoding for the +// multibase string, Base58 is used for CIDV0. +func (c Cid) String() string { + switch c.Version() { + case 0: + return c.Hash().B58String() + case 1: + mbstr, err := mbase.Encode(mbase.Base32, c.Bytes()) + if err != nil { + panic("should not error with hardcoded mbase: " + err.Error()) + } + + return mbstr + default: + panic("not possible to reach this point") + } +} + +// String returns the string representation of a Cid +// encoded is selected base +func (c Cid) StringOfBase(base mbase.Encoding) (string, error) { + switch c.Version() { + case 0: + if base != mbase.Base58BTC { + return "", ErrInvalidEncoding + } + return c.Hash().B58String(), nil + case 1: + return mbase.Encode(base, c.Bytes()) + default: + panic("not possible to reach this point") + } +} + +// Encode return the string representation of a Cid in a given base +// when applicable. Version 0 Cid's are always in Base58 as they do +// not take a multibase prefix. +func (c Cid) Encode(base mbase.Encoder) string { + switch c.Version() { + case 0: + return c.Hash().B58String() + case 1: + return base.Encode(c.Bytes()) + default: + panic("not possible to reach this point") + } +} + +// Hash returns the multihash contained by a Cid. +func (c Cid) Hash() mh.Multihash { + bytes := c.Bytes() + + if c.Version() == 0 { + return mh.Multihash(bytes) + } + + // skip version length + _, n1, _ := varint.FromUvarint(bytes) + // skip codec length + _, n2, _ := varint.FromUvarint(bytes[n1:]) + + return mh.Multihash(bytes[n1+n2:]) +} + +// Bytes returns the byte representation of a Cid. +// The output of bytes can be parsed back into a Cid +// with Cast(). +func (c Cid) Bytes() []byte { + return []byte(c.str) +} + +// ByteLen returns the length of the CID in bytes. +// It's equivalent to `len(c.Bytes())`, but works without an allocation, +// and should therefore be preferred. +// +// (See also the WriteTo method for other important operations that work without allocation.) +func (c Cid) ByteLen() int { + return len(c.str) +} + +// WriteBytes writes the CID bytes to the given writer. +// This method works without incurring any allocation. +// +// (See also the ByteLen method for other important operations that work without allocation.) +func (c Cid) WriteBytes(w io.Writer) (int, error) { + n, err := io.WriteString(w, c.str) + if err != nil { + return n, err + } + if n != len(c.str) { + return n, fmt.Errorf("failed to write entire cid string") + } + return n, nil +} + +// MarshalBinary is equivalent to Bytes(). It implements the +// encoding.BinaryMarshaler interface. +func (c Cid) MarshalBinary() ([]byte, error) { + return c.Bytes(), nil +} + +// MarshalText is equivalent to String(). It implements the +// encoding.TextMarshaler interface. +func (c Cid) MarshalText() ([]byte, error) { + return []byte(c.String()), nil +} + +// Equals checks that two Cids are the same. +// In order for two Cids to be considered equal, the +// Version, the Codec and the Multihash must match. +func (c Cid) Equals(o Cid) bool { + return c == o +} + +// UnmarshalJSON parses the JSON representation of a Cid. +func (c *Cid) UnmarshalJSON(b []byte) error { + if len(b) < 2 { + return fmt.Errorf("invalid cid json blob") + } + obj := struct { + CidTarget string `json:"/"` + }{} + objptr := &obj + err := json.Unmarshal(b, &objptr) + if err != nil { + return err + } + if objptr == nil { + *c = Cid{} + return nil + } + + if obj.CidTarget == "" { + return fmt.Errorf("cid was incorrectly formatted") + } + + out, err := Decode(obj.CidTarget) + if err != nil { + return err + } + + *c = out + + return nil +} + +// MarshalJSON procudes a JSON representation of a Cid, which looks as follows: +// +// { "/": "" } +// +// Note that this formatting comes from the IPLD specification +// (https://github.com/ipld/specs/tree/master/ipld) +func (c Cid) MarshalJSON() ([]byte, error) { + if !c.Defined() { + return []byte("null"), nil + } + return []byte(fmt.Sprintf("{\"/\":\"%s\"}", c.String())), nil +} + +// KeyString returns the binary representation of the Cid as a string +func (c Cid) KeyString() string { + return c.str +} + +// Loggable returns a Loggable (as defined by +// https://godoc.org/github.com/ipfs/go-log). +func (c Cid) Loggable() map[string]interface{} { + return map[string]interface{}{ + "cid": c, + } +} + +// Prefix builds and returns a Prefix out of a Cid. +func (c Cid) Prefix() Prefix { + dec, _ := mh.Decode(c.Hash()) // assuming we got a valid multiaddr, this will not error + return Prefix{ + MhType: dec.Code, + MhLength: dec.Length, + Version: c.Version(), + Codec: c.Type(), + } +} + +// Prefix represents all the metadata of a Cid, +// that is, the Version, the Codec, the Multihash type +// and the Multihash length. It does not contains +// any actual content information. +// NOTE: The use -1 in MhLength to mean default length is deprecated, +// use the V0Builder or V1Builder structures instead +type Prefix struct { + Version uint64 + Codec uint64 + MhType uint64 + MhLength int +} + +// Sum uses the information in a prefix to perform a multihash.Sum() +// and return a newly constructed Cid with the resulting multihash. +func (p Prefix) Sum(data []byte) (Cid, error) { + length := p.MhLength + if p.MhType == mh.ID { + length = -1 + } + + if p.Version == 0 && (p.MhType != mh.SHA2_256 || + (p.MhLength != 32 && p.MhLength != -1)) { + + return Undef, fmt.Errorf("invalid v0 prefix") + } + + hash, err := mh.Sum(data, p.MhType, length) + if err != nil { + return Undef, err + } + + switch p.Version { + case 0: + return NewCidV0(hash), nil + case 1: + return NewCidV1(p.Codec, hash), nil + default: + return Undef, fmt.Errorf("invalid cid version") + } +} + +// Bytes returns a byte representation of a Prefix. It looks like: +// +// +func (p Prefix) Bytes() []byte { + size := varint.UvarintSize(p.Version) + size += varint.UvarintSize(p.Codec) + size += varint.UvarintSize(p.MhType) + size += varint.UvarintSize(uint64(p.MhLength)) + + buf := make([]byte, size) + n := varint.PutUvarint(buf, p.Version) + n += varint.PutUvarint(buf[n:], p.Codec) + n += varint.PutUvarint(buf[n:], p.MhType) + n += varint.PutUvarint(buf[n:], uint64(p.MhLength)) + if n != size { + panic("size mismatch") + } + return buf +} + +// PrefixFromBytes parses a Prefix-byte representation onto a +// Prefix. +func PrefixFromBytes(buf []byte) (Prefix, error) { + r := bytes.NewReader(buf) + vers, err := varint.ReadUvarint(r) + if err != nil { + return Prefix{}, err + } + + codec, err := varint.ReadUvarint(r) + if err != nil { + return Prefix{}, err + } + + mhtype, err := varint.ReadUvarint(r) + if err != nil { + return Prefix{}, err + } + + mhlen, err := varint.ReadUvarint(r) + if err != nil { + return Prefix{}, err + } + + return Prefix{ + Version: vers, + Codec: codec, + MhType: mhtype, + MhLength: int(mhlen), + }, nil +} + +func CidFromBytes(data []byte) (int, Cid, error) { + if len(data) > 2 && data[0] == mh.SHA2_256 && data[1] == 32 { + if len(data) < 34 { + return 0, Undef, fmt.Errorf("not enough bytes for cid v0") + } + + h, err := mh.Cast(data[:34]) + if err != nil { + return 0, Undef, err + } + + return 34, Cid{string(h)}, nil + } + + vers, n, err := varint.FromUvarint(data) + if err != nil { + return 0, Undef, err + } + + if vers != 1 { + return 0, Undef, fmt.Errorf("expected 1 as the cid version number, got: %d", vers) + } + + _, cn, err := varint.FromUvarint(data[n:]) + if err != nil { + return 0, Undef, err + } + + mhnr, _, err := mh.MHFromBytes(data[n+cn:]) + if err != nil { + return 0, Undef, err + } + + l := n + cn + mhnr + + return l, Cid{string(data[0:l])}, nil +} diff --git a/vendor/github.com/ipfs/go-cid/cid_fuzz.go b/vendor/github.com/ipfs/go-cid/cid_fuzz.go new file mode 100644 index 0000000000..99842b5350 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/cid_fuzz.go @@ -0,0 +1,37 @@ +// +build gofuzz + +package cid + +func Fuzz(data []byte) int { + cid, err := Cast(data) + + if err != nil { + return 0 + } + + _ = cid.Bytes() + _ = cid.String() + p := cid.Prefix() + _ = p.Bytes() + + if !cid.Equals(cid) { + panic("inequality") + } + + // json loop + json, err := cid.MarshalJSON() + if err != nil { + panic(err.Error()) + } + cid2 := Cid{} + err = cid2.UnmarshalJSON(json) + if err != nil { + panic(err.Error()) + } + + if !cid.Equals(cid2) { + panic("json loop not equal") + } + + return 1 +} diff --git a/vendor/github.com/ipfs/go-cid/codecov.yml b/vendor/github.com/ipfs/go-cid/codecov.yml new file mode 100644 index 0000000000..5f88a9ea27 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/codecov.yml @@ -0,0 +1,3 @@ +coverage: + range: "50...100" +comment: off diff --git a/vendor/github.com/ipfs/go-cid/deprecated.go b/vendor/github.com/ipfs/go-cid/deprecated.go new file mode 100644 index 0000000000..cd889f984a --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/deprecated.go @@ -0,0 +1,28 @@ +package cid + +import ( + mh "github.com/multiformats/go-multihash" +) + +// NewPrefixV0 returns a CIDv0 prefix with the specified multihash type. +// DEPRECATED: Use V0Builder +func NewPrefixV0(mhType uint64) Prefix { + return Prefix{ + MhType: mhType, + MhLength: mh.DefaultLengths[mhType], + Version: 0, + Codec: DagProtobuf, + } +} + +// NewPrefixV1 returns a CIDv1 prefix with the specified codec and multihash +// type. +// DEPRECATED: Use V1Builder +func NewPrefixV1(codecType uint64, mhType uint64) Prefix { + return Prefix{ + MhType: mhType, + MhLength: mh.DefaultLengths[mhType], + Version: 1, + Codec: codecType, + } +} diff --git a/vendor/github.com/ipfs/go-cid/go.mod b/vendor/github.com/ipfs/go-cid/go.mod new file mode 100644 index 0000000000..dd390f476c --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/go.mod @@ -0,0 +1,9 @@ +module github.com/ipfs/go-cid + +require ( + github.com/multiformats/go-multibase v0.0.1 + github.com/multiformats/go-multihash v0.0.13 + github.com/multiformats/go-varint v0.0.5 +) + +go 1.13 diff --git a/vendor/github.com/ipfs/go-cid/go.sum b/vendor/github.com/ipfs/go-cid/go.sum new file mode 100644 index 0000000000..c564628660 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/go.sum @@ -0,0 +1,30 @@ +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.12 h1:i2PQZWlsq8asUZwPS5w7VMCoUKEz/k/XG6WH30gsTU8= +github.com/multiformats/go-multihash v0.0.12/go.mod h1:2+oRiLVLqXx+yxM/RIdhLstp1q2WMJAlQ4kdLkS3un0= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.4 h1:CplQWhUouUgTZ53vNFE8VoWr2VjaKXci+xyrKyyFuSw= +github.com/multiformats/go-varint v0.0.4/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/ipfs/go-cid/package.json b/vendor/github.com/ipfs/go-cid/package.json new file mode 100644 index 0000000000..c98a77ee2d --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/package.json @@ -0,0 +1,30 @@ +{ + "author": "whyrusleeping", + "bugs": { + "url": "https://github.com/ipfs/go-cid" + }, + "gx": { + "dvcsimport": "github.com/ipfs/go-cid" + }, + "gxDependencies": [ + { + "author": "whyrusleeping", + "hash": "QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW", + "name": "go-multihash", + "version": "1.0.9" + }, + { + "author": "whyrusleeping", + "hash": "QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd", + "name": "go-multibase", + "version": "0.3.0" + } + ], + "gxVersion": "0.8.0", + "language": "go", + "license": "MIT", + "name": "go-cid", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "0.9.3" +} + diff --git a/vendor/github.com/ipfs/go-cid/set.go b/vendor/github.com/ipfs/go-cid/set.go new file mode 100644 index 0000000000..eb3b3f0dc1 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/set.go @@ -0,0 +1,65 @@ +package cid + +// Set is a implementation of a set of Cids, that is, a structure +// to which holds a single copy of every Cids that is added to it. +type Set struct { + set map[Cid]struct{} +} + +// NewSet initializes and returns a new Set. +func NewSet() *Set { + return &Set{set: make(map[Cid]struct{})} +} + +// Add puts a Cid in the Set. +func (s *Set) Add(c Cid) { + s.set[c] = struct{}{} +} + +// Has returns if the Set contains a given Cid. +func (s *Set) Has(c Cid) bool { + _, ok := s.set[c] + return ok +} + +// Remove deletes a Cid from the Set. +func (s *Set) Remove(c Cid) { + delete(s.set, c) +} + +// Len returns how many elements the Set has. +func (s *Set) Len() int { + return len(s.set) +} + +// Keys returns the Cids in the set. +func (s *Set) Keys() []Cid { + out := make([]Cid, 0, len(s.set)) + for k := range s.set { + out = append(out, k) + } + return out +} + +// Visit adds a Cid to the set only if it is +// not in it already. +func (s *Set) Visit(c Cid) bool { + if !s.Has(c) { + s.Add(c) + return true + } + + return false +} + +// ForEach allows to run a custom function on each +// Cid in the set. +func (s *Set) ForEach(f func(c Cid) error) error { + for c := range s.set { + err := f(c) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/ipfs/go-cid/varint.go b/vendor/github.com/ipfs/go-cid/varint.go new file mode 100644 index 0000000000..ed5eba1ad2 --- /dev/null +++ b/vendor/github.com/ipfs/go-cid/varint.go @@ -0,0 +1,40 @@ +package cid + +import ( + "github.com/multiformats/go-varint" +) + +// Version of varint function that work with a string rather than +// []byte to avoid unnecessary allocation + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license as given at https://golang.org/LICENSE + +// uvarint decodes a uint64 from buf and returns that value and the +// number of characters read (> 0). If an error occurred, the value is 0 +// and the number of bytes n is <= 0 meaning: +// +// n == 0: buf too small +// n < 0: value larger than 64 bits (overflow) +// and -n is the number of bytes read +// +func uvarint(buf string) (uint64, int, error) { + var x uint64 + var s uint + // we have a binary string so we can't use a range loope + for i := 0; i < len(buf); i++ { + b := buf[i] + if b < 0x80 { + if i > 9 || i == 9 && b > 1 { + return 0, 0, varint.ErrOverflow + } else if b == 0 && i > 0 { + return 0, 0, varint.ErrNotMinimal + } + return x | uint64(b)< key-value datastore interfaces + +## Lead Maintainer + +[Steven Allen](https://github.com/Stebalien) + +## Table of Contents + +- [Background](#background) +- [Documentation](#documentation) +- [Contribute](#contribute) +- [License](#license) + +## Background + +Datastore is a generic layer of abstraction for data store and database access. It is a simple API with the aim to enable application development in a datastore-agnostic way, allowing datastores to be swapped seamlessly without changing application code. Thus, one can leverage different datastores with different strengths without committing the application to one datastore throughout its lifetime. + +In addition, grouped datastores significantly simplify interesting data access patterns (such as caching and sharding). + +Based on [datastore.py](https://github.com/datastore/datastore). + +## Documentation + +https://godoc.org/github.com/ipfs/go-datastore + +## Contribute + +Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-datastore/issues)! + +This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +### Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) + +## License + +MIT + diff --git a/vendor/github.com/ipfs/go-datastore/basic_ds.go b/vendor/github.com/ipfs/go-datastore/basic_ds.go new file mode 100644 index 0000000000..4c851875da --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/basic_ds.go @@ -0,0 +1,287 @@ +package datastore + +import ( + "log" + + dsq "github.com/ipfs/go-datastore/query" +) + +// Here are some basic datastore implementations. + +// MapDatastore uses a standard Go map for internal storage. +type MapDatastore struct { + values map[Key][]byte +} + +// NewMapDatastore constructs a MapDatastore. It is _not_ thread-safe by +// default, wrap using sync.MutexWrap if you need thread safety (the answer here +// is usually yes). +func NewMapDatastore() (d *MapDatastore) { + return &MapDatastore{ + values: make(map[Key][]byte), + } +} + +// Put implements Datastore.Put +func (d *MapDatastore) Put(key Key, value []byte) (err error) { + d.values[key] = value + return nil +} + +// Sync implements Datastore.Sync +func (d *MapDatastore) Sync(prefix Key) error { + return nil +} + +// Get implements Datastore.Get +func (d *MapDatastore) Get(key Key) (value []byte, err error) { + val, found := d.values[key] + if !found { + return nil, ErrNotFound + } + return val, nil +} + +// Has implements Datastore.Has +func (d *MapDatastore) Has(key Key) (exists bool, err error) { + _, found := d.values[key] + return found, nil +} + +// GetSize implements Datastore.GetSize +func (d *MapDatastore) GetSize(key Key) (size int, err error) { + if v, found := d.values[key]; found { + return len(v), nil + } + return -1, ErrNotFound +} + +// Delete implements Datastore.Delete +func (d *MapDatastore) Delete(key Key) (err error) { + delete(d.values, key) + return nil +} + +// Query implements Datastore.Query +func (d *MapDatastore) Query(q dsq.Query) (dsq.Results, error) { + re := make([]dsq.Entry, 0, len(d.values)) + for k, v := range d.values { + e := dsq.Entry{Key: k.String(), Size: len(v)} + if !q.KeysOnly { + e.Value = v + } + re = append(re, e) + } + r := dsq.ResultsWithEntries(q, re) + r = dsq.NaiveQueryApply(q, r) + return r, nil +} + +func (d *MapDatastore) Batch() (Batch, error) { + return NewBasicBatch(d), nil +} + +func (d *MapDatastore) Close() error { + return nil +} + +// NullDatastore stores nothing, but conforms to the API. +// Useful to test with. +type NullDatastore struct { +} + +// NewNullDatastore constructs a null datastoe +func NewNullDatastore() *NullDatastore { + return &NullDatastore{} +} + +// Put implements Datastore.Put +func (d *NullDatastore) Put(key Key, value []byte) (err error) { + return nil +} + +// Sync implements Datastore.Sync +func (d *NullDatastore) Sync(prefix Key) error { + return nil +} + +// Get implements Datastore.Get +func (d *NullDatastore) Get(key Key) (value []byte, err error) { + return nil, ErrNotFound +} + +// Has implements Datastore.Has +func (d *NullDatastore) Has(key Key) (exists bool, err error) { + return false, nil +} + +// Has implements Datastore.GetSize +func (d *NullDatastore) GetSize(key Key) (size int, err error) { + return -1, ErrNotFound +} + +// Delete implements Datastore.Delete +func (d *NullDatastore) Delete(key Key) (err error) { + return nil +} + +// Query implements Datastore.Query +func (d *NullDatastore) Query(q dsq.Query) (dsq.Results, error) { + return dsq.ResultsWithEntries(q, nil), nil +} + +func (d *NullDatastore) Batch() (Batch, error) { + return NewBasicBatch(d), nil +} + +func (d *NullDatastore) Close() error { + return nil +} + +// LogDatastore logs all accesses through the datastore. +type LogDatastore struct { + Name string + child Datastore +} + +// Shim is a datastore which has a child. +type Shim interface { + Datastore + + Children() []Datastore +} + +// NewLogDatastore constructs a log datastore. +func NewLogDatastore(ds Datastore, name string) *LogDatastore { + if len(name) < 1 { + name = "LogDatastore" + } + return &LogDatastore{Name: name, child: ds} +} + +// Children implements Shim +func (d *LogDatastore) Children() []Datastore { + return []Datastore{d.child} +} + +// Put implements Datastore.Put +func (d *LogDatastore) Put(key Key, value []byte) (err error) { + log.Printf("%s: Put %s\n", d.Name, key) + // log.Printf("%s: Put %s ```%s```", d.Name, key, value) + return d.child.Put(key, value) +} + +// Sync implements Datastore.Sync +func (d *LogDatastore) Sync(prefix Key) error { + log.Printf("%s: Sync %s\n", d.Name, prefix) + return d.child.Sync(prefix) +} + +// Get implements Datastore.Get +func (d *LogDatastore) Get(key Key) (value []byte, err error) { + log.Printf("%s: Get %s\n", d.Name, key) + return d.child.Get(key) +} + +// Has implements Datastore.Has +func (d *LogDatastore) Has(key Key) (exists bool, err error) { + log.Printf("%s: Has %s\n", d.Name, key) + return d.child.Has(key) +} + +// GetSize implements Datastore.GetSize +func (d *LogDatastore) GetSize(key Key) (size int, err error) { + log.Printf("%s: GetSize %s\n", d.Name, key) + return d.child.GetSize(key) +} + +// Delete implements Datastore.Delete +func (d *LogDatastore) Delete(key Key) (err error) { + log.Printf("%s: Delete %s\n", d.Name, key) + return d.child.Delete(key) +} + +// DiskUsage implements the PersistentDatastore interface. +func (d *LogDatastore) DiskUsage() (uint64, error) { + log.Printf("%s: DiskUsage\n", d.Name) + return DiskUsage(d.child) +} + +// Query implements Datastore.Query +func (d *LogDatastore) Query(q dsq.Query) (dsq.Results, error) { + log.Printf("%s: Query\n", d.Name) + log.Printf("%s: q.Prefix: %s\n", d.Name, q.Prefix) + log.Printf("%s: q.KeysOnly: %v\n", d.Name, q.KeysOnly) + log.Printf("%s: q.Filters: %d\n", d.Name, len(q.Filters)) + log.Printf("%s: q.Orders: %d\n", d.Name, len(q.Orders)) + log.Printf("%s: q.Offset: %d\n", d.Name, q.Offset) + + return d.child.Query(q) +} + +// LogBatch logs all accesses through the batch. +type LogBatch struct { + Name string + child Batch +} + +func (d *LogDatastore) Batch() (Batch, error) { + log.Printf("%s: Batch\n", d.Name) + if bds, ok := d.child.(Batching); ok { + b, err := bds.Batch() + + if err != nil { + return nil, err + } + return &LogBatch{ + Name: d.Name, + child: b, + }, nil + } + return nil, ErrBatchUnsupported +} + +// Put implements Batch.Put +func (d *LogBatch) Put(key Key, value []byte) (err error) { + log.Printf("%s: BatchPut %s\n", d.Name, key) + // log.Printf("%s: Put %s ```%s```", d.Name, key, value) + return d.child.Put(key, value) +} + +// Delete implements Batch.Delete +func (d *LogBatch) Delete(key Key) (err error) { + log.Printf("%s: BatchDelete %s\n", d.Name, key) + return d.child.Delete(key) +} + +// Commit implements Batch.Commit +func (d *LogBatch) Commit() (err error) { + log.Printf("%s: BatchCommit\n", d.Name) + return d.child.Commit() +} + +func (d *LogDatastore) Close() error { + log.Printf("%s: Close\n", d.Name) + return d.child.Close() +} + +func (d *LogDatastore) Check() error { + if c, ok := d.child.(CheckedDatastore); ok { + return c.Check() + } + return nil +} + +func (d *LogDatastore) Scrub() error { + if c, ok := d.child.(ScrubbedDatastore); ok { + return c.Scrub() + } + return nil +} + +func (d *LogDatastore) CollectGarbage() error { + if c, ok := d.child.(GCDatastore); ok { + return c.CollectGarbage() + } + return nil +} diff --git a/vendor/github.com/ipfs/go-datastore/batch.go b/vendor/github.com/ipfs/go-datastore/batch.go new file mode 100644 index 0000000000..41e23ffe44 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/batch.go @@ -0,0 +1,47 @@ +package datastore + +type op struct { + delete bool + value []byte +} + +// basicBatch implements the transaction interface for datastores who do +// not have any sort of underlying transactional support +type basicBatch struct { + ops map[Key]op + + target Datastore +} + +func NewBasicBatch(ds Datastore) Batch { + return &basicBatch{ + ops: make(map[Key]op), + target: ds, + } +} + +func (bt *basicBatch) Put(key Key, val []byte) error { + bt.ops[key] = op{value: val} + return nil +} + +func (bt *basicBatch) Delete(key Key) error { + bt.ops[key] = op{delete: true} + return nil +} + +func (bt *basicBatch) Commit() error { + var err error + for k, op := range bt.ops { + if op.delete { + err = bt.target.Delete(k) + } else { + err = bt.target.Put(k, op.value) + } + if err != nil { + break + } + } + + return err +} diff --git a/vendor/github.com/ipfs/go-datastore/datastore.go b/vendor/github.com/ipfs/go-datastore/datastore.go new file mode 100644 index 0000000000..04ca726c4a --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/datastore.go @@ -0,0 +1,251 @@ +package datastore + +import ( + "errors" + "io" + "time" + + query "github.com/ipfs/go-datastore/query" +) + +/* +Datastore represents storage for any key-value pair. + +Datastores are general enough to be backed by all kinds of different storage: +in-memory caches, databases, a remote datastore, flat files on disk, etc. + +The general idea is to wrap a more complicated storage facility in a simple, +uniform interface, keeping the freedom of using the right tools for the job. +In particular, a Datastore can aggregate other datastores in interesting ways, +like sharded (to distribute load) or tiered access (caches before databases). + +While Datastores should be written general enough to accept all sorts of +values, some implementations will undoubtedly have to be specific (e.g. SQL +databases where fields should be decomposed into columns), particularly to +support queries efficiently. Moreover, certain datastores may enforce certain +types of values (e.g. requiring an io.Reader, a specific struct, etc) or +serialization formats (JSON, Protobufs, etc). + +IMPORTANT: No Datastore should ever Panic! This is a cross-module interface, +and thus it should behave predictably and handle exceptional conditions with +proper error reporting. Thus, all Datastore calls may return errors, which +should be checked by callers. +*/ +type Datastore interface { + Read + Write + // Sync guarantees that any Put or Delete calls under prefix that returned + // before Sync(prefix) was called will be observed after Sync(prefix) + // returns, even if the program crashes. If Put/Delete operations already + // satisfy these requirements then Sync may be a no-op. + // + // If the prefix fails to Sync this method returns an error. + Sync(prefix Key) error + io.Closer +} + +// Write is the write-side of the Datastore interface. +type Write interface { + // Put stores the object `value` named by `key`. + // + // The generalized Datastore interface does not impose a value type, + // allowing various datastore middleware implementations (which do not + // handle the values directly) to be composed together. + // + // Ultimately, the lowest-level datastore will need to do some value checking + // or risk getting incorrect values. It may also be useful to expose a more + // type-safe interface to your application, and do the checking up-front. + Put(key Key, value []byte) error + + // Delete removes the value for given `key`. If the key is not in the + // datastore, this method returns no error. + Delete(key Key) error +} + +// Read is the read-side of the Datastore interface. +type Read interface { + // Get retrieves the object `value` named by `key`. + // Get will return ErrNotFound if the key is not mapped to a value. + Get(key Key) (value []byte, err error) + + // Has returns whether the `key` is mapped to a `value`. + // In some contexts, it may be much cheaper only to check for existence of + // a value, rather than retrieving the value itself. (e.g. HTTP HEAD). + // The default implementation is found in `GetBackedHas`. + Has(key Key) (exists bool, err error) + + // GetSize returns the size of the `value` named by `key`. + // In some contexts, it may be much cheaper to only get the size of the + // value rather than retrieving the value itself. + GetSize(key Key) (size int, err error) + + // Query searches the datastore and returns a query result. This function + // may return before the query actually runs. To wait for the query: + // + // result, _ := ds.Query(q) + // + // // use the channel interface; result may come in at different times + // for entry := range result.Next() { ... } + // + // // or wait for the query to be completely done + // entries, _ := result.Rest() + // for entry := range entries { ... } + // + Query(q query.Query) (query.Results, error) +} + +// Batching datastores support deferred, grouped updates to the database. +// `Batch`es do NOT have transactional semantics: updates to the underlying +// datastore are not guaranteed to occur in the same iota of time. Similarly, +// batched updates will not be flushed to the underlying datastore until +// `Commit` has been called. `Txn`s from a `TxnDatastore` have all the +// capabilities of a `Batch`, but the reverse is NOT true. +type Batching interface { + Datastore + + Batch() (Batch, error) +} + +// ErrBatchUnsupported is returned if the by Batch if the Datastore doesn't +// actually support batching. +var ErrBatchUnsupported = errors.New("this datastore does not support batching") + +// CheckedDatastore is an interface that should be implemented by datastores +// which may need checking on-disk data integrity. +type CheckedDatastore interface { + Datastore + + Check() error +} + +// ScrubbedDatastore is an interface that should be implemented by datastores +// which want to provide a mechanism to check data integrity and/or +// error correction. +type ScrubbedDatastore interface { + Datastore + + Scrub() error +} + +// GCDatastore is an interface that should be implemented by datastores which +// don't free disk space by just removing data from them. +type GCDatastore interface { + Datastore + + CollectGarbage() error +} + +// PersistentDatastore is an interface that should be implemented by datastores +// which can report disk usage. +type PersistentDatastore interface { + Datastore + + // DiskUsage returns the space used by a datastore, in bytes. + DiskUsage() (uint64, error) +} + +// DiskUsage checks if a Datastore is a +// PersistentDatastore and returns its DiskUsage(), +// otherwise returns 0. +func DiskUsage(d Datastore) (uint64, error) { + persDs, ok := d.(PersistentDatastore) + if !ok { + return 0, nil + } + return persDs.DiskUsage() +} + +// TTLDatastore is an interface that should be implemented by datastores that +// support expiring entries. +type TTLDatastore interface { + Datastore + TTL +} + +// TTL encapulates the methods that deal with entries with time-to-live. +type TTL interface { + PutWithTTL(key Key, value []byte, ttl time.Duration) error + SetTTL(key Key, ttl time.Duration) error + GetExpiration(key Key) (time.Time, error) +} + +// Txn extends the Datastore type. Txns allow users to batch queries and +// mutations to the Datastore into atomic groups, or transactions. Actions +// performed on a transaction will not take hold until a successful call to +// Commit has been made. Likewise, transactions can be aborted by calling +// Discard before a successful Commit has been made. +type Txn interface { + Read + Write + + // Commit finalizes a transaction, attempting to commit it to the Datastore. + // May return an error if the transaction has gone stale. The presence of an + // error is an indication that the data was not committed to the Datastore. + Commit() error + // Discard throws away changes recorded in a transaction without committing + // them to the underlying Datastore. Any calls made to Discard after Commit + // has been successfully called will have no effect on the transaction and + // state of the Datastore, making it safe to defer. + Discard() +} + +// TxnDatastore is an interface that should be implemented by datastores that +// support transactions. +type TxnDatastore interface { + Datastore + + NewTransaction(readOnly bool) (Txn, error) +} + +// Errors + +type dsError struct { + error + isNotFound bool +} + +func (e *dsError) NotFound() bool { + return e.isNotFound +} + +// ErrNotFound is returned by Get and GetSize when a datastore does not map the +// given key to a value. +var ErrNotFound error = &dsError{error: errors.New("datastore: key not found"), isNotFound: true} + +// GetBackedHas provides a default Datastore.Has implementation. +// It exists so Datastore.Has implementations can use it, like so: +// +// func (*d SomeDatastore) Has(key Key) (exists bool, err error) { +// return GetBackedHas(d, key) +// } +func GetBackedHas(ds Read, key Key) (bool, error) { + _, err := ds.Get(key) + switch err { + case nil: + return true, nil + case ErrNotFound: + return false, nil + default: + return false, err + } +} + +// GetBackedSize provides a default Datastore.GetSize implementation. +// It exists so Datastore.GetSize implementations can use it, like so: +// +// func (*d SomeDatastore) GetSize(key Key) (size int, err error) { +// return GetBackedSize(d, key) +// } +func GetBackedSize(ds Read, key Key) (int, error) { + value, err := ds.Get(key) + if err == nil { + return len(value), nil + } + return -1, err +} + +type Batch interface { + Write + + Commit() error +} diff --git a/vendor/github.com/ipfs/go-datastore/go.mod b/vendor/github.com/ipfs/go-datastore/go.mod new file mode 100644 index 0000000000..709a9c1268 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/go.mod @@ -0,0 +1,12 @@ +module github.com/ipfs/go-datastore + +require ( + github.com/google/uuid v1.1.1 + github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8 + github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 + github.com/kr/pretty v0.1.0 // indirect + golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 +) + +go 1.12 diff --git a/vendor/github.com/ipfs/go-datastore/go.sum b/vendor/github.com/ipfs/go-datastore/go.sum new file mode 100644 index 0000000000..d1289721f2 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/go.sum @@ -0,0 +1,16 @@ +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8 h1:NAviDvJ0WXgD+yiL2Rj35AmnfgI11+pHXbdciD917U0= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/ipfs/go-datastore/key.go b/vendor/github.com/ipfs/go-datastore/key.go new file mode 100644 index 0000000000..42cea30844 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/key.go @@ -0,0 +1,309 @@ +package datastore + +import ( + "encoding/json" + "path" + "strings" + + dsq "github.com/ipfs/go-datastore/query" + + "github.com/google/uuid" +) + +/* +A Key represents the unique identifier of an object. +Our Key scheme is inspired by file systems and Google App Engine key model. + +Keys are meant to be unique across a system. Keys are hierarchical, +incorporating more and more specific namespaces. Thus keys can be deemed +'children' or 'ancestors' of other keys:: + + Key("/Comedy") + Key("/Comedy/MontyPython") + +Also, every namespace can be parametrized to embed relevant object +information. For example, the Key `name` (most specific namespace) could +include the object type:: + + Key("/Comedy/MontyPython/Actor:JohnCleese") + Key("/Comedy/MontyPython/Sketch:CheeseShop") + Key("/Comedy/MontyPython/Sketch:CheeseShop/Character:Mousebender") + +*/ +type Key struct { + string +} + +// NewKey constructs a key from string. it will clean the value. +func NewKey(s string) Key { + k := Key{s} + k.Clean() + return k +} + +// RawKey creates a new Key without safety checking the input. Use with care. +func RawKey(s string) Key { + // accept an empty string and fix it to avoid special cases + // elsewhere + if len(s) == 0 { + return Key{"/"} + } + + // perform a quick sanity check that the key is in the correct + // format, if it is not then it is a programmer error and it is + // okay to panic + if len(s) == 0 || s[0] != '/' || (len(s) > 1 && s[len(s)-1] == '/') { + panic("invalid datastore key: " + s) + } + + return Key{s} +} + +// KeyWithNamespaces constructs a key out of a namespace slice. +func KeyWithNamespaces(ns []string) Key { + return NewKey(strings.Join(ns, "/")) +} + +// Clean up a Key, using path.Clean. +func (k *Key) Clean() { + switch { + case len(k.string) == 0: + k.string = "/" + case k.string[0] == '/': + k.string = path.Clean(k.string) + default: + k.string = path.Clean("/" + k.string) + } +} + +// Strings is the string value of Key +func (k Key) String() string { + return k.string +} + +// Bytes returns the string value of Key as a []byte +func (k Key) Bytes() []byte { + return []byte(k.string) +} + +// Equal checks equality of two keys +func (k Key) Equal(k2 Key) bool { + return k.string == k2.string +} + +// Less checks whether this key is sorted lower than another. +func (k Key) Less(k2 Key) bool { + list1 := k.List() + list2 := k2.List() + for i, c1 := range list1 { + if len(list2) < (i + 1) { + return false + } + + c2 := list2[i] + if c1 < c2 { + return true + } else if c1 > c2 { + return false + } + // c1 == c2, continue + } + + // list1 is shorter or exactly the same. + return len(list1) < len(list2) +} + +// List returns the `list` representation of this Key. +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").List() +// ["Comedy", "MontyPythong", "Actor:JohnCleese"] +func (k Key) List() []string { + return strings.Split(k.string, "/")[1:] +} + +// Reverse returns the reverse of this Key. +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Reverse() +// NewKey("/Actor:JohnCleese/MontyPython/Comedy") +func (k Key) Reverse() Key { + l := k.List() + r := make([]string, len(l)) + for i, e := range l { + r[len(l)-i-1] = e + } + return KeyWithNamespaces(r) +} + +// Namespaces returns the `namespaces` making up this Key. +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Namespaces() +// ["Comedy", "MontyPython", "Actor:JohnCleese"] +func (k Key) Namespaces() []string { + return k.List() +} + +// BaseNamespace returns the "base" namespace of this key (path.Base(filename)) +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").BaseNamespace() +// "Actor:JohnCleese" +func (k Key) BaseNamespace() string { + n := k.Namespaces() + return n[len(n)-1] +} + +// Type returns the "type" of this key (value of last namespace). +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Type() +// "Actor" +func (k Key) Type() string { + return NamespaceType(k.BaseNamespace()) +} + +// Name returns the "name" of this key (field of last namespace). +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Name() +// "JohnCleese" +func (k Key) Name() string { + return NamespaceValue(k.BaseNamespace()) +} + +// Instance returns an "instance" of this type key (appends value to namespace). +// NewKey("/Comedy/MontyPython/Actor").Instance("JohnClesse") +// NewKey("/Comedy/MontyPython/Actor:JohnCleese") +func (k Key) Instance(s string) Key { + return NewKey(k.string + ":" + s) +} + +// Path returns the "path" of this key (parent + type). +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Path() +// NewKey("/Comedy/MontyPython/Actor") +func (k Key) Path() Key { + s := k.Parent().string + "/" + NamespaceType(k.BaseNamespace()) + return NewKey(s) +} + +// Parent returns the `parent` Key of this Key. +// NewKey("/Comedy/MontyPython/Actor:JohnCleese").Parent() +// NewKey("/Comedy/MontyPython") +func (k Key) Parent() Key { + n := k.List() + if len(n) == 1 { + return RawKey("/") + } + return NewKey(strings.Join(n[:len(n)-1], "/")) +} + +// Child returns the `child` Key of this Key. +// NewKey("/Comedy/MontyPython").Child(NewKey("Actor:JohnCleese")) +// NewKey("/Comedy/MontyPython/Actor:JohnCleese") +func (k Key) Child(k2 Key) Key { + switch { + case k.string == "/": + return k2 + case k2.string == "/": + return k + default: + return RawKey(k.string + k2.string) + } +} + +// ChildString returns the `child` Key of this Key -- string helper. +// NewKey("/Comedy/MontyPython").ChildString("Actor:JohnCleese") +// NewKey("/Comedy/MontyPython/Actor:JohnCleese") +func (k Key) ChildString(s string) Key { + return NewKey(k.string + "/" + s) +} + +// IsAncestorOf returns whether this key is a prefix of `other` +// NewKey("/Comedy").IsAncestorOf("/Comedy/MontyPython") +// true +func (k Key) IsAncestorOf(other Key) bool { + // equivalent to HasPrefix(other, k.string + "/") + + if len(other.string) <= len(k.string) { + // We're not long enough to be a child. + return false + } + + if k.string == "/" { + // We're the root and the other key is longer. + return true + } + + // "other" starts with /k.string/ + return other.string[len(k.string)] == '/' && other.string[:len(k.string)] == k.string +} + +// IsDescendantOf returns whether this key contains another as a prefix. +// NewKey("/Comedy/MontyPython").IsDescendantOf("/Comedy") +// true +func (k Key) IsDescendantOf(other Key) bool { + return other.IsAncestorOf(k) +} + +// IsTopLevel returns whether this key has only one namespace. +func (k Key) IsTopLevel() bool { + return len(k.List()) == 1 +} + +// MarshalJSON implements the json.Marshaler interface, +// keys are represented as JSON strings +func (k Key) MarshalJSON() ([]byte, error) { + return json.Marshal(k.String()) +} + +// UnmarshalJSON implements the json.Unmarshaler interface, +// keys will parse any value specified as a key to a string +func (k *Key) UnmarshalJSON(data []byte) error { + var key string + if err := json.Unmarshal(data, &key); err != nil { + return err + } + *k = NewKey(key) + return nil +} + +// RandomKey returns a randomly (uuid) generated key. +// RandomKey() +// NewKey("/f98719ea086343f7b71f32ea9d9d521d") +func RandomKey() Key { + return NewKey(strings.Replace(uuid.New().String(), "-", "", -1)) +} + +/* +A Key Namespace is like a path element. +A namespace can optionally include a type (delimited by ':') + + > NamespaceValue("Song:PhilosopherSong") + PhilosopherSong + > NamespaceType("Song:PhilosopherSong") + Song + > NamespaceType("Music:Song:PhilosopherSong") + Music:Song +*/ + +// NamespaceType is the first component of a namespace. `foo` in `foo:bar` +func NamespaceType(namespace string) string { + parts := strings.Split(namespace, ":") + if len(parts) < 2 { + return "" + } + return strings.Join(parts[0:len(parts)-1], ":") +} + +// NamespaceValue returns the last component of a namespace. `baz` in `f:b:baz` +func NamespaceValue(namespace string) string { + parts := strings.Split(namespace, ":") + return parts[len(parts)-1] +} + +// KeySlice attaches the methods of sort.Interface to []Key, +// sorting in increasing order. +type KeySlice []Key + +func (p KeySlice) Len() int { return len(p) } +func (p KeySlice) Less(i, j int) bool { return p[i].Less(p[j]) } +func (p KeySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// EntryKeys +func EntryKeys(e []dsq.Entry) []Key { + ks := make([]Key, len(e)) + for i, e := range e { + ks[i] = NewKey(e.Key) + } + return ks +} diff --git a/vendor/github.com/ipfs/go-datastore/keytransform/doc.go b/vendor/github.com/ipfs/go-datastore/keytransform/doc.go new file mode 100644 index 0000000000..b389dcfaf3 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/keytransform/doc.go @@ -0,0 +1,25 @@ +// Package keytransform introduces a Datastore Shim that transforms keys before +// passing them to its child. It can be used to manipulate what keys look like +// to the user, for example namespacing keys, reversing them, etc. +// +// Use the Wrap function to wrap a datastore with any KeyTransform. +// A KeyTransform is simply an interface with two functions, a conversion and +// its inverse. For example: +// +// import ( +// ktds "github.com/ipfs/go-datastore/keytransform" +// ds "github.com/ipfs/go-datastore" +// ) +// +// func reverseKey(k ds.Key) ds.Key { +// return k.Reverse() +// } +// +// func invertKeys(d ds.Datastore) { +// return ktds.Wrap(d, &ktds.Pair{ +// Convert: reverseKey, +// Invert: reverseKey, // reverse is its own inverse. +// }) +// } +// +package keytransform diff --git a/vendor/github.com/ipfs/go-datastore/keytransform/interface.go b/vendor/github.com/ipfs/go-datastore/keytransform/interface.go new file mode 100644 index 0000000000..4f07967a39 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/keytransform/interface.go @@ -0,0 +1,13 @@ +package keytransform + +import ds "github.com/ipfs/go-datastore" + +// KeyMapping is a function that maps one key to annother +type KeyMapping func(ds.Key) ds.Key + +// KeyTransform is an object with a pair of functions for (invertibly) +// transforming keys +type KeyTransform interface { + ConvertKey(ds.Key) ds.Key + InvertKey(ds.Key) ds.Key +} diff --git a/vendor/github.com/ipfs/go-datastore/keytransform/keytransform.go b/vendor/github.com/ipfs/go-datastore/keytransform/keytransform.go new file mode 100644 index 0000000000..cd03487ca0 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/keytransform/keytransform.go @@ -0,0 +1,260 @@ +package keytransform + +import ( + ds "github.com/ipfs/go-datastore" + dsq "github.com/ipfs/go-datastore/query" +) + +// Wrap wraps a given datastore with a KeyTransform function. +// The resulting wrapped datastore will use the transform on all Datastore +// operations. +func Wrap(child ds.Datastore, t KeyTransform) *Datastore { + if t == nil { + panic("t (KeyTransform) is nil") + } + + if child == nil { + panic("child (ds.Datastore) is nil") + } + + return &Datastore{child: child, KeyTransform: t} +} + +// Datastore keeps a KeyTransform function +type Datastore struct { + child ds.Datastore + + KeyTransform +} + +// Children implements ds.Shim +func (d *Datastore) Children() []ds.Datastore { + return []ds.Datastore{d.child} +} + +// Put stores the given value, transforming the key first. +func (d *Datastore) Put(key ds.Key, value []byte) (err error) { + return d.child.Put(d.ConvertKey(key), value) +} + +// Sync implements Datastore.Sync +func (d *Datastore) Sync(prefix ds.Key) error { + return d.child.Sync(d.ConvertKey(prefix)) +} + +// Get returns the value for given key, transforming the key first. +func (d *Datastore) Get(key ds.Key) (value []byte, err error) { + return d.child.Get(d.ConvertKey(key)) +} + +// Has returns whether the datastore has a value for a given key, transforming +// the key first. +func (d *Datastore) Has(key ds.Key) (exists bool, err error) { + return d.child.Has(d.ConvertKey(key)) +} + +// GetSize returns the size of the value named by the given key, transforming +// the key first. +func (d *Datastore) GetSize(key ds.Key) (size int, err error) { + return d.child.GetSize(d.ConvertKey(key)) +} + +// Delete removes the value for given key +func (d *Datastore) Delete(key ds.Key) (err error) { + return d.child.Delete(d.ConvertKey(key)) +} + +// Query implements Query, inverting keys on the way back out. +func (d *Datastore) Query(q dsq.Query) (dsq.Results, error) { + nq, cq := d.prepareQuery(q) + + cqr, err := d.child.Query(cq) + if err != nil { + return nil, err + } + + qr := dsq.ResultsFromIterator(q, dsq.Iterator{ + Next: func() (dsq.Result, bool) { + r, ok := cqr.NextSync() + if !ok { + return r, false + } + if r.Error == nil { + r.Entry.Key = d.InvertKey(ds.RawKey(r.Entry.Key)).String() + } + return r, true + }, + Close: func() error { + return cqr.Close() + }, + }) + return dsq.NaiveQueryApply(nq, qr), nil +} + +// Split the query into a child query and a naive query. That way, we can make +// the child datastore do as much work as possible. +func (d *Datastore) prepareQuery(q dsq.Query) (naive, child dsq.Query) { + + // First, put everything in the child query. Then, start taking things + // out. + child = q + + // Always let the child handle the key prefix. + child.Prefix = d.ConvertKey(ds.NewKey(child.Prefix)).String() + + // Check if the key transform is order-preserving so we can use the + // child datastore's built-in ordering. + orderPreserving := false + switch d.KeyTransform.(type) { + case PrefixTransform, *PrefixTransform: + orderPreserving = true + } + + // Try to let the child handle ordering. +orders: + for i, o := range child.Orders { + switch o.(type) { + case dsq.OrderByValue, *dsq.OrderByValue, + dsq.OrderByValueDescending, *dsq.OrderByValueDescending: + // Key doesn't matter. + continue + case dsq.OrderByKey, *dsq.OrderByKey, + dsq.OrderByKeyDescending, *dsq.OrderByKeyDescending: + // if the key transform preserves order, we can delegate + // to the child datastore. + if orderPreserving { + // When sorting, we compare with the first + // Order, then, if equal, we compare with the + // second Order, etc. However, keys are _unique_ + // so we'll never apply any additional orders + // after ordering by key. + child.Orders = child.Orders[:i+1] + break orders + } + } + + // Can't handle this order under transform, punt it to a naive + // ordering. + naive.Orders = q.Orders + child.Orders = nil + naive.Offset = q.Offset + child.Offset = 0 + naive.Limit = q.Limit + child.Limit = 0 + break + } + + // Try to let the child handle the filters. + + // don't modify the original filters. + child.Filters = append([]dsq.Filter(nil), child.Filters...) + + for i, f := range child.Filters { + switch f := f.(type) { + case dsq.FilterValueCompare, *dsq.FilterValueCompare: + continue + case dsq.FilterKeyCompare: + child.Filters[i] = dsq.FilterKeyCompare{ + Op: f.Op, + Key: d.ConvertKey(ds.NewKey(f.Key)).String(), + } + continue + case *dsq.FilterKeyCompare: + child.Filters[i] = &dsq.FilterKeyCompare{ + Op: f.Op, + Key: d.ConvertKey(ds.NewKey(f.Key)).String(), + } + continue + case dsq.FilterKeyPrefix: + child.Filters[i] = dsq.FilterKeyPrefix{ + Prefix: d.ConvertKey(ds.NewKey(f.Prefix)).String(), + } + continue + case *dsq.FilterKeyPrefix: + child.Filters[i] = &dsq.FilterKeyPrefix{ + Prefix: d.ConvertKey(ds.NewKey(f.Prefix)).String(), + } + continue + } + + // Not a known filter, defer to the naive implementation. + naive.Filters = q.Filters + child.Filters = nil + naive.Offset = q.Offset + child.Offset = 0 + naive.Limit = q.Limit + child.Limit = 0 + break + } + return +} + +func (d *Datastore) Close() error { + return d.child.Close() +} + +// DiskUsage implements the PersistentDatastore interface. +func (d *Datastore) DiskUsage() (uint64, error) { + return ds.DiskUsage(d.child) +} + +func (d *Datastore) Batch() (ds.Batch, error) { + bds, ok := d.child.(ds.Batching) + if !ok { + return nil, ds.ErrBatchUnsupported + } + + childbatch, err := bds.Batch() + if err != nil { + return nil, err + } + return &transformBatch{ + dst: childbatch, + f: d.ConvertKey, + }, nil +} + +type transformBatch struct { + dst ds.Batch + + f KeyMapping +} + +func (t *transformBatch) Put(key ds.Key, val []byte) error { + return t.dst.Put(t.f(key), val) +} + +func (t *transformBatch) Delete(key ds.Key) error { + return t.dst.Delete(t.f(key)) +} + +func (t *transformBatch) Commit() error { + return t.dst.Commit() +} + +func (d *Datastore) Check() error { + if c, ok := d.child.(ds.CheckedDatastore); ok { + return c.Check() + } + return nil +} + +func (d *Datastore) Scrub() error { + if c, ok := d.child.(ds.ScrubbedDatastore); ok { + return c.Scrub() + } + return nil +} + +func (d *Datastore) CollectGarbage() error { + if c, ok := d.child.(ds.GCDatastore); ok { + return c.CollectGarbage() + } + return nil +} + +var _ ds.Datastore = (*Datastore)(nil) +var _ ds.GCDatastore = (*Datastore)(nil) +var _ ds.Batching = (*Datastore)(nil) +var _ ds.PersistentDatastore = (*Datastore)(nil) +var _ ds.ScrubbedDatastore = (*Datastore)(nil) diff --git a/vendor/github.com/ipfs/go-datastore/keytransform/transforms.go b/vendor/github.com/ipfs/go-datastore/keytransform/transforms.go new file mode 100644 index 0000000000..cc39897e19 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/keytransform/transforms.go @@ -0,0 +1,49 @@ +package keytransform + +import ds "github.com/ipfs/go-datastore" + +// Pair is a convince struct for constructing a key transform. +type Pair struct { + Convert KeyMapping + Invert KeyMapping +} + +func (t *Pair) ConvertKey(k ds.Key) ds.Key { + return t.Convert(k) +} + +func (t *Pair) InvertKey(k ds.Key) ds.Key { + return t.Invert(k) +} + +var _ KeyTransform = (*Pair)(nil) + +// PrefixTransform constructs a KeyTransform with a pair of functions that +// add or remove the given prefix key. +// +// Warning: will panic if prefix not found when it should be there. This is +// to avoid insidious data inconsistency errors. +type PrefixTransform struct { + Prefix ds.Key +} + +// ConvertKey adds the prefix. +func (p PrefixTransform) ConvertKey(k ds.Key) ds.Key { + return p.Prefix.Child(k) +} + +// InvertKey removes the prefix. panics if prefix not found. +func (p PrefixTransform) InvertKey(k ds.Key) ds.Key { + if p.Prefix.String() == "/" { + return k + } + + if !p.Prefix.IsAncestorOf(k) { + panic("expected prefix not found") + } + + s := k.String()[len(p.Prefix.String()):] + return ds.RawKey(s) +} + +var _ KeyTransform = (*PrefixTransform)(nil) diff --git a/vendor/github.com/ipfs/go-datastore/namespace/doc.go b/vendor/github.com/ipfs/go-datastore/namespace/doc.go new file mode 100644 index 0000000000..9ff9a8ca36 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/namespace/doc.go @@ -0,0 +1,24 @@ +// Package namespace introduces a namespace Datastore Shim, which basically +// mounts the entire child datastore under a prefix. +// +// Use the Wrap function to wrap a datastore with any Key prefix. For example: +// +// import ( +// "fmt" +// +// ds "github.com/ipfs/go-datastore" +// nsds "github.com/ipfs/go-datastore/namespace" +// ) +// +// func main() { +// mp := ds.NewMapDatastore() +// ns := nsds.Wrap(mp, ds.NewKey("/foo/bar")) +// +// // in the Namespace Datastore: +// ns.Put(ds.NewKey("/beep"), "boop") +// v2, _ := ns.Get(ds.NewKey("/beep")) // v2 == "boop" +// +// // and, in the underlying MapDatastore: +// v3, _ := mp.Get(ds.NewKey("/foo/bar/beep")) // v3 == "boop" +// } +package namespace diff --git a/vendor/github.com/ipfs/go-datastore/namespace/namespace.go b/vendor/github.com/ipfs/go-datastore/namespace/namespace.go new file mode 100644 index 0000000000..1913fb790c --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/namespace/namespace.go @@ -0,0 +1,26 @@ +package namespace + +import ( + ds "github.com/ipfs/go-datastore" + ktds "github.com/ipfs/go-datastore/keytransform" +) + +// PrefixTransform constructs a KeyTransform with a pair of functions that +// add or remove the given prefix key. +// +// Warning: will panic if prefix not found when it should be there. This is +// to avoid insidious data inconsistency errors. +// +// DEPRECATED: Use ktds.PrefixTransform directly. +func PrefixTransform(prefix ds.Key) ktds.PrefixTransform { + return ktds.PrefixTransform{Prefix: prefix} +} + +// Wrap wraps a given datastore with a key-prefix. +func Wrap(child ds.Datastore, prefix ds.Key) *ktds.Datastore { + if child == nil { + panic("child (ds.Datastore) is nil") + } + + return ktds.Wrap(child, PrefixTransform(prefix)) +} diff --git a/vendor/github.com/ipfs/go-datastore/query/filter.go b/vendor/github.com/ipfs/go-datastore/query/filter.go new file mode 100644 index 0000000000..1935c4888a --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/query/filter.go @@ -0,0 +1,102 @@ +package query + +import ( + "bytes" + "fmt" + "strings" +) + +// Filter is an object that tests ResultEntries +type Filter interface { + // Filter returns whether an entry passes the filter + Filter(e Entry) bool +} + +// Op is a comparison operator +type Op string + +var ( + Equal = Op("==") + NotEqual = Op("!=") + GreaterThan = Op(">") + GreaterThanOrEqual = Op(">=") + LessThan = Op("<") + LessThanOrEqual = Op("<=") +) + +// FilterValueCompare is used to signal to datastores they +// should apply internal comparisons. unfortunately, there +// is no way to apply comparisons* to interface{} types in +// Go, so if the datastore doesnt have a special way to +// handle these comparisons, you must provided the +// TypedFilter to actually do filtering. +// +// [*] other than == and !=, which use reflect.DeepEqual. +type FilterValueCompare struct { + Op Op + Value []byte +} + +func (f FilterValueCompare) Filter(e Entry) bool { + cmp := bytes.Compare(e.Value, f.Value) + switch f.Op { + case Equal: + return cmp == 0 + case NotEqual: + return cmp != 0 + case LessThan: + return cmp < 0 + case LessThanOrEqual: + return cmp <= 0 + case GreaterThan: + return cmp > 0 + case GreaterThanOrEqual: + return cmp >= 0 + default: + panic(fmt.Errorf("unknown operation: %s", f.Op)) + } +} + +func (f FilterValueCompare) String() string { + return fmt.Sprintf("VALUE %s %q", f.Op, string(f.Value)) +} + +type FilterKeyCompare struct { + Op Op + Key string +} + +func (f FilterKeyCompare) Filter(e Entry) bool { + switch f.Op { + case Equal: + return e.Key == f.Key + case NotEqual: + return e.Key != f.Key + case GreaterThan: + return e.Key > f.Key + case GreaterThanOrEqual: + return e.Key >= f.Key + case LessThan: + return e.Key < f.Key + case LessThanOrEqual: + return e.Key <= f.Key + default: + panic(fmt.Errorf("unknown op '%s'", f.Op)) + } +} + +func (f FilterKeyCompare) String() string { + return fmt.Sprintf("KEY %s %q", f.Op, f.Key) +} + +type FilterKeyPrefix struct { + Prefix string +} + +func (f FilterKeyPrefix) Filter(e Entry) bool { + return strings.HasPrefix(e.Key, f.Prefix) +} + +func (f FilterKeyPrefix) String() string { + return fmt.Sprintf("PREFIX(%q)", f.Prefix) +} diff --git a/vendor/github.com/ipfs/go-datastore/query/order.go b/vendor/github.com/ipfs/go-datastore/query/order.go new file mode 100644 index 0000000000..19931557e4 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/query/order.go @@ -0,0 +1,94 @@ +package query + +import ( + "bytes" + "sort" + "strings" +) + +// Order is an object used to order objects +type Order interface { + Compare(a, b Entry) int +} + +// OrderByFunction orders the results based on the result of the given function. +type OrderByFunction func(a, b Entry) int + +func (o OrderByFunction) Compare(a, b Entry) int { + return o(a, b) +} + +func (OrderByFunction) String() string { + return "FN" +} + +// OrderByValue is used to signal to datastores they should apply internal +// orderings. +type OrderByValue struct{} + +func (o OrderByValue) Compare(a, b Entry) int { + return bytes.Compare(a.Value, b.Value) +} + +func (OrderByValue) String() string { + return "VALUE" +} + +// OrderByValueDescending is used to signal to datastores they +// should apply internal orderings. +type OrderByValueDescending struct{} + +func (o OrderByValueDescending) Compare(a, b Entry) int { + return -bytes.Compare(a.Value, b.Value) +} + +func (OrderByValueDescending) String() string { + return "desc(VALUE)" +} + +// OrderByKey +type OrderByKey struct{} + +func (o OrderByKey) Compare(a, b Entry) int { + return strings.Compare(a.Key, b.Key) +} + +func (OrderByKey) String() string { + return "KEY" +} + +// OrderByKeyDescending +type OrderByKeyDescending struct{} + +func (o OrderByKeyDescending) Compare(a, b Entry) int { + return -strings.Compare(a.Key, b.Key) +} + +func (OrderByKeyDescending) String() string { + return "desc(KEY)" +} + +// Less returns true if a comes before b with the requested orderings. +func Less(orders []Order, a, b Entry) bool { + for _, cmp := range orders { + switch cmp.Compare(a, b) { + case 0: + case -1: + return true + case 1: + return false + } + } + + // This gives us a *stable* sort for free. We don't care + // preserving the order from the underlying datastore + // because it's undefined. + return a.Key < b.Key +} + +// Sort sorts the given entries using the given orders. +func Sort(orders []Order, entries []Entry) { + sort.Slice(entries, func(i int, j int) bool { + return Less(orders, entries[i], entries[j]) + }) +} diff --git a/vendor/github.com/ipfs/go-datastore/query/query.go b/vendor/github.com/ipfs/go-datastore/query/query.go new file mode 100644 index 0000000000..a390e5bf38 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/query/query.go @@ -0,0 +1,426 @@ +package query + +import ( + "fmt" + "time" + + goprocess "github.com/jbenet/goprocess" +) + +/* +Query represents storage for any key-value pair. + +tl;dr: + + queries are supported across datastores. + Cheap on top of relational dbs, and expensive otherwise. + Pick the right tool for the job! + +In addition to the key-value store get and set semantics, datastore +provides an interface to retrieve multiple records at a time through +the use of queries. The datastore Query model gleans a common set of +operations performed when querying. To avoid pasting here years of +database research, let’s summarize the operations datastore supports. + +Query Operations, applied in-order: + + * prefix - scope the query to a given path prefix + * filters - select a subset of values by applying constraints + * orders - sort the results by applying sort conditions, hierarchically. + * offset - skip a number of results (for efficient pagination) + * limit - impose a numeric limit on the number of results + +Datastore combines these operations into a simple Query class that allows +applications to define their constraints in a simple, generic, way without +introducing datastore specific calls, languages, etc. + +However, take heed: not all datastores support efficiently performing these +operations. Pick a datastore based on your needs. If you need efficient look-ups, +go for a simple key/value store. If you need efficient queries, consider an SQL +backed datastore. + +Notes: + + * Prefix: When a query filters by prefix, it selects keys that are strict + children of the prefix. For example, a prefix "/foo" would select "/foo/bar" + but not "/foobar" or "/foo", + * Orders: Orders are applied hierarchically. Results are sorted by the first + ordering, then entries equal under the first ordering are sorted with the + second ordering, etc. + * Limits & Offset: Limits and offsets are applied after everything else. +*/ +type Query struct { + Prefix string // namespaces the query to results whose keys have Prefix + Filters []Filter // filter results. apply sequentially + Orders []Order // order results. apply hierarchically + Limit int // maximum number of results + Offset int // skip given number of results + KeysOnly bool // return only keys. + ReturnExpirations bool // return expirations (see TTLDatastore) + ReturnsSizes bool // always return sizes. If not set, datastore impl can return + // // it anyway if it doesn't involve a performance cost. If KeysOnly + // // is not set, Size should always be set. +} + +// String returns a string representation of the Query for debugging/validation +// purposes. Do not use it for SQL queries. +func (q Query) String() string { + s := "SELECT keys" + if !q.KeysOnly { + s += ",vals" + } + if q.ReturnExpirations { + s += ",exps" + } + + s += " " + + if q.Prefix != "" { + s += fmt.Sprintf("FROM %q ", q.Prefix) + } + + if len(q.Filters) > 0 { + s += fmt.Sprintf("FILTER [%s", q.Filters[0]) + for _, f := range q.Filters[1:] { + s += fmt.Sprintf(", %s", f) + } + s += "] " + } + + if len(q.Orders) > 0 { + s += fmt.Sprintf("ORDER [%s", q.Orders[0]) + for _, f := range q.Orders[1:] { + s += fmt.Sprintf(", %s", f) + } + s += "] " + } + + if q.Offset > 0 { + s += fmt.Sprintf("OFFSET %d ", q.Offset) + } + + if q.Limit > 0 { + s += fmt.Sprintf("LIMIT %d ", q.Limit) + } + // Will always end with a space, strip it. + return s[:len(s)-1] +} + +// Entry is a query result entry. +type Entry struct { + Key string // cant be ds.Key because circular imports ...!!! + Value []byte // Will be nil if KeysOnly has been passed. + Expiration time.Time // Entry expiration timestamp if requested and supported (see TTLDatastore). + Size int // Might be -1 if the datastore doesn't support listing the size with KeysOnly + // // or if ReturnsSizes is not set +} + +// Result is a special entry that includes an error, so that the client +// may be warned about internal errors. If Error is non-nil, Entry must be +// empty. +type Result struct { + Entry + + Error error +} + +// Results is a set of Query results. This is the interface for clients. +// Example: +// +// qr, _ := myds.Query(q) +// for r := range qr.Next() { +// if r.Error != nil { +// // handle. +// break +// } +// +// fmt.Println(r.Entry.Key, r.Entry.Value) +// } +// +// or, wait on all results at once: +// +// qr, _ := myds.Query(q) +// es, _ := qr.Rest() +// for _, e := range es { +// fmt.Println(e.Key, e.Value) +// } +// +type Results interface { + Query() Query // the query these Results correspond to + Next() <-chan Result // returns a channel to wait for the next result + NextSync() (Result, bool) // blocks and waits to return the next result, second parameter returns false when results are exhausted + Rest() ([]Entry, error) // waits till processing finishes, returns all entries at once. + Close() error // client may call Close to signal early exit + + // Process returns a goprocess.Process associated with these results. + // most users will not need this function (Close is all they want), + // but it's here in case you want to connect the results to other + // goprocess-friendly things. + Process() goprocess.Process +} + +// results implements Results +type results struct { + query Query + proc goprocess.Process + res <-chan Result +} + +func (r *results) Next() <-chan Result { + return r.res +} + +func (r *results) NextSync() (Result, bool) { + val, ok := <-r.res + return val, ok +} + +func (r *results) Rest() ([]Entry, error) { + var es []Entry + for e := range r.res { + if e.Error != nil { + return es, e.Error + } + es = append(es, e.Entry) + } + <-r.proc.Closed() // wait till the processing finishes. + return es, nil +} + +func (r *results) Process() goprocess.Process { + return r.proc +} + +func (r *results) Close() error { + return r.proc.Close() +} + +func (r *results) Query() Query { + return r.query +} + +// ResultBuilder is what implementors use to construct results +// Implementors of datastores and their clients must respect the +// Process of the Request: +// +// * clients must call r.Process().Close() on an early exit, so +// implementations can reclaim resources. +// * if the Entries are read to completion (channel closed), Process +// should be closed automatically. +// * datastores must respect <-Process.Closing(), which intermediates +// an early close signal from the client. +// +type ResultBuilder struct { + Query Query + Process goprocess.Process + Output chan Result +} + +// Results returns a Results to to this builder. +func (rb *ResultBuilder) Results() Results { + return &results{ + query: rb.Query, + proc: rb.Process, + res: rb.Output, + } +} + +const NormalBufSize = 1 +const KeysOnlyBufSize = 128 + +func NewResultBuilder(q Query) *ResultBuilder { + bufSize := NormalBufSize + if q.KeysOnly { + bufSize = KeysOnlyBufSize + } + b := &ResultBuilder{ + Query: q, + Output: make(chan Result, bufSize), + } + b.Process = goprocess.WithTeardown(func() error { + close(b.Output) + return nil + }) + return b +} + +// ResultsWithChan returns a Results object from a channel +// of Result entries. +// +// DEPRECATED: This iterator is impossible to cancel correctly. Canceling it +// will leave anything trying to write to the result channel hanging. +func ResultsWithChan(q Query, res <-chan Result) Results { + return ResultsWithProcess(q, func(worker goprocess.Process, out chan<- Result) { + for { + select { + case <-worker.Closing(): // client told us to close early + return + case e, more := <-res: + if !more { + return + } + + select { + case out <- e: + case <-worker.Closing(): // client told us to close early + return + } + } + } + }) +} + +// ResultsWithProcess returns a Results object with the results generated by the +// passed subprocess. +func ResultsWithProcess(q Query, proc func(goprocess.Process, chan<- Result)) Results { + b := NewResultBuilder(q) + + // go consume all the entries and add them to the results. + b.Process.Go(func(worker goprocess.Process) { + proc(worker, b.Output) + }) + + go b.Process.CloseAfterChildren() //nolint + return b.Results() +} + +// ResultsWithEntries returns a Results object from a list of entries +func ResultsWithEntries(q Query, res []Entry) Results { + i := 0 + return ResultsFromIterator(q, Iterator{ + Next: func() (Result, bool) { + if i >= len(res) { + return Result{}, false + } + next := res[i] + i++ + return Result{Entry: next}, true + }, + }) +} + +func ResultsReplaceQuery(r Results, q Query) Results { + switch r := r.(type) { + case *results: + // note: not using field names to make sure all fields are copied + return &results{q, r.proc, r.res} + case *resultsIter: + // note: not using field names to make sure all fields are copied + lr := r.legacyResults + if lr != nil { + lr = &results{q, lr.proc, lr.res} + } + return &resultsIter{q, r.next, r.close, lr} + default: + panic("unknown results type") + } +} + +// +// ResultFromIterator provides an alternative way to to construct +// results without the use of channels. +// + +func ResultsFromIterator(q Query, iter Iterator) Results { + if iter.Close == nil { + iter.Close = noopClose + } + return &resultsIter{ + query: q, + next: iter.Next, + close: iter.Close, + } +} + +func noopClose() error { + return nil +} + +type Iterator struct { + Next func() (Result, bool) + Close func() error // note: might be called more than once +} + +type resultsIter struct { + query Query + next func() (Result, bool) + close func() error + legacyResults *results +} + +func (r *resultsIter) Next() <-chan Result { + r.useLegacyResults() + return r.legacyResults.Next() +} + +func (r *resultsIter) NextSync() (Result, bool) { + if r.legacyResults != nil { + return r.legacyResults.NextSync() + } else { + res, ok := r.next() + if !ok { + r.close() + } + return res, ok + } +} + +func (r *resultsIter) Rest() ([]Entry, error) { + var es []Entry + for { + e, ok := r.NextSync() + if !ok { + break + } + if e.Error != nil { + return es, e.Error + } + es = append(es, e.Entry) + } + return es, nil +} + +func (r *resultsIter) Process() goprocess.Process { + r.useLegacyResults() + return r.legacyResults.Process() +} + +func (r *resultsIter) Close() error { + if r.legacyResults != nil { + return r.legacyResults.Close() + } else { + return r.close() + } +} + +func (r *resultsIter) Query() Query { + return r.query +} + +func (r *resultsIter) useLegacyResults() { + if r.legacyResults != nil { + return + } + + b := NewResultBuilder(r.query) + + // go consume all the entries and add them to the results. + b.Process.Go(func(worker goprocess.Process) { + defer r.close() + for { + e, ok := r.next() + if !ok { + break + } + select { + case b.Output <- e: + case <-worker.Closing(): // client told us to close early + return + } + } + }) + + go b.Process.CloseAfterChildren() //nolint + + r.legacyResults = b.Results().(*results) +} diff --git a/vendor/github.com/ipfs/go-datastore/query/query_impl.go b/vendor/github.com/ipfs/go-datastore/query/query_impl.go new file mode 100644 index 0000000000..dd554e7433 --- /dev/null +++ b/vendor/github.com/ipfs/go-datastore/query/query_impl.go @@ -0,0 +1,158 @@ +package query + +import ( + "path" + + goprocess "github.com/jbenet/goprocess" +) + +// NaiveFilter applies a filter to the results. +func NaiveFilter(qr Results, filter Filter) Results { + return ResultsFromIterator(qr.Query(), Iterator{ + Next: func() (Result, bool) { + for { + e, ok := qr.NextSync() + if !ok { + return Result{}, false + } + if e.Error != nil || filter.Filter(e.Entry) { + return e, true + } + } + }, + Close: func() error { + return qr.Close() + }, + }) +} + +// NaiveLimit truncates the results to a given int limit +func NaiveLimit(qr Results, limit int) Results { + if limit == 0 { + // 0 means no limit + return qr + } + closed := false + return ResultsFromIterator(qr.Query(), Iterator{ + Next: func() (Result, bool) { + if limit == 0 { + if !closed { + closed = true + err := qr.Close() + if err != nil { + return Result{Error: err}, true + } + } + return Result{}, false + } + limit-- + return qr.NextSync() + }, + Close: func() error { + if closed { + return nil + } + closed = true + return qr.Close() + }, + }) +} + +// NaiveOffset skips a given number of results +func NaiveOffset(qr Results, offset int) Results { + return ResultsFromIterator(qr.Query(), Iterator{ + Next: func() (Result, bool) { + for ; offset > 0; offset-- { + res, ok := qr.NextSync() + if !ok || res.Error != nil { + return res, ok + } + } + return qr.NextSync() + }, + Close: func() error { + return qr.Close() + }, + }) +} + +// NaiveOrder reorders results according to given orders. +// WARNING: this is the only non-stream friendly operation! +func NaiveOrder(qr Results, orders ...Order) Results { + // Short circuit. + if len(orders) == 0 { + return qr + } + + return ResultsWithProcess(qr.Query(), func(worker goprocess.Process, out chan<- Result) { + defer qr.Close() + var entries []Entry + collect: + for { + select { + case <-worker.Closing(): + return + case e, ok := <-qr.Next(): + if !ok { + break collect + } + if e.Error != nil { + out <- e + continue + } + entries = append(entries, e.Entry) + } + } + + Sort(orders, entries) + + for _, e := range entries { + select { + case <-worker.Closing(): + return + case out <- Result{Entry: e}: + } + } + }) +} + +func NaiveQueryApply(q Query, qr Results) Results { + if q.Prefix != "" { + // Clean the prefix as a key and append / so a prefix of /bar + // only finds /bar/baz, not /barbaz. + prefix := q.Prefix + if len(prefix) == 0 { + prefix = "/" + } else { + if prefix[0] != '/' { + prefix = "/" + prefix + } + prefix = path.Clean(prefix) + } + // If the prefix is empty, ignore it. + if prefix != "/" { + qr = NaiveFilter(qr, FilterKeyPrefix{prefix + "/"}) + } + } + for _, f := range q.Filters { + qr = NaiveFilter(qr, f) + } + if len(q.Orders) > 0 { + qr = NaiveOrder(qr, q.Orders...) + } + if q.Offset != 0 { + qr = NaiveOffset(qr, q.Offset) + } + if q.Limit != 0 { + qr = NaiveLimit(qr, q.Limit) + } + return qr +} + +func ResultEntriesFrom(keys []string, vals [][]byte) []Entry { + re := make([]Entry, len(keys)) + for i, k := range keys { + re[i] = Entry{Key: k, Size: len(vals[i]), Value: vals[i]} + } + return re +} diff --git a/vendor/github.com/ipfs/go-filestore/LICENSE-APACHE b/vendor/github.com/ipfs/go-filestore/LICENSE-APACHE new file mode 100644 index 0000000000..14478a3b60 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/LICENSE-APACHE @@ -0,0 +1,5 @@ +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/vendor/github.com/ipfs/go-filestore/LICENSE-MIT b/vendor/github.com/ipfs/go-filestore/LICENSE-MIT new file mode 100644 index 0000000000..72dc60d84b --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/LICENSE-MIT @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-filestore/README.md b/vendor/github.com/ipfs/go-filestore/README.md new file mode 100644 index 0000000000..cf6940ef48 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/README.md @@ -0,0 +1,38 @@ +# go-filestore + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/ipfs/go-filestore?status.svg)](https://godoc.org/github.com/ipfs/go-filestore) + +> a by-reference file-backed blockstore + +## Lead Maintainer + +[Steven Allen](https://github.com/Stebalien) + +## Table of Contents + +- [Documentation](#documentation) +- [Contribute](#contribute) +- [License](#license) + +## Documentation + +https://godoc.org/github.com/ipfs/go-filestore + +## Contribute + +Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-filestore/issues)! + +This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +### Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) + +## License + +MIT + diff --git a/vendor/github.com/ipfs/go-filestore/filestore.go b/vendor/github.com/ipfs/go-filestore/filestore.go new file mode 100644 index 0000000000..a9c36c5d30 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/filestore.go @@ -0,0 +1,251 @@ +// Package filestore implements a Blockstore which is able to read certain +// blocks of data directly from its original location in the filesystem. +// +// In a Filestore, object leaves are stored as FilestoreNodes. FilestoreNodes +// include a filesystem path and an offset, allowing a Blockstore dealing with +// such blocks to avoid storing the whole contents and reading them from their +// filesystem location instead. +package filestore + +import ( + "context" + "errors" + + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + dsq "github.com/ipfs/go-datastore/query" + blockstore "github.com/ipfs/go-ipfs-blockstore" + posinfo "github.com/ipfs/go-ipfs-posinfo" + logging "github.com/ipfs/go-log" +) + +var logger = logging.Logger("filestore") + +var ErrFilestoreNotEnabled = errors.New("filestore is not enabled, see https://git.io/vNItf") +var ErrUrlstoreNotEnabled = errors.New("urlstore is not enabled") + +// Filestore implements a Blockstore by combining a standard Blockstore +// to store regular blocks and a special Blockstore called +// FileManager to store blocks which data exists in an external file. +type Filestore struct { + fm *FileManager + bs blockstore.Blockstore +} + +// FileManager returns the FileManager in Filestore. +func (f *Filestore) FileManager() *FileManager { + return f.fm +} + +// MainBlockstore returns the standard Blockstore in the Filestore. +func (f *Filestore) MainBlockstore() blockstore.Blockstore { + return f.bs +} + +// NewFilestore creates one using the given Blockstore and FileManager. +func NewFilestore(bs blockstore.Blockstore, fm *FileManager) *Filestore { + return &Filestore{fm, bs} +} + +// AllKeysChan returns a channel from which to read the keys stored in +// the blockstore. If the given context is cancelled the channel will be closed. +func (f *Filestore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + ctx, cancel := context.WithCancel(ctx) + + a, err := f.bs.AllKeysChan(ctx) + if err != nil { + cancel() + return nil, err + } + + out := make(chan cid.Cid, dsq.KeysOnlyBufSize) + go func() { + defer cancel() + defer close(out) + + var done bool + for !done { + select { + case c, ok := <-a: + if !ok { + done = true + continue + } + select { + case out <- c: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + + // Can't do these at the same time because the abstractions around + // leveldb make us query leveldb for both operations. We apparently + // cant query leveldb concurrently + b, err := f.fm.AllKeysChan(ctx) + if err != nil { + logger.Error("error querying filestore: ", err) + return + } + + done = false + for !done { + select { + case c, ok := <-b: + if !ok { + done = true + continue + } + select { + case out <- c: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + return out, nil +} + +// DeleteBlock deletes the block with the given key from the +// blockstore. As expected, in the case of FileManager blocks, only the +// reference is deleted, not its contents. It may return +// ErrNotFound when the block is not stored. +func (f *Filestore) DeleteBlock(c cid.Cid) error { + err1 := f.bs.DeleteBlock(c) + if err1 != nil && err1 != blockstore.ErrNotFound { + return err1 + } + + err2 := f.fm.DeleteBlock(c) + // if we successfully removed something from the blockstore, but the + // filestore didnt have it, return success + + switch err2 { + case nil: + return nil + case blockstore.ErrNotFound: + if err1 == blockstore.ErrNotFound { + return blockstore.ErrNotFound + } + return nil + default: + return err2 + } +} + +// Get retrieves the block with the given Cid. It may return +// ErrNotFound when the block is not stored. +func (f *Filestore) Get(c cid.Cid) (blocks.Block, error) { + blk, err := f.bs.Get(c) + switch err { + case nil: + return blk, nil + case blockstore.ErrNotFound: + return f.fm.Get(c) + default: + return nil, err + } +} + +// GetSize returns the size of the requested block. It may return ErrNotFound +// when the block is not stored. +func (f *Filestore) GetSize(c cid.Cid) (int, error) { + size, err := f.bs.GetSize(c) + switch err { + case nil: + return size, nil + case blockstore.ErrNotFound: + return f.fm.GetSize(c) + default: + return -1, err + } +} + +// Has returns true if the block with the given Cid is +// stored in the Filestore. +func (f *Filestore) Has(c cid.Cid) (bool, error) { + has, err := f.bs.Has(c) + if err != nil { + return false, err + } + + if has { + return true, nil + } + + return f.fm.Has(c) +} + +// Put stores a block in the Filestore. For blocks of +// underlying type FilestoreNode, the operation is +// delegated to the FileManager, while the rest of blocks +// are handled by the regular blockstore. +func (f *Filestore) Put(b blocks.Block) error { + has, err := f.Has(b.Cid()) + if err != nil { + return err + } + + if has { + return nil + } + + switch b := b.(type) { + case *posinfo.FilestoreNode: + return f.fm.Put(b) + default: + return f.bs.Put(b) + } +} + +// PutMany is like Put(), but takes a slice of blocks, allowing +// the underlying blockstore to perform batch transactions. +func (f *Filestore) PutMany(bs []blocks.Block) error { + var normals []blocks.Block + var fstores []*posinfo.FilestoreNode + + for _, b := range bs { + has, err := f.Has(b.Cid()) + if err != nil { + return err + } + + if has { + continue + } + + switch b := b.(type) { + case *posinfo.FilestoreNode: + fstores = append(fstores, b) + default: + normals = append(normals, b) + } + } + + if len(normals) > 0 { + err := f.bs.PutMany(normals) + if err != nil { + return err + } + } + + if len(fstores) > 0 { + err := f.fm.PutMany(fstores) + if err != nil { + return err + } + } + return nil +} + +// HashOnRead calls blockstore.HashOnRead. +func (f *Filestore) HashOnRead(enabled bool) { + f.bs.HashOnRead(enabled) +} + +var _ blockstore.Blockstore = (*Filestore)(nil) diff --git a/vendor/github.com/ipfs/go-filestore/fsrefstore.go b/vendor/github.com/ipfs/go-filestore/fsrefstore.go new file mode 100644 index 0000000000..bc183fc38f --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/fsrefstore.go @@ -0,0 +1,339 @@ +package filestore + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + + pb "github.com/ipfs/go-filestore/pb" + + proto "github.com/gogo/protobuf/proto" + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + ds "github.com/ipfs/go-datastore" + dsns "github.com/ipfs/go-datastore/namespace" + dsq "github.com/ipfs/go-datastore/query" + blockstore "github.com/ipfs/go-ipfs-blockstore" + dshelp "github.com/ipfs/go-ipfs-ds-help" + posinfo "github.com/ipfs/go-ipfs-posinfo" + mh "github.com/multiformats/go-multihash" +) + +// FilestorePrefix identifies the key prefix for FileManager blocks. +var FilestorePrefix = ds.NewKey("filestore") + +// FileManager is a blockstore implementation which stores special +// blocks FilestoreNode type. These nodes only contain a reference +// to the actual location of the block data in the filesystem +// (a path and an offset). +type FileManager struct { + AllowFiles bool + AllowUrls bool + ds ds.Batching + root string +} + +// CorruptReferenceError implements the error interface. +// It is used to indicate that the block contents pointed +// by the referencing blocks cannot be retrieved (i.e. the +// file is not found, or the data changed as it was being read). +type CorruptReferenceError struct { + Code Status + Err error +} + +// Error() returns the error message in the CorruptReferenceError +// as a string. +func (c CorruptReferenceError) Error() string { + return c.Err.Error() +} + +// NewFileManager initializes a new file manager with the given +// datastore and root. All FilestoreNodes paths are relative to the +// root path given here, which is prepended for any operations. +func NewFileManager(ds ds.Batching, root string) *FileManager { + return &FileManager{ds: dsns.Wrap(ds, FilestorePrefix), root: root} +} + +// AllKeysChan returns a channel from which to read the keys stored in +// the FileManager. If the given context is cancelled the channel will be +// closed. +// +// All CIDs returned are of type Raw. +func (f *FileManager) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + q := dsq.Query{KeysOnly: true} + + res, err := f.ds.Query(q) + if err != nil { + return nil, err + } + + out := make(chan cid.Cid, dsq.KeysOnlyBufSize) + go func() { + defer close(out) + for { + v, ok := res.NextSync() + if !ok { + return + } + + k := ds.RawKey(v.Key) + mhash, err := dshelp.DsKeyToMultihash(k) + if err != nil { + logger.Errorf("decoding cid from filestore: %s", err) + continue + } + + select { + case out <- cid.NewCidV1(cid.Raw, mhash): + case <-ctx.Done(): + return + } + } + }() + + return out, nil +} + +// DeleteBlock deletes the reference-block from the underlying +// datastore. It does not touch the referenced data. +func (f *FileManager) DeleteBlock(c cid.Cid) error { + err := f.ds.Delete(dshelp.MultihashToDsKey(c.Hash())) + if err == ds.ErrNotFound { + return blockstore.ErrNotFound + } + return err +} + +// Get reads a block from the datastore. Reading a block +// is done in two steps: the first step retrieves the reference +// block from the datastore. The second step uses the stored +// path and offsets to read the raw block data directly from disk. +func (f *FileManager) Get(c cid.Cid) (blocks.Block, error) { + dobj, err := f.getDataObj(c.Hash()) + if err != nil { + return nil, err + } + out, err := f.readDataObj(c.Hash(), dobj) + if err != nil { + return nil, err + } + + return blocks.NewBlockWithCid(out, c) +} + +// GetSize gets the size of the block from the datastore. +// +// This method may successfully return the size even if returning the block +// would fail because the associated file is no longer available. +func (f *FileManager) GetSize(c cid.Cid) (int, error) { + dobj, err := f.getDataObj(c.Hash()) + if err != nil { + return -1, err + } + return int(dobj.GetSize_()), nil +} + +func (f *FileManager) readDataObj(m mh.Multihash, d *pb.DataObj) ([]byte, error) { + if IsURL(d.GetFilePath()) { + return f.readURLDataObj(m, d) + } + return f.readFileDataObj(m, d) +} + +func (f *FileManager) getDataObj(m mh.Multihash) (*pb.DataObj, error) { + o, err := f.ds.Get(dshelp.MultihashToDsKey(m)) + switch err { + case ds.ErrNotFound: + return nil, blockstore.ErrNotFound + default: + return nil, err + case nil: + // + } + + return unmarshalDataObj(o) +} + +func unmarshalDataObj(data []byte) (*pb.DataObj, error) { + var dobj pb.DataObj + if err := proto.Unmarshal(data, &dobj); err != nil { + return nil, err + } + + return &dobj, nil +} + +func (f *FileManager) readFileDataObj(m mh.Multihash, d *pb.DataObj) ([]byte, error) { + if !f.AllowFiles { + return nil, ErrFilestoreNotEnabled + } + + p := filepath.FromSlash(d.GetFilePath()) + abspath := filepath.Join(f.root, p) + + fi, err := os.Open(abspath) + if os.IsNotExist(err) { + return nil, &CorruptReferenceError{StatusFileNotFound, err} + } else if err != nil { + return nil, &CorruptReferenceError{StatusFileError, err} + } + defer fi.Close() + + _, err = fi.Seek(int64(d.GetOffset()), io.SeekStart) + if err != nil { + return nil, &CorruptReferenceError{StatusFileError, err} + } + + outbuf := make([]byte, d.GetSize_()) + _, err = io.ReadFull(fi, outbuf) + if err == io.EOF || err == io.ErrUnexpectedEOF { + return nil, &CorruptReferenceError{StatusFileChanged, err} + } else if err != nil { + return nil, &CorruptReferenceError{StatusFileError, err} + } + + // Work with CIDs for this, as they are a nice wrapper and things + // will not break if multihashes underlying types change. + origCid := cid.NewCidV1(cid.Raw, m) + outcid, err := origCid.Prefix().Sum(outbuf) + if err != nil { + return nil, err + } + + if !origCid.Equals(outcid) { + return nil, &CorruptReferenceError{StatusFileChanged, + fmt.Errorf("data in file did not match. %s offset %d", d.GetFilePath(), d.GetOffset())} + } + + return outbuf, nil +} + +// reads and verifies the block from URL +func (f *FileManager) readURLDataObj(m mh.Multihash, d *pb.DataObj) ([]byte, error) { + if !f.AllowUrls { + return nil, ErrUrlstoreNotEnabled + } + + req, err := http.NewRequest("GET", d.GetFilePath(), nil) + if err != nil { + return nil, err + } + + req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", d.GetOffset(), d.GetOffset()+d.GetSize_()-1)) + + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, &CorruptReferenceError{StatusFileError, err} + } + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusPartialContent { + return nil, &CorruptReferenceError{StatusFileError, + fmt.Errorf("expected HTTP 200 or 206 got %d", res.StatusCode)} + } + + outbuf := make([]byte, d.GetSize_()) + _, err = io.ReadFull(res.Body, outbuf) + if err == io.EOF || err == io.ErrUnexpectedEOF { + return nil, &CorruptReferenceError{StatusFileChanged, err} + } else if err != nil { + return nil, &CorruptReferenceError{StatusFileError, err} + } + res.Body.Close() + + // Work with CIDs for this, as they are a nice wrapper and things + // will not break if multihashes underlying types change. + origCid := cid.NewCidV1(cid.Raw, m) + outcid, err := origCid.Prefix().Sum(outbuf) + if err != nil { + return nil, err + } + + if !origCid.Equals(outcid) { + return nil, &CorruptReferenceError{StatusFileChanged, + fmt.Errorf("data in file did not match. %s offset %d", d.GetFilePath(), d.GetOffset())} + } + + return outbuf, nil +} + +// Has returns if the FileManager is storing a block reference. It does not +// validate the data, nor checks if the reference is valid. +func (f *FileManager) Has(c cid.Cid) (bool, error) { + // NOTE: interesting thing to consider. Has doesnt validate the data. + // So the data on disk could be invalid, and we could think we have it. + dsk := dshelp.MultihashToDsKey(c.Hash()) + return f.ds.Has(dsk) +} + +type putter interface { + Put(ds.Key, []byte) error +} + +// Put adds a new reference block to the FileManager. It does not check +// that the reference is valid. +func (f *FileManager) Put(b *posinfo.FilestoreNode) error { + return f.putTo(b, f.ds) +} + +func (f *FileManager) putTo(b *posinfo.FilestoreNode, to putter) error { + var dobj pb.DataObj + + if IsURL(b.PosInfo.FullPath) { + if !f.AllowUrls { + return ErrUrlstoreNotEnabled + } + dobj.FilePath = b.PosInfo.FullPath + } else { + if !f.AllowFiles { + return ErrFilestoreNotEnabled + } + if !filepath.HasPrefix(b.PosInfo.FullPath, f.root) { //nolint:staticcheck + return fmt.Errorf("cannot add filestore references outside ipfs root (%s)", f.root) + } + + p, err := filepath.Rel(f.root, b.PosInfo.FullPath) + if err != nil { + return err + } + + dobj.FilePath = filepath.ToSlash(p) + } + dobj.Offset = b.PosInfo.Offset + dobj.Size_ = uint64(len(b.RawData())) + + data, err := proto.Marshal(&dobj) + if err != nil { + return err + } + + return to.Put(dshelp.MultihashToDsKey(b.Cid().Hash()), data) +} + +// PutMany is like Put() but takes a slice of blocks instead, +// allowing it to create a batch transaction. +func (f *FileManager) PutMany(bs []*posinfo.FilestoreNode) error { + batch, err := f.ds.Batch() + if err != nil { + return err + } + + for _, b := range bs { + if err := f.putTo(b, batch); err != nil { + return err + } + } + + return batch.Commit() +} + +// IsURL returns true if the string represents a valid URL that the +// urlstore can handle. More specifically it returns true if a string +// begins with 'http://' or 'https://'. +func IsURL(str string) bool { + return (len(str) > 7 && str[0] == 'h' && str[1] == 't' && str[2] == 't' && str[3] == 'p') && + ((len(str) > 8 && str[4] == 's' && str[5] == ':' && str[6] == '/' && str[7] == '/') || + (str[4] == ':' && str[5] == '/' && str[6] == '/')) +} diff --git a/vendor/github.com/ipfs/go-filestore/go.mod b/vendor/github.com/ipfs/go-filestore/go.mod new file mode 100644 index 0000000000..096a5f1061 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/go.mod @@ -0,0 +1,16 @@ +module github.com/ipfs/go-filestore + +go 1.12 + +require ( + github.com/gogo/protobuf v1.3.1 + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.5 + github.com/ipfs/go-datastore v0.4.4 + github.com/ipfs/go-ipfs-blockstore v1.0.0 + github.com/ipfs/go-ipfs-ds-help v1.0.0 + github.com/ipfs/go-ipfs-posinfo v0.0.1 + github.com/ipfs/go-log v1.0.2 + github.com/ipfs/go-merkledag v0.3.1 + github.com/multiformats/go-multihash v0.0.13 +) diff --git a/vendor/github.com/ipfs/go-filestore/go.sum b/vendor/github.com/ipfs/go-filestore/go.sum new file mode 100644 index 0000000000..b1f4d4e3b5 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/go.sum @@ -0,0 +1,387 @@ +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c h1:aEbSeNALREWXk0G7UdNhR3ayBV7tZ4M2PNmnrCAph6Q= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ipfs/bbloom v0.0.1 h1:s7KkiBPfxCeDVo47KySjK0ACPc5GJRUxFpdyWEuDjhw= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitswap v0.1.0 h1:28YsHYw9ut6wootnImPXH0WpnU5Dbo3qm6cvQ6e6wYY= +github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-blockservice v0.1.0 h1:dh2i7xjMbCtf0ZSMyQAF2qpV/pEEmM7yVpQ00+gik6U= +github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-datastore v0.0.1 h1:AW/KZCScnBWlSb5JbnEnLKFWXL224LBEh/9KXXOrUms= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5 h1:q3OfiOZV5rlsK1H5V8benjeUApRfMGs4Mrhmr6NriQo= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.0 h1:TOxI04l8CmO4zGtesENhzm4PwkFwJXY3rKiYaaMf9fI= +github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.3.1 h1:SS1t869a6cctoSYmZXUk8eL6AzVXgASmKIWFNQkQ1jU= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.1 h1:W4ZfzyhNi3xmuU5dQhjfuRn/wFuqEE1KnOmmQiOevEY= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ipfs-blockstore v0.0.1 h1:O9n3PbmTYZoNhkgkEyrXTznbmktIXif62xLX+8dPHzc= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blockstore v0.1.0 h1:V1GZorHFUIB6YgTJQdq7mcaIpUfCM3fCyVi+MTo9O88= +github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= +github.com/ipfs/go-ipfs-blockstore v1.0.0 h1:pmFp5sFYsYVvMOp9X01AK3s85usVcLvkBTRsN6SnfUA= +github.com/ipfs/go-ipfs-blockstore v1.0.0/go.mod h1:knLVdhVU9L7CC4T+T4nvGdeUIPAXlnd9zmXfp+9MIjU= +github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1 h1:QBg+Ts2zgeemK/dB0saiF/ykzRGgfoFMT90Rzo0OnVU= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g= +github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= +github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= +github.com/ipfs/go-ipfs-pq v0.0.1 h1:zgUotX8dcAB/w/HidJh1zzc1yFq6Vm8J7T2F4itj/RU= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.3 h1:ENsxvybwkmke7Z/QJOmeJfoguj6GH3Y0YOaGrfy9Q0I= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.2 h1:s19ZwJxH8rPWzypjcDpqPLIyV7BnbLqvpli3iZoqYK0= +github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= +github.com/ipfs/go-log/v2 v2.0.2 h1:xguurydRdfKMJjKyxNXNU8lYP0VZH1NUwJRwUorjuEw= +github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-merkledag v0.3.1 h1:3UqWINBEr3/N+r6OwgFXAddDP/8zpQX/8J7IGVOCqRQ= +github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-peertaskqueue v0.1.0 h1:bpRbgv76eT4avutNPDFZuCPOQus6qTgurEYxfulgZW4= +github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security-multistream v0.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-libp2p v0.1.0 h1:8VXadcPNni74ODoZ+7326LMAppFYmz1fRQOUuT5iZvQ= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-blankhost v0.1.1 h1:X919sCh+KLqJcNRApj43xCSiQRYqOSI88Fdf55ngf78= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2 h1:86uOwW+O6Uc7NbaK4diuLZo2/Ikvqw2rgyV03VcSbLE= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-nat v0.0.4 h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0 h1:MKh7pRNPHSh1fLPj8u/M/s/napdmeNpoi9BRy9lPN0E= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-record v0.1.0 h1:wHwBGbFzymoIl69BpgwIu0O6ta3TXGcMPvHUAcodzRc= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-secio v0.1.0 h1:NNP5KLxuP97sE5Bu3iuwOWyT/dKEGMN5zSLMWdB7GTQ= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-swarm v0.1.0 h1:HrFk2p0awrGEgch9JXK/qp/hfjqQfgNxpLWnCiWPg5s= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3 h1:bdij4bKaaND7tCsaXVjRfYkMpvoOeKj9AVQGJllA6jM= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-yamux v0.2.0 h1:TSPZ5cMMz/wdoYsye/wU1TE4G3LDGMoeEN0xgnCKU/I= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-maddr-filter v0.0.4 h1:hx8HIuuwk34KePddrp2mM5ivgPkZ09JH4AvsALRbFUs= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-msgio v0.0.2 h1:ivPvEKHxmVkTClHzg6RXTYHqaJQ0V9cDbq+6lKb3UV0= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.3 h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0 h1:IGhowvEqyMFknOar4FWCKSWE0zL36UFKQtiRQD60/8o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-testutil v0.1.0 h1:4QhjaWGO89udplblLVpgGDOQjzFlRavZOjuEnz2rLMc= +github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-yamux v1.2.2 h1:s6J6o7+ajoQMjHe7BEnq+EynOj5D2EoG8CuQgL3F2vg= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0 h1:U41/2erhAKcmSI14xh/ZTUdBPOzDOIfS93ibzUSl8KM= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4 h1:WgMSI84/eRLdbptXMkMWDXPjPq7SPLIgGUVm2eroyU4= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2 h1:/Bbsgsy3R6e3jf2qBahzNHzww6usYaZ0NhNH3sqdFS8= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-fmt v0.0.1 h1:5YjeOIzbX8OTKVaN72aOzGIYW7PnrZrnkDyOfAWRSMA= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-net v0.0.1 h1:76O59E3FavvHqNg7jvzWzsPSW5JSi/ek0E4eiDVbg9g= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7 h1:C2F/nMkR/9sfUTpvR3QrjBuTdvMUC/cFajkphs1YLQo= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158 h1:v73Zw0Y1htnV0qaOAYSNiuIAviPSBkNtdy1tPi1+zpY= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/ipfs/go-filestore/pb/Rules.mk b/vendor/github.com/ipfs/go-filestore/pb/Rules.mk new file mode 100644 index 0000000000..505f70e754 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/pb/Rules.mk @@ -0,0 +1,8 @@ +include mk/header.mk + +PB_$(d) = $(wildcard $(d)/*.proto) +TGTS_$(d) = $(PB_$(d):.proto=.pb.go) + +#DEPS_GO += $(TGTS_$(d)) + +include mk/footer.mk diff --git a/vendor/github.com/ipfs/go-filestore/pb/dataobj.pb.go b/vendor/github.com/ipfs/go-filestore/pb/dataobj.pb.go new file mode 100644 index 0000000000..5ecc2489e0 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/pb/dataobj.pb.go @@ -0,0 +1,375 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dataobj.proto + +package datastore_pb + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type DataObj struct { + FilePath string `protobuf:"bytes,1,opt,name=FilePath" json:"FilePath"` + Offset uint64 `protobuf:"varint,2,opt,name=Offset" json:"Offset"` + Size_ uint64 `protobuf:"varint,3,opt,name=Size" json:"Size"` +} + +func (m *DataObj) Reset() { *m = DataObj{} } +func (m *DataObj) String() string { return proto.CompactTextString(m) } +func (*DataObj) ProtoMessage() {} +func (*DataObj) Descriptor() ([]byte, []int) { + return fileDescriptor_a76cb282d869d683, []int{0} +} +func (m *DataObj) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DataObj) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DataObj.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DataObj) XXX_Merge(src proto.Message) { + xxx_messageInfo_DataObj.Merge(m, src) +} +func (m *DataObj) XXX_Size() int { + return m.Size() +} +func (m *DataObj) XXX_DiscardUnknown() { + xxx_messageInfo_DataObj.DiscardUnknown(m) +} + +var xxx_messageInfo_DataObj proto.InternalMessageInfo + +func (m *DataObj) GetFilePath() string { + if m != nil { + return m.FilePath + } + return "" +} + +func (m *DataObj) GetOffset() uint64 { + if m != nil { + return m.Offset + } + return 0 +} + +func (m *DataObj) GetSize_() uint64 { + if m != nil { + return m.Size_ + } + return 0 +} + +func init() { + proto.RegisterType((*DataObj)(nil), "datastore.pb.DataObj") +} + +func init() { proto.RegisterFile("dataobj.proto", fileDescriptor_a76cb282d869d683) } + +var fileDescriptor_a76cb282d869d683 = []byte{ + // 150 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x49, 0x2c, 0x49, + 0xcc, 0x4f, 0xca, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x01, 0x71, 0x8b, 0x4b, 0xf2, + 0x8b, 0x52, 0xf5, 0x0a, 0x92, 0x94, 0x92, 0xb9, 0xd8, 0x5d, 0x12, 0x4b, 0x12, 0xfd, 0x93, 0xb2, + 0x84, 0x14, 0xb8, 0x38, 0xdc, 0x32, 0x73, 0x52, 0x03, 0x12, 0x4b, 0x32, 0x24, 0x18, 0x15, 0x18, + 0x35, 0x38, 0x9d, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0x8b, 0x0a, 0xc9, 0x70, 0xb1, 0xf9, + 0xa7, 0xa5, 0x15, 0xa7, 0x96, 0x48, 0x30, 0x29, 0x30, 0x6a, 0xb0, 0x40, 0xe5, 0xa1, 0x62, 0x42, + 0x12, 0x5c, 0x2c, 0xc1, 0x99, 0x55, 0xa9, 0x12, 0xcc, 0x48, 0x72, 0x60, 0x11, 0x27, 0x89, 0x13, + 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, + 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x00, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5d, 0x4a, + 0x76, 0xa0, 0x9c, 0x00, 0x00, 0x00, +} + +func (m *DataObj) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DataObj) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DataObj) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintDataobj(dAtA, i, uint64(m.Size_)) + i-- + dAtA[i] = 0x18 + i = encodeVarintDataobj(dAtA, i, uint64(m.Offset)) + i-- + dAtA[i] = 0x10 + i -= len(m.FilePath) + copy(dAtA[i:], m.FilePath) + i = encodeVarintDataobj(dAtA, i, uint64(len(m.FilePath))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintDataobj(dAtA []byte, offset int, v uint64) int { + offset -= sovDataobj(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *DataObj) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FilePath) + n += 1 + l + sovDataobj(uint64(l)) + n += 1 + sovDataobj(uint64(m.Offset)) + n += 1 + sovDataobj(uint64(m.Size_)) + return n +} + +func sovDataobj(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozDataobj(x uint64) (n int) { + return sovDataobj(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *DataObj) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDataobj + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DataObj: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DataObj: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FilePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDataobj + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthDataobj + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthDataobj + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FilePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType) + } + m.Offset = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDataobj + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Offset |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) + } + m.Size_ = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDataobj + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size_ |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipDataobj(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthDataobj + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthDataobj + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipDataobj(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDataobj + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDataobj + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDataobj + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthDataobj + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupDataobj + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthDataobj + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthDataobj = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowDataobj = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupDataobj = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/github.com/ipfs/go-filestore/pb/dataobj.proto b/vendor/github.com/ipfs/go-filestore/pb/dataobj.proto new file mode 100644 index 0000000000..909d22b77f --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/pb/dataobj.proto @@ -0,0 +1,9 @@ +syntax = "proto2"; + +package datastore.pb; + +message DataObj { + optional string FilePath = 1; + optional uint64 Offset = 2; + optional uint64 Size = 3; +} diff --git a/vendor/github.com/ipfs/go-filestore/util.go b/vendor/github.com/ipfs/go-filestore/util.go new file mode 100644 index 0000000000..dc860f7352 --- /dev/null +++ b/vendor/github.com/ipfs/go-filestore/util.go @@ -0,0 +1,291 @@ +package filestore + +import ( + "fmt" + "sort" + + pb "github.com/ipfs/go-filestore/pb" + + cid "github.com/ipfs/go-cid" + ds "github.com/ipfs/go-datastore" + dsq "github.com/ipfs/go-datastore/query" + blockstore "github.com/ipfs/go-ipfs-blockstore" + dshelp "github.com/ipfs/go-ipfs-ds-help" + mh "github.com/multiformats/go-multihash" +) + +// Status is used to identify the state of the block data referenced +// by a FilestoreNode. Among other places, it is used by CorruptReferenceError. +type Status int32 + +// These are the supported Status codes. +const ( + StatusOk Status = 0 + StatusFileError Status = 10 // Backing File Error + StatusFileNotFound Status = 11 // Backing File Not Found + StatusFileChanged Status = 12 // Contents of the file changed + StatusOtherError Status = 20 // Internal Error, likely corrupt entry + StatusKeyNotFound Status = 30 +) + +// String provides a human-readable representation for Status codes. +func (s Status) String() string { + switch s { + case StatusOk: + return "ok" + case StatusFileError: + return "error" + case StatusFileNotFound: + return "no-file" + case StatusFileChanged: + return "changed" + case StatusOtherError: + return "ERROR" + case StatusKeyNotFound: + return "missing" + default: + return "???" + } +} + +// Format returns the status formatted as a string +// with leading 0s. +func (s Status) Format() string { + return fmt.Sprintf("%-7s", s.String()) +} + +// ListRes wraps the response of the List*() functions, which +// allows to obtain and verify blocks stored by the FileManager +// of a Filestore. It includes information about the referenced +// block. +type ListRes struct { + Status Status + ErrorMsg string + Key cid.Cid + FilePath string + Offset uint64 + Size uint64 +} + +// FormatLong returns a human readable string for a ListRes object +func (r *ListRes) FormatLong(enc func(cid.Cid) string) string { + if enc == nil { + enc = (cid.Cid).String + } + switch { + case !r.Key.Defined(): + return "" + case r.FilePath == "": + return r.Key.String() + default: + return fmt.Sprintf("%-50s %6d %s %d", enc(r.Key), r.Size, r.FilePath, r.Offset) + } +} + +// List fetches the block with the given key from the Filemanager +// of the given Filestore and returns a ListRes object with the information. +// List does not verify that the reference is valid or whether the +// raw data is accesible. See Verify(). +func List(fs *Filestore, key cid.Cid) *ListRes { + return list(fs, false, key.Hash()) +} + +// ListAll returns a function as an iterator which, once invoked, returns +// one by one each block in the Filestore's FileManager. +// ListAll does not verify that the references are valid or whether +// the raw data is accessible. See VerifyAll(). +func ListAll(fs *Filestore, fileOrder bool) (func() *ListRes, error) { + if fileOrder { + return listAllFileOrder(fs, false) + } + return listAll(fs, false) +} + +// Verify fetches the block with the given key from the Filemanager +// of the given Filestore and returns a ListRes object with the information. +// Verify makes sure that the reference is valid and the block data can be +// read. +func Verify(fs *Filestore, key cid.Cid) *ListRes { + return list(fs, true, key.Hash()) +} + +// VerifyAll returns a function as an iterator which, once invoked, +// returns one by one each block in the Filestore's FileManager. +// VerifyAll checks that the reference is valid and that the block data +// can be read. +func VerifyAll(fs *Filestore, fileOrder bool) (func() *ListRes, error) { + if fileOrder { + return listAllFileOrder(fs, true) + } + return listAll(fs, true) +} + +func list(fs *Filestore, verify bool, key mh.Multihash) *ListRes { + dobj, err := fs.fm.getDataObj(key) + if err != nil { + return mkListRes(key, nil, err) + } + if verify { + _, err = fs.fm.readDataObj(key, dobj) + } + return mkListRes(key, dobj, err) +} + +func listAll(fs *Filestore, verify bool) (func() *ListRes, error) { + q := dsq.Query{} + qr, err := fs.fm.ds.Query(q) + if err != nil { + return nil, err + } + + return func() *ListRes { + mhash, dobj, err := next(qr) + if dobj == nil && err == nil { + return nil + } else if err == nil && verify { + _, err = fs.fm.readDataObj(mhash, dobj) + } + return mkListRes(mhash, dobj, err) + }, nil +} + +func next(qr dsq.Results) (mh.Multihash, *pb.DataObj, error) { + v, ok := qr.NextSync() + if !ok { + return nil, nil, nil + } + + k := ds.RawKey(v.Key) + mhash, err := dshelp.DsKeyToMultihash(k) + if err != nil { + return nil, nil, fmt.Errorf("decoding multihash from filestore: %s", err) + } + + dobj, err := unmarshalDataObj(v.Value) + if err != nil { + return mhash, nil, err + } + + return mhash, dobj, nil +} + +func listAllFileOrder(fs *Filestore, verify bool) (func() *ListRes, error) { + q := dsq.Query{} + qr, err := fs.fm.ds.Query(q) + if err != nil { + return nil, err + } + + var entries listEntries + + for { + v, ok := qr.NextSync() + if !ok { + break + } + dobj, err := unmarshalDataObj(v.Value) + if err != nil { + entries = append(entries, &listEntry{ + dsKey: v.Key, + err: err, + }) + } else { + entries = append(entries, &listEntry{ + dsKey: v.Key, + filePath: dobj.GetFilePath(), + offset: dobj.GetOffset(), + size: dobj.GetSize_(), + }) + } + } + sort.Sort(entries) + + i := 0 + return func() *ListRes { + if i >= len(entries) { + return nil + } + v := entries[i] + i++ + // attempt to convert the datastore key to a Multihash, + // store the error but don't use it yet + mhash, keyErr := dshelp.DsKeyToMultihash(ds.RawKey(v.dsKey)) + // first if they listRes already had an error return that error + if v.err != nil { + return mkListRes(mhash, nil, v.err) + } + // now reconstruct the DataObj + dobj := pb.DataObj{ + FilePath: v.filePath, + Offset: v.offset, + Size_: v.size, + } + // now if we could not convert the datastore key return that + // error + if keyErr != nil { + return mkListRes(mhash, &dobj, keyErr) + } + // finally verify the dataobj if requested + var err error + if verify { + _, err = fs.fm.readDataObj(mhash, &dobj) + } + return mkListRes(mhash, &dobj, err) + }, nil +} + +type listEntry struct { + filePath string + offset uint64 + dsKey string + size uint64 + err error +} + +type listEntries []*listEntry + +func (l listEntries) Len() int { return len(l) } +func (l listEntries) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l listEntries) Less(i, j int) bool { + if l[i].filePath == l[j].filePath { + if l[i].offset == l[j].offset { + return l[i].dsKey < l[j].dsKey + } + return l[i].offset < l[j].offset + } + return l[i].filePath < l[j].filePath +} + +func mkListRes(m mh.Multihash, d *pb.DataObj, err error) *ListRes { + status := StatusOk + errorMsg := "" + if err != nil { + if err == ds.ErrNotFound || err == blockstore.ErrNotFound { + status = StatusKeyNotFound + } else if err, ok := err.(*CorruptReferenceError); ok { + status = err.Code + } else { + status = StatusOtherError + } + errorMsg = err.Error() + } + + c := cid.NewCidV1(cid.Raw, m) + + if d == nil { + return &ListRes{ + Status: status, + ErrorMsg: errorMsg, + Key: c, + } + } + + return &ListRes{ + Status: status, + ErrorMsg: errorMsg, + Key: c, + FilePath: d.FilePath, + Size: d.Size_, + Offset: d.Offset, + } +} diff --git a/vendor/github.com/ipfs/go-graphsync/.golangci.yml b/vendor/github.com/ipfs/go-graphsync/.golangci.yml new file mode 100644 index 0000000000..ba18d3a450 --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/.golangci.yml @@ -0,0 +1,3 @@ +run: + skip-files: + - testutil/chaintypes/testchain_gen.go \ No newline at end of file diff --git a/vendor/github.com/ipfs/go-graphsync/COPYRIGHT b/vendor/github.com/ipfs/go-graphsync/COPYRIGHT new file mode 100644 index 0000000000..771e6f7cd7 --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/COPYRIGHT @@ -0,0 +1,3 @@ +Copyright 2019. Protocol Labs, Inc. + +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/vendor/github.com/ipfs/go-graphsync/LICENSE-APACHE b/vendor/github.com/ipfs/go-graphsync/LICENSE-APACHE new file mode 100644 index 0000000000..546514363d --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2019. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/ipfs/go-graphsync/LICENSE-MIT b/vendor/github.com/ipfs/go-graphsync/LICENSE-MIT new file mode 100644 index 0000000000..ea532a8305 --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2019. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ipfs/go-graphsync/README.md b/vendor/github.com/ipfs/go-graphsync/README.md new file mode 100644 index 0000000000..6d8d9c6bef --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/README.md @@ -0,0 +1,234 @@ +# go-graphsync + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![Matrix](https://img.shields.io/badge/matrix-%23ipfs%3Amatrix.org-blue.svg?style=flat-square)](https://matrix.to/#/#ipfs:matrix.org) +[![IRC](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![Discord](https://img.shields.io/discord/475789330380488707?color=blueviolet&label=discord&style=flat-square)](https://discord.gg/24fmuwR) +[![Coverage Status](https://codecov.io/gh/ipfs/go-graphsync/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-graphsync/branch/master) +[![Build Status](https://circleci.com/gh/ipfs/go-bitswap.svg?style=svg)](https://circleci.com/gh/ipfs/go-graphsync) + +> An implementation of the [graphsync protocol](https://github.com/ipld/specs/blob/master/block-layer/graphsync/graphsync.md) in go! + +## Table of Contents + +- [Background](#background) +- [Install](#install) +- [Usage](#usage) +- [Architecture](#architecture) +- [Contribute](#contribute) +- [License](#license) + +## Background + +[GraphSync](https://github.com/ipld/specs/blob/master/block-layer/graphsync/graphsync.md) is a protocol for synchronizing IPLD graphs among peers. It allows a host to make a single request to a remote peer for all of the results of traversing an [IPLD selector](https://github.com/ipld/specs/blob/master/block-layer/selectors/selectors.md) on the remote peer's local IPLD graph. + +`go-graphsync` provides an implementation of the Graphsync protocol in go. + +### Go-IPLD-Prime + +`go-graphsync` relies on `go-ipld-prime` to traverse IPLD Selectors in an IPLD graph. `go-ipld-prime` implements the [IPLD specification](https://github.com/ipld/specs) in go and is an alternative to older implementations such as `go-ipld-format` and `go-ipld-cbor`. In order to use `go-graphsync`, some understanding and use of `go-ipld-prime` concepts is necessary. + +If your existing library (i.e. `go-ipfs` or `go-filecoin`) uses these other older libraries, you can largely use go-graphsync without switching to `go-ipld-prime` across your codebase, but it will require some translations + +## Install + +`go-graphsync` requires Go >= 1.11 and can be installed using Go modules + +## Usage + +### Initializing a GraphSync Exchange + +```golang +import ( + graphsync "github.com/ipfs/go-graphsync/impl" + gsnet "github.com/ipfs/go-graphsync/network" + ipld "github.com/ipld/go-ipld-prime" +) + +var ctx context.Context +var host libp2p.Host +var loader ipld.Loader +var storer ipld.Storer + +network := gsnet.NewFromLibp2pHost(host) +exchange := graphsync.New(ctx, network, loader, storer) +``` + +Parameter Notes: + +1. `context` is just the parent context for all of GraphSync +2. `network` is a network abstraction provided to Graphsync on top +of libp2p. This allows graphsync to be tested without the actual network +3. `loader` is used to load blocks from content ids from the local block store. It's used when RESPONDING to requests from other clients. It should conform to the IPLD loader interface: https://github.com/ipld/go-ipld-prime/blob/master/linking.go +4. `storer` is used to store incoming blocks to the local block store. It's used when REQUESTING a graphsync query, to store blocks locally once they are validated as part of the correct response. It should conform to the IPLD storer interface: https://github.com/ipld/go-ipld-prime/blob/master/linking.go + +### Using GraphSync With An IPFS BlockStore + +GraphSync provides two convenience functions in the `storeutil` package for +integrating with BlockStore's from IPFS. + +```golang +import ( + graphsync "github.com/ipfs/go-graphsync/impl" + gsnet "github.com/ipfs/go-graphsync/network" + storeutil "github.com/ipfs/go-graphsync/storeutil" + ipld "github.com/ipld/go-ipld-prime" + blockstore "github.com/ipfs/go-ipfs-blockstore" +) + +var ctx context.Context +var host libp2p.Host +var bs blockstore.Blockstore + +network := gsnet.NewFromLibp2pHost(host) +loader := storeutil.LoaderForBlockstore(bs) +storer := storeutil.StorerForBlockstore(bs) + +exchange := graphsync.New(ctx, network, loader, storer) +``` + +### Write A Loader An IPFS BlockStore + +If you are using a traditional go-ipfs-blockstore, your link loading function looks like this: + +```golang +type BlockStore interface { + Get(lnk cid.Cid) (blocks.Block, error) +} +``` + +or, more generally: + +```golang +type Cid2BlockFn func (lnk cid.Cid) (blocks.Block, error) +``` + +in `go-ipld-prime`, the signature for a link loader is as follows: + +```golang +type Loader func(lnk Link, lnkCtx LinkContext) (io.Reader, error) +``` + +`go-ipld-prime` intentionally keeps its interfaces as abstract as possible to limit dependencies on other ipfs/filecoin specific packages. An IPLD Link is an abstraction for a CID, and IPLD expects io.Reader's rather than an actual block. IPLD provides a `cidLink` package for working with Links that use CIDs as the underlying data, and it's safe to assume that's the type in use if your code deals only with CIDs. A conversion would look something like this: + +```golang +import ( + ipld "github.com/ipld/go-ipld-prime" + cidLink "github.com/ipld/go-ipld-prime/linking/cid" +) + +func LoaderFromCid2BlockFn(cid2BlockFn Cid2BlockFn) ipld.Loader { + return func(lnk ipld.Link, lnkCtx ipld.LinkContext) (io.Reader, error) { + asCidLink, ok := lnk.(cidlink.Link) + if !ok { + return nil, fmt.Errorf("Unsupported Link Type") + } + block, err := cid2BlockFn(asCidLink.Cid) + if err != nil { + return nil, err + } + return bytes.NewReader(block.RawData()), nil + } +} +``` + +### Write A Storer From An IPFS BlockStore + +If you are using a traditional go-ipfs-blockstore, your storage function looks like this: + +```golang +type BlockStore interface { + Put(blocks.Block) error +} +``` + +or, more generally: + +```golang +type BlockStoreFn func (blocks.Block) (error) +``` + +in `go-ipld-prime`, the signature for a link storer is a bit different: + +```golang +type StoreCommitter func(Link) error +type Storer func(lnkCtx LinkContext) (io.Writer, StoreCommitter, error) +``` + +`go-ipld-prime` stores in two parts to support streaming -- the storer is called and returns an IO.Writer and a function to commit changes when finished. Here's how you can write a storer from a traditional block storing signature. + +```golang +import ( + blocks "github.com/ipfs/go-block-format" + ipld "github.com/ipld/go-ipld-prime" + cidLink "github.com/ipld/go-ipld-prime/linking/cid" +) + +func StorerFromBlockStoreFn(blockStoreFn BlockStoreFn) ipld.Storer { + return func(lnkCtx ipld.LinkContext) (io.Writer, ipld.StoreCommitter, error) { + var buffer bytes.Buffer + committer := func(lnk ipld.Link) error { + asCidLink, ok := lnk.(cidlink.Link) + if !ok { + return fmt.Errorf("Unsupported Link Type") + } + block := blocks.NewBlockWithCid(buffer.Bytes(), asCidLink.Cid) + return blockStoreFn(block) + } + return &buffer, committer, nil + } +} +``` + +### Calling Graphsync + +```golang +var exchange graphsync.GraphSync +var ctx context.Context +var p peer.ID +var selector ipld.Node +var rootLink ipld.Link + +var responseProgress <-chan graphsync.ResponseProgress +var errors <-chan error + +responseProgress, errors = exchange.Request(ctx context.Context, p peer.ID, root ipld.Link, selector ipld.Node) +``` + +Paramater Notes: +1. `ctx` is the context for this request. To cancel an in progress request, cancel the context. +2. `p` is the peer you will send this request to +3. `link` is an IPLD Link, i.e. a CID (cidLink.Link{Cid}) +4. `selector` is an IPLD selector node. Recommend using selector builders from go-ipld-prime to construct these + +### Response Type + +```golang + +type ResponseProgress struct { + Node ipld.Node // a node which matched the graphsync query + Path ipld.Path // the path of that node relative to the traversal start + LastBlock struct { // LastBlock stores the Path and Link of the last block edge we had to load. + ipld.Path + ipld.Link + } +} + +``` + +The above provides both immediate and relevant metadata for matching nodes in a traversal, and is very similar to the information provided by a local IPLD selector traversal in `go-ipld-prime` + +## Contribute + +PRs are welcome! + +Before doing anything heavy, checkout the [Graphsync Architecture](docs/architecture.md) + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +This library is dual-licensed under Apache 2.0 and MIT terms. + +Copyright 2019. Protocol Labs, Inc. diff --git a/vendor/github.com/ipfs/go-graphsync/go.mod b/vendor/github.com/ipfs/go-graphsync/go.mod new file mode 100644 index 0000000000..fb603f1434 --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/go.mod @@ -0,0 +1,42 @@ +module github.com/ipfs/go-graphsync + +go 1.12 + +require ( + github.com/gogo/protobuf v1.3.1 + github.com/golang/protobuf v1.3.2 // indirect + github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect + github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-blockservice v0.1.3 + github.com/ipfs/go-cid v0.0.5 + github.com/ipfs/go-datastore v0.4.4 + github.com/ipfs/go-ipfs-blockstore v0.1.4 + github.com/ipfs/go-ipfs-blocksutil v0.0.1 + github.com/ipfs/go-ipfs-chunker v0.0.5 + github.com/ipfs/go-ipfs-exchange-offline v0.0.1 + github.com/ipfs/go-ipfs-files v0.0.8 + github.com/ipfs/go-ipfs-util v0.0.1 + github.com/ipfs/go-ipld-cbor v0.0.4 // indirect + github.com/ipfs/go-ipld-format v0.2.0 + github.com/ipfs/go-log v1.0.2 + github.com/ipfs/go-merkledag v0.3.1 + github.com/ipfs/go-peertaskqueue v0.2.0 + github.com/ipfs/go-unixfs v0.2.4 + github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e + github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1 + github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c + github.com/libp2p/go-libp2p v0.6.0 + github.com/libp2p/go-libp2p-core v0.5.0 + github.com/libp2p/go-libp2p-record v0.1.1 // indirect + github.com/multiformats/go-multiaddr v0.2.1 + github.com/multiformats/go-multihash v0.0.13 + github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a // indirect + github.com/smartystreets/assertions v1.0.1 // indirect + github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect + github.com/stretchr/testify v1.5.1 + github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105 // indirect + go.uber.org/multierr v1.4.0 // indirect + golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect + golang.org/x/tools v0.0.0-20191216173652-a0e659d51361 // indirect +) diff --git a/vendor/github.com/ipfs/go-graphsync/go.sum b/vendor/github.com/ipfs/go-graphsync/go.sum new file mode 100644 index 0000000000..daf4e10c25 --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/go.sum @@ -0,0 +1,711 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= +github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 h1:qkOC5Gd33k54tobS36cXdAzJbeHaduLtnLQQwNoIi78= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c h1:aEbSeNALREWXk0G7UdNhR3ayBV7tZ4M2PNmnrCAph6Q= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 h1:A/EVblehb75cUgXA5njHPn0kLAsykn6mJGz7rnmW5W0= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= +github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ipfs/bbloom v0.0.1 h1:s7KkiBPfxCeDVo47KySjK0ACPc5GJRUxFpdyWEuDjhw= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= +github.com/ipfs/go-bitswap v0.1.2 h1:IkhOPiifc6b2LWTi/vp8TXwNT0eGCsizI1JFbZ08IQQ= +github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= +github.com/ipfs/go-bitswap v0.1.8 h1:38X1mKXkiU6Nzw4TOSWD8eTVY5eX3slQunv3QEWfXKg= +github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-blockservice v0.1.0 h1:dh2i7xjMbCtf0ZSMyQAF2qpV/pEEmM7yVpQ00+gik6U= +github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= +github.com/ipfs/go-blockservice v0.1.3 h1:9XgsPMwwWJSC9uVr2pMDsW2qFTBSkxpGMhmna8mIjPM= +github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-datastore v0.0.1 h1:AW/KZCScnBWlSb5JbnEnLKFWXL224LBEh/9KXXOrUms= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5 h1:q3OfiOZV5rlsK1H5V8benjeUApRfMGs4Mrhmr6NriQo= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= +github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ipfs-blockstore v0.0.1 h1:O9n3PbmTYZoNhkgkEyrXTznbmktIXif62xLX+8dPHzc= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= +github.com/ipfs/go-ipfs-blockstore v0.1.4 h1:2SGI6U1B44aODevza8Rde3+dY30Pb+lbcObe1LETxOQ= +github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE27SEw= +github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= +github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= +github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1 h1:QBg+Ts2zgeemK/dB0saiF/ykzRGgfoFMT90Rzo0OnVU= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-ds-help v0.1.1 h1:IW/bXGeaAZV2VH0Kuok+Ohva/zHkHmeLFBxC1k7mNPc= +github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= +github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= +github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= +github.com/ipfs/go-ipfs-pq v0.0.1 h1:zgUotX8dcAB/w/HidJh1zzc1yFq6Vm8J7T2F4itj/RU= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= +github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.2 h1:amzFztBQQQ69UA5+f7JRfoXF/z2l//MGfEDHVkS20+s= +github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.3 h1:ENsxvybwkmke7Z/QJOmeJfoguj6GH3Y0YOaGrfy9Q0I= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.4 h1:Aw3KPOKXjvrm6VjwJvFf1F1ekR/BH3jdof3Bk7OTiSA= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= +github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.2 h1:s19ZwJxH8rPWzypjcDpqPLIyV7BnbLqvpli3iZoqYK0= +github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= +github.com/ipfs/go-log/v2 v2.0.2 h1:xguurydRdfKMJjKyxNXNU8lYP0VZH1NUwJRwUorjuEw= +github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-merkledag v0.2.3 h1:aMdkK9G1hEeNvn3VXfiEMLY0iJnbiQQUHnM0HFJREsE= +github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= +github.com/ipfs/go-merkledag v0.3.1 h1:3UqWINBEr3/N+r6OwgFXAddDP/8zpQX/8J7IGVOCqRQ= +github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-peertaskqueue v0.1.0 h1:bpRbgv76eT4avutNPDFZuCPOQus6qTgurEYxfulgZW4= +github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN1EJOjc= +github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= +github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo= +github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e h1:ZISbJlM0urTANR9KRfRaqlBmyOj5uUtxs2r4Up9IXsA= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1 h1:K1Ysr7kgIlo7YQkPqdkA6H7BVdIugvuAz7OQUTJxLdE= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= +github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c h1:uUx61FiAa1GI6ZmVd2wf2vULeQZIKG66eybjNXKYCz4= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security-multistream v0.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ= +github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= +github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= +github.com/libp2p/go-libp2p v0.6.0 h1:EFArryT9N7AVA70LCcOh8zxsW+FeDnxwcpWQx9k7+GM= +github.com/libp2p/go-libp2p v0.6.0/go.mod h1:mfKWI7Soz3ABX+XEBR61lGbg+ewyMtJHVt043oWeqwg= +github.com/libp2p/go-libp2p-autonat v0.1.0 h1:aCWAu43Ri4nU0ZPO7NyLzUvvfqd0nE3dX0R/ZGYVgOU= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-autonat v0.1.1 h1:WLBZcIRsjZlWdAZj9CiBSvU2wQXoUOiS1Zk1tM7DTJI= +github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-blankhost v0.1.4 h1:I96SWjR4rK9irDHcHq3XHN6hawCRTPUADzkJacgZLvk= +github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= +github.com/libp2p/go-libp2p-circuit v0.1.0 h1:eniLL3Y9aq/sryfyV1IAHj5rlvuyj3b7iz8tSiZpdhY= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-circuit v0.1.4 h1:Phzbmrg3BkVzbqd4ZZ149JxCuUWu2wZcXf/Kr6hZJj8= +github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= +github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= +github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= +github.com/libp2p/go-libp2p-core v0.2.4 h1:Et6ykkTwI6PU44tr8qUF9k43vP0aduMNniShAbUJJw8= +github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= +github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.0 h1:FBQ1fpq2Fo/ClyjojVJ5AKXlKhvNc/B6U0O+7AN1ffE= +github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.1.0 h1:j+R6cokKcGbnZLf4kcNwpx6mDEUPF3N6SrqMymQhmvs= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-discovery v0.2.0 h1:1p3YSOq7VsgaL+xVHPi8XAmtGyas6D2J6rWBEfz/aiY= +github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-mplex v0.2.2 h1:+Ld7YDAfVERQ0E+qqjE7o6fHwKuM0SqTzYiwN1lVVSA= +github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= +github.com/libp2p/go-libp2p-nat v0.0.4 h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-nat v0.0.5 h1:/mH8pXFVKleflDL1YwqMg27W9GD8kjEx7NY0P6eGc98= +github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-peerstore v0.1.3 h1:wMgajt1uM2tMiqf4M+4qWKVyyFc8SfA+84VV9glZq1M= +github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= +github.com/libp2p/go-libp2p-peerstore v0.2.0 h1:XcgJhI8WyUOCbHyRLNEX5542YNj8hnLSJ2G1InRjDhk= +github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= +github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= +github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= +github.com/libp2p/go-libp2p-record v0.1.0 h1:wHwBGbFzymoIl69BpgwIu0O6ta3TXGcMPvHUAcodzRc= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-record v0.1.1 h1:ZJK2bHXYUBqObHX+rHLSNrM3M8fmJUlUHrodDPPATmY= +github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-secio v0.2.0 h1:ywzZBsWEEz2KNTn5RtzauEDq5RFEefPsttXYwAWqHng= +github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= +github.com/libp2p/go-libp2p-secio v0.2.1 h1:eNWbJTdyPA7NxhP7J3c5lT97DC5d+u+IldkgCYFTPVA= +github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-swarm v0.2.2 h1:T4hUpgEs2r371PweU3DuH7EOmBIdTBCwWs+FLcgx3bQ= +github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4 h1:Qev57UR47GcLPXWjrunv5aLIQGO4n9mhI/8/EIrEEFc= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.1.0 h1:WaFRj/t3HdMZGNZqnU2pS7pDRBmMeoDx7/HDNpeyT9U= +github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU= +github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0 h1:5EhPgQhXZNyfL22ERZTUoVp9UVVbNowWNVtELQaKCHk= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1 h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-libp2p-yamux v0.2.2 h1:eGvbqWqWY9S5lrpe2gA0UCOLCdzCgYSAR3vo/xCsNQg= +github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg= +github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-mplex v0.1.1 h1:huPH/GGRJzmsHR9IZJJsrSwIM5YE2gL4ssgl1YWb/ps= +github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.3 h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= +github.com/libp2p/go-nat v0.0.4 h1:KbizNnq8YIf7+Hn7+VFL/xE0eDrkPru2zIO9NMwL8UQ= +github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= +github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= +github.com/libp2p/go-openssl v0.0.3 h1:wjlG7HvQkt4Fq4cfH33Ivpwp0omaElYEi9z26qaIkIk= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1 h1:Ce6e2Pyu+b5MC1k3eeFtAax0pW4gc6MosYSLV05UeLw= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0 h1:IGhowvEqyMFknOar4FWCKSWE0zL36UFKQtiRQD60/8o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-tcp-transport v0.1.1 h1:yGlqURmqgNA2fvzjSgZNlHcsd/IulAnKM8Ncu+vlqnw= +github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= +github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.1.0 h1:F+0OvvdmPTDsVc4AjPHjV7L7Pk1B7D5QwtDcKE2oag4= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-ws-transport v0.2.0 h1:MJCw2OrPA9+76YNRvdo1wMnSOxb9Bivj6sVFY1Xrj6w= +github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.0 h1:FsYzT16Wq2XqUGJsBbOxoz9g+dFklvNi7jN6YFPfl7U= +github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5 h1:l16XLUUJ34wIz+RIvLhSwGvLvKyy+W598b135bJN6mg= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0 h1:U41/2erhAKcmSI14xh/ZTUdBPOzDOIfS93ibzUSl8KM= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multiaddr v0.0.1 h1:/QUV3VBMDI6pi6xfiw7lr6xhDWWvQKn9udPn68kLSdY= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4 h1:WgMSI84/eRLdbptXMkMWDXPjPq7SPLIgGUVm2eroyU4= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.1 h1:rVAztJYMhCQ7vEFr8FvxW3mS+HF2eY/oPbOMeS0ZDnE= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.2.1 h1:SgG/cw5vqyB5QQe5FPe2TqggU9WtrA9X4nZw7LlVqOI= +github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2 h1:/Bbsgsy3R6e3jf2qBahzNHzww6usYaZ0NhNH3sqdFS8= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= +github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-fmt v0.0.1 h1:5YjeOIzbX8OTKVaN72aOzGIYW7PnrZrnkDyOfAWRSMA= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1 h1:76O59E3FavvHqNg7jvzWzsPSW5JSi/ek0E4eiDVbg9g= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.2 h1:P7zcBH9FRETdPkDrylcXVjQLQ2t1JQtNItZULWNWgeg= +github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI= +github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14 h1:2m16U/rLwVaRdz7ANkHtHTodP3zTP3N451MADg64x5k= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 h1:CskT+S6Ay54OwxBGB0R3Rsx4Muto6UnEYTyKJbyRIAI= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105 h1:Sh6UG5dW5xW8Ek2CtRGq4ipdEvvx9hOyBJjEGyTYDl0= +github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b h1:+/WWzjwW6gidDJnMKWLKLX1gxn7irUTF1fLpQovfQ5M= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7 h1:C2F/nMkR/9sfUTpvR3QrjBuTdvMUC/cFajkphs1YLQo= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361 h1:RIIXAeV6GvDBuADKumTODatUqANFZ+5BPMnzsy4hulY= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/ipfs/go-graphsync/graphsync.go b/vendor/github.com/ipfs/go-graphsync/graphsync.go new file mode 100644 index 0000000000..df2e157f63 --- /dev/null +++ b/vendor/github.com/ipfs/go-graphsync/graphsync.go @@ -0,0 +1,254 @@ +package graphsync + +import ( + "context" + "errors" + + "github.com/ipfs/go-cid" + "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/traversal" + "github.com/libp2p/go-libp2p-core/peer" +) + +// RequestID is a unique identifier for a GraphSync request. +type RequestID int32 + +// Priority a priority for a GraphSync request. +type Priority int32 + +// ResponseStatusCode is a status returned for a GraphSync Request. +type ResponseStatusCode int32 + +// ExtensionName is a name for a GraphSync extension +type ExtensionName string + +// ExtensionData is a name/data pair for a graphsync extension +type ExtensionData struct { + Name ExtensionName + Data []byte +} + +const ( + + // Known Graphsync Extensions + + // ExtensionMetadata provides response metadata for a Graphsync request and is + // documented at + // https://github.com/ipld/specs/blob/master/block-layer/graphsync/known_extensions.md + ExtensionMetadata = ExtensionName("graphsync/response-metadata") + + // ExtensionDoNotSendCIDs tells the responding peer not to send certain blocks if they + // are encountered in a traversal and is documented at + // https://github.com/ipld/specs/blob/master/block-layer/graphsync/known_extensions.md + ExtensionDoNotSendCIDs = ExtensionName("graphsync/do-not-send-cids") + + // GraphSync Response Status Codes + + // Informational Response Codes (partial) + + // RequestAcknowledged means the request was received and is being worked on. + RequestAcknowledged = ResponseStatusCode(10) + // AdditionalPeers means additional peers were found that may be able + // to satisfy the request and contained in the extra block of the response. + AdditionalPeers = ResponseStatusCode(11) + // NotEnoughGas means fulfilling this request requires payment. + NotEnoughGas = ResponseStatusCode(12) + // OtherProtocol means a different type of response than GraphSync is + // contained in extra. + OtherProtocol = ResponseStatusCode(13) + // PartialResponse may include blocks and metadata about the in progress response + // in extra. + PartialResponse = ResponseStatusCode(14) + // RequestPaused indicates a request is paused and will not send any more data + // until unpaused + RequestPaused = ResponseStatusCode(15) + + // Success Response Codes (request terminated) + + // RequestCompletedFull means the entire fulfillment of the GraphSync request + // was sent back. + RequestCompletedFull = ResponseStatusCode(20) + // RequestCompletedPartial means the response is completed, and part of the + // GraphSync request was sent back, but not the complete request. + RequestCompletedPartial = ResponseStatusCode(21) + + // Error Response Codes (request terminated) + + // RequestRejected means the node did not accept the incoming request. + RequestRejected = ResponseStatusCode(30) + // RequestFailedBusy means the node is too busy, try again later. Backoff may + // be contained in extra. + RequestFailedBusy = ResponseStatusCode(31) + // RequestFailedUnknown means the request failed for an unspecified reason. May + // contain data about why in extra. + RequestFailedUnknown = ResponseStatusCode(32) + // RequestFailedLegal means the request failed for legal reasons. + RequestFailedLegal = ResponseStatusCode(33) + // RequestFailedContentNotFound means the respondent does not have the content. + RequestFailedContentNotFound = ResponseStatusCode(34) +) + +var ( + // ErrExtensionAlreadyRegistered means a user extension can be registered only once + ErrExtensionAlreadyRegistered = errors.New("extension already registered") +) + +// ResponseProgress is the fundamental unit of responses making progress in Graphsync. +type ResponseProgress struct { + Node ipld.Node // a node which matched the graphsync query + Path ipld.Path // the path of that node relative to the traversal start + LastBlock struct { // LastBlock stores the Path and Link of the last block edge we had to load. + Path ipld.Path + Link ipld.Link + } +} + +// RequestData describes a received graphsync request. +type RequestData interface { + // ID Returns the request ID for this Request + ID() RequestID + + // Root returns the CID to the root block of this request + Root() cid.Cid + + // Selector returns the byte representation of the selector for this request + Selector() ipld.Node + + // Priority returns the priority of this request + Priority() Priority + + // Extension returns the content for an extension on a response, or errors + // if extension is not present + Extension(name ExtensionName) ([]byte, bool) + + // IsCancel returns true if this particular request is being cancelled + IsCancel() bool +} + +// ResponseData describes a received Graphsync response +type ResponseData interface { + // RequestID returns the request ID for this response + RequestID() RequestID + + // Status returns the status for a response + Status() ResponseStatusCode + + // Extension returns the content for an extension on a response, or errors + // if extension is not present + Extension(name ExtensionName) ([]byte, bool) +} + +// BlockData gives information about a block included in a graphsync response +type BlockData interface { + // Link is the link/cid for the block + Link() ipld.Link + + // BlockSize specifies the size of the block + BlockSize() uint64 + + // BlockSize specifies the amount of data actually transmitted over the network + BlockSizeOnWire() uint64 +} + +// IncomingRequestHookActions are actions that a request hook can take to change +// behavior for the response +type IncomingRequestHookActions interface { + SendExtensionData(ExtensionData) + UsePersistenceOption(name string) + UseLinkTargetNodeStyleChooser(traversal.LinkTargetNodeStyleChooser) + TerminateWithError(error) + ValidateRequest() +} + +// OutgoingBlockHookActions are actions that an outgoing block hook can take to +// change the execution of a request +type OutgoingBlockHookActions interface { + SendExtensionData(ExtensionData) + TerminateWithError(error) + PauseResponse() +} + +// OutgoingRequestHookActions are actions that an outgoing request hook can take +// to change the execution of a request +type OutgoingRequestHookActions interface { + UsePersistenceOption(name string) + UseLinkTargetNodeStyleChooser(traversal.LinkTargetNodeStyleChooser) +} + +// IncomingResponseHookActions are actions that incoming response hook can take +// to change the execution of a request +type IncomingResponseHookActions interface { + TerminateWithError(error) + UpdateRequestWithExtensions(...ExtensionData) +} + +// RequestUpdatedHookActions are actions that can be taken in a request updated hook to +// change execution of the response +type RequestUpdatedHookActions interface { + TerminateWithError(error) + SendExtensionData(ExtensionData) + UnpauseResponse() +} + +// OnIncomingRequestHook is a hook that runs each time a new request is received. +// It receives the peer that sent the request and all data about the request. +// It receives an interface for customizing the response to this request +type OnIncomingRequestHook func(p peer.ID, request RequestData, hookActions IncomingRequestHookActions) + +// OnIncomingResponseHook is a hook that runs each time a new response is received. +// It receives the peer that sent the response and all data about the response. +// If it returns an error processing is halted and the original request is cancelled. +type OnIncomingResponseHook func(p peer.ID, responseData ResponseData, hookActions IncomingResponseHookActions) + +// OnOutgoingRequestHook is a hook that runs immediately prior to sending a request +// It receives the peer we're sending a request to and all the data aobut the request +// It receives an interface for customizing how we handle executing this request +type OnOutgoingRequestHook func(p peer.ID, request RequestData, hookActions OutgoingRequestHookActions) + +// OnOutgoingBlockHook is a hook that runs immediately after a requestor sends a new block +// on a response +// It receives the peer we're sending a request to, all the data aobut the request, a link for the block sent, +// and the size of the block sent +// It receives an interface for taking further action on the response +type OnOutgoingBlockHook func(p peer.ID, request RequestData, block BlockData, hookActions OutgoingBlockHookActions) + +// OnRequestUpdatedHook is a hook that runs when an update to a request is received +// It receives the peer we're sending to, the original request, the request update +// It receives an interface to taking further action on the response +type OnRequestUpdatedHook func(p peer.ID, request RequestData, updateRequest RequestData, hookActions RequestUpdatedHookActions) + +// OnResponseCompletedListener provides a way to listen for when responder has finished serving a response +type OnResponseCompletedListener func(p peer.ID, request RequestData, status ResponseStatusCode) + +// UnregisterHookFunc is a function call to unregister a hook that was previously registered +type UnregisterHookFunc func() + +// GraphExchange is a protocol that can exchange IPLD graphs based on a selector +type GraphExchange interface { + // Request initiates a new GraphSync request to the given peer using the given selector spec. + Request(ctx context.Context, p peer.ID, root ipld.Link, selector ipld.Node, extensions ...ExtensionData) (<-chan ResponseProgress, <-chan error) + + // RegisterPersistenceOption registers an alternate loader/storer combo that can be substituted for the default + RegisterPersistenceOption(name string, loader ipld.Loader, storer ipld.Storer) error + + // RegisterIncomingRequestHook adds a hook that runs when a request is received + RegisterIncomingRequestHook(hook OnIncomingRequestHook) UnregisterHookFunc + + // RegisterIncomingResponseHook adds a hook that runs when a response is received + RegisterIncomingResponseHook(OnIncomingResponseHook) UnregisterHookFunc + + // RegisterOutgoingRequestHook adds a hook that runs immediately prior to sending a new request + RegisterOutgoingRequestHook(hook OnOutgoingRequestHook) UnregisterHookFunc + + // RegisterOutgoingBlockHook adds a hook that runs every time a block is sent from a responder + RegisterOutgoingBlockHook(hook OnOutgoingBlockHook) UnregisterHookFunc + + // RegisterRequestUpdatedHook adds a hook that runs every time an update to a request is received + RegisterRequestUpdatedHook(hook OnRequestUpdatedHook) UnregisterHookFunc + + // RegisterCompletedResponseListener adds a listener on the responder for completed responses + RegisterCompletedResponseListener(listener OnResponseCompletedListener) UnregisterHookFunc + + // UnpauseResponse unpauses a response that was paused in a block hook based on peer ID and request ID + UnpauseResponse(peer.ID, RequestID) error +} diff --git a/vendor/github.com/ipfs/go-hamt-ipld/.gitignore b/vendor/github.com/ipfs/go-hamt-ipld/.gitignore new file mode 100644 index 0000000000..398baf21b2 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/.gitignore @@ -0,0 +1,17 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +.idea diff --git a/vendor/github.com/ipfs/go-hamt-ipld/.travis.yml b/vendor/github.com/ipfs/go-hamt-ipld/.travis.yml new file mode 100644 index 0000000000..923835bc58 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/.travis.yml @@ -0,0 +1,31 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-hamt-ipld/LICENSE b/vendor/github.com/ipfs/go-hamt-ipld/LICENSE new file mode 100644 index 0000000000..83f48ce5a4 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Whyrusleeping + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-hamt-ipld/Makefile b/vendor/github.com/ipfs/go-hamt-ipld/Makefile new file mode 100644 index 0000000000..0ad4560a70 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/Makefile @@ -0,0 +1,14 @@ +all: build + +build: + go build ./... +.PHONY: build + +test: + go test ./... +.PHONY: test + +benchmark: + go test -bench=./... +.PHONY: benchmark + diff --git a/vendor/github.com/ipfs/go-hamt-ipld/README.md b/vendor/github.com/ipfs/go-hamt-ipld/README.md new file mode 100644 index 0000000000..f3b9327fa2 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/README.md @@ -0,0 +1,34 @@ +go-hamt-ipld +================== + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://libp2p.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![Travis CI](https://travis-ci.org/ipfs/go-hamt-ipld.svg?branch=master)](https://travis-ci.org/ipfs/go-hamt-ipld) + +> A CHAMP HAMT implemented using ipld + + +## Table of Contents + +- [Usage](#usage) +- [API](#api) +- [Contribute](#contribute) +- [License](#license) + + +## Examples + +```go +// TODO +``` + +## Contribute + +PRs are welcome! + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Whyrusleeping diff --git a/vendor/github.com/ipfs/go-hamt-ipld/cbor_gen.go b/vendor/github.com/ipfs/go-hamt-ipld/cbor_gen.go new file mode 100644 index 0000000000..409007f64e --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/cbor_gen.go @@ -0,0 +1,214 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package hamt + +import ( + "fmt" + "io" + "math/big" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +// NOTE: This is a generated file, but it has been modified to encode the +// bitfield big.Int as a byte array. The bitfield is only a big.Int because +// thats a convenient type for the operations we need to perform on it, but it +// is fundamentally an array of bytes (bits) + +var _ = xerrors.Errorf + +var lengthBufNode = []byte{130} + +func (t *Node) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufNode); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Bitfield (big.Int) (struct) + { + var b []byte + if t.Bitfield != nil { + b = t.Bitfield.Bytes() + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(b))); err != nil { + return err + } + if _, err := w.Write(b); err != nil { + return err + } + } + + // t.Pointers ([]*hamt.Pointer) (slice) + if len(t.Pointers) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Pointers was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Pointers))); err != nil { + return err + } + for _, v := range t.Pointers { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *Node) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Bitfield (big.Int) (struct) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if maj != cbg.MajByteString { + return fmt.Errorf("big ints should be tagged cbor byte strings") + } + + if extra > 256 { + return fmt.Errorf("t.Bitfield: cbor bignum was too large") + } + + if extra > 0 { + buf := make([]byte, extra) + if _, err := io.ReadFull(br, buf); err != nil { + return err + } + t.Bitfield = big.NewInt(0).SetBytes(buf) + } else { + t.Bitfield = big.NewInt(0) + } + // t.Pointers ([]*hamt.Pointer) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Pointers: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Pointers = make([]*Pointer, extra) + } + + for i := 0; i < int(extra); i++ { + + var v Pointer + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Pointers[i] = &v + } + + return nil +} + +var lengthBufKV = []byte{130} + +func (t *KV) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufKV); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Key ([]uint8) (slice) + if len(t.Key) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Key was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Key))); err != nil { + return err + } + + if _, err := w.Write(t.Key); err != nil { + return err + } + + // t.Value (typegen.Deferred) (struct) + if err := t.Value.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *KV) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Key ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Key: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Key = make([]byte, extra) + if _, err := io.ReadFull(br, t.Key); err != nil { + return err + } + // t.Value (typegen.Deferred) (struct) + + { + + t.Value = new(cbg.Deferred) + + if err := t.Value.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("failed to read deferred field: %w", err) + } + } + return nil +} diff --git a/vendor/github.com/ipfs/go-hamt-ipld/codecov.yml b/vendor/github.com/ipfs/go-hamt-ipld/codecov.yml new file mode 100644 index 0000000000..5f88a9ea27 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/codecov.yml @@ -0,0 +1,3 @@ +coverage: + range: "50...100" +comment: off diff --git a/vendor/github.com/ipfs/go-hamt-ipld/go.mod b/vendor/github.com/ipfs/go-hamt-ipld/go.mod new file mode 100644 index 0000000000..b85720e53f --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/go.mod @@ -0,0 +1,14 @@ +module github.com/ipfs/go-hamt-ipld + +require ( + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 + github.com/ipfs/go-ipld-cbor v0.0.4 + github.com/ipfs/go-ipld-format v0.0.2 // indirect + github.com/spaolacci/murmur3 v1.1.0 + github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d + golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +) + +go 1.13 diff --git a/vendor/github.com/ipfs/go-hamt-ipld/go.sum b/vendor/github.com/ipfs/go-hamt-ipld/go.sum new file mode 100644 index 0000000000..1a09d64cf6 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/go.sum @@ -0,0 +1,86 @@ +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4 h1:UlfXKrZx1DjZoBhQHmNHLC1fK1dUJDN20Y28A7s+gJ8= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 h1:QN88Q0kT2QiDaLxpR/SDsqOBtNIEF/F3n96gSDUimkA= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.4 h1:Aw3KPOKXjvrm6VjwJvFf1F1ekR/BH3jdof3Bk7OTiSA= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 h1:WXhVOwj2USAXB5oMDwRl3piOux2XMV9TANaYxXHdkoE= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e h1:JY8o/ebUUrCYetWmjRCNghxC59cOEaili83rxPRQCLw= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501014322-5f9941ef88e0 h1:dmdwCOVtJAm7qwONARangN4jgCisVFmSJ486JZ1LYaA= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501014322-5f9941ef88e0/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d h1:Y25auOnuZb/GuJvqMflRSDWBz8/HBRME8fiD+H8zLfs= +github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/ipfs/go-hamt-ipld/hamt.go b/vendor/github.com/ipfs/go-hamt-ipld/hamt.go new file mode 100644 index 0000000000..af34088edb --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/hamt.go @@ -0,0 +1,456 @@ +package hamt + +import ( + "bytes" + "context" + "fmt" + "math/big" + + cid "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +const arrayWidth = 3 +const defaultBitWidth = 8 + +type Node struct { + Bitfield *big.Int `refmt:"bf"` + Pointers []*Pointer `refmt:"p"` + + bitWidth int + + // for fetching and storing children + store cbor.IpldStore +} + +// Option is a function that configures the node +type Option func(*Node) + +// UseTreeBitWidth allows you to set the width of the HAMT tree +// in bits (from 1-8) via a customized hash function +func UseTreeBitWidth(bitWidth int) Option { + return func(nd *Node) { + if bitWidth > 0 && bitWidth <= 8 { + nd.bitWidth = bitWidth + } + } +} + +// NewNode creates a new IPLD HAMT Node with the given store and given +// options +func NewNode(cs cbor.IpldStore, options ...Option) *Node { + nd := &Node{ + Bitfield: big.NewInt(0), + Pointers: make([]*Pointer, 0), + store: cs, + bitWidth: defaultBitWidth, + } + // apply functional options to node before using + for _, option := range options { + option(nd) + } + return nd +} + +type KV struct { + Key []byte + Value *cbg.Deferred +} + +type Pointer struct { + KVs []*KV `refmt:"v,omitempty"` + Link cid.Cid `refmt:"l,omitempty"` + + // cached node to avoid too many serialization operations + cache *Node +} + +func (n *Node) Find(ctx context.Context, k string, out interface{}) error { + return n.getValue(ctx, &hashBits{b: hash([]byte(k))}, k, func(kv *KV) error { + // used to just see if the thing exists in the set + if out == nil { + return nil + } + + if um, ok := out.(cbg.CBORUnmarshaler); ok { + return um.UnmarshalCBOR(bytes.NewReader(kv.Value.Raw)) + } + + if err := cbor.DecodeInto(kv.Value.Raw, out); err != nil { + return xerrors.Errorf("cbor decoding value: %w", err) + } + + return nil + }) +} + +func (n *Node) FindRaw(ctx context.Context, k string) ([]byte, error) { + var ret []byte + err := n.getValue(ctx, &hashBits{b: hash([]byte(k))}, k, func(kv *KV) error { + ret = kv.Value.Raw + return nil + }) + return ret, err +} + +func (n *Node) Delete(ctx context.Context, k string) error { + kb := []byte(k) + return n.modifyValue(ctx, &hashBits{b: hash(kb)}, kb, nil) +} + +var ErrNotFound = fmt.Errorf("not found") +var ErrMaxDepth = fmt.Errorf("attempted to traverse hamt beyond max depth") + +func (n *Node) getValue(ctx context.Context, hv *hashBits, k string, cb func(*KV) error) error { + idx, err := hv.Next(n.bitWidth) + if err != nil { + return ErrMaxDepth + } + + if n.Bitfield.Bit(idx) == 0 { + return ErrNotFound + } + + cindex := byte(n.indexForBitPos(idx)) + + c := n.getChild(cindex) + if c.isShard() { + chnd, err := c.loadChild(ctx, n.store, n.bitWidth) + if err != nil { + return err + } + + return chnd.getValue(ctx, hv, k, cb) + } + + for _, kv := range c.KVs { + if string(kv.Key) == k { + return cb(kv) + } + } + + return ErrNotFound +} + +func (p *Pointer) loadChild(ctx context.Context, ns cbor.IpldStore, bitWidth int) (*Node, error) { + if p.cache != nil { + return p.cache, nil + } + + out, err := LoadNode(ctx, ns, p.Link) + if err != nil { + return nil, err + } + out.bitWidth = bitWidth + + p.cache = out + return out, nil +} + +func LoadNode(ctx context.Context, cs cbor.IpldStore, c cid.Cid, options ...Option) (*Node, error) { + var out Node + if err := cs.Get(ctx, c, &out); err != nil { + return nil, err + } + + out.store = cs + out.bitWidth = defaultBitWidth + // apply functional options to node before using + for _, option := range options { + option(&out) + } + + return &out, nil +} + +func (n *Node) checkSize(ctx context.Context) (uint64, error) { + c, err := n.store.Put(ctx, n) + if err != nil { + return 0, err + } + + var def cbg.Deferred + if err := n.store.Get(ctx, c, &def); err != nil { + return 0, nil + } + + totsize := uint64(len(def.Raw)) + for _, ch := range n.Pointers { + if ch.isShard() { + chnd, err := ch.loadChild(ctx, n.store, n.bitWidth) + if err != nil { + return 0, err + } + chsize, err := chnd.checkSize(ctx) + if err != nil { + return 0, err + } + totsize += chsize + } + } + + return totsize, nil +} + +func (n *Node) Flush(ctx context.Context) error { + for _, p := range n.Pointers { + if p.cache != nil { + if err := p.cache.Flush(ctx); err != nil { + return err + } + + c, err := n.store.Put(ctx, p.cache) + if err != nil { + return err + } + + p.cache = nil + p.Link = c + } + } + return nil +} + +// SetRaw sets key k to cbor bytes raw +func (n *Node) SetRaw(ctx context.Context, k string, raw []byte) error { + d := &cbg.Deferred{Raw: raw} + kb := []byte(k) + return n.modifyValue(ctx, &hashBits{b: hash(kb)}, kb, d) +} + +func (n *Node) Set(ctx context.Context, k string, v interface{}) error { + var d *cbg.Deferred + + kb := []byte(k) + + cm, ok := v.(cbg.CBORMarshaler) + if ok { + buf := new(bytes.Buffer) + if err := cm.MarshalCBOR(buf); err != nil { + return err + } + d = &cbg.Deferred{Raw: buf.Bytes()} + } else { + b, err := cbor.DumpObject(v) + if err != nil { + return err + } + d = &cbg.Deferred{Raw: b} + } + + return n.modifyValue(ctx, &hashBits{b: hash(kb)}, kb, d) +} + +func (n *Node) cleanChild(chnd *Node, cindex byte) error { + l := len(chnd.Pointers) + switch { + case l == 0: + return fmt.Errorf("incorrectly formed HAMT") + case l == 1: + // TODO: only do this if its a value, cant do this for shards unless pairs requirements are met. + + ps := chnd.Pointers[0] + if ps.isShard() { + return nil + } + + return n.setChild(cindex, ps) + case l <= arrayWidth: + var chvals []*KV + for _, p := range chnd.Pointers { + if p.isShard() { + return nil + } + + for _, sp := range p.KVs { + if len(chvals) == arrayWidth { + return nil + } + chvals = append(chvals, sp) + } + } + return n.setChild(cindex, &Pointer{KVs: chvals}) + default: + return nil + } +} + +func (n *Node) modifyValue(ctx context.Context, hv *hashBits, k []byte, v *cbg.Deferred) error { + idx, err := hv.Next(n.bitWidth) + if err != nil { + return ErrMaxDepth + } + + if n.Bitfield.Bit(idx) != 1 { + return n.insertChild(idx, k, v) + } + + cindex := byte(n.indexForBitPos(idx)) + + child := n.getChild(cindex) + if child.isShard() { + chnd, err := child.loadChild(ctx, n.store, n.bitWidth) + if err != nil { + return err + } + + if err := chnd.modifyValue(ctx, hv, k, v); err != nil { + return err + } + + // CHAMP optimization, ensure trees look correct after deletions + if v == nil { + if err := n.cleanChild(chnd, cindex); err != nil { + return err + } + } + + return nil + } + + if v == nil { + for i, p := range child.KVs { + if bytes.Equal(p.Key, k) { + if len(child.KVs) == 1 { + return n.rmChild(cindex, idx) + } + + copy(child.KVs[i:], child.KVs[i+1:]) + child.KVs = child.KVs[:len(child.KVs)-1] + return nil + } + } + return ErrNotFound + } + + // check if key already exists + for _, p := range child.KVs { + if bytes.Equal(p.Key, k) { + p.Value = v + return nil + } + } + + // If the array is full, create a subshard and insert everything into it + if len(child.KVs) >= arrayWidth { + sub := NewNode(n.store) + sub.bitWidth = n.bitWidth + hvcopy := &hashBits{b: hv.b, consumed: hv.consumed} + if err := sub.modifyValue(ctx, hvcopy, k, v); err != nil { + return err + } + + for _, p := range child.KVs { + chhv := &hashBits{b: hash(p.Key), consumed: hv.consumed} + if err := sub.modifyValue(ctx, chhv, p.Key, p.Value); err != nil { + return err + } + } + + c, err := n.store.Put(ctx, sub) + if err != nil { + return err + } + + return n.setChild(cindex, &Pointer{Link: c}) + } + + // otherwise insert the new element into the array in order + np := &KV{Key: k, Value: v} + for i := 0; i < len(child.KVs); i++ { + if bytes.Compare(k, child.KVs[i].Key) < 0 { + child.KVs = append(child.KVs[:i], append([]*KV{np}, child.KVs[i:]...)...) + return nil + } + } + child.KVs = append(child.KVs, np) + return nil +} + +func (n *Node) insertChild(idx int, k []byte, v *cbg.Deferred) error { + if v == nil { + return ErrNotFound + } + + i := n.indexForBitPos(idx) + n.Bitfield.SetBit(n.Bitfield, idx, 1) + + p := &Pointer{KVs: []*KV{{Key: k, Value: v}}} + + n.Pointers = append(n.Pointers[:i], append([]*Pointer{p}, n.Pointers[i:]...)...) + return nil +} + +func (n *Node) setChild(i byte, p *Pointer) error { + n.Pointers[i] = p + return nil +} + +func (n *Node) rmChild(i byte, idx int) error { + copy(n.Pointers[i:], n.Pointers[i+1:]) + n.Pointers = n.Pointers[:len(n.Pointers)-1] + n.Bitfield.SetBit(n.Bitfield, idx, 0) + + return nil +} + +func (n *Node) getChild(i byte) *Pointer { + if int(i) >= len(n.Pointers) || i < 0 { + return nil + } + + return n.Pointers[i] +} + +func (n *Node) Copy() *Node { + nn := NewNode(n.store) + nn.bitWidth = n.bitWidth + nn.Bitfield.Set(n.Bitfield) + nn.Pointers = make([]*Pointer, len(n.Pointers)) + + for i, p := range n.Pointers { + pp := &Pointer{} + if p.cache != nil { + pp.cache = p.cache.Copy() + } + pp.Link = p.Link + if p.KVs != nil { + pp.KVs = make([]*KV, len(p.KVs)) + for j, kv := range p.KVs { + pp.KVs[j] = &KV{Key: kv.Key, Value: kv.Value} + } + } + nn.Pointers[i] = pp + } + + return nn +} + +func (p *Pointer) isShard() bool { + return p.Link.Defined() +} + +func (n *Node) ForEach(ctx context.Context, f func(k string, val interface{}) error) error { + for _, p := range n.Pointers { + if p.isShard() { + chnd, err := p.loadChild(ctx, n.store, n.bitWidth) + if err != nil { + return err + } + + if err := chnd.ForEach(ctx, f); err != nil { + return err + } + } else { + for _, kv := range p.KVs { + // TODO: consider removing 'strings as keys' from every interface, go full-on bytes everywhere + if err := f(string(kv.Key), kv.Value); err != nil { + return err + } + } + } + } + return nil +} diff --git a/vendor/github.com/ipfs/go-hamt-ipld/hash.go b/vendor/github.com/ipfs/go-hamt-ipld/hash.go new file mode 100644 index 0000000000..e784d2a215 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/hash.go @@ -0,0 +1,56 @@ +package hamt + +import ( + "fmt" + + "github.com/spaolacci/murmur3" +) + +// hashBits is a helper that allows the reading of the 'next n bits' as an integer. +type hashBits struct { + b []byte + consumed int +} + +func mkmask(n int) byte { + return (1 << uint(n)) - 1 +} + +// Next returns the next 'i' bits of the hashBits value as an integer, or an +// error if there aren't enough bits. +func (hb *hashBits) Next(i int) (int, error) { + if hb.consumed+i > len(hb.b)*8 { + return 0, fmt.Errorf("sharded directory too deep") + } + return hb.next(i), nil +} + +func (hb *hashBits) next(i int) int { + curbi := hb.consumed / 8 + leftb := 8 - (hb.consumed % 8) + + curb := hb.b[curbi] + if i == leftb { + out := int(mkmask(i) & curb) + hb.consumed += i + return out + } else if i < leftb { + a := curb & mkmask(leftb) // mask out the high bits we don't want + b := a & ^mkmask(leftb-i) // mask out the low bits we don't want + c := b >> uint(leftb-i) // shift whats left down + hb.consumed += i + return int(c) + } else { + out := int(mkmask(leftb) & curb) + out <<= uint(i - leftb) + hb.consumed += leftb + out += hb.next(i - leftb) + return out + } +} + +var hash = func(val []byte) []byte { + h := murmur3.New64() + h.Write(val) + return h.Sum(nil) +} diff --git a/vendor/github.com/ipfs/go-hamt-ipld/pointer_cbor.go b/vendor/github.com/ipfs/go-hamt-ipld/pointer_cbor.go new file mode 100644 index 0000000000..8734626336 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/pointer_cbor.go @@ -0,0 +1,133 @@ +package hamt + +import ( + "fmt" + "io" + + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" +) + +var keyZero = []byte("0") +var keyOne = []byte("1") + +func (t *Pointer) MarshalCBOR(w io.Writer) error { + if t.Link != cid.Undef && len(t.KVs) > 0 { + return fmt.Errorf("hamt Pointer cannot have both a link and KVs") + } + + scratch := make([]byte, 9) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajMap, 1); err != nil { + return err + } + + if t.Link != cid.Undef { + // key for links is "0" + // Refmt (and the general IPLD data model currently) can't deal + // with non string keys. So we have this weird restriction right now + // hoping to be able to use integer keys soon + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, 1); err != nil { + return err + } + + if _, err := w.Write(keyZero); err != nil { + return err + } + + if err := cbg.WriteCidBuf(scratch, w, t.Link); err != nil { + return err + } + } else { + // key for KVs is "1" + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, 1); err != nil { + return err + } + + if _, err := w.Write(keyOne); err != nil { + return err + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.KVs))); err != nil { + return err + } + + for _, kv := range t.KVs { + if err := kv.MarshalCBOR(w); err != nil { + return err + } + } + } + + return nil +} + +func (t *Pointer) UnmarshalCBOR(br io.Reader) error { + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of map") + } + + if extra != 1 { + return fmt.Errorf("Pointers should be a single element map") + } + + maj, val, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if maj != cbg.MajTextString { + return fmt.Errorf("expected text string key") + } + + if val != 1 { + return fmt.Errorf("map keys in pointers must be a single byte long") + } + + if _, err := io.ReadAtLeast(br, scratch[:1], 1); err != nil { + return err + } + + switch scratch[0] { + case '0': + c, err := cbg.ReadCid(br) + if err != nil { + return err + } + t.Link = c + return nil + case '1': + maj, length, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected an array of KVs in cbor input") + } + + if length > 32 { + return fmt.Errorf("KV array in cbor input for pointer was too long") + } + + t.KVs = make([]*KV, length) + for i := 0; i < int(length); i++ { + var kv KV + if err := kv.UnmarshalCBOR(br); err != nil { + return err + } + + t.KVs[i] = &kv + } + + return nil + default: + return fmt.Errorf("invalid pointer map key in cbor input: %d", val) + } +} diff --git a/vendor/github.com/ipfs/go-hamt-ipld/uhamt.go b/vendor/github.com/ipfs/go-hamt-ipld/uhamt.go new file mode 100644 index 0000000000..e7cf8a4001 --- /dev/null +++ b/vendor/github.com/ipfs/go-hamt-ipld/uhamt.go @@ -0,0 +1,27 @@ +package hamt + +import ( + "math/big" + "math/bits" +) + +// indexForBitPos returns the index within the collapsed array corresponding to +// the given bit in the bitset. The collapsed array contains only one entry +// per bit set in the bitfield, and this function is used to map the indices. +func (n *Node) indexForBitPos(bp int) int { + return indexForBitPos(bp, n.Bitfield) +} + +func indexForBitPos(bp int, bitfield *big.Int) int { + var x uint + var count, i int + w := bitfield.Bits() + for x = uint(bp); x > bits.UintSize && i < len(w); x -= bits.UintSize { + count += bits.OnesCount(uint(w[i])) + i++ + } + if i == len(w) { + return count + } + return count + bits.OnesCount(uint(w[i])&((1< go-ipfs-blockstore implements a thin wrapper over a datastore, giving a clean interface for Getting and Putting block objects. + +## Lead Maintainer + +[Steven Allen](https://github.com/Stebalien) + + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [Contribute](#contribute) +- [License](#license) + +## Install + +`go-ipfs-blockstore` works like a regular Go module: + +``` +> go get github.com/ipfs/go-ipfs-blockstore +``` + +## Usage + +``` +import "github.com/ipfs/go-ipfs-blockstore" +``` + +Check the [GoDoc documentation](https://godoc.org/github.com/ipfs/go-ipfs-blockstore) + +## Contribute + +PRs accepted. + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Protocol Labs, Inc. diff --git a/vendor/github.com/ipfs/go-ipfs-blockstore/arc_cache.go b/vendor/github.com/ipfs/go-ipfs-blockstore/arc_cache.go new file mode 100644 index 0000000000..e2b930dcad --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-blockstore/arc_cache.go @@ -0,0 +1,184 @@ +package blockstore + +import ( + "context" + + lru "github.com/hashicorp/golang-lru" + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + metrics "github.com/ipfs/go-metrics-interface" +) + +type cacheHave bool +type cacheSize int + +// arccache wraps a BlockStore with an Adaptive Replacement Cache (ARC) for +// block Cids. This provides block access-time improvements, allowing +// to short-cut many searches without query-ing the underlying datastore. +type arccache struct { + arc *lru.TwoQueueCache + blockstore Blockstore + + hits metrics.Counter + total metrics.Counter +} + +func newARCCachedBS(ctx context.Context, bs Blockstore, lruSize int) (*arccache, error) { + arc, err := lru.New2Q(lruSize) + if err != nil { + return nil, err + } + c := &arccache{arc: arc, blockstore: bs} + c.hits = metrics.NewCtx(ctx, "arc.hits_total", "Number of ARC cache hits").Counter() + c.total = metrics.NewCtx(ctx, "arc_total", "Total number of ARC cache requests").Counter() + + return c, nil +} + +func (b *arccache) DeleteBlock(k cid.Cid) error { + if has, _, ok := b.hasCached(k); ok && !has { + return nil + } + + b.arc.Remove(k) // Invalidate cache before deleting. + err := b.blockstore.DeleteBlock(k) + if err == nil { + b.cacheHave(k, false) + } + return err +} + +// if ok == false has is inconclusive +// if ok == true then has respons to question: is it contained +func (b *arccache) hasCached(k cid.Cid) (has bool, size int, ok bool) { + b.total.Inc() + if !k.Defined() { + log.Error("undefined cid in arccache") + // Return cache invalid so the call to blockstore happens + // in case of invalid key and correct error is created. + return false, -1, false + } + + h, ok := b.arc.Get(string(k.Hash())) + if ok { + b.hits.Inc() + switch h := h.(type) { + case cacheHave: + return bool(h), -1, true + case cacheSize: + return true, int(h), true + } + } + return false, -1, false +} + +func (b *arccache) Has(k cid.Cid) (bool, error) { + if has, _, ok := b.hasCached(k); ok { + return has, nil + } + has, err := b.blockstore.Has(k) + if err != nil { + return false, err + } + b.cacheHave(k, has) + return has, nil +} + +func (b *arccache) GetSize(k cid.Cid) (int, error) { + if has, blockSize, ok := b.hasCached(k); ok { + if !has { + // don't have it, return + return -1, ErrNotFound + } + if blockSize >= 0 { + // have it and we know the size + return blockSize, nil + } + // we have it but don't know the size, ask the datastore. + } + blockSize, err := b.blockstore.GetSize(k) + if err == ErrNotFound { + b.cacheHave(k, false) + } else if err == nil { + b.cacheSize(k, blockSize) + } + return blockSize, err +} + +func (b *arccache) Get(k cid.Cid) (blocks.Block, error) { + if !k.Defined() { + log.Error("undefined cid in arc cache") + return nil, ErrNotFound + } + + if has, _, ok := b.hasCached(k); ok && !has { + return nil, ErrNotFound + } + + bl, err := b.blockstore.Get(k) + if bl == nil && err == ErrNotFound { + b.cacheHave(k, false) + } else if bl != nil { + b.cacheSize(k, len(bl.RawData())) + } + return bl, err +} + +func (b *arccache) Put(bl blocks.Block) error { + if has, _, ok := b.hasCached(bl.Cid()); ok && has { + return nil + } + + err := b.blockstore.Put(bl) + if err == nil { + b.cacheSize(bl.Cid(), len(bl.RawData())) + } + return err +} + +func (b *arccache) PutMany(bs []blocks.Block) error { + var good []blocks.Block + for _, block := range bs { + // call put on block if result is inconclusive or we are sure that + // the block isn't in storage + if has, _, ok := b.hasCached(block.Cid()); !ok || (ok && !has) { + good = append(good, block) + } + } + err := b.blockstore.PutMany(good) + if err != nil { + return err + } + for _, block := range good { + b.cacheSize(block.Cid(), len(block.RawData())) + } + return nil +} + +func (b *arccache) HashOnRead(enabled bool) { + b.blockstore.HashOnRead(enabled) +} + +func (b *arccache) cacheHave(c cid.Cid, have bool) { + b.arc.Add(string(c.Hash()), cacheHave(have)) +} + +func (b *arccache) cacheSize(c cid.Cid, blockSize int) { + b.arc.Add(string(c.Hash()), cacheSize(blockSize)) +} + +func (b *arccache) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + return b.blockstore.AllKeysChan(ctx) +} + +func (b *arccache) GCLock() Unlocker { + return b.blockstore.(GCBlockstore).GCLock() +} + +func (b *arccache) PinLock() Unlocker { + return b.blockstore.(GCBlockstore).PinLock() +} + +func (b *arccache) GCRequested() bool { + return b.blockstore.(GCBlockstore).GCRequested() +} diff --git a/vendor/github.com/ipfs/go-ipfs-blockstore/blockstore.go b/vendor/github.com/ipfs/go-ipfs-blockstore/blockstore.go new file mode 100644 index 0000000000..e815642da0 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-blockstore/blockstore.go @@ -0,0 +1,279 @@ +// Package blockstore implements a thin wrapper over a datastore, giving a +// clean interface for Getting and Putting block objects. +package blockstore + +import ( + "context" + "errors" + "sync" + "sync/atomic" + + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + ds "github.com/ipfs/go-datastore" + dsns "github.com/ipfs/go-datastore/namespace" + dsq "github.com/ipfs/go-datastore/query" + dshelp "github.com/ipfs/go-ipfs-ds-help" + logging "github.com/ipfs/go-log" +) + +var log = logging.Logger("blockstore") + +// BlockPrefix namespaces blockstore datastores +var BlockPrefix = ds.NewKey("blocks") + +// ErrHashMismatch is an error returned when the hash of a block +// is different than expected. +var ErrHashMismatch = errors.New("block in storage has different hash than requested") + +// ErrNotFound is an error returned when a block is not found. +var ErrNotFound = errors.New("blockstore: block not found") + +// Blockstore wraps a Datastore block-centered methods and provides a layer +// of abstraction which allows to add different caching strategies. +type Blockstore interface { + DeleteBlock(cid.Cid) error + Has(cid.Cid) (bool, error) + Get(cid.Cid) (blocks.Block, error) + + // GetSize returns the CIDs mapped BlockSize + GetSize(cid.Cid) (int, error) + + // Put puts a given block to the underlying datastore + Put(blocks.Block) error + + // PutMany puts a slice of blocks at the same time using batching + // capabilities of the underlying datastore whenever possible. + PutMany([]blocks.Block) error + + // AllKeysChan returns a channel from which + // the CIDs in the Blockstore can be read. It should respect + // the given context, closing the channel if it becomes Done. + AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) + + // HashOnRead specifies if every read block should be + // rehashed to make sure it matches its CID. + HashOnRead(enabled bool) +} + +// GCLocker abstract functionality to lock a blockstore when performing +// garbage-collection operations. +type GCLocker interface { + // GCLock locks the blockstore for garbage collection. No operations + // that expect to finish with a pin should ocurr simultaneously. + // Reading during GC is safe, and requires no lock. + GCLock() Unlocker + + // PinLock locks the blockstore for sequences of puts expected to finish + // with a pin (before GC). Multiple put->pin sequences can write through + // at the same time, but no GC should happen simulatenously. + // Reading during Pinning is safe, and requires no lock. + PinLock() Unlocker + + // GcRequested returns true if GCLock has been called and is waiting to + // take the lock + GCRequested() bool +} + +// GCBlockstore is a blockstore that can safely run garbage-collection +// operations. +type GCBlockstore interface { + Blockstore + GCLocker +} + +// NewGCBlockstore returns a default implementation of GCBlockstore +// using the given Blockstore and GCLocker. +func NewGCBlockstore(bs Blockstore, gcl GCLocker) GCBlockstore { + return gcBlockstore{bs, gcl} +} + +type gcBlockstore struct { + Blockstore + GCLocker +} + +// NewBlockstore returns a default Blockstore implementation +// using the provided datastore.Batching backend. +func NewBlockstore(d ds.Batching) Blockstore { + var dsb ds.Batching + dd := dsns.Wrap(d, BlockPrefix) + dsb = dd + return &blockstore{ + datastore: dsb, + } +} + +type blockstore struct { + datastore ds.Batching + + rehash bool +} + +func (bs *blockstore) HashOnRead(enabled bool) { + bs.rehash = enabled +} + +func (bs *blockstore) Get(k cid.Cid) (blocks.Block, error) { + if !k.Defined() { + log.Error("undefined cid in blockstore") + return nil, ErrNotFound + } + bdata, err := bs.datastore.Get(dshelp.MultihashToDsKey(k.Hash())) + if err == ds.ErrNotFound { + return nil, ErrNotFound + } + if err != nil { + return nil, err + } + if bs.rehash { + rbcid, err := k.Prefix().Sum(bdata) + if err != nil { + return nil, err + } + + if !rbcid.Equals(k) { + return nil, ErrHashMismatch + } + + return blocks.NewBlockWithCid(bdata, rbcid) + } + return blocks.NewBlockWithCid(bdata, k) +} + +func (bs *blockstore) Put(block blocks.Block) error { + k := dshelp.MultihashToDsKey(block.Cid().Hash()) + + // Has is cheaper than Put, so see if we already have it + exists, err := bs.datastore.Has(k) + if err == nil && exists { + return nil // already stored. + } + return bs.datastore.Put(k, block.RawData()) +} + +func (bs *blockstore) PutMany(blocks []blocks.Block) error { + t, err := bs.datastore.Batch() + if err != nil { + return err + } + for _, b := range blocks { + k := dshelp.MultihashToDsKey(b.Cid().Hash()) + exists, err := bs.datastore.Has(k) + if err == nil && exists { + continue + } + + err = t.Put(k, b.RawData()) + if err != nil { + return err + } + } + return t.Commit() +} + +func (bs *blockstore) Has(k cid.Cid) (bool, error) { + return bs.datastore.Has(dshelp.MultihashToDsKey(k.Hash())) +} + +func (bs *blockstore) GetSize(k cid.Cid) (int, error) { + size, err := bs.datastore.GetSize(dshelp.MultihashToDsKey(k.Hash())) + if err == ds.ErrNotFound { + return -1, ErrNotFound + } + return size, err +} + +func (bs *blockstore) DeleteBlock(k cid.Cid) error { + return bs.datastore.Delete(dshelp.MultihashToDsKey(k.Hash())) +} + +// AllKeysChan runs a query for keys from the blockstore. +// this is very simplistic, in the future, take dsq.Query as a param? +// +// AllKeysChan respects context. +func (bs *blockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + + // KeysOnly, because that would be _a lot_ of data. + q := dsq.Query{KeysOnly: true} + res, err := bs.datastore.Query(q) + if err != nil { + return nil, err + } + + output := make(chan cid.Cid, dsq.KeysOnlyBufSize) + go func() { + defer func() { + res.Close() // ensure exit (signals early exit, too) + close(output) + }() + + for { + e, ok := res.NextSync() + if !ok { + return + } + if e.Error != nil { + log.Errorf("blockstore.AllKeysChan got err: %s", e.Error) + return + } + + // need to convert to key.Key using key.KeyFromDsKey. + bk, err := dshelp.BinaryFromDsKey(ds.RawKey(e.Key)) + if err != nil { + log.Warningf("error parsing key from binary: %s", err) + continue + } + k := cid.NewCidV1(cid.Raw, bk) + select { + case <-ctx.Done(): + return + case output <- k: + } + } + }() + + return output, nil +} + +// NewGCLocker returns a default implementation of +// GCLocker using standard [RW] mutexes. +func NewGCLocker() GCLocker { + return &gclocker{} +} + +type gclocker struct { + lk sync.RWMutex + gcreq int32 +} + +// Unlocker represents an object which can Unlock +// something. +type Unlocker interface { + Unlock() +} + +type unlocker struct { + unlock func() +} + +func (u *unlocker) Unlock() { + u.unlock() + u.unlock = nil // ensure its not called twice +} + +func (bs *gclocker) GCLock() Unlocker { + atomic.AddInt32(&bs.gcreq, 1) + bs.lk.Lock() + atomic.AddInt32(&bs.gcreq, -1) + return &unlocker{bs.lk.Unlock} +} + +func (bs *gclocker) PinLock() Unlocker { + bs.lk.RLock() + return &unlocker{bs.lk.RUnlock} +} + +func (bs *gclocker) GCRequested() bool { + return atomic.LoadInt32(&bs.gcreq) > 0 +} diff --git a/vendor/github.com/ipfs/go-ipfs-blockstore/bloom_cache.go b/vendor/github.com/ipfs/go-ipfs-blockstore/bloom_cache.go new file mode 100644 index 0000000000..b4fadc2ef0 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-blockstore/bloom_cache.go @@ -0,0 +1,204 @@ +package blockstore + +import ( + "context" + "fmt" + "sync/atomic" + "time" + + bloom "github.com/ipfs/bbloom" + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + metrics "github.com/ipfs/go-metrics-interface" +) + +// bloomCached returns a Blockstore that caches Has requests using a Bloom +// filter. bloomSize is size of bloom filter in bytes. hashCount specifies the +// number of hashing functions in the bloom filter (usually known as k). +func bloomCached(ctx context.Context, bs Blockstore, bloomSize, hashCount int) (*bloomcache, error) { + bl, err := bloom.New(float64(bloomSize), float64(hashCount)) + if err != nil { + return nil, err + } + bc := &bloomcache{ + blockstore: bs, + bloom: bl, + hits: metrics.NewCtx(ctx, "bloom.hits_total", + "Number of cache hits in bloom cache").Counter(), + total: metrics.NewCtx(ctx, "bloom_total", + "Total number of requests to bloom cache").Counter(), + buildChan: make(chan struct{}), + } + go func() { + err := bc.build(ctx) + if err != nil { + select { + case <-ctx.Done(): + log.Warning("Cache rebuild closed by context finishing: ", err) + default: + log.Error(err) + } + return + } + if metrics.Active() { + fill := metrics.NewCtx(ctx, "bloom_fill_ratio", + "Ratio of bloom filter fullnes, (updated once a minute)").Gauge() + + t := time.NewTicker(1 * time.Minute) + defer t.Stop() + for { + select { + case <-ctx.Done(): + return + case <-t.C: + fill.Set(bc.bloom.FillRatioTS()) + } + } + } + }() + return bc, nil +} + +type bloomcache struct { + active int32 + + bloom *bloom.Bloom + buildErr error + + buildChan chan struct{} + blockstore Blockstore + + // Statistics + hits metrics.Counter + total metrics.Counter +} + +func (b *bloomcache) BloomActive() bool { + return atomic.LoadInt32(&b.active) != 0 +} + +func (b *bloomcache) Wait(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + case <-b.buildChan: + return b.buildErr + } +} + +func (b *bloomcache) build(ctx context.Context) error { + evt := log.EventBegin(ctx, "bloomcache.build") + defer evt.Done() + defer close(b.buildChan) + + ch, err := b.blockstore.AllKeysChan(ctx) + if err != nil { + b.buildErr = fmt.Errorf("AllKeysChan failed in bloomcache rebuild with: %v", err) + return b.buildErr + } + for { + select { + case key, ok := <-ch: + if !ok { + atomic.StoreInt32(&b.active, 1) + return nil + } + b.bloom.AddTS(key.Hash()) // Use binary key, the more compact the better + case <-ctx.Done(): + b.buildErr = ctx.Err() + return b.buildErr + } + } +} + +func (b *bloomcache) DeleteBlock(k cid.Cid) error { + if has, ok := b.hasCached(k); ok && !has { + return nil + } + + return b.blockstore.DeleteBlock(k) +} + +// if ok == false has is inconclusive +// if ok == true then has respons to question: is it contained +func (b *bloomcache) hasCached(k cid.Cid) (has bool, ok bool) { + b.total.Inc() + if !k.Defined() { + log.Error("undefined in bloom cache") + // Return cache invalid so call to blockstore + // in case of invalid key is forwarded deeper + return false, false + } + if b.BloomActive() { + blr := b.bloom.HasTS(k.Hash()) + if !blr { // not contained in bloom is only conclusive answer bloom gives + b.hits.Inc() + return false, true + } + } + return false, false +} + +func (b *bloomcache) Has(k cid.Cid) (bool, error) { + if has, ok := b.hasCached(k); ok { + return has, nil + } + + return b.blockstore.Has(k) +} + +func (b *bloomcache) GetSize(k cid.Cid) (int, error) { + return b.blockstore.GetSize(k) +} + +func (b *bloomcache) Get(k cid.Cid) (blocks.Block, error) { + if has, ok := b.hasCached(k); ok && !has { + return nil, ErrNotFound + } + + return b.blockstore.Get(k) +} + +func (b *bloomcache) Put(bl blocks.Block) error { + // See comment in PutMany + err := b.blockstore.Put(bl) + if err == nil { + b.bloom.AddTS(bl.Cid().Hash()) + } + return err +} + +func (b *bloomcache) PutMany(bs []blocks.Block) error { + // bloom cache gives only conclusive resulty if key is not contained + // to reduce number of puts we need conclusive information if block is contained + // this means that PutMany can't be improved with bloom cache so we just + // just do a passthrough. + err := b.blockstore.PutMany(bs) + if err != nil { + return err + } + for _, bl := range bs { + b.bloom.AddTS(bl.Cid().Hash()) + } + return nil +} + +func (b *bloomcache) HashOnRead(enabled bool) { + b.blockstore.HashOnRead(enabled) +} + +func (b *bloomcache) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + return b.blockstore.AllKeysChan(ctx) +} + +func (b *bloomcache) GCLock() Unlocker { + return b.blockstore.(GCBlockstore).GCLock() +} + +func (b *bloomcache) PinLock() Unlocker { + return b.blockstore.(GCBlockstore).PinLock() +} + +func (b *bloomcache) GCRequested() bool { + return b.blockstore.(GCBlockstore).GCRequested() +} diff --git a/vendor/github.com/ipfs/go-ipfs-blockstore/caching.go b/vendor/github.com/ipfs/go-ipfs-blockstore/caching.go new file mode 100644 index 0000000000..798b84ce2b --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-blockstore/caching.go @@ -0,0 +1,55 @@ +package blockstore + +import ( + "context" + "errors" + + metrics "github.com/ipfs/go-metrics-interface" +) + +// CacheOpts wraps options for CachedBlockStore(). +// Next to each option is it aproximate memory usage per unit +type CacheOpts struct { + HasBloomFilterSize int // 1 byte + HasBloomFilterHashes int // No size, 7 is usually best, consult bloom papers + HasARCCacheSize int // 32 bytes +} + +// DefaultCacheOpts returns a CacheOpts initialized with default values. +func DefaultCacheOpts() CacheOpts { + return CacheOpts{ + HasBloomFilterSize: 512 << 10, + HasBloomFilterHashes: 7, + HasARCCacheSize: 64 << 10, + } +} + +// CachedBlockstore returns a blockstore wrapped in an ARCCache and +// then in a bloom filter cache, if the options indicate it. +func CachedBlockstore( + ctx context.Context, + bs Blockstore, + opts CacheOpts) (cbs Blockstore, err error) { + cbs = bs + + if opts.HasBloomFilterSize < 0 || opts.HasBloomFilterHashes < 0 || + opts.HasARCCacheSize < 0 { + return nil, errors.New("all options for cache need to be greater than zero") + } + + if opts.HasBloomFilterSize != 0 && opts.HasBloomFilterHashes == 0 { + return nil, errors.New("bloom filter hash count can't be 0 when there is size set") + } + + ctx = metrics.CtxSubScope(ctx, "bs.cache") + + if opts.HasARCCacheSize > 0 { + cbs, err = newARCCachedBS(ctx, cbs, opts.HasARCCacheSize) + } + if opts.HasBloomFilterSize != 0 { + // *8 because of bytes to bits conversion + cbs, err = bloomCached(ctx, cbs, opts.HasBloomFilterSize*8, opts.HasBloomFilterHashes) + } + + return cbs, err +} diff --git a/vendor/github.com/ipfs/go-ipfs-blockstore/go.mod b/vendor/github.com/ipfs/go-ipfs-blockstore/go.mod new file mode 100644 index 0000000000..8c86f5535e --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-blockstore/go.mod @@ -0,0 +1,16 @@ +module github.com/ipfs/go-ipfs-blockstore + +require ( + github.com/hashicorp/golang-lru v0.5.4 + github.com/ipfs/bbloom v0.0.4 + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.5 + github.com/ipfs/go-datastore v0.4.1 + github.com/ipfs/go-ipfs-ds-help v1.0.0 + github.com/ipfs/go-ipfs-util v0.0.1 + github.com/ipfs/go-log v0.0.1 + github.com/ipfs/go-metrics-interface v0.0.1 + github.com/multiformats/go-multihash v0.0.13 +) + +go 1.13 diff --git a/vendor/github.com/ipfs/go-ipfs-blockstore/go.sum b/vendor/github.com/ipfs/go-ipfs-blockstore/go.sum new file mode 100644 index 0000000000..6e0a1efadc --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-blockstore/go.sum @@ -0,0 +1,95 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-datastore v0.4.1 h1:W4ZfzyhNi3xmuU5dQhjfuRn/wFuqEE1KnOmmQiOevEY= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g= +github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7 h1:C2F/nMkR/9sfUTpvR3QrjBuTdvMUC/cFajkphs1YLQo= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/ipfs/go-ipfs-blockstore/idstore.go b/vendor/github.com/ipfs/go-ipfs-blockstore/idstore.go new file mode 100644 index 0000000000..2a5bf84156 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-blockstore/idstore.go @@ -0,0 +1,86 @@ +package blockstore + +import ( + "context" + + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" +) + +// idstore wraps a BlockStore to add support for identity hashes +type idstore struct { + bs Blockstore +} + +func NewIdStore(bs Blockstore) Blockstore { + return &idstore{bs} +} + +func extractContents(k cid.Cid) (bool, []byte) { + dmh, err := mh.Decode(k.Hash()) + if err != nil || dmh.Code != mh.ID { + return false, nil + } + return true, dmh.Digest +} + +func (b *idstore) DeleteBlock(k cid.Cid) error { + isId, _ := extractContents(k) + if isId { + return nil + } + return b.bs.DeleteBlock(k) +} + +func (b *idstore) Has(k cid.Cid) (bool, error) { + isId, _ := extractContents(k) + if isId { + return true, nil + } + return b.bs.Has(k) +} + +func (b *idstore) GetSize(k cid.Cid) (int, error) { + isId, bdata := extractContents(k) + if isId { + return len(bdata), nil + } + return b.bs.GetSize(k) +} + +func (b *idstore) Get(k cid.Cid) (blocks.Block, error) { + isId, bdata := extractContents(k) + if isId { + return blocks.NewBlockWithCid(bdata, k) + } + return b.bs.Get(k) +} + +func (b *idstore) Put(bl blocks.Block) error { + isId, _ := extractContents(bl.Cid()) + if isId { + return nil + } + return b.bs.Put(bl) +} + +func (b *idstore) PutMany(bs []blocks.Block) error { + toPut := make([]blocks.Block, 0, len(bs)) + for _, bl := range bs { + isId, _ := extractContents(bl.Cid()) + if isId { + continue + } + toPut = append(toPut, bl) + } + return b.bs.PutMany(toPut) +} + +func (b *idstore) HashOnRead(enabled bool) { + b.bs.HashOnRead(enabled) +} + +func (b *idstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + return b.bs.AllKeysChan(ctx) +} diff --git a/vendor/github.com/ipfs/go-ipfs-ds-help/.travis.yml b/vendor/github.com/ipfs/go-ipfs-ds-help/.travis.yml new file mode 100644 index 0000000000..a156d3eb5e --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-ds-help/.travis.yml @@ -0,0 +1,30 @@ +os: + - linux + +language: go + +go: + - 1.13.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-ipfs-ds-help/LICENSE b/vendor/github.com/ipfs/go-ipfs-ds-help/LICENSE new file mode 100644 index 0000000000..e4224df5b7 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-ds-help/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 IPFS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ipfs/go-ipfs-ds-help/Makefile b/vendor/github.com/ipfs/go-ipfs-ds-help/Makefile new file mode 100644 index 0000000000..73f2841f61 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-ds-help/Makefile @@ -0,0 +1,18 @@ +all: deps +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go +deps: gx + gx --verbose install --global + gx-go rewrite +test: deps + gx test -v -race -coverprofile=coverage.txt -covermode=atomic . +rw: + gx-go rewrite +rwundo: + gx-go rewrite --undo +publish: rwundo + gx publish +.PHONY: all gx deps test rw rwundo publish + + diff --git a/vendor/github.com/ipfs/go-ipfs-ds-help/README.md b/vendor/github.com/ipfs/go-ipfs-ds-help/README.md new file mode 100644 index 0000000000..2af3bff469 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-ds-help/README.md @@ -0,0 +1,44 @@ +# go-ipfs-ds-help + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/ipfs/go-ipfs-ds-help?status.svg)](https://godoc.org/github.com/ipfs/go-ipfs-ds-help) +[![Build Status](https://travis-ci.org/ipfs/go-ipfs-ds-help.svg?branch=master)](https://travis-ci.org/ipfs/go-ipfs-ds-help) + +> go-ipfs-ds-help provides utilities for parsing and creating datastore keys used by go-ipfs. + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [Contribute](#contribute) +- [License](#license) + +## Install + +`go-ipfs-ds-help` works like a regular Go module: + +``` +> go get github.com/ipfs/go-ipfs-ds-help +``` + +## Usage + +``` +import "github.com/ipfs/go-ipfs-ds-help" +``` + +Check the [GoDoc documentation](https://godoc.org/github.com/ipfs/go-ipfs-ds-help) + +This module uses [Gx](https://github.com/whyrusleeping/gx) to manage dependencies. You can use `make all` to build it with the `gx` dependencies. + +## Contribute + +PRs accepted. + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Protocol Labs, Inc. diff --git a/vendor/github.com/ipfs/go-ipfs-ds-help/go.mod b/vendor/github.com/ipfs/go-ipfs-ds-help/go.mod new file mode 100644 index 0000000000..0c91c87072 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-ds-help/go.mod @@ -0,0 +1,10 @@ +module github.com/ipfs/go-ipfs-ds-help + +require ( + github.com/ipfs/go-cid v0.0.5 + github.com/ipfs/go-datastore v0.4.1 + github.com/multiformats/go-base32 v0.0.3 + github.com/multiformats/go-multihash v0.0.13 +) + +go 1.13 diff --git a/vendor/github.com/ipfs/go-ipfs-ds-help/go.sum b/vendor/github.com/ipfs/go-ipfs-ds-help/go.sum new file mode 100644 index 0000000000..da0e2055f5 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-ds-help/go.sum @@ -0,0 +1,56 @@ +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/ipfs/go-cid v0.0.4 h1:UlfXKrZx1DjZoBhQHmNHLC1fK1dUJDN20Y28A7s+gJ8= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-datastore v0.1.1 h1:F4k0TkTAZGLFzBOrVKDAvch6JZtuN4NHkfdcEZL50aI= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.1 h1:SS1t869a6cctoSYmZXUk8eL6AzVXgASmKIWFNQkQ1jU= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.1 h1:W4ZfzyhNi3xmuU5dQhjfuRn/wFuqEE1KnOmmQiOevEY= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/ipfs/go-ipfs-ds-help/key.go b/vendor/github.com/ipfs/go-ipfs-ds-help/key.go new file mode 100644 index 0000000000..32b73a61e6 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-ds-help/key.go @@ -0,0 +1,51 @@ +// Package dshelp provides utilities for parsing and creating +// datastore keys used by go-ipfs +package dshelp + +import ( + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/multiformats/go-base32" + mh "github.com/multiformats/go-multihash" +) + +// NewKeyFromBinary creates a new key from a byte slice. +func NewKeyFromBinary(rawKey []byte) datastore.Key { + buf := make([]byte, 1+base32.RawStdEncoding.EncodedLen(len(rawKey))) + buf[0] = '/' + base32.RawStdEncoding.Encode(buf[1:], rawKey) + return datastore.RawKey(string(buf)) +} + +// BinaryFromDsKey returns the byte slice corresponding to the given Key. +func BinaryFromDsKey(k datastore.Key) ([]byte, error) { + return base32.RawStdEncoding.DecodeString(k.String()[1:]) +} + +// MultihashToDsKey creates a Key from the given Multihash. +// If working with Cids, you can call cid.Hash() to obtain +// the multihash. Note that different CIDs might represent +// the same multihash. +func MultihashToDsKey(k mh.Multihash) datastore.Key { + return NewKeyFromBinary(k) +} + +// DsKeyToMultihash converts a dsKey to the corresponding Multihash. +func DsKeyToMultihash(dsKey datastore.Key) (mh.Multihash, error) { + kb, err := BinaryFromDsKey(dsKey) + if err != nil { + return nil, err + } + return mh.Cast(kb) +} + +// DsKeyToCidV1Raw converts the given Key (which should be a raw multihash +// key) to a Cid V1 of the given type (see +// https://godoc.org/github.com/ipfs/go-cid#pkg-constants). +func DsKeyToCidV1(dsKey datastore.Key, codecType uint64) (cid.Cid, error) { + hash, err := DsKeyToMultihash(dsKey) + if err != nil { + return cid.Cid{}, err + } + return cid.NewCidV1(codecType, hash), nil +} diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/.travis.yml b/vendor/github.com/ipfs/go-ipfs-exchange-interface/.travis.yml new file mode 100644 index 0000000000..4cfe98c242 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/LICENSE b/vendor/github.com/ipfs/go-ipfs-exchange-interface/LICENSE new file mode 100644 index 0000000000..e4224df5b7 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 IPFS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/Makefile b/vendor/github.com/ipfs/go-ipfs-exchange-interface/Makefile new file mode 100644 index 0000000000..20619413c9 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/Makefile @@ -0,0 +1,11 @@ +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go + +deps: gx + gx --verbose install --global + gx-go rewrite + +publish: + gx-go rewrite --undo + diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/README.md b/vendor/github.com/ipfs/go-ipfs-exchange-interface/README.md new file mode 100644 index 0000000000..8dbcfe1c3b --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/README.md @@ -0,0 +1,42 @@ +# go-ipfs-exchange-interface + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/ipfs/go-ipfs-exchange-interface?status.svg)](https://godoc.org/github.com/ipfs/go-ipfs-exchange-interface) +[![Build Status](https://travis-ci.org/ipfs/go-ipfs-exchange-interface.svg?branch=master)](https://travis-ci.org/ipfs/go-ipfs-exchange-interface) + +> go-ipfs-exchange-interface defines the IPFS exchange interface + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [Contribute](#contribute) +- [License](#license) + +## Install + +`go-ipfs-exchange-interface` works like a regular Go module: + +``` +> go get github.com/ipfs/go-ipfs-exchange-interface +``` + +## Usage + +``` +import "github.com/ipfs/go-ipfs-exchange-interface" +``` + +Check the [GoDoc documentation](https://godoc.org/github.com/ipfs/go-ipfs-exchange-interface) + +## Contribute + +PRs accepted. + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Protocol Labs, Inc. diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/go.mod b/vendor/github.com/ipfs/go-ipfs-exchange-interface/go.mod new file mode 100644 index 0000000000..fade39b99e --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/go.mod @@ -0,0 +1,6 @@ +module github.com/ipfs/go-ipfs-exchange-interface + +require ( + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.1 +) diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/go.sum b/vendor/github.com/ipfs/go-ipfs-exchange-interface/go.sum new file mode 100644 index 0000000000..aa764c6aaa --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/go.sum @@ -0,0 +1,26 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/interface.go b/vendor/github.com/ipfs/go-ipfs-exchange-interface/interface.go new file mode 100644 index 0000000000..c3032b2350 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/interface.go @@ -0,0 +1,37 @@ +// Package exchange defines the IPFS exchange interface +package exchange + +import ( + "context" + "io" + + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" +) + +// Interface defines the functionality of the IPFS block exchange protocol. +type Interface interface { // type Exchanger interface + Fetcher + + // TODO Should callers be concerned with whether the block was made + // available on the network? + HasBlock(blocks.Block) error + + IsOnline() bool + + io.Closer +} + +// Fetcher is an object that can be used to retrieve blocks +type Fetcher interface { + // GetBlock returns the block associated with a given key. + GetBlock(context.Context, cid.Cid) (blocks.Block, error) + GetBlocks(context.Context, []cid.Cid) (<-chan blocks.Block, error) +} + +// SessionExchange is an exchange.Interface which supports +// sessions. +type SessionExchange interface { + Interface + NewSession(context.Context) Fetcher +} diff --git a/vendor/github.com/ipfs/go-ipfs-exchange-interface/package.json b/vendor/github.com/ipfs/go-ipfs-exchange-interface/package.json new file mode 100644 index 0000000000..c5f83220d5 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-exchange-interface/package.json @@ -0,0 +1,30 @@ +{ + "author": "hsanjuan", + "bugs": { + "url": "https://github.com/ipfs/go-ipfs-exchange-interface" + }, + "gx": { + "dvcsimport": "github.com/ipfs/go-ipfs-exchange-interface" + }, + "gxDependencies": [ + { + "author": "stebalien", + "hash": "QmYYLnAzR28nAQ4U5MFniLprnktu6eTFKibeNt96V21EZK", + "name": "go-block-format", + "version": "0.2.2" + }, + { + "author": "whyrusleeping", + "hash": "QmTbxNB1NwDesLmKTscr4udL2tVP7MaxvXnD1D9yX7g3PN", + "name": "go-cid", + "version": "0.9.3" + } + ], + "gxVersion": "0.12.1", + "language": "go", + "license": "MIT", + "name": "go-ipfs-exchange-interface", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "0.1.3" +} + diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/.gitignore b/vendor/github.com/ipfs/go-ipfs-posinfo/.gitignore new file mode 100644 index 0000000000..a1338d6851 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/.gitignore @@ -0,0 +1,14 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/.travis.yml b/vendor/github.com/ipfs/go-ipfs-posinfo/.travis.yml new file mode 100644 index 0000000000..4cfe98c242 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/LICENSE b/vendor/github.com/ipfs/go-ipfs-posinfo/LICENSE new file mode 100644 index 0000000000..e4224df5b7 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 IPFS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/Makefile b/vendor/github.com/ipfs/go-ipfs-posinfo/Makefile new file mode 100644 index 0000000000..24d71558e7 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/Makefile @@ -0,0 +1,18 @@ +all: deps +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go +deps: gx + gx --verbose install --global + gx-go rewrite +test: deps + go test -v -covermode count -coverprofile=coverage.out . +rw: + gx-go rewrite +rwundo: + gx-go rewrite --undo +publish: rwundo + gx publish +.PHONY: all gx deps test rw rwundo publish + + diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/README.md b/vendor/github.com/ipfs/go-ipfs-posinfo/README.md new file mode 100644 index 0000000000..bd509c17e0 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/README.md @@ -0,0 +1,37 @@ +# go-ipfs-posinfo + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/ipfs/go-ipfs-posinfo?status.svg)](https://godoc.org/github.com/ipfs/go-ipfs-posinfo) +[![Build Status](https://travis-ci.org/ipfs/go-ipfs-posinfo.svg?branch=master)](https://travis-ci.org/ipfs/go-ipfs-posinfo) + +> Posinfo wraps offset information for ipfs filestore nodes + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [Contribute](#contribute) +- [License](#license) + +## Install + +``` +go get github.com/ipfs/go-ipfs-posinfo +``` + +## Usage + +See the [GoDoc documentation](https://godoc.org/github.com/ipfs/go-ipfs-posinfo) + + +## Contribute + +PRs accepted. + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Protocol Labs, Inc. diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/go.mod b/vendor/github.com/ipfs/go-ipfs-posinfo/go.mod new file mode 100644 index 0000000000..d006408484 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/go.mod @@ -0,0 +1,3 @@ +module github.com/ipfs/go-ipfs-posinfo + +require github.com/ipfs/go-ipld-format v0.0.1 diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/go.sum b/vendor/github.com/ipfs/go-ipfs-posinfo/go.sum new file mode 100644 index 0000000000..9e2d1534a1 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/go.sum @@ -0,0 +1,28 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/package.json b/vendor/github.com/ipfs/go-ipfs-posinfo/package.json new file mode 100644 index 0000000000..f1815f5825 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/package.json @@ -0,0 +1,24 @@ +{ + "author": "hector", + "bugs": { + "url": "https://github.com/ipfs/go-ipfs-posinfo" + }, + "gx": { + "dvcsimport": "github.com/ipfs/go-ipfs-posinfo" + }, + "gxDependencies": [ + { + "author": "whyrusleeping", + "hash": "QmZ6nzCLwGLVfRzYLpD7pW6UNuBDKEcA2imJtVpbEx2rxy", + "name": "go-ipld-format", + "version": "0.8.1" + } + ], + "gxVersion": "0.12.1", + "language": "go", + "license": "MIT", + "name": "go-ipfs-posinfo", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "0.1.5" +} + diff --git a/vendor/github.com/ipfs/go-ipfs-posinfo/posinfo.go b/vendor/github.com/ipfs/go-ipfs-posinfo/posinfo.go new file mode 100644 index 0000000000..0b32c89da1 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-posinfo/posinfo.go @@ -0,0 +1,23 @@ +// Package posinfo wraps offset information used by ipfs filestore nodes +package posinfo + +import ( + "os" + + ipld "github.com/ipfs/go-ipld-format" +) + +// PosInfo stores information about the file offset, its path and +// stat. +type PosInfo struct { + Offset uint64 + FullPath string + Stat os.FileInfo // can be nil +} + +// FilestoreNode is an ipld.Node which arries PosInfo with it +// allowing to map it directly to a filesystem object. +type FilestoreNode struct { + ipld.Node + PosInfo *PosInfo +} diff --git a/vendor/github.com/ipfs/go-ipfs-util/.gitignore b/vendor/github.com/ipfs/go-ipfs-util/.gitignore new file mode 100644 index 0000000000..1377554ebe --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/vendor/github.com/ipfs/go-ipfs-util/.travis.yml b/vendor/github.com/ipfs/go-ipfs-util/.travis.yml new file mode 100644 index 0000000000..4cfe98c242 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-ipfs-util/LICENSE b/vendor/github.com/ipfs/go-ipfs-util/LICENSE new file mode 100644 index 0000000000..9ce9744462 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-ipfs-util/README.md b/vendor/github.com/ipfs/go-ipfs-util/README.md new file mode 100644 index 0000000000..33bff12cd5 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/README.md @@ -0,0 +1,45 @@ +# go-ipfs-util + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![](https://img.shields.io/badge/discussion_repo-go_to_issues-brightgreen.svg?style=flat-square)](https://github.com/ipfs/NAME/issues) + +> Common utilities used by go-ipfs and other related go packages + +## Install + +This is a Go module which can be installed with `go get github.com/ipfs/go-ipfs-util`. `go-ipfs-util` is however packaged with Gx, so it is recommended to use Gx to install it (see Usage section). + +## Usage + +This module is packaged with [Gx](https://github.com/whyrusleeping/gx). +In order to use it in your own project do: + +``` +go get -u github.com/whyrusleeping/gx +go get -u github.com/whyrusleeping/gx-go +cd +gx init +gx import github.com/ipfs/go-ipfs-util +gx install --global +gx-go --rewrite +``` + +Please check [Gx](https://github.com/whyrusleeping/gx) and [Gx-go](https://github.com/whyrusleeping/gx-go) documentation for more information. + + +## Contribute + +Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-ipfs-util/issues)! + +This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +### Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) + +## License + +MIT diff --git a/vendor/github.com/ipfs/go-ipfs-util/file.go b/vendor/github.com/ipfs/go-ipfs-util/file.go new file mode 100644 index 0000000000..e6e30df4d3 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/file.go @@ -0,0 +1,12 @@ +package util + +import "os" + +// FileExists check if the file with the given path exits. +func FileExists(filename string) bool { + fi, err := os.Lstat(filename) + if fi != nil || (err != nil && !os.IsNotExist(err)) { + return true + } + return false +} diff --git a/vendor/github.com/ipfs/go-ipfs-util/go.mod b/vendor/github.com/ipfs/go-ipfs-util/go.mod new file mode 100644 index 0000000000..112c925b57 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/go.mod @@ -0,0 +1,6 @@ +module github.com/ipfs/go-ipfs-util + +require ( + github.com/mr-tron/base58 v1.1.0 + github.com/multiformats/go-multihash v0.0.1 +) diff --git a/vendor/github.com/ipfs/go-ipfs-util/go.sum b/vendor/github.com/ipfs/go-ipfs-util/go.sum new file mode 100644 index 0000000000..25c9723e81 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/go.sum @@ -0,0 +1,16 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/ipfs/go-ipfs-util/package.json b/vendor/github.com/ipfs/go-ipfs-util/package.json new file mode 100644 index 0000000000..3c3ed116bc --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/package.json @@ -0,0 +1,28 @@ +{ + "author": "whyrusleeping", + "bugs": {}, + "gx": { + "dvcsimport": "github.com/ipfs/go-ipfs-util" + }, + "gxDependencies": [ + { + "author": "multiformats", + "hash": "QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW", + "name": "go-multihash", + "version": "1.0.9" + }, + { + "author": "mr-tron", + "hash": "QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY", + "name": "go-base58-fast", + "version": "0.1.1" + } + ], + "gxVersion": "0.9.1", + "language": "go", + "license": "", + "name": "go-ipfs-util", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "1.2.9" +} + diff --git a/vendor/github.com/ipfs/go-ipfs-util/time.go b/vendor/github.com/ipfs/go-ipfs-util/time.go new file mode 100644 index 0000000000..37d720fb1b --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/time.go @@ -0,0 +1,22 @@ +package util + +import "time" + +// TimeFormatIpfs is the format ipfs uses to represent time in string form. +var TimeFormatIpfs = time.RFC3339Nano + +// ParseRFC3339 parses an RFC3339Nano-formatted time stamp and +// returns the UTC time. +func ParseRFC3339(s string) (time.Time, error) { + t, err := time.Parse(TimeFormatIpfs, s) + if err != nil { + return time.Time{}, err + } + return t.UTC(), nil +} + +// FormatRFC3339 returns the string representation of the +// UTC value of the given time in RFC3339Nano format. +func FormatRFC3339(t time.Time) string { + return t.UTC().Format(TimeFormatIpfs) +} diff --git a/vendor/github.com/ipfs/go-ipfs-util/util.go b/vendor/github.com/ipfs/go-ipfs-util/util.go new file mode 100644 index 0000000000..8ebe3c706f --- /dev/null +++ b/vendor/github.com/ipfs/go-ipfs-util/util.go @@ -0,0 +1,158 @@ +// Package util implements various utility functions used within ipfs +// that do not currently have a better place to live. +package util + +import ( + "errors" + "io" + "math/rand" + "os" + "path/filepath" + "runtime/debug" + "strings" + "time" + + b58 "github.com/mr-tron/base58/base58" + mh "github.com/multiformats/go-multihash" +) + +// DefaultIpfsHash is the current default hash function used by IPFS. +const DefaultIpfsHash = mh.SHA2_256 + +// Debug is a global flag for debugging. +var Debug bool + +// ErrNotImplemented signifies a function has not been implemented yet. +var ErrNotImplemented = errors.New("Error: not implemented yet.") + +// ErrTimeout implies that a timeout has been triggered +var ErrTimeout = errors.New("Error: Call timed out.") + +// ErrSearchIncomplete implies that a search type operation didnt +// find the expected node, but did find 'a' node. +var ErrSearchIncomplete = errors.New("Error: Search Incomplete.") + +// ErrCast is returned when a cast fails AND the program should not panic. +func ErrCast() error { + debug.PrintStack() + return errCast +} + +var errCast = errors.New("cast error") + +// ExpandPathnames takes a set of paths and turns them into absolute paths +func ExpandPathnames(paths []string) ([]string, error) { + var out []string + for _, p := range paths { + abspath, err := filepath.Abs(p) + if err != nil { + return nil, err + } + out = append(out, abspath) + } + return out, nil +} + +type randGen struct { + rand.Rand +} + +// NewTimeSeededRand returns a random bytes reader +// which has been initialized with the current time. +func NewTimeSeededRand() io.Reader { + src := rand.NewSource(time.Now().UnixNano()) + return &randGen{ + Rand: *rand.New(src), + } +} + +// NewSeededRand returns a random bytes reader +// initialized with the given seed. +func NewSeededRand(seed int64) io.Reader { + src := rand.NewSource(seed) + return &randGen{ + Rand: *rand.New(src), + } +} + +func (r *randGen) Read(p []byte) (n int, err error) { + for i := 0; i < len(p); i++ { + p[i] = byte(r.Rand.Intn(255)) + } + return len(p), nil +} + +// GetenvBool is the way to check an env var as a boolean +func GetenvBool(name string) bool { + v := strings.ToLower(os.Getenv(name)) + return v == "true" || v == "t" || v == "1" +} + +// MultiErr is a util to return multiple errors +type MultiErr []error + +func (m MultiErr) Error() string { + if len(m) == 0 { + return "no errors" + } + + s := "Multiple errors: " + for i, e := range m { + if i != 0 { + s += ", " + } + s += e.Error() + } + return s +} + +// Partition splits a subject 3 parts: prefix, separator, suffix. +// The first occurrence of the separator will be matched. +// ie. Partition("Ready, steady, go!", ", ") -> ["Ready", ", ", "steady, go!"] +func Partition(subject string, sep string) (string, string, string) { + if i := strings.Index(subject, sep); i != -1 { + return subject[:i], subject[i : i+len(sep)], subject[i+len(sep):] + } + return subject, "", "" +} + +// RPartition splits a subject 3 parts: prefix, separator, suffix. +// The last occurrence of the separator will be matched. +// ie. RPartition("Ready, steady, go!", ", ") -> ["Ready, steady", ", ", "go!"] +func RPartition(subject string, sep string) (string, string, string) { + if i := strings.LastIndex(subject, sep); i != -1 { + return subject[:i], subject[i : i+len(sep)], subject[i+len(sep):] + } + return subject, "", "" +} + +// Hash is the global IPFS hash function. uses multihash SHA2_256, 256 bits +func Hash(data []byte) mh.Multihash { + h, err := mh.Sum(data, DefaultIpfsHash, -1) + if err != nil { + // this error can be safely ignored (panic) because multihash only fails + // from the selection of hash function. If the fn + length are valid, it + // won't error. + panic("multihash failed to hash using SHA2_256.") + } + return h +} + +// IsValidHash checks whether a given hash is valid (b58 decodable, len > 0) +func IsValidHash(s string) bool { + out, err := b58.Decode(s) + if err != nil { + return false + } + _, err = mh.Cast(out) + return err == nil +} + +// XOR takes two byte slices, XORs them together, returns the resulting slice. +func XOR(a, b []byte) []byte { + c := make([]byte, len(a)) + for i := 0; i < len(a); i++ { + c[i] = a[i] ^ b[i] + } + return c +} diff --git a/vendor/github.com/ipfs/go-ipld-cbor/.travis.yml b/vendor/github.com/ipfs/go-ipld-cbor/.travis.yml new file mode 100644 index 0000000000..923835bc58 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/.travis.yml @@ -0,0 +1,31 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-ipld-cbor/LICENSE b/vendor/github.com/ipfs/go-ipld-cbor/LICENSE new file mode 100644 index 0000000000..26100332ba --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Jeromy Johnson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-ipld-cbor/Makefile b/vendor/github.com/ipfs/go-ipld-cbor/Makefile new file mode 100644 index 0000000000..0ad4560a70 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/Makefile @@ -0,0 +1,14 @@ +all: build + +build: + go build ./... +.PHONY: build + +test: + go test ./... +.PHONY: test + +benchmark: + go test -bench=./... +.PHONY: benchmark + diff --git a/vendor/github.com/ipfs/go-ipld-cbor/README.md b/vendor/github.com/ipfs/go-ipld-cbor/README.md new file mode 100644 index 0000000000..b74dbf3e62 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/README.md @@ -0,0 +1,57 @@ +go-ipld-cbor +================== + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://libp2p.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-floodsub/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-floodsub?branch=master) +[![Travis CI](https://travis-ci.org/libp2p/js-libp2p-floodsub.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-floodsub) + +> An implementation of a cbor encoded merkledag object. + +## Lead Maintainer + +[Eric Myhre](https://github.com/warpfork) + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [API](#api) +- [Contribute](#contribute) +- [License](#license) + +## Install + +```sh +make install +``` + +## Usage + +TODO: Right now this package isn't the easiest to use, it will be getting better rapidly, soon. +```go +// Make an object +obj := map[interface{}]interface{}{ + "foo": "bar", + "baz": &Link{ + Target: myCid, + }, +} + +// Parse it into an ipldcbor node +nd, err := WrapMap(obj) + +fmt.Println(nd.Links()) + +``` + +## Contribute + +PRs are welcome! + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Jeromy Johnson diff --git a/vendor/github.com/ipfs/go-ipld-cbor/codecov.yml b/vendor/github.com/ipfs/go-ipld-cbor/codecov.yml new file mode 100644 index 0000000000..5f88a9ea27 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/codecov.yml @@ -0,0 +1,3 @@ +coverage: + range: "50...100" +comment: off diff --git a/vendor/github.com/ipfs/go-ipld-cbor/encoding/cloner.go b/vendor/github.com/ipfs/go-ipld-cbor/encoding/cloner.go new file mode 100644 index 0000000000..d054eb4144 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/encoding/cloner.go @@ -0,0 +1,41 @@ +package encoding + +import ( + "sync" + + refmt "github.com/polydawn/refmt" + "github.com/polydawn/refmt/obj/atlas" +) + +// PooledCloner is a thread-safe pooled object cloner. +type PooledCloner struct { + pool sync.Pool +} + +// NewPooledCloner returns a PooledCloner with the given atlas. Do not copy +// after use. +func NewPooledCloner(atl atlas.Atlas) PooledCloner { + return PooledCloner{ + pool: sync.Pool{ + New: func() interface{} { + return refmt.NewCloner(atl) + }, + }, + } +} + +type selfCloner interface { + Clone(b interface{}) error +} + +// Clone clones a into b using a cloner from the pool. +func (p *PooledCloner) Clone(a, b interface{}) error { + if self, ok := a.(selfCloner); ok { + return self.Clone(b) + } + + c := p.pool.Get().(refmt.Cloner) + err := c.Clone(a, b) + p.pool.Put(c) + return err +} diff --git a/vendor/github.com/ipfs/go-ipld-cbor/encoding/marshaller.go b/vendor/github.com/ipfs/go-ipld-cbor/encoding/marshaller.go new file mode 100644 index 0000000000..a517f472e6 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/encoding/marshaller.go @@ -0,0 +1,92 @@ +package encoding + +import ( + "bytes" + "io" + "sync" + + cbor "github.com/polydawn/refmt/cbor" + "github.com/polydawn/refmt/obj/atlas" +) + +type proxyWriter struct { + w io.Writer +} + +func (w *proxyWriter) Write(b []byte) (int, error) { + return w.w.Write(b) +} + +// Marshaller is a reusbale CBOR marshaller. +type Marshaller struct { + marshal *cbor.Marshaller + writer proxyWriter +} + +// NewMarshallerAtlased constructs a new cbor Marshaller using the given atlas. +func NewMarshallerAtlased(atl atlas.Atlas) *Marshaller { + m := new(Marshaller) + m.marshal = cbor.NewMarshallerAtlased(&m.writer, atl) + return m +} + +type cborMarshaler interface { + MarshalCBOR(w io.Writer) error +} + +// Encode encodes the given object to the given writer. +func (m *Marshaller) Encode(obj interface{}, w io.Writer) error { + m.writer.w = w + var err error + selfMarshaling, ok := obj.(cborMarshaler) + if ok { + err = selfMarshaling.MarshalCBOR(w) + } else { + err = m.marshal.Marshal(obj) + } + m.writer.w = nil + return err +} + +// Marshal marshels the given object to a byte slice. +func (m *Marshaller) Marshal(obj interface{}) ([]byte, error) { + var buf bytes.Buffer + if err := m.Encode(obj, &buf); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// PooledMarshaller is a thread-safe pooled CBOR marshaller. +type PooledMarshaller struct { + pool sync.Pool +} + +// NewPooledMarshaller returns a PooledMarshaller with the given atlas. Do not +// copy after use. +func NewPooledMarshaller(atl atlas.Atlas) PooledMarshaller { + return PooledMarshaller{ + pool: sync.Pool{ + New: func() interface{} { + return NewMarshallerAtlased(atl) + }, + }, + } +} + +// Marshal marshals the passed object using the pool of marshallers. +func (p *PooledMarshaller) Marshal(obj interface{}) ([]byte, error) { + m := p.pool.Get().(*Marshaller) + bts, err := m.Marshal(obj) + p.pool.Put(m) + return bts, err +} + +// Encode encodes the passed object to the given writer using the pool of +// marshallers. +func (p *PooledMarshaller) Encode(obj interface{}, w io.Writer) error { + m := p.pool.Get().(*Marshaller) + err := m.Encode(obj, w) + p.pool.Put(m) + return err +} diff --git a/vendor/github.com/ipfs/go-ipld-cbor/encoding/unmarshaller.go b/vendor/github.com/ipfs/go-ipld-cbor/encoding/unmarshaller.go new file mode 100644 index 0000000000..559cbeb8e1 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/encoding/unmarshaller.go @@ -0,0 +1,88 @@ +package encoding + +import ( + "bytes" + "io" + "sync" + + cbor "github.com/polydawn/refmt/cbor" + "github.com/polydawn/refmt/obj/atlas" +) + +type proxyReader struct { + r io.Reader +} + +func (r *proxyReader) Read(b []byte) (int, error) { + return r.r.Read(b) +} + +// Unmarshaller is a reusable CBOR unmarshaller. +type Unmarshaller struct { + unmarshal *cbor.Unmarshaller + reader proxyReader +} + +// NewUnmarshallerAtlased creates a new reusable unmarshaller. +func NewUnmarshallerAtlased(atl atlas.Atlas) *Unmarshaller { + m := new(Unmarshaller) + m.unmarshal = cbor.NewUnmarshallerAtlased(cbor.DecodeOptions{CoerceUndefToNull: true}, &m.reader, atl) + return m +} + +type cborUnmarshaler interface { + UnmarshalCBOR(r io.Reader) error +} + +// Decode reads a CBOR object from the given reader and decodes it into the +// given object. +func (m *Unmarshaller) Decode(r io.Reader, obj interface{}) (err error) { + m.reader.r = r + selfUnmarshaler, ok := obj.(cborUnmarshaler) + if ok { + err = selfUnmarshaler.UnmarshalCBOR(r) + } else { + err = m.unmarshal.Unmarshal(obj) + } + m.reader.r = nil + return err +} + +// Unmarshal unmarshals the given CBOR byte slice into the given object. +func (m *Unmarshaller) Unmarshal(b []byte, obj interface{}) error { + return m.Decode(bytes.NewReader(b), obj) +} + +// PooledUnmarshaller is a thread-safe pooled CBOR unmarshaller. +type PooledUnmarshaller struct { + pool sync.Pool +} + +// NewPooledUnmarshaller returns a PooledUnmarshaller with the given atlas. Do +// not copy after use. +func NewPooledUnmarshaller(atl atlas.Atlas) PooledUnmarshaller { + return PooledUnmarshaller{ + pool: sync.Pool{ + New: func() interface{} { + return NewUnmarshallerAtlased(atl) + }, + }, + } +} + +// Decode decodes an object from the passed reader into the given object using +// the pool of unmarshallers. +func (p *PooledUnmarshaller) Decode(r io.Reader, obj interface{}) error { + u := p.pool.Get().(*Unmarshaller) + err := u.Decode(r, obj) + p.pool.Put(u) + return err +} + +// Unmarshal unmarshals the passed object using the pool of unmarshallers. +func (p *PooledUnmarshaller) Unmarshal(b []byte, obj interface{}) error { + u := p.pool.Get().(*Unmarshaller) + err := u.Unmarshal(b, obj) + p.pool.Put(u) + return err +} diff --git a/vendor/github.com/ipfs/go-ipld-cbor/go.mod b/vendor/github.com/ipfs/go-ipld-cbor/go.mod new file mode 100644 index 0000000000..51b8bd2b25 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/go.mod @@ -0,0 +1,15 @@ +module github.com/ipfs/go-ipld-cbor + +require ( + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.3 + github.com/ipfs/go-ipfs-util v0.0.1 + github.com/ipfs/go-ipld-format v0.0.1 + github.com/multiformats/go-multihash v0.0.10 + github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 + github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa // indirect + github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 // indirect + github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 +) + +go 1.13 diff --git a/vendor/github.com/ipfs/go-ipld-cbor/go.sum b/vendor/github.com/ipfs/go-ipld-cbor/go.sum new file mode 100644 index 0000000000..2471a67c4f --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/go.sum @@ -0,0 +1,62 @@ +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 h1:WXhVOwj2USAXB5oMDwRl3piOux2XMV9TANaYxXHdkoE= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/ipfs/go-ipld-cbor/node.go b/vendor/github.com/ipfs/go-ipld-cbor/node.go new file mode 100644 index 0000000000..139498c82b --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/node.go @@ -0,0 +1,545 @@ +package cbornode + +import ( + "encoding/json" + "errors" + "io" + "math" + "strconv" + "strings" + + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + node "github.com/ipfs/go-ipld-format" + mh "github.com/multiformats/go-multihash" +) + +// CBORTagLink is the integer used to represent tags in CBOR. +const CBORTagLink = 42 + +// Node represents an IPLD node. +type Node struct { + obj interface{} + tree []string + links []*node.Link + raw []byte + cid cid.Cid +} + +// Compile time check to make sure Node implements the node.Node interface +var _ node.Node = (*Node)(nil) + +var ( + // ErrNoSuchLink is returned when no link with the given name was found. + ErrNoSuchLink = errors.New("no such link found") + ErrNonLink = errors.New("non-link found at given path") + ErrInvalidLink = errors.New("link value should have been bytes") + ErrInvalidKeys = errors.New("map keys must be strings") + ErrArrayOutOfRange = errors.New("array index out of range") + ErrNoLinks = errors.New("tried to resolve through object that had no links") + ErrEmptyLink = errors.New("link value was empty") + ErrInvalidMultibase = errors.New("invalid multibase on IPLD link") + ErrNonStringLink = errors.New("link should have been a string") +) + +// DecodeBlock decodes a CBOR encoded Block into an IPLD Node. +// +// This method *does not* canonicalize and *will* preserve the CID. As a matter +// of fact, it will assume that `block.Cid()` returns the correct CID and will +// make no effort to validate this assumption. +// +// In general, you should not be calling this method directly. Instead, you +// should be calling the `Decode` method from the `go-ipld-format` package. That +// method will pick the right decoder based on the Block's CID. +// +// Note: This function keeps a reference to `block` and assumes that it is +// immutable. +func DecodeBlock(block blocks.Block) (node.Node, error) { + return decodeBlock(block) +} + +func decodeBlock(block blocks.Block) (*Node, error) { + var m interface{} + if err := DecodeInto(block.RawData(), &m); err != nil { + return nil, err + } + return newObject(block, m) +} + +func newObject(block blocks.Block, m interface{}) (*Node, error) { + tree, links, err := compute(m) + if err != nil { + return nil, err + } + + return &Node{ + obj: m, + tree: tree, + links: links, + raw: block.RawData(), + cid: block.Cid(), + }, nil +} + +var _ node.DecodeBlockFunc = DecodeBlock + +// Decode decodes a CBOR object into an IPLD Node. +// +// If passed a non-canonical CBOR node, this function will canonicalize it. +// Therefore, `bytes.Equal(b, Decode(b).RawData())` may not hold. If you already +// have a CID for this data and want to ensure that it doesn't change, you +// should use `DecodeBlock`. +// mhType is multihash code to use for hashing, for example mh.SHA2_256 +// +// Note: This function does not hold onto `b`. You may reuse it. +func Decode(b []byte, mhType uint64, mhLen int) (*Node, error) { + var m interface{} + if err := DecodeInto(b, &m); err != nil { + return nil, err + } + + // We throw away `b` here to ensure that we canonicalize the encoded + // CBOR object. + return WrapObject(m, mhType, mhLen) +} + +// DecodeInto decodes a serialized IPLD cbor object into the given object. +func DecodeInto(b []byte, v interface{}) error { + return unmarshaller.Unmarshal(b, v) +} + +func DecodeReader(r io.Reader, v interface{}) error { + return unmarshaller.Decode(r, v) +} + +// WrapObject converts an arbitrary object into a Node. +func WrapObject(m interface{}, mhType uint64, mhLen int) (*Node, error) { + data, err := marshaller.Marshal(m) + if err != nil { + return nil, err + } + + var obj interface{} + err = cloner.Clone(m, &obj) + if err != nil { + return nil, err + } + + if mhType == math.MaxUint64 { + mhType = mh.SHA2_256 + } + + hash, err := mh.Sum(data, mhType, mhLen) + if err != nil { + return nil, err + } + c := cid.NewCidV1(cid.DagCBOR, hash) + + block, err := blocks.NewBlockWithCid(data, c) + if err != nil { + // TODO: Shouldn't this just panic? + return nil, err + } + // No need to deserialize. We can just deep copy. + return newObject(block, obj) +} + +// Resolve resolves a given path, and returns the object found at the end, as well +// as the possible tail of the path that was not resolved. +func (n *Node) Resolve(path []string) (interface{}, []string, error) { + var cur interface{} = n.obj + for i, val := range path { + switch curv := cur.(type) { + case map[string]interface{}: + next, ok := curv[val] + if !ok { + return nil, nil, ErrNoSuchLink + } + + cur = next + case map[interface{}]interface{}: + next, ok := curv[val] + if !ok { + return nil, nil, ErrNoSuchLink + } + + cur = next + case []interface{}: + n, err := strconv.Atoi(val) + if err != nil { + return nil, nil, err + } + + if n < 0 || n >= len(curv) { + return nil, nil, ErrArrayOutOfRange + } + + cur = curv[n] + case cid.Cid: + return &node.Link{Cid: curv}, path[i:], nil + default: + return nil, nil, ErrNoLinks + } + } + + lnk, ok := cur.(cid.Cid) + if ok { + return &node.Link{Cid: lnk}, nil, nil + } + + jsonish, err := convertToJSONIsh(cur) + if err != nil { + return nil, nil, err + } + + return jsonish, nil, nil +} + +// Copy creates a copy of the Node. +func (n *Node) Copy() node.Node { + links := make([]*node.Link, len(n.links)) + copy(links, n.links) + + raw := make([]byte, len(n.raw)) + copy(raw, n.raw) + + tree := make([]string, len(n.tree)) + copy(tree, n.tree) + + return &Node{ + obj: copyObj(n.obj), + links: links, + raw: raw, + tree: tree, + cid: n.cid, + } +} + +func copyObj(i interface{}) interface{} { + switch i := i.(type) { + case map[string]interface{}: + out := make(map[string]interface{}) + for k, v := range i { + out[k] = copyObj(v) + } + return out + case map[interface{}]interface{}: + out := make(map[interface{}]interface{}) + for k, v := range i { + out[k] = copyObj(v) + } + return out + case []interface{}: + var out []interface{} + for _, v := range i { + out = append(out, copyObj(v)) + } + return out + default: + // TODO: do not be lazy + // being lazy for now + // use caution + return i + } +} + +// ResolveLink resolves a path and returns the raw Link at the end, as well as +// the possible tail of the path that was not resolved. +func (n *Node) ResolveLink(path []string) (*node.Link, []string, error) { + obj, rest, err := n.Resolve(path) + if err != nil { + return nil, nil, err + } + + lnk, ok := obj.(*node.Link) + if !ok { + return nil, rest, ErrNonLink + } + + return lnk, rest, nil +} + +// Tree returns a flattend array of paths at the given path for the given depth. +func (n *Node) Tree(path string, depth int) []string { + if path == "" && depth == -1 { + return n.tree + } + + var out []string + for _, t := range n.tree { + if !strings.HasPrefix(t, path) { + continue + } + + sub := strings.TrimLeft(t[len(path):], "/") + if sub == "" { + continue + } + + if depth < 0 { + out = append(out, sub) + continue + } + + parts := strings.Split(sub, "/") + if len(parts) <= depth { + out = append(out, sub) + } + } + return out +} + +func compute(obj interface{}) (tree []string, links []*node.Link, err error) { + err = traverse(obj, "", func(name string, val interface{}) error { + if name != "" { + tree = append(tree, name[1:]) + } + if lnk, ok := val.(cid.Cid); ok { + links = append(links, &node.Link{Cid: lnk}) + } + return nil + }) + if err != nil { + return nil, nil, err + } + + return tree, links, nil +} + +// Links lists all known links of the Node. +func (n *Node) Links() []*node.Link { + return n.links +} + +func traverse(obj interface{}, cur string, cb func(string, interface{}) error) error { + if err := cb(cur, obj); err != nil { + return err + } + + switch obj := obj.(type) { + case map[string]interface{}: + for k, v := range obj { + this := cur + "/" + k + if err := traverse(v, this, cb); err != nil { + return err + } + } + return nil + case map[interface{}]interface{}: + for k, v := range obj { + ks, ok := k.(string) + if !ok { + return errors.New("map key was not a string") + } + this := cur + "/" + ks + if err := traverse(v, this, cb); err != nil { + return err + } + } + return nil + case []interface{}: + for i, v := range obj { + this := cur + "/" + strconv.Itoa(i) + if err := traverse(v, this, cb); err != nil { + return err + } + } + return nil + default: + return nil + } +} + +// RawData returns the raw bytes that represent the Node as serialized CBOR. +func (n *Node) RawData() []byte { + return n.raw +} + +// Cid returns the canonical Cid of the NOde. +func (n *Node) Cid() cid.Cid { + return n.cid +} + +// Loggable returns a loggable representation of the Node. +func (n *Node) Loggable() map[string]interface{} { + return map[string]interface{}{ + "node_type": "cbor", + "cid": n.Cid(), + } +} + +// Size returns the size of the binary representation of the Node. +func (n *Node) Size() (uint64, error) { + return uint64(len(n.RawData())), nil +} + +// Stat returns stats about the Node. +// TODO: implement? +func (n *Node) Stat() (*node.NodeStat, error) { + return &node.NodeStat{}, nil +} + +// String returns the string representation of the CID of the Node. +func (n *Node) String() string { + return n.Cid().String() +} + +// MarshalJSON converts the Node into its JSON representation. +func (n *Node) MarshalJSON() ([]byte, error) { + out, err := convertToJSONIsh(n.obj) + if err != nil { + return nil, err + } + + return json.Marshal(out) +} + +// DumpObject marshals any object into its CBOR serialized byte representation +// TODO: rename +func DumpObject(obj interface{}) (out []byte, err error) { + return marshaller.Marshal(obj) +} + +func toSaneMap(n map[interface{}]interface{}) (interface{}, error) { + if lnk, ok := n["/"]; ok && len(n) == 1 { + lnkb, ok := lnk.([]byte) + if !ok { + return nil, ErrInvalidLink + } + + c, err := cid.Cast(lnkb) + if err != nil { + return nil, err + } + + return map[string]interface{}{"/": c}, nil + } + out := make(map[string]interface{}) + for k, v := range n { + ks, ok := k.(string) + if !ok { + return nil, ErrInvalidKeys + } + + obj, err := convertToJSONIsh(v) + if err != nil { + return nil, err + } + + out[ks] = obj + } + + return out, nil +} + +func convertToJSONIsh(v interface{}) (interface{}, error) { + switch v := v.(type) { + case map[interface{}]interface{}: + return toSaneMap(v) + case []interface{}: + var out []interface{} + if len(v) == 0 && v != nil { + return []interface{}{}, nil + } + for _, i := range v { + obj, err := convertToJSONIsh(i) + if err != nil { + return nil, err + } + + out = append(out, obj) + } + return out, nil + default: + return v, nil + } +} + +// FromJSON converts incoming JSON into a Node. +func FromJSON(r io.Reader, mhType uint64, mhLen int) (*Node, error) { + var m interface{} + err := json.NewDecoder(r).Decode(&m) + if err != nil { + return nil, err + } + + obj, err := convertToCborIshObj(m) + if err != nil { + return nil, err + } + + return WrapObject(obj, mhType, mhLen) +} + +func convertToCborIshObj(i interface{}) (interface{}, error) { + switch v := i.(type) { + case map[string]interface{}: + if len(v) == 0 && v != nil { + return v, nil + } + + if lnk, ok := v["/"]; ok && len(v) == 1 { + // special case for links + vstr, ok := lnk.(string) + if !ok { + return nil, ErrNonStringLink + } + + return cid.Decode(vstr) + } + + for a, b := range v { + val, err := convertToCborIshObj(b) + if err != nil { + return nil, err + } + + v[a] = val + } + return v, nil + case []interface{}: + if len(v) == 0 && v != nil { + return v, nil + } + + var out []interface{} + for _, o := range v { + obj, err := convertToCborIshObj(o) + if err != nil { + return nil, err + } + + out = append(out, obj) + } + + return out, nil + default: + return v, nil + } +} + +func castBytesToCid(x []byte) (cid.Cid, error) { + if len(x) == 0 { + return cid.Cid{}, ErrEmptyLink + } + + // TODO: manually doing multibase checking here since our deps don't + // support binary multibase yet + if x[0] != 0 { + return cid.Cid{}, ErrInvalidMultibase + } + + c, err := cid.Cast(x[1:]) + if err != nil { + return cid.Cid{}, ErrInvalidLink + } + + return c, nil +} + +func castCidToBytes(link cid.Cid) ([]byte, error) { + if !link.Defined() { + return nil, ErrEmptyLink + } + return append([]byte{0}, link.Bytes()...), nil +} diff --git a/vendor/github.com/ipfs/go-ipld-cbor/readable.go b/vendor/github.com/ipfs/go-ipld-cbor/readable.go new file mode 100644 index 0000000000..cc9d03facc --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/readable.go @@ -0,0 +1,33 @@ +package cbornode + +import ( + "bufio" + "bytes" + + cbor "github.com/polydawn/refmt/cbor" + "github.com/polydawn/refmt/pretty" + "github.com/polydawn/refmt/shared" +) + +//HumanReadable returns a string representation of a CBOR blob +func HumanReadable(blob []byte) (string, error) { + reader := bytes.NewReader(blob) + + var buf bytes.Buffer + writer := bufio.NewWriter(&buf) + + err := shared.TokenPump{ + TokenSource: cbor.NewDecoder(cbor.DecodeOptions{}, reader), + TokenSink: pretty.NewEncoder(writer), + }.Run() + + if err != nil { + return "", err + } + + if err = writer.Flush(); err != nil { + return "", err + } + + return buf.String(), nil +} diff --git a/vendor/github.com/ipfs/go-ipld-cbor/refmt.go b/vendor/github.com/ipfs/go-ipld-cbor/refmt.go new file mode 100644 index 0000000000..e8bd7ded51 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/refmt.go @@ -0,0 +1,72 @@ +package cbornode + +import ( + "math/big" + + cid "github.com/ipfs/go-cid" + + encoding "github.com/ipfs/go-ipld-cbor/encoding" + + "github.com/polydawn/refmt/obj/atlas" +) + +// This atlas describes the CBOR Tag (42) for IPLD links, such that refmt can marshal and unmarshal them +var cidAtlasEntry = atlas.BuildEntry(cid.Cid{}). + UseTag(CBORTagLink). + Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + castCidToBytes, + )). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + castBytesToCid, + )). + Complete() + +// BigIntAtlasEntry gives a reasonable default encoding for big.Int. It is not +// included in the entries by default. +var BigIntAtlasEntry = atlas.BuildEntry(big.Int{}).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(i big.Int) ([]byte, error) { + return i.Bytes(), nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(x []byte) (big.Int, error) { + return *big.NewInt(0).SetBytes(x), nil + })). + Complete() + +// CborAtlas is the refmt.Atlas used by the CBOR IPLD decoder/encoder. +var CborAtlas atlas.Atlas +var cborSortingMode = atlas.KeySortMode_RFC7049 +var atlasEntries = []*atlas.AtlasEntry{cidAtlasEntry} + +var ( + cloner encoding.PooledCloner + unmarshaller encoding.PooledUnmarshaller + marshaller encoding.PooledMarshaller +) + +func init() { + rebuildAtlas() +} + +func rebuildAtlas() { + CborAtlas = atlas.MustBuild(atlasEntries...). + WithMapMorphism(atlas.MapMorphism{KeySortMode: atlas.KeySortMode_RFC7049}) + + marshaller = encoding.NewPooledMarshaller(CborAtlas) + unmarshaller = encoding.NewPooledUnmarshaller(CborAtlas) + cloner = encoding.NewPooledCloner(CborAtlas) +} + +// RegisterCborType allows to register a custom cbor type +func RegisterCborType(i interface{}) { + var entry *atlas.AtlasEntry + if ae, ok := i.(*atlas.AtlasEntry); ok { + entry = ae + } else { + entry = atlas.BuildEntry(i).StructMap().AutogenerateWithSortingScheme(atlas.KeySortMode_RFC7049).Complete() + } + atlasEntries = append(atlasEntries, entry) + rebuildAtlas() +} diff --git a/vendor/github.com/ipfs/go-ipld-cbor/store.go b/vendor/github.com/ipfs/go-ipld-cbor/store.go new file mode 100644 index 0000000000..05f51e345a --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-cbor/store.go @@ -0,0 +1,179 @@ +package cbornode + +import ( + "bytes" + "context" + "fmt" + + block "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" + recbor "github.com/polydawn/refmt/cbor" + atlas "github.com/polydawn/refmt/obj/atlas" + cbg "github.com/whyrusleeping/cbor-gen" +) + +// IpldStore wraps a Blockstore and provides an interface for storing and retrieving CBOR encoded data. +type IpldStore interface { + Get(ctx context.Context, c cid.Cid, out interface{}) error + Put(ctx context.Context, v interface{}) (cid.Cid, error) +} + +// IpldBlockstore defines a subset of the go-ipfs-blockstore Blockstore interface providing methods +// for storing and retrieving block-centered data. +type IpldBlockstore interface { + Get(cid.Cid) (block.Block, error) + Put(block.Block) error +} + +// BasicIpldStore wraps and IpldBlockstore and implements the IpldStore interface. +type BasicIpldStore struct { + Blocks IpldBlockstore + Atlas *atlas.Atlas +} + +var _ IpldStore = &BasicIpldStore{} + +// NewCborStore returns an IpldStore implementation backed by the provided IpldBlockstore. +func NewCborStore(bs IpldBlockstore) *BasicIpldStore { + return &BasicIpldStore{Blocks: bs} +} + +// Get reads and unmarshals the content at `c` into `out`. +func (s *BasicIpldStore) Get(ctx context.Context, c cid.Cid, out interface{}) error { + blk, err := s.Blocks.Get(c) + if err != nil { + return err + } + + cu, ok := out.(cbg.CBORUnmarshaler) + if ok { + if err := cu.UnmarshalCBOR(bytes.NewReader(blk.RawData())); err != nil { + return NewSerializationError(err) + } + return nil + } + + if s.Atlas == nil { + return DecodeInto(blk.RawData(), out) + } else { + return recbor.UnmarshalAtlased(recbor.DecodeOptions{}, blk.RawData(), out, *s.Atlas) + } +} + +type cidProvider interface { + Cid() cid.Cid +} + +// Put marshals and writes content `v` to the backing blockstore returning its CID. +func (s *BasicIpldStore) Put(ctx context.Context, v interface{}) (cid.Cid, error) { + mhType := uint64(mh.BLAKE2B_MIN + 31) + mhLen := -1 + codec := uint64(cid.DagCBOR) + + var expCid cid.Cid + if c, ok := v.(cidProvider); ok { + expCid := c.Cid() + pref := expCid.Prefix() + mhType = pref.MhType + mhLen = pref.MhLength + codec = pref.Codec + } + + cm, ok := v.(cbg.CBORMarshaler) + if ok { + buf := new(bytes.Buffer) + if err := cm.MarshalCBOR(buf); err != nil { + return cid.Undef, NewSerializationError(err) + } + + pref := cid.Prefix{ + Codec: codec, + MhType: mhType, + MhLength: mhLen, + Version: 1, + } + c, err := pref.Sum(buf.Bytes()) + if err != nil { + return cid.Undef, err + } + + blk, err := block.NewBlockWithCid(buf.Bytes(), c) + if err != nil { + return cid.Undef, err + } + + if err := s.Blocks.Put(blk); err != nil { + return cid.Undef, err + } + + blkCid := blk.Cid() + if expCid != cid.Undef && blkCid != expCid { + return cid.Undef, fmt.Errorf("your object is not being serialized the way it expects to") + } + + return blkCid, nil + } + + nd, err := WrapObject(v, mhType, mhLen) + if err != nil { + return cid.Undef, err + } + + if err := s.Blocks.Put(nd); err != nil { + return cid.Undef, err + } + + ndCid := nd.Cid() + if expCid != cid.Undef && ndCid != expCid { + return cid.Undef, fmt.Errorf("your object is not being serialized the way it expects to") + } + + return ndCid, nil +} + +func NewSerializationError(err error) error { + return SerializationError{err} +} + +type SerializationError struct { + err error +} + +func (se SerializationError) Error() string { + return se.err.Error() +} + +func (se SerializationError) Unwrap() error { + return se.err +} + +func (se SerializationError) Is(o error) bool { + _, ok := o.(*SerializationError) + return ok +} + +func NewMemCborStore() IpldStore { + return NewCborStore(newMockBlocks()) +} + +type mockBlocks struct { + data map[cid.Cid]block.Block +} + +func newMockBlocks() *mockBlocks { + return &mockBlocks{make(map[cid.Cid]block.Block)} +} + +func (mb *mockBlocks) Get(c cid.Cid) (block.Block, error) { + d, ok := mb.data[c] + if ok { + return d, nil + } + return nil, fmt.Errorf("Not Found") +} + +func (mb *mockBlocks) Put(b block.Block) error { + mb.data[b.Cid()] = b + return nil +} diff --git a/vendor/github.com/ipfs/go-ipld-format/.travis.yml b/vendor/github.com/ipfs/go-ipld-format/.travis.yml new file mode 100644 index 0000000000..936d6a426e --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/.travis.yml @@ -0,0 +1,30 @@ +os: + - linux + +language: go + +go: + - 1.14.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-ipld-format/LICENSE b/vendor/github.com/ipfs/go-ipld-format/LICENSE new file mode 100644 index 0000000000..26100332ba --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Jeromy Johnson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-ipld-format/Makefile b/vendor/github.com/ipfs/go-ipld-format/Makefile new file mode 100644 index 0000000000..7811c099ea --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/Makefile @@ -0,0 +1,15 @@ +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go + +covertools: + go get github.com/mattn/goveralls + go get golang.org/x/tools/cmd/cover + +deps: gx covertools + gx --verbose install --global + gx-go rewrite + +publish: + gx-go rewrite --undo + diff --git a/vendor/github.com/ipfs/go-ipld-format/README.md b/vendor/github.com/ipfs/go-ipld-format/README.md new file mode 100644 index 0000000000..425c80c7d9 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/README.md @@ -0,0 +1,38 @@ +go-ipld-format +================== + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![Coverage Status](https://codecov.io/gh/ipfs/go-ipld-format/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipld-format/branch/master) +[![Travis CI](https://travis-ci.org/ipfs/go-ipld-format.svg?branch=master)](https://travis-ci.org/ipfs/go-ipld-format) + +> go-ipld-format is a set of interfaces that a type needs to implement in order to be a part of the ipld merkle-forest. + +## Lead Maintainer + +[Eric Myhre](https://github.com/warpfork) + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [API](#api) +- [Contribute](#contribute) +- [License](#license) + +## Install + +```sh +make install +``` + +## Contribute + +PRs are welcome! + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Jeromy Johnson diff --git a/vendor/github.com/ipfs/go-ipld-format/batch.go b/vendor/github.com/ipfs/go-ipld-format/batch.go new file mode 100644 index 0000000000..28491032c4 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/batch.go @@ -0,0 +1,301 @@ +package format + +import ( + "context" + "errors" + "runtime" + + cid "github.com/ipfs/go-cid" +) + +// parallelBatchCommits is the number of batch commits that can be in-flight before blocking. +// TODO(ipfs/go-ipfs#4299): Experiment with multiple datastores, storage +// devices, and CPUs to find the right value/formula. +var parallelCommits = runtime.NumCPU() + +// ErrNotCommited is returned when closing a batch that hasn't been successfully +// committed. +var ErrNotCommited = errors.New("error: batch not commited") + +// ErrClosed is returned when operating on a batch that has already been closed. +var ErrClosed = errors.New("error: batch closed") + +// NewBatch returns a node buffer (Batch) that buffers nodes internally and +// commits them to the underlying DAGService in batches. Use this if you intend +// to add or remove a lot of nodes all at once. +// +// If the passed context is canceled, any in-progress commits are aborted. +// +func NewBatch(ctx context.Context, na NodeAdder, opts ...BatchOption) *Batch { + ctx, cancel := context.WithCancel(ctx) + bopts := defaultBatchOptions + for _, o := range opts { + o(&bopts) + } + + // Commit numCPU batches at once, but split the maximum buffer size over all commits in flight. + bopts.maxSize /= parallelCommits + bopts.maxNodes /= parallelCommits + return &Batch{ + na: na, + ctx: ctx, + cancel: cancel, + commitResults: make(chan error, parallelCommits), + opts: bopts, + } +} + +// Batch is a buffer for batching adds to a dag. +type Batch struct { + na NodeAdder + + ctx context.Context + cancel func() + + activeCommits int + err error + commitResults chan error + + nodes []Node + size int + + opts batchOptions +} + +func (t *Batch) processResults() { + for t.activeCommits > 0 { + select { + case err := <-t.commitResults: + t.activeCommits-- + if err != nil { + t.setError(err) + return + } + default: + return + } + } +} + +func (t *Batch) asyncCommit() { + numBlocks := len(t.nodes) + if numBlocks == 0 { + return + } + if t.activeCommits >= parallelCommits { + select { + case err := <-t.commitResults: + t.activeCommits-- + + if err != nil { + t.setError(err) + return + } + case <-t.ctx.Done(): + t.setError(t.ctx.Err()) + return + } + } + go func(ctx context.Context, b []Node, result chan error, na NodeAdder) { + select { + case result <- na.AddMany(ctx, b): + case <-ctx.Done(): + } + }(t.ctx, t.nodes, t.commitResults, t.na) + + t.activeCommits++ + t.nodes = make([]Node, 0, numBlocks) + t.size = 0 + + return +} + +// Add adds a node to the batch and commits the batch if necessary. +func (t *Batch) Add(ctx context.Context, nd Node) error { + return t.AddMany(ctx, []Node{nd}) +} + +// AddMany many calls Add for every given Node, thus batching and +// commiting them as needed. +func (t *Batch) AddMany(ctx context.Context, nodes []Node) error { + if t.err != nil { + return t.err + } + // Not strictly necessary but allows us to catch errors early. + t.processResults() + + if t.err != nil { + return t.err + } + + t.nodes = append(t.nodes, nodes...) + for _, nd := range nodes { + t.size += len(nd.RawData()) + } + + if t.size > t.opts.maxSize || len(t.nodes) > t.opts.maxNodes { + t.asyncCommit() + } + return t.err +} + +// Commit commits batched nodes. +func (t *Batch) Commit() error { + if t.err != nil { + return t.err + } + + t.asyncCommit() + +loop: + for t.activeCommits > 0 { + select { + case err := <-t.commitResults: + t.activeCommits-- + if err != nil { + t.setError(err) + break loop + } + case <-t.ctx.Done(): + t.setError(t.ctx.Err()) + break loop + } + } + + return t.err +} + +func (t *Batch) setError(err error) { + t.err = err + + t.cancel() + + // Drain as much as we can without blocking. +loop: + for { + select { + case <-t.commitResults: + default: + break loop + } + } + + // Be nice and cleanup. These can take a *lot* of memory. + t.commitResults = nil + t.na = nil + t.ctx = nil + t.nodes = nil + t.size = 0 + t.activeCommits = 0 +} + +// BatchOption provides a way of setting internal options of +// a Batch. +// +// See this post about the "functional options" pattern: +// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis +type BatchOption func(o *batchOptions) + +type batchOptions struct { + maxSize int + maxNodes int +} + +var defaultBatchOptions = batchOptions{ + maxSize: 8 << 20, + + // By default, only batch up to 128 nodes at a time. + // The current implementation of flatfs opens this many file + // descriptors at the same time for the optimized batch write. + maxNodes: 128, +} + +// MaxSizeBatchOption sets the maximum amount of buffered data before writing +// blocks. +func MaxSizeBatchOption(size int) BatchOption { + return func(o *batchOptions) { + o.maxSize = size + } +} + +// MaxNodesBatchOption sets the maximum number of buffered nodes before writing +// blocks. +func MaxNodesBatchOption(num int) BatchOption { + return func(o *batchOptions) { + o.maxNodes = num + } +} + +// BufferedDAG implements DAGService using a Batch NodeAdder to wrap add +// operations in the given DAGService. It will trigger Commit() before any +// non-Add operations, but otherwise calling Commit() is left to the user. +type BufferedDAG struct { + ds DAGService + b *Batch +} + +// NewBufferedDAG creates a BufferedDAG using the given DAGService and the +// given options for the Batch NodeAdder. +func NewBufferedDAG(ctx context.Context, ds DAGService, opts ...BatchOption) *BufferedDAG { + return &BufferedDAG{ + ds: ds, + b: NewBatch(ctx, ds, opts...), + } +} + +// Commit calls commit on the Batch. +func (bd *BufferedDAG) Commit() error { + return bd.b.Commit() +} + +// Add adds a new node using Batch. +func (bd *BufferedDAG) Add(ctx context.Context, n Node) error { + return bd.b.Add(ctx, n) +} + +// AddMany adds many nodes using Batch. +func (bd *BufferedDAG) AddMany(ctx context.Context, nds []Node) error { + return bd.b.AddMany(ctx, nds) +} + +// Get commits and gets a node from the DAGService. +func (bd *BufferedDAG) Get(ctx context.Context, c cid.Cid) (Node, error) { + err := bd.b.Commit() + if err != nil { + return nil, err + } + return bd.ds.Get(ctx, c) +} + +// GetMany commits and gets nodes from the DAGService. +func (bd *BufferedDAG) GetMany(ctx context.Context, cs []cid.Cid) <-chan *NodeOption { + err := bd.b.Commit() + if err != nil { + ch := make(chan *NodeOption, 1) + defer close(ch) + ch <- &NodeOption{ + Node: nil, + Err: err, + } + return ch + } + return bd.ds.GetMany(ctx, cs) +} + +// Remove commits and removes a node from the DAGService. +func (bd *BufferedDAG) Remove(ctx context.Context, c cid.Cid) error { + err := bd.b.Commit() + if err != nil { + return err + } + return bd.ds.Remove(ctx, c) +} + +// RemoveMany commits and removes nodes from the DAGService. +func (bd *BufferedDAG) RemoveMany(ctx context.Context, cs []cid.Cid) error { + err := bd.b.Commit() + if err != nil { + return err + } + return bd.ds.RemoveMany(ctx, cs) +} diff --git a/vendor/github.com/ipfs/go-ipld-format/codecov.yml b/vendor/github.com/ipfs/go-ipld-format/codecov.yml new file mode 100644 index 0000000000..5f88a9ea27 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/codecov.yml @@ -0,0 +1,3 @@ +coverage: + range: "50...100" +comment: off diff --git a/vendor/github.com/ipfs/go-ipld-format/coding.go b/vendor/github.com/ipfs/go-ipld-format/coding.go new file mode 100644 index 0000000000..e202f75a14 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/coding.go @@ -0,0 +1,62 @@ +package format + +import ( + "fmt" + "sync" + + blocks "github.com/ipfs/go-block-format" +) + +// DecodeBlockFunc functions decode blocks into nodes. +type DecodeBlockFunc func(block blocks.Block) (Node, error) + +type BlockDecoder interface { + Register(codec uint64, decoder DecodeBlockFunc) + Decode(blocks.Block) (Node, error) +} +type safeBlockDecoder struct { + // Can be replaced with an RCU if necessary. + lock sync.RWMutex + decoders map[uint64]DecodeBlockFunc +} + +// Register registers decoder for all blocks with the passed codec. +// +// This will silently replace any existing registered block decoders. +func (d *safeBlockDecoder) Register(codec uint64, decoder DecodeBlockFunc) { + d.lock.Lock() + defer d.lock.Unlock() + d.decoders[codec] = decoder +} + +func (d *safeBlockDecoder) Decode(block blocks.Block) (Node, error) { + // Short-circuit by cast if we already have a Node. + if node, ok := block.(Node); ok { + return node, nil + } + + ty := block.Cid().Type() + + d.lock.RLock() + decoder, ok := d.decoders[ty] + d.lock.RUnlock() + + if ok { + return decoder(block) + } else { + // TODO: get the *long* name for this format + return nil, fmt.Errorf("unrecognized object type: %d", ty) + } +} + +var DefaultBlockDecoder BlockDecoder = &safeBlockDecoder{decoders: make(map[uint64]DecodeBlockFunc)} + +// Decode decodes the given block using the default BlockDecoder. +func Decode(block blocks.Block) (Node, error) { + return DefaultBlockDecoder.Decode(block) +} + +// Register registers block decoders with the default BlockDecoder. +func Register(codec uint64, decoder DecodeBlockFunc) { + DefaultBlockDecoder.Register(codec, decoder) +} diff --git a/vendor/github.com/ipfs/go-ipld-format/daghelpers.go b/vendor/github.com/ipfs/go-ipld-format/daghelpers.go new file mode 100644 index 0000000000..70ad0b91ea --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/daghelpers.go @@ -0,0 +1,118 @@ +package format + +import ( + "context" + + cid "github.com/ipfs/go-cid" +) + +// GetLinks returns the CIDs of the children of the given node. Prefer this +// method over looking up the node itself and calling `Links()` on it as this +// method may be able to use a link cache. +func GetLinks(ctx context.Context, ng NodeGetter, c cid.Cid) ([]*Link, error) { + if c.Type() == cid.Raw { + return nil, nil + } + if gl, ok := ng.(LinkGetter); ok { + return gl.GetLinks(ctx, c) + } + node, err := ng.Get(ctx, c) + if err != nil { + return nil, err + } + return node.Links(), nil +} + +// GetDAG will fill out all of the links of the given Node. +// It returns an array of NodePromise with the linked nodes all in the proper +// order. +func GetDAG(ctx context.Context, ds NodeGetter, root Node) []*NodePromise { + var cids []cid.Cid + for _, lnk := range root.Links() { + cids = append(cids, lnk.Cid) + } + + return GetNodes(ctx, ds, cids) +} + +// GetNodes returns an array of 'FutureNode' promises, with each corresponding +// to the key with the same index as the passed in keys +func GetNodes(ctx context.Context, ds NodeGetter, keys []cid.Cid) []*NodePromise { + + // Early out if no work to do + if len(keys) == 0 { + return nil + } + + promises := make([]*NodePromise, len(keys)) + for i := range keys { + promises[i] = NewNodePromise(ctx) + } + + dedupedKeys := dedupeKeys(keys) + go func() { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + nodechan := ds.GetMany(ctx, dedupedKeys) + + for count := 0; count < len(keys); { + select { + case opt, ok := <-nodechan: + if !ok { + for _, p := range promises { + p.Fail(ErrNotFound) + } + return + } + + if opt.Err != nil { + for _, p := range promises { + p.Fail(opt.Err) + } + return + } + + nd := opt.Node + c := nd.Cid() + for i, lnk_c := range keys { + if c.Equals(lnk_c) { + count++ + promises[i].Send(nd) + } + } + case <-ctx.Done(): + return + } + } + }() + return promises +} + +func Copy(ctx context.Context, from, to DAGService, root cid.Cid) error { + node, err := from.Get(ctx, root) + if err != nil { + return err + } + links := node.Links() + for _, link := range links { + err := Copy(ctx, from, to, link.Cid) + if err != nil { + return err + } + } + err = to.Add(ctx, node) + if err != nil { + return err + } + return nil +} + +// Remove duplicates from a list of keys +func dedupeKeys(cids []cid.Cid) []cid.Cid { + set := cid.NewSet() + for _, c := range cids { + set.Add(c) + } + return set.Keys() +} diff --git a/vendor/github.com/ipfs/go-ipld-format/format.go b/vendor/github.com/ipfs/go-ipld-format/format.go new file mode 100644 index 0000000000..990e1ce0f5 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/format.go @@ -0,0 +1,90 @@ +package format + +import ( + "context" + "fmt" + + blocks "github.com/ipfs/go-block-format" + + cid "github.com/ipfs/go-cid" +) + +type Resolver interface { + // Resolve resolves a path through this node, stopping at any link boundary + // and returning the object found as well as the remaining path to traverse + Resolve(path []string) (interface{}, []string, error) + + // Tree lists all paths within the object under 'path', and up to the given depth. + // To list the entire object (similar to `find .`) pass "" and -1 + Tree(path string, depth int) []string +} + +// Node is the base interface all IPLD nodes must implement. +// +// Nodes are **Immutable** and all methods defined on the interface are +// **Thread Safe**. +type Node interface { + blocks.Block + Resolver + + // ResolveLink is a helper function that calls resolve and asserts the + // output is a link + ResolveLink(path []string) (*Link, []string, error) + + // Copy returns a deep copy of this node + Copy() Node + + // Links is a helper function that returns all links within this object + Links() []*Link + + // TODO: not sure if stat deserves to stay + Stat() (*NodeStat, error) + + // Size returns the size in bytes of the serialized object + Size() (uint64, error) +} + +// Link represents an IPFS Merkle DAG Link between Nodes. +type Link struct { + // utf string name. should be unique per object + Name string // utf8 + + // cumulative size of target object + Size uint64 + + // multihash of the target object + Cid cid.Cid +} + +// NodeStat is a statistics object for a Node. Mostly sizes. +type NodeStat struct { + Hash string + NumLinks int // number of links in link table + BlockSize int // size of the raw, encoded data + LinksSize int // size of the links segment + DataSize int // size of the data segment + CumulativeSize int // cumulative size of object and its references +} + +func (ns NodeStat) String() string { + f := "NodeStat{NumLinks: %d, BlockSize: %d, LinksSize: %d, DataSize: %d, CumulativeSize: %d}" + return fmt.Sprintf(f, ns.NumLinks, ns.BlockSize, ns.LinksSize, ns.DataSize, ns.CumulativeSize) +} + +// MakeLink creates a link to the given node +func MakeLink(n Node) (*Link, error) { + s, err := n.Size() + if err != nil { + return nil, err + } + + return &Link{ + Size: s, + Cid: n.Cid(), + }, nil +} + +// GetNode returns the MDAG Node that this link points to +func (l *Link) GetNode(ctx context.Context, serv NodeGetter) (Node, error) { + return serv.Get(ctx, l.Cid) +} diff --git a/vendor/github.com/ipfs/go-ipld-format/go.mod b/vendor/github.com/ipfs/go-ipld-format/go.mod new file mode 100644 index 0000000000..0aab53b207 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/go.mod @@ -0,0 +1,10 @@ +module github.com/ipfs/go-ipld-format + +require ( + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.2 + github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/multiformats/go-multihash v0.0.1 +) + +go 1.13 diff --git a/vendor/github.com/ipfs/go-ipld-format/go.sum b/vendor/github.com/ipfs/go-ipld-format/go.sum new file mode 100644 index 0000000000..f900301234 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/go.sum @@ -0,0 +1,30 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/ipfs/go-ipld-format/merkledag.go b/vendor/github.com/ipfs/go-ipld-format/merkledag.go new file mode 100644 index 0000000000..755b90f6f5 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/merkledag.go @@ -0,0 +1,67 @@ +package format + +import ( + "context" + "fmt" + + cid "github.com/ipfs/go-cid" +) + +var ErrNotFound = fmt.Errorf("merkledag: not found") + +// Either a node or an error. +type NodeOption struct { + Node Node + Err error +} + +// The basic Node resolution service. +type NodeGetter interface { + // Get retrieves nodes by CID. Depending on the NodeGetter + // implementation, this may involve fetching the Node from a remote + // machine; consider setting a deadline in the context. + Get(context.Context, cid.Cid) (Node, error) + + // GetMany returns a channel of NodeOptions given a set of CIDs. + GetMany(context.Context, []cid.Cid) <-chan *NodeOption +} + +// NodeAdder adds nodes to a DAG. +type NodeAdder interface { + // Add adds a node to this DAG. + Add(context.Context, Node) error + + // AddMany adds many nodes to this DAG. + // + // Consider using the Batch NodeAdder (`NewBatch`) if you make + // extensive use of this function. + AddMany(context.Context, []Node) error +} + +// NodeGetters can optionally implement this interface to make finding linked +// objects faster. +type LinkGetter interface { + NodeGetter + + // TODO(ipfs/go-ipld-format#9): This should return []cid.Cid + + // GetLinks returns the children of the node refered to by the given + // CID. + GetLinks(ctx context.Context, nd cid.Cid) ([]*Link, error) +} + +// DAGService is an IPFS Merkle DAG service. +type DAGService interface { + NodeGetter + NodeAdder + + // Remove removes a node from this DAG. + // + // Remove returns no error if the requested node is not present in this DAG. + Remove(context.Context, cid.Cid) error + + // RemoveMany removes many nodes from this DAG. + // + // It returns success even if the nodes were not present in the DAG. + RemoveMany(context.Context, []cid.Cid) error +} diff --git a/vendor/github.com/ipfs/go-ipld-format/navipld.go b/vendor/github.com/ipfs/go-ipld-format/navipld.go new file mode 100644 index 0000000000..1298673779 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/navipld.go @@ -0,0 +1,149 @@ +package format + +import ( + "context" + + cid "github.com/ipfs/go-cid" +) + +// NavigableIPLDNode implements the `NavigableNode` interface wrapping +// an IPLD `Node` and providing support for node promises. +type NavigableIPLDNode struct { + node Node + + // The CID of each child of the node. + childCIDs []cid.Cid + + // Node promises for child nodes requested. + childPromises []*NodePromise + // TODO: Consider encapsulating it in a single structure alongside `childCIDs`. + + nodeGetter NodeGetter + // TODO: Should this be stored in the `Walker`'s context to avoid passing + // it along to every node? It seems like a structure that doesn't need + // to be replicated (the entire DAG will use the same `NodeGetter`). +} + +// NewNavigableIPLDNode returns a `NavigableIPLDNode` wrapping the provided +// `node`. +func NewNavigableIPLDNode(node Node, nodeGetter NodeGetter) *NavigableIPLDNode { + nn := &NavigableIPLDNode{ + node: node, + nodeGetter: nodeGetter, + } + + nn.childCIDs = getLinkCids(node) + nn.childPromises = make([]*NodePromise, len(nn.childCIDs)) + + return nn +} + +// FetchChild implements the `NavigableNode` interface using node promises +// to preload the following child nodes to `childIndex` leaving them ready +// for subsequent `FetchChild` calls. +func (nn *NavigableIPLDNode) FetchChild(ctx context.Context, childIndex uint) (NavigableNode, error) { + // This function doesn't check that `childIndex` is valid, that's + // the `Walker` responsibility. + + // If we drop to <= preloadSize/2 preloading nodes, preload the next 10. + for i := childIndex; i < childIndex+preloadSize/2 && i < uint(len(nn.childPromises)); i++ { + // TODO: Check if canceled. + if nn.childPromises[i] == nil { + nn.preload(ctx, i) + break + } + } + + child, err := nn.getPromiseValue(ctx, childIndex) + + switch err { + case nil: + case context.DeadlineExceeded, context.Canceled: + if ctx.Err() != nil { + return nil, ctx.Err() + } + + // In this case, the context used to *preload* the node (in a previous + // `FetchChild` call) has been canceled. We need to retry the load with + // the current context and we might as well preload some extra nodes + // while we're at it. + nn.preload(ctx, childIndex) + child, err = nn.getPromiseValue(ctx, childIndex) + if err != nil { + return nil, err + } + default: + return nil, err + } + + return NewNavigableIPLDNode(child, nn.nodeGetter), nil +} + +// Number of nodes to preload every time a child is requested. +// TODO: Give more visibility to this constant, it could be an attribute +// set in the `Walker` context that gets passed in `FetchChild`. +const preloadSize = 10 + +// Preload at most `preloadSize` child nodes from `beg` through promises +// created using this `ctx`. +func (nn *NavigableIPLDNode) preload(ctx context.Context, beg uint) { + end := beg + preloadSize + if end >= uint(len(nn.childCIDs)) { + end = uint(len(nn.childCIDs)) + } + + copy(nn.childPromises[beg:], GetNodes(ctx, nn.nodeGetter, nn.childCIDs[beg:end])) +} + +// Fetch the actual node (this is the blocking part of the mechanism) +// and invalidate the promise. `preload` should always be called first +// for the `childIndex` being fetch. +// +// TODO: Include `preload` into the beginning of this function? +// (And collapse the two calls in `FetchChild`). +func (nn *NavigableIPLDNode) getPromiseValue(ctx context.Context, childIndex uint) (Node, error) { + value, err := nn.childPromises[childIndex].Get(ctx) + nn.childPromises[childIndex] = nil + return value, err +} + +// Get the CID of all the links of this `node`. +func getLinkCids(node Node) []cid.Cid { + links := node.Links() + out := make([]cid.Cid, 0, len(links)) + + for _, l := range links { + out = append(out, l.Cid) + } + return out +} + +// GetIPLDNode returns the IPLD `Node` wrapped into this structure. +func (nn *NavigableIPLDNode) GetIPLDNode() Node { + return nn.node +} + +// ChildTotal implements the `NavigableNode` returning the number +// of links (of child nodes) in this node. +func (nn *NavigableIPLDNode) ChildTotal() uint { + return uint(len(nn.GetIPLDNode().Links())) +} + +// ExtractIPLDNode is a helper function that takes a `NavigableNode` +// and returns the IPLD `Node` wrapped inside. Used in the `Visitor` +// function. +// TODO: Check for errors to avoid a panic? +func ExtractIPLDNode(node NavigableNode) Node { + return node.(*NavigableIPLDNode).GetIPLDNode() +} + +// TODO: `Cleanup` is not supported at the moment in the `Walker`. +// +// Called in `Walker.up()` when the node is not part of the path anymore. +//func (nn *NavigableIPLDNode) Cleanup() { +// // TODO: Ideally this would be the place to issue a context `cancel()` +// // but since the DAG reader uses multiple contexts in the same session +// // (through `Read` and `CtxReadFull`) we would need to store an array +// // with the multiple contexts in `NavigableIPLDNode` with its corresponding +// // cancel functions. +//} diff --git a/vendor/github.com/ipfs/go-ipld-format/promise.go b/vendor/github.com/ipfs/go-ipld-format/promise.go new file mode 100644 index 0000000000..02743b03c8 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/promise.go @@ -0,0 +1,66 @@ +package format + +import ( + "context" +) + +// NodePromise provides a promise like interface for a dag Node +// the first call to Get will block until the Node is received +// from its internal channels, subsequent calls will return the +// cached node. +// +// Thread Safety: This is multiple-consumer/single-producer safe. +func NewNodePromise(ctx context.Context) *NodePromise { + return &NodePromise{ + done: make(chan struct{}), + ctx: ctx, + } +} + +type NodePromise struct { + value Node + err error + done chan struct{} + + ctx context.Context +} + +// Call this function to fail a promise. +// +// Once a promise has been failed or fulfilled, further attempts to fail it will +// be silently dropped. +func (np *NodePromise) Fail(err error) { + if np.err != nil || np.value != nil { + // Already filled. + return + } + np.err = err + close(np.done) +} + +// Fulfill this promise. +// +// Once a promise has been fulfilled or failed, calling this function will +// panic. +func (np *NodePromise) Send(nd Node) { + // if promise has a value, don't fail it + if np.err != nil || np.value != nil { + panic("already filled") + } + np.value = nd + close(np.done) +} + +// Get the value of this promise. +// +// This function is safe to call concurrently from any number of goroutines. +func (np *NodePromise) Get(ctx context.Context) (Node, error) { + select { + case <-np.done: + return np.value, np.err + case <-np.ctx.Done(): + return nil, np.ctx.Err() + case <-ctx.Done(): + return nil, ctx.Err() + } +} diff --git a/vendor/github.com/ipfs/go-ipld-format/walker.go b/vendor/github.com/ipfs/go-ipld-format/walker.go new file mode 100644 index 0000000000..81380936b3 --- /dev/null +++ b/vendor/github.com/ipfs/go-ipld-format/walker.go @@ -0,0 +1,436 @@ +package format + +import ( + "context" + "errors" +) + +// Walker provides methods to move through a DAG of nodes that implement +// the `NavigableNode` interface. It uses iterative algorithms (instead +// of recursive ones) that expose the `path` of nodes from the root to +// the `ActiveNode` it currently points to. +// +// It provides multiple ways to walk through the DAG (e.g. `Iterate` +// and `Seek`). When using them, you provide a Visitor function that +// will be called for each node the Walker traverses. The Visitor can +// read data from those nodes and, optionally, direct the movement of +// the Walker by calling `Pause` (to stop traversing and return) or +// `NextChild` (to skip a child and its descendants). See the DAG reader +// in `github.com/ipfs/go-unixfs/io/dagreader.go` for a usage example. +// TODO: This example isn't merged yet. +type Walker struct { + + // Sequence of nodes in the DAG from the root to the `ActiveNode`, each + // position in the slice being the parent of the next one. The `ActiveNode` + // resides in the position indexed by `currentDepth` (the slice may contain + // more elements past that point but they should be ignored since the slice + // is not truncated to leverage the already allocated space). + // + // Every time `down` is called the `currentDepth` increases and the child + // of the `ActiveNode` is inserted after it (effectively becoming the new + // `ActiveNode`). + // + // The slice must *always* have a length bigger than zero with the root + // of the DAG at the first position (empty DAGs are not valid). + path []NavigableNode + + // Depth of the `ActiveNode`. It grows downwards, root being 0, its child 1, + // and so on. It controls the effective length of `path` and `childIndex`. + // + // A currentDepth of -1 signals the start case of a new `Walker` that hasn't + // moved yet. Although this state is an invalid index to the slices, it + // allows to centralize all the visit calls in the `down` move (starting at + // zero would require a special visit case inside every walk operation like + // `Iterate()` and `Seek`). This value should never be returned to after + // the first `down` movement, moving up from the root should always return + // `errUpOnRoot`. + currentDepth int + + // This slice has the index of the child each node in `path` is pointing + // to. The child index in the node can be set past all of its child nodes + // (having a value equal to `ChildTotal`) to signal it has visited (or + // skipped) all of them. A leaf node with no children that has its index + // in zero would also comply with this format. + // + // Complement to `path`, not only do we need to know which nodes have been + // traversed to reach the `ActiveNode` but also which child nodes they are + // to correctly have the active path of the DAG. (Reword this paragraph.) + childIndex []uint + + // Flag to signal that a pause in the current walk operation has been + // requested by the user inside `Visitor`. + pauseRequested bool + + // Used to pass information from the central `Walker` structure to the + // distributed `NavigableNode`s (to have a centralized configuration + // structure to control the behavior of all of them), e.g., to tell + // the `NavigableIPLDNode` which context should be used to load node + // promises (but this could later be used in more elaborate ways). + ctx context.Context +} + +// `Walker` implementation details: +// +// The `Iterate` and `Seek` walk operations are implemented through two +// basic move methods `up` and `down`, that change which node is the +// `ActiveNode` (modifying the `path` that leads to it). The `NextChild` +// method allows to change which child the `ActiveNode` is pointing to +// in order to change the direction of the descent. +// +// The `down` method is the analogous of a recursive call and the one in +// charge of visiting (possible new) nodes (through `Visitor`) and performing +// some user-defined logic. A `Pause` method is available to interrupt the +// current walk operation after visiting a node. +// +// Key terms and concepts: +// * Walk operation (e.g., `Iterate`). +// * Move methods: `up` and `down`. +// * Active node. +// * Path to the active node. + +// Function called each time a node is arrived upon in a walk operation +// through the `down` method (not when going back `up`). It is the main +// API to implement DAG functionality (e.g., read and seek a file DAG) +// on top of the `Walker` structure. +// +// Its argument is the current `node` being visited (the `ActiveNode`). +// Any error it returns (apart from the internal `errPauseWalkOperation`) +// will be forwarded to the caller of the walk operation (pausing it). +// +// Any of the exported methods of this API should be allowed to be called +// from within this method, e.g., `NextChild`. +// TODO: Check that. Can `ResetPosition` be called without breaking +// the `Walker` integrity? +type Visitor func(node NavigableNode) error + +// NavigableNode is the interface the nodes of a DAG need to implement in +// order to be traversed by the `Walker`. +type NavigableNode interface { + + // FetchChild returns the child of this node pointed to by `childIndex`. + // A `Context` stored in the `Walker` is passed (`ctx`) that may contain + // configuration attributes stored by the user before initiating the + // walk operation. + FetchChild(ctx context.Context, childIndex uint) (NavigableNode, error) + + // ChildTotal returns the number of children of the `ActiveNode`. + ChildTotal() uint + + // TODO: Evaluate providing the `Cleanup` and `Reset` methods. + + // Cleanup is an optional method that is called by the `Walker` when + // this node leaves the active `path`, i.e., when this node is the + // `ActiveNode` and the `up` movement is called. + //Cleanup() + // Allow this method to return an error? That would imply + // modifying the `Walker` API, `up()` would now return an error + // different than `errUpOnRoot`. + + // Reset is an optional function that is called by the `Walker` when + // `ResetPosition` is called, it is only applied to the root node + // of the DAG. + //Reset() +} + +// NewWalker creates a new `Walker` structure from a `root` +// NavigableNode. +func NewWalker(ctx context.Context, root NavigableNode) *Walker { + return &Walker{ + ctx: ctx, + + path: []NavigableNode{root}, + childIndex: []uint{0}, + + currentDepth: -1, + // Starting position, "on top" of the root node, see `currentDepth`. + } +} + +// ActiveNode returns the `NavigableNode` that `Walker` is pointing +// to at the moment. It changes when `up` or `down` is called. +func (w *Walker) ActiveNode() NavigableNode { + return w.path[w.currentDepth] + // TODO: Add a check for the initial state of `currentDepth` -1? +} + +// ErrDownNoChild signals there is no child at `ActiveChildIndex` in the +// `ActiveNode` to go down to. +var ErrDownNoChild = errors.New("can't go down, the child does not exist") + +// errUpOnRoot signals the end of the DAG after returning to the root. +var errUpOnRoot = errors.New("can't go up, already on root") + +// EndOfDag wraps the `errUpOnRoot` and signals to the user that the +// entire DAG has been iterated. +var EndOfDag = errors.New("end of DAG") + +// ErrNextNoChild signals the end of this parent child nodes. +var ErrNextNoChild = errors.New("can't go to the next child, no more child nodes in this parent") + +// errPauseWalkOperation signals the pause of the walk operation. +var errPauseWalkOperation = errors.New("pause in the current walk operation") + +// ErrNilVisitor signals the lack of a `Visitor` function. +var ErrNilVisitor = errors.New("no Visitor function specified") + +// Iterate the DAG through the DFS pre-order walk algorithm, going down +// as much as possible, then `NextChild` to the other siblings, and then up +// (to go down again). The position is saved throughout iterations (and +// can be previously set in `Seek`) allowing `Iterate` to be called +// repeatedly (after a `Pause`) to continue the iteration. +// +// This function returns the errors received from `down` (generated either +// inside the `Visitor` call or any other errors while fetching the child +// nodes), the rest of the move errors are handled within the function and +// are not returned. +func (w *Walker) Iterate(visitor Visitor) error { + + // Iterate until either: the end of the DAG (`errUpOnRoot`), a `Pause` + // is requested (`errPauseWalkOperation`) or an error happens (while + // going down). + for { + + // First, go down as much as possible. + for { + err := w.down(visitor) + + if err == ErrDownNoChild { + break + // Can't keep going down from this node, try to move Next. + } + + if err == errPauseWalkOperation { + return nil + // Pause requested, `errPauseWalkOperation` is just an internal + // error to signal to pause, don't pass it along. + } + + if err != nil { + return err + // `down` is the only movement that can return *any* error. + } + } + + // Can't move down anymore, turn to the next child in the `ActiveNode` + // to go down a different path. If there are no more child nodes + // available, go back up. + for { + err := w.NextChild() + if err == nil { + break + // No error, it turned to the next child. Try to go down again. + } + + // It can't go Next (`ErrNextNoChild`), try to move up. + err = w.up() + if err != nil { + // Can't move up, on the root again (`errUpOnRoot`). + return EndOfDag + } + + // Moved up, try `NextChild` again. + } + + // Turned to the next child (after potentially many up moves), + // try going down again. + } +} + +// Seek a specific node in a downwards manner. The `Visitor` should be +// used to steer the seek selecting at each node which child will the +// seek continue to (extending the `path` in that direction) or pause it +// (if the desired node has been found). The seek always starts from +// the root. It modifies the position so it shouldn't be used in-between +// `Iterate` calls (it can be used to set the position *before* iterating). +// If the visitor returns any non-`nil` errors the seek will stop. +// +// TODO: The seek could be extended to seek from the current position. +// (Is there something in the logic that would prevent it at the moment?) +func (w *Walker) Seek(visitor Visitor) error { + + if visitor == nil { + return ErrNilVisitor + // Although valid, there is no point in calling `Seek` without + // any extra logic, it would just go down to the leftmost leaf, + // so this would probably be a user error. + } + + // Go down until it the desired node is found (that will be signaled + // pausing the seek with `errPauseWalkOperation`) or a leaf node is + // reached (end of the DAG). + for { + err := w.down(visitor) + + if err == errPauseWalkOperation { + return nil + // Found the node, `errPauseWalkOperation` is just an internal + // error to signal to pause, don't pass it along. + } + + if err == ErrDownNoChild { + return nil + // Can't keep going down from this node, either at a leaf node + // or the `Visitor` has moved the child index past the + // available index (probably because none indicated that the + // target node could be down from there). + } + + if err != nil { + return err + // `down()` is the only movement that can return *any* error. + } + } + // TODO: Copied from the first part of `Iterate()` (although conceptually + // different from it). Could this be encapsulated in a function to avoid + // repeating code? The way the pause signal is handled it wouldn't seem + // very useful: the `errPauseWalkOperation` needs to be processed at this + // depth to return from the function (and pause the seek, returning + // from another function here wouldn't cause it to stop). +} + +// Go down one level in the DAG to the child of the `ActiveNode` +// pointed to by `ActiveChildIndex` and perform some logic on it by +// through the user-specified `visitor`. +// +// This should always be the first move in any walk operation +// (to visit the root node and move the `currentDepth` away +// from the negative value). +func (w *Walker) down(visitor Visitor) error { + child, err := w.fetchChild() + if err != nil { + return err + } + + w.extendPath(child) + + return w.visitActiveNode(visitor) +} + +// Fetch the child from the `ActiveNode` through the `FetchChild` +// method of the `NavigableNode` interface. +func (w *Walker) fetchChild() (NavigableNode, error) { + if w.currentDepth == -1 { + // First time `down()` is called, `currentDepth` is -1, + // return the root node. Don't check available child nodes + // (as the `Walker` is not actually on any node just yet + // and `ActiveChildIndex` is of no use yet). + return w.path[0], nil + } + + // Check if the child to fetch exists. + if w.ActiveChildIndex() >= w.ActiveNode().ChildTotal() { + return nil, ErrDownNoChild + } + + return w.ActiveNode().FetchChild(w.ctx, w.ActiveChildIndex()) + + // TODO: Maybe call `extendPath` here and hide it away + // from `down`. +} + +// Increase the `currentDepth` and extend the `path` to the fetched +// `child` node (which now becomes the new `ActiveNode`) +func (w *Walker) extendPath(child NavigableNode) { + w.currentDepth++ + + // Extend the slices if needed (doubling its capacity). + if w.currentDepth >= len(w.path) { + w.path = append(w.path, make([]NavigableNode, len(w.path))...) + w.childIndex = append(w.childIndex, make([]uint, len(w.childIndex))...) + // TODO: Check the performance of this grow mechanism. + } + + // `child` now becomes the `ActiveNode()`. + w.path[w.currentDepth] = child + w.childIndex[w.currentDepth] = 0 +} + +// Call the `Visitor` on the `ActiveNode`. This function should only be +// called from `down`. This is a wrapper function to `Visitor` to process +// the `Pause` signal and do other minor checks (taking this logic away +// from `down`). +func (w *Walker) visitActiveNode(visitor Visitor) error { + if visitor == nil { + return nil + // No need to check `pauseRequested` as `Pause` should + // only be called from within the `Visitor`. + } + + err := visitor(w.ActiveNode()) + + if w.pauseRequested { + // If a pause was requested make sure an error is returned + // that will cause the current walk operation to return. If + // `Visitor` didn't return an error set an artificial one + // generated by the `Walker`. + if err == nil { + err = errPauseWalkOperation + } + + w.pauseRequested = false + } + + return err +} + +// Go up from the `ActiveNode`. The only possible error this method +// can return is to signal it's already at the root and can't go up. +func (w *Walker) up() error { + if w.currentDepth < 1 { + return errUpOnRoot + } + + w.currentDepth-- + + // w.ActiveNode().Cleanup() + // If `Cleanup` is supported this would be the place to call it. + + return nil +} + +// NextChild increases the child index of the `ActiveNode` to point +// to the next child (which may exist or may be the end of the available +// child nodes). +// +// This method doesn't change the `ActiveNode`, it just changes where +// is it pointing to next, it could be interpreted as "turn to the next +// child". +func (w *Walker) NextChild() error { + w.incrementActiveChildIndex() + + if w.ActiveChildIndex() == w.ActiveNode().ChildTotal() { + return ErrNextNoChild + // At the end of the available children, signal it. + } + + return nil +} + +// incrementActiveChildIndex increments the child index of the `ActiveNode` to +// point to the next child (if it exists) or to the position past all of +// the child nodes (`ChildTotal`) to signal that all of its children have +// been visited/skipped (if already at that last position, do nothing). +func (w *Walker) incrementActiveChildIndex() { + if w.ActiveChildIndex()+1 <= w.ActiveNode().ChildTotal() { + w.childIndex[w.currentDepth]++ + } +} + +// ActiveChildIndex returns the index of the child the `ActiveNode()` +// is pointing to. +func (w *Walker) ActiveChildIndex() uint { + return w.childIndex[w.currentDepth] +} + +// SetContext changes the internal `Walker` (that is provided to the +// `NavigableNode`s when calling `FetchChild`) with the one passed +// as argument. +func (w *Walker) SetContext(ctx context.Context) { + w.ctx = ctx +} + +// Pause the current walk operation. This function must be called from +// within the `Visitor` function. +func (w *Walker) Pause() { + w.pauseRequested = true +} diff --git a/vendor/github.com/ipfs/go-log/.travis.yml b/vendor/github.com/ipfs/go-log/.travis.yml new file mode 100644 index 0000000000..923835bc58 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/.travis.yml @@ -0,0 +1,31 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-log/LICENSE b/vendor/github.com/ipfs/go-log/LICENSE new file mode 100644 index 0000000000..c7386b3c94 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-log/README.md b/vendor/github.com/ipfs/go-log/README.md new file mode 100644 index 0000000000..b0b5b9f6fa --- /dev/null +++ b/vendor/github.com/ipfs/go-log/README.md @@ -0,0 +1,79 @@ +# go-log + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/ipfs/go-log?status.svg)](https://godoc.org/github.com/ipfs/go-log) +[![Build Status](https://travis-ci.org/ipfs/go-log.svg?branch=master)](https://travis-ci.org/ipfs/go-log) + + + + +> The logging library used by go-ipfs + +It currently uses a modified version of [go-logging](https://github.com/whyrusleeping/go-logging) to implement the standard printf-style log output. + +## Install + +```sh +go get github.com/ipfs/go-log +``` + +## Usage + +Once the package is imported under the name `logging`, an instance of `EventLogger` can be created like so: + +```go +var log = logging.Logger("subsystem name") +``` + +It can then be used to emit log messages, either plain printf-style messages at six standard levels or structured messages using `Start`, `StartFromParentState`, `Finish` and `FinishWithErr` methods. + +## Example + +```go +func (s *Session) GetBlock(ctx context.Context, c *cid.Cid) (blk blocks.Block, err error) { + + // Starts Span called "Session.GetBlock", associates with `ctx` + ctx = log.Start(ctx, "Session.GetBlock") + + // defer so `blk` and `err` can be evaluated after call + defer func() { + // tag span associated with `ctx` + log.SetTags(ctx, map[string]interface{}{ + "cid": c, + "block", blk, + }) + // if err is non-nil tag the span with an error + log.FinishWithErr(ctx, err) + }() + + if shouldStartSomething() { + // log message on span associated with `ctx` + log.LogKV(ctx, "startSomething", true) + } + ... +} +``` +## Tracing + +`go-log` wraps the [opentracing-go](https://github.com/opentracing/opentracing-go) methods - `StartSpan`, `Finish`, `LogKV`, and `SetTag`. + +`go-log` implements its own tracer - `loggabletracer` - based on the [basictracer-go](https://github.com/opentracing/basictracer-go) implementation. If there is an active [`WriterGroup`](https://github.com/ipfs/go-log/blob/master/writer/option.go) the `loggabletracer` will [record](https://github.com/ipfs/go-log/blob/master/tracer/recorder.go) span data to the `WriterGroup`. An example of this can be seen in the [`log tail`](https://github.com/ipfs/go-ipfs/blob/master/core/commands/log.go) command of `go-ipfs`. + +Third party tracers may be used by calling `opentracing.SetGlobalTracer()` with your desired tracing implementation. An example of this can be seen using the [`go-jaeger-plugin`](https://github.com/ipfs/go-jaeger-plugin) and the `go-ipfs` [tracer plugin](https://github.com/ipfs/go-ipfs/blob/master/plugin/tracer.go) + +## Contribute + +Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-log/issues)! + +This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +### Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) + +## License + +MIT diff --git a/vendor/github.com/ipfs/go-log/context.go b/vendor/github.com/ipfs/go-log/context.go new file mode 100644 index 0000000000..b8ef5bc836 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/context.go @@ -0,0 +1,38 @@ +package log + +import ( + "context" + "errors" +) + +type key int + +const metadataKey key = 0 + +// ContextWithLoggable returns a derived context which contains the provided +// Loggable. Any Events logged with the derived context will include the +// provided Loggable. +func ContextWithLoggable(ctx context.Context, l Loggable) context.Context { + existing, err := MetadataFromContext(ctx) + if err != nil { + // context does not contain meta. just set the new metadata + child := context.WithValue(ctx, metadataKey, Metadata(l.Loggable())) + return child + } + + merged := DeepMerge(existing, l.Loggable()) + child := context.WithValue(ctx, metadataKey, merged) + return child +} + +// MetadataFromContext extracts Matadata from a given context's value. +func MetadataFromContext(ctx context.Context) (Metadata, error) { + value := ctx.Value(metadataKey) + if value != nil { + metadata, ok := value.(Metadata) + if ok { + return metadata, nil + } + } + return nil, errors.New("context contains no metadata") +} diff --git a/vendor/github.com/ipfs/go-log/entry.go b/vendor/github.com/ipfs/go-log/entry.go new file mode 100644 index 0000000000..63c02135c8 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/entry.go @@ -0,0 +1,7 @@ +package log + +type entry struct { + loggables []Loggable + system string + event string +} diff --git a/vendor/github.com/ipfs/go-log/go.mod b/vendor/github.com/ipfs/go-log/go.mod new file mode 100644 index 0000000000..7565c6d1d7 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/go.mod @@ -0,0 +1,10 @@ +module github.com/ipfs/go-log + +require ( + github.com/gogo/protobuf v1.3.1 + github.com/ipfs/go-log/v2 v2.0.5 + github.com/opentracing/opentracing-go v1.1.0 + go.uber.org/zap v1.14.1 +) + +go 1.12 diff --git a/vendor/github.com/ipfs/go-log/go.sum b/vendor/github.com/ipfs/go-log/go.sum new file mode 100644 index 0000000000..ab58ec8bd9 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/go.sum @@ -0,0 +1,65 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/ipfs/go-log/v2 v2.0.5 h1:fL4YI+1g5V/b1Yxr1qAiXTMg1H8z9vx/VmJxBuQMHvU= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/ipfs/go-log/levels.go b/vendor/github.com/ipfs/go-log/levels.go new file mode 100644 index 0000000000..22e6b8828d --- /dev/null +++ b/vendor/github.com/ipfs/go-log/levels.go @@ -0,0 +1,30 @@ +package log + +import ( + log2 "github.com/ipfs/go-log/v2" +) + +// LogLevel represents a log severity level. Use the package variables as an +// enum. +type LogLevel = log2.LogLevel + +var ( + LevelDebug = log2.LevelDebug + LevelInfo = log2.LevelInfo + LevelWarn = log2.LevelWarn + LevelError = log2.LevelError + LevelDPanic = log2.LevelDPanic + LevelPanic = log2.LevelPanic + LevelFatal = log2.LevelFatal +) + +// LevelFromString parses a string-based level and returns the corresponding +// LogLevel. +// +// Supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and +// their lower-case forms. +// +// The returned LogLevel must be discarded if error is not nil. +func LevelFromString(level string) (LogLevel, error) { + return log2.LevelFromString(level) +} diff --git a/vendor/github.com/ipfs/go-log/log.go b/vendor/github.com/ipfs/go-log/log.go new file mode 100644 index 0000000000..5581d508bc --- /dev/null +++ b/vendor/github.com/ipfs/go-log/log.go @@ -0,0 +1,420 @@ +// Package log is the logging library used by IPFS +// (https://github.com/ipfs/go-ipfs). It uses a modified version of +// https://godoc.org/github.com/whyrusleeping/go-logging . +package log + +import ( + "bytes" + "context" + "encoding/json" + "path" + "runtime" + "time" + + log2 "github.com/ipfs/go-log/v2" + writer "github.com/ipfs/go-log/writer" + + opentrace "github.com/opentracing/opentracing-go" + otExt "github.com/opentracing/opentracing-go/ext" + "go.uber.org/zap" +) + +var log = Logger("eventlog") + +// StandardLogger provides API compatibility with standard printf loggers +// eg. go-logging +type StandardLogger interface { + log2.StandardLogger + // Deprecated use Warn + Warning(args ...interface{}) + // Deprecated use Warnf + Warningf(format string, args ...interface{}) +} + +// EventLogger extends the StandardLogger interface to allow for log items +// containing structured metadata +type EventLogger interface { + StandardLogger + + // Event merges structured data from the provided inputs into a single + // machine-readable log event. + // + // If the context contains metadata, a copy of this is used as the base + // metadata accumulator. + // + // If one or more loggable objects are provided, these are deep-merged into base blob. + // + // Next, the event name is added to the blob under the key "event". If + // the key "event" already exists, it will be over-written. + // + // Finally the timestamp and package name are added to the accumulator and + // the metadata is logged. + // DEPRECATED + // Deprecated: Stop using go-log for event logging + Event(ctx context.Context, event string, m ...Loggable) + + // DEPRECATED + // Deprecated: Stop using go-log for event logging + EventBegin(ctx context.Context, event string, m ...Loggable) *EventInProgress + + // Start starts an opentracing span with `name`, using + // any Span found within `ctx` as a ChildOfRef. If no such parent could be + // found, Start creates a root (parentless) Span. + // + // The return value is a context.Context object built around the + // returned Span. + // + // Example usage: + // + // SomeFunction(ctx context.Context, ...) { + // ctx := log.Start(ctx, "SomeFunction") + // defer log.Finish(ctx) + // ... + // } + // Deprecated: Stop using go-log for event logging + Start(ctx context.Context, name string) context.Context + + // StartFromParentState starts an opentracing span with `name`, using + // any Span found within `ctx` as a ChildOfRef. If no such parent could be + // found, StartSpanFromParentState creates a root (parentless) Span. + // + // StartFromParentState will attempt to deserialize a SpanContext from `parent`, + // using any Span found within to continue the trace + // + // The return value is a context.Context object built around the + // returned Span. + // + // An error is returned when `parent` cannot be deserialized to a SpanContext + // + // Example usage: + // + // SomeFunction(ctx context.Context, bParent []byte) { + // ctx := log.StartFromParentState(ctx, "SomeFunction", bParent) + // defer log.Finish(ctx) + // ... + // } + // Deprecated: Stop using go-log for event logging + StartFromParentState(ctx context.Context, name string, parent []byte) (context.Context, error) + + // Finish completes the span associated with `ctx`. + // + // Finish() must be the last call made to any span instance, and to do + // otherwise leads to undefined behavior. + // Finish will do its best to notify (log) when used in correctly + // .e.g called twice, or called on a spanless `ctx` + // Deprecated: Stop using go-log for event logging + Finish(ctx context.Context) + + // FinishWithErr completes the span associated with `ctx` and also calls + // SetErr if `err` is non-nil + // + // FinishWithErr() must be the last call made to any span instance, and to do + // otherwise leads to undefined behavior. + // FinishWithErr will do its best to notify (log) when used in correctly + // .e.g called twice, or called on a spanless `ctx` + // Deprecated: Stop using go-log for event logging + FinishWithErr(ctx context.Context, err error) + + // SetErr tags the span associated with `ctx` to reflect an error occured, and + // logs the value `err` under key `error`. + // Deprecated: Stop using go-log for event logging + SetErr(ctx context.Context, err error) + + // LogKV records key:value logging data about an event stored in `ctx` + // Eexample: + // log.LogKV( + // "error", "resolve failure", + // "type", "cache timeout", + // "waited.millis", 1500) + // Deprecated: Stop using go-log for event logging + LogKV(ctx context.Context, alternatingKeyValues ...interface{}) + + // SetTag tags key `k` and value `v` on the span associated with `ctx` + // Deprecated: Stop using go-log for event logging + SetTag(ctx context.Context, key string, value interface{}) + + // SetTags tags keys from the `tags` maps on the span associated with `ctx` + // Example: + // log.SetTags(ctx, map[string]{ + // "type": bizStruct, + // "request": req, + // }) + // Deprecated: Stop using go-log for event logging + SetTags(ctx context.Context, tags map[string]interface{}) + + // SerializeContext takes the SpanContext instance stored in `ctx` and Seralizes + // it to bytes. An error is returned if the `ctx` cannot be serialized to + // a bytes array + // Deprecated: Stop using go-log for event logging + SerializeContext(ctx context.Context) ([]byte, error) +} + +var _ EventLogger = Logger("test-logger") + +// Logger retrieves an event logger by name +func Logger(system string) *ZapEventLogger { + if len(system) == 0 { + setuplog := Logger("setup-logger") + setuplog.Error("Missing name parameter") + system = "undefined" + } + logger := log2.Logger(system) + return &ZapEventLogger{system: system, SugaredLogger: logger.SugaredLogger} +} + +// ZapEventLogger implements the EventLogger and wraps a go-logging Logger +type ZapEventLogger struct { + zap.SugaredLogger + + system string + // TODO add log-level +} + +// Deprecated: use Warn +func (el *ZapEventLogger) Warning(args ...interface{}) { + el.Warn(args...) +} + +// Deprecated: use Warnf +func (el *ZapEventLogger) Warningf(format string, args ...interface{}) { + el.Warnf(format, args...) +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) Start(ctx context.Context, operationName string) context.Context { + span, ctx := opentrace.StartSpanFromContext(ctx, operationName) + span.SetTag("system", el.system) + return ctx +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) StartFromParentState(ctx context.Context, operationName string, parent []byte) (context.Context, error) { + sc, err := deserializeContext(parent) + if err != nil { + return nil, err + } + + //TODO RPCServerOption is probably not the best tag, as this is likely from a peer + span, ctx := opentrace.StartSpanFromContext(ctx, operationName, otExt.RPCServerOption(sc)) + span.SetTag("system", el.system) + return ctx, nil +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) SerializeContext(ctx context.Context) ([]byte, error) { + gTracer := opentrace.GlobalTracer() + b := make([]byte, 0) + carrier := bytes.NewBuffer(b) + span := opentrace.SpanFromContext(ctx) + if err := gTracer.Inject(span.Context(), opentrace.Binary, carrier); err != nil { + return nil, err + } + return carrier.Bytes(), nil +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) LogKV(ctx context.Context, alternatingKeyValues ...interface{}) { + span := opentrace.SpanFromContext(ctx) + if span == nil { + _, file, line, _ := runtime.Caller(1) + log.Errorf("LogKV with no Span in context called on %s:%d", path.Base(file), line) + return + } + span.LogKV(alternatingKeyValues...) +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) SetTag(ctx context.Context, k string, v interface{}) { + span := opentrace.SpanFromContext(ctx) + if span == nil { + _, file, line, _ := runtime.Caller(1) + log.Errorf("SetTag with no Span in context called on %s:%d", path.Base(file), line) + return + } + span.SetTag(k, v) +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) SetTags(ctx context.Context, tags map[string]interface{}) { + span := opentrace.SpanFromContext(ctx) + if span == nil { + _, file, line, _ := runtime.Caller(1) + log.Errorf("SetTags with no Span in context called on %s:%d", path.Base(file), line) + return + } + for k, v := range tags { + span.SetTag(k, v) + } +} + +func (el *ZapEventLogger) setErr(ctx context.Context, err error, skip int) { + span := opentrace.SpanFromContext(ctx) + if span == nil { + _, file, line, _ := runtime.Caller(skip) + log.Errorf("SetErr with no Span in context called on %s:%d", path.Base(file), line) + return + } + if err == nil { + return + } + + otExt.Error.Set(span, true) + span.LogKV("error", err.Error()) +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) SetErr(ctx context.Context, err error) { + el.setErr(ctx, err, 1) +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) Finish(ctx context.Context) { + span := opentrace.SpanFromContext(ctx) + if span == nil { + _, file, line, _ := runtime.Caller(1) + log.Errorf("Finish with no Span in context called on %s:%d", path.Base(file), line) + return + } + span.Finish() +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) FinishWithErr(ctx context.Context, err error) { + el.setErr(ctx, err, 2) + el.Finish(ctx) +} + +func deserializeContext(bCtx []byte) (opentrace.SpanContext, error) { + gTracer := opentrace.GlobalTracer() + carrier := bytes.NewReader(bCtx) + spanContext, err := gTracer.Extract(opentrace.Binary, carrier) + if err != nil { + log.Warning("Failed to deserialize context %s", err) + return nil, err + } + return spanContext, nil +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) EventBegin(ctx context.Context, event string, metadata ...Loggable) *EventInProgress { + ctx = el.Start(ctx, event) + + for _, m := range metadata { + for l, v := range m.Loggable() { + el.LogKV(ctx, l, v) + } + } + + eip := &EventInProgress{} + eip.doneFunc = func(additional []Loggable) { + // anything added during the operation + // e.g. deprecated methods event.Append(...) or event.SetError(...) + for _, m := range eip.loggables { + for l, v := range m.Loggable() { + el.LogKV(ctx, l, v) + } + } + el.Finish(ctx) + } + return eip +} + +// Deprecated: Stop using go-log for event logging +func (el *ZapEventLogger) Event(ctx context.Context, event string, metadata ...Loggable) { + + // short circuit if theres nothing to write to + if !writer.WriterGroup.Active() { + return + } + + // Collect loggables for later logging + var loggables []Loggable + + // get any existing metadata from the context + existing, err := MetadataFromContext(ctx) + if err != nil { + existing = Metadata{} + } + loggables = append(loggables, existing) + loggables = append(loggables, metadata...) + + e := entry{ + loggables: loggables, + system: el.system, + event: event, + } + + accum := Metadata{} + for _, loggable := range e.loggables { + accum = DeepMerge(accum, loggable.Loggable()) + } + + // apply final attributes to reserved keys + // TODO accum["level"] = level + accum["event"] = e.event + accum["system"] = e.system + accum["time"] = FormatRFC3339(time.Now()) + + var buf bytes.Buffer + encoder := json.NewEncoder(&buf) + encoder.SetEscapeHTML(false) + err = encoder.Encode(accum) + if err != nil { + el.Errorf("ERROR FORMATTING EVENT ENTRY: %s", err) + return + } + + _, _ = writer.WriterGroup.Write(buf.Bytes()) +} + +// DEPRECATED +// EventInProgress represent and event which is happening +// Deprecated: Stop using go-log for event logging +type EventInProgress struct { + loggables []Loggable + doneFunc func([]Loggable) +} + +// DEPRECATED use `LogKV` or `SetTag` +// Append adds loggables to be included in the call to Done +func (eip *EventInProgress) Append(l Loggable) { + eip.loggables = append(eip.loggables, l) +} + +// DEPRECATED use `SetError(ctx, error)` +// SetError includes the provided error +func (eip *EventInProgress) SetError(err error) { + eip.loggables = append(eip.loggables, LoggableMap{ + "error": err.Error(), + }) +} + +// Done creates a new Event entry that includes the duration and appended +// loggables. +// Deprecated: Stop using go-log for event logging +func (eip *EventInProgress) Done() { + eip.doneFunc(eip.loggables) // create final event with extra data +} + +// DEPRECATED use `FinishWithErr` +// DoneWithErr creates a new Event entry that includes the duration and appended +// loggables. DoneWithErr accepts an error, if err is non-nil, it is set on +// the EventInProgress. Otherwise the logic is the same as the `Done()` method +func (eip *EventInProgress) DoneWithErr(err error) { + if err != nil { + eip.SetError(err) + } + eip.doneFunc(eip.loggables) +} + +// Close is an alias for done +// Deprecated: Stop using go-log for event logging +func (eip *EventInProgress) Close() error { + eip.Done() + return nil +} + +// FormatRFC3339 returns the given time in UTC with RFC3999Nano format. +func FormatRFC3339(t time.Time) string { + return t.UTC().Format(time.RFC3339Nano) +} diff --git a/vendor/github.com/ipfs/go-log/loggable.go b/vendor/github.com/ipfs/go-log/loggable.go new file mode 100644 index 0000000000..f4edb26845 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/loggable.go @@ -0,0 +1,42 @@ +package log + +// Loggable describes objects that can be marshalled into Metadata for logging +type Loggable interface { + Loggable() map[string]interface{} +} + +// LoggableMap is just a generic map keyed by string. It +// implements the Loggable interface. +type LoggableMap map[string]interface{} + +// Loggable implements the Loggable interface for LoggableMap +func (l LoggableMap) Loggable() map[string]interface{} { + return l +} + +// LoggableF converts a func into a Loggable +type LoggableF func() map[string]interface{} + +// Loggable implements the Loggable interface by running +// the LoggableF function. +func (l LoggableF) Loggable() map[string]interface{} { + return l() +} + +// Deferred returns a LoggableF where the execution of the +// provided function is deferred. +func Deferred(key string, f func() string) Loggable { + function := func() map[string]interface{} { + return map[string]interface{}{ + key: f(), + } + } + return LoggableF(function) +} + +// Pair returns a Loggable where key is paired to Loggable. +func Pair(key string, l Loggable) Loggable { + return LoggableMap{ + key: l, + } +} diff --git a/vendor/github.com/ipfs/go-log/metadata.go b/vendor/github.com/ipfs/go-log/metadata.go new file mode 100644 index 0000000000..07947b54a0 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/metadata.go @@ -0,0 +1,77 @@ +package log + +import ( + "encoding/json" + "errors" + "reflect" +) + +// Metadata is a convenience type for generic maps +type Metadata map[string]interface{} + +// DeepMerge merges the second Metadata parameter into the first. +// Nested Metadata are merged recursively. Primitives are over-written. +func DeepMerge(b, a Metadata) Metadata { + out := Metadata{} + for k, v := range b { + out[k] = v + } + for k, v := range a { + + maybe, err := Metadatify(v) + if err != nil { + // if the new value is not meta. just overwrite the dest vaue + if out[k] != nil { + log.Debugf("Overwriting key: %s, old: %s, new: %s", k, out[k], v) + } + out[k] = v + continue + } + + // it is meta. What about dest? + outv, exists := out[k] + if !exists { + // the new value is meta, but there's no dest value. just write it + out[k] = v + continue + } + + outMetadataValue, err := Metadatify(outv) + if err != nil { + // the new value is meta and there's a dest value, but the dest + // value isn't meta. just overwrite + out[k] = v + continue + } + + // both are meta. merge them. + out[k] = DeepMerge(outMetadataValue, maybe) + } + return out +} + +// Loggable implements the Loggable interface. +func (m Metadata) Loggable() map[string]interface{} { + // NB: method defined on value to avoid de-referencing nil Metadata + return m +} + +// JsonString returns the marshaled JSON string for the metadata. +func (m Metadata) JsonString() (string, error) { + // NB: method defined on value + b, err := json.Marshal(m) + return string(b), err +} + +// Metadatify converts maps into Metadata. +func Metadatify(i interface{}) (Metadata, error) { + value := reflect.ValueOf(i) + if value.Kind() == reflect.Map { + m := map[string]interface{}{} + for _, k := range value.MapKeys() { + m[k.String()] = value.MapIndex(k).Interface() + } + return Metadata(m), nil + } + return nil, errors.New("is not a map") +} diff --git a/vendor/github.com/ipfs/go-log/oldlog.go b/vendor/github.com/ipfs/go-log/oldlog.go new file mode 100644 index 0000000000..f0ad558d0a --- /dev/null +++ b/vendor/github.com/ipfs/go-log/oldlog.go @@ -0,0 +1,68 @@ +package log + +import ( + tracer "github.com/ipfs/go-log/tracer" + lwriter "github.com/ipfs/go-log/writer" + "os" + + opentrace "github.com/opentracing/opentracing-go" + + log2 "github.com/ipfs/go-log/v2" +) + +func init() { + SetupLogging() +} + +// Logging environment variables +const ( + envTracingFile = "GOLOG_TRACING_FILE" // /path/to/file +) + +func SetupLogging() { + // We're importing V2. Given that we setup logging on init, we should be + // fine skipping the rest of the initialization. + + // TracerPlugins are instantiated after this, so use loggable tracer + // by default, if a TracerPlugin is added it will override this + lgblRecorder := tracer.NewLoggableRecorder() + lgblTracer := tracer.New(lgblRecorder) + opentrace.SetGlobalTracer(lgblTracer) + + if tracingfp := os.Getenv(envTracingFile); len(tracingfp) > 0 { + f, err := os.Create(tracingfp) + if err != nil { + log.Error("failed to create tracing file: %s", tracingfp) + } else { + lwriter.WriterGroup.AddWriter(f) + } + } +} + +// SetDebugLogging calls SetAllLoggers with logging.DEBUG +func SetDebugLogging() { + log2.SetDebugLogging() +} + +// SetAllLoggers changes the logging level of all loggers to lvl +func SetAllLoggers(lvl LogLevel) { + log2.SetAllLoggers(lvl) +} + +// SetLogLevel changes the log level of a specific subsystem +// name=="*" changes all subsystems +func SetLogLevel(name, level string) error { + return log2.SetLogLevel(name, level) +} + +// SetLogLevelRegex sets all loggers to level `l` that match expression `e`. +// An error is returned if `e` fails to compile. +func SetLogLevelRegex(e, l string) error { + return log2.SetLogLevelRegex(e, l) +} + +// GetSubsystems returns a slice containing the +// names of the current loggers +func GetSubsystems() []string { + return log2.GetSubsystems() +} diff --git a/vendor/github.com/ipfs/go-log/package.json b/vendor/github.com/ipfs/go-log/package.json new file mode 100644 index 0000000000..adcf8cd08e --- /dev/null +++ b/vendor/github.com/ipfs/go-log/package.json @@ -0,0 +1,41 @@ +{ + "bugs": { + "url": "https://github.com/ipfs/go-log" + }, + "gx": { + "dvcsimport": "github.com/ipfs/go-log" + }, + "gxDependencies": [ + { + "author": "whyrusleeping", + "hash": "QmcaSwFc5RBg8yCq54QURwEU4nwjfCpjbpmaAm4VbdGLKv", + "name": "go-logging", + "version": "0.0.0" + }, + { + "author": "frist", + "hash": "QmWLWmRVSiagqP15jczsGME1qpob6HDbtbHAY2he9W5iUo", + "name": "opentracing-go", + "version": "0.0.3" + }, + { + "author": "mattn", + "hash": "QmTsHcKgTQ4VeYZd8eKYpTXeLW7KNwkRD9wjnrwsV2sToq", + "name": "go-colorable", + "version": "0.2.0" + }, + { + "author": "whyrusleeping", + "hash": "QmddjPSGZb3ieihSseFeCfVRpZzcqczPNsD2DvarSwnjJB", + "name": "gogo-protobuf", + "version": "1.2.1" + } + ], + "gxVersion": "0.12.1", + "language": "go", + "license": "", + "name": "go-log", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "1.5.9" +} + diff --git a/vendor/github.com/ipfs/go-log/tracer/LICENSE b/vendor/github.com/ipfs/go-log/tracer/LICENSE new file mode 100644 index 0000000000..148509a403 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 The OpenTracing Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ipfs/go-log/tracer/context.go b/vendor/github.com/ipfs/go-log/tracer/context.go new file mode 100644 index 0000000000..f1ebf61f67 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/context.go @@ -0,0 +1,42 @@ +package loggabletracer + +// SpanContext holds the basic Span metadata. +type SpanContext struct { + // A probabilistically unique identifier for a [multi-span] trace. + TraceID uint64 + + // A probabilistically unique identifier for a span. + SpanID uint64 + + // Whether the trace is sampled. + Sampled bool + + // The span's associated baggage. + Baggage map[string]string // initialized on first use +} + +// ForeachBaggageItem belongs to the opentracing.SpanContext interface +func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool) { + for k, v := range c.Baggage { + if !handler(k, v) { + break + } + } +} + +// WithBaggageItem returns an entirely new loggabletracer SpanContext with the +// given key:value baggage pair set. +func (c SpanContext) WithBaggageItem(key, val string) SpanContext { + var newBaggage map[string]string + if c.Baggage == nil { + newBaggage = map[string]string{key: val} + } else { + newBaggage = make(map[string]string, len(c.Baggage)+1) + for k, v := range c.Baggage { + newBaggage[k] = v + } + newBaggage[key] = val + } + // Use positional parameters so the compiler will help catch new fields. + return SpanContext{c.TraceID, c.SpanID, c.Sampled, newBaggage} +} diff --git a/vendor/github.com/ipfs/go-log/tracer/debug.go b/vendor/github.com/ipfs/go-log/tracer/debug.go new file mode 100644 index 0000000000..8c302b3703 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/debug.go @@ -0,0 +1,78 @@ +package loggabletracer + +import ( + "bytes" + "fmt" + "runtime" + "strconv" + "sync" +) + +const debugGoroutineIDTag = "_initial_goroutine" + +type errAssertionFailed struct { + span *spanImpl + msg string +} + +// Error implements the error interface. +func (err *errAssertionFailed) Error() string { + return fmt.Sprintf("%s:\n%+v", err.msg, err.span) +} + +func (s *spanImpl) Lock() { + s.Mutex.Lock() + s.maybeAssertSanityLocked() +} + +func (s *spanImpl) maybeAssertSanityLocked() { + if s.tracer == nil { + s.Mutex.Unlock() + panic(&errAssertionFailed{span: s, msg: "span used after call to Finish()"}) + } + if s.tracer.options.DebugAssertSingleGoroutine { + startID := curGoroutineID() + curID, ok := s.raw.Tags[debugGoroutineIDTag].(uint64) + if !ok { + // This is likely invoked in the context of the SetTag which sets + // debugGoroutineTag. + return + } + if startID != curID { + s.Mutex.Unlock() + panic(&errAssertionFailed{ + span: s, + msg: fmt.Sprintf("span started on goroutine %d, but now running on %d", startID, curID), + }) + } + } +} + +var goroutineSpace = []byte("goroutine ") +var littleBuf = sync.Pool{ + New: func() interface{} { + buf := make([]byte, 64) + return &buf + }, +} + +// Credit to @bradfitz: +// https://github.com/golang/net/blob/master/http2/gotrack.go#L51 +func curGoroutineID() uint64 { + bp := littleBuf.Get().(*[]byte) + defer littleBuf.Put(bp) + b := *bp + b = b[:runtime.Stack(b, false)] + // Parse the 4707 out of "goroutine 4707 [" + b = bytes.TrimPrefix(b, goroutineSpace) + i := bytes.IndexByte(b, ' ') + if i < 0 { + panic(fmt.Sprintf("No space found in %q", b)) + } + b = b[:i] + n, err := strconv.ParseUint(string(b), 10, 64) + if err != nil { + panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err)) + } + return n +} diff --git a/vendor/github.com/ipfs/go-log/tracer/event.go b/vendor/github.com/ipfs/go-log/tracer/event.go new file mode 100644 index 0000000000..9dbcb76a69 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/event.go @@ -0,0 +1,62 @@ +package loggabletracer + +import "github.com/opentracing/opentracing-go" + +// A SpanEvent is emitted when a mutating command is called on a Span. +type SpanEvent interface{} + +// EventCreate is emitted when a Span is created. +type EventCreate struct{ OperationName string } + +// EventTag is received when SetTag is called. +type EventTag struct { + Key string + Value interface{} +} + +// EventBaggage is received when SetBaggageItem is called. +type EventBaggage struct { + Key, Value string +} + +// EventLogFields is received when LogFields or LogKV is called. +type EventLogFields opentracing.LogRecord + +// EventLog is received when Log (or one of its derivatives) is called. +// +// DEPRECATED +type EventLog opentracing.LogData + +// EventFinish is received when Finish is called. +type EventFinish RawSpan + +func (s *spanImpl) onCreate(opName string) { + if s.event != nil { + s.event(EventCreate{OperationName: opName}) + } +} +func (s *spanImpl) onTag(key string, value interface{}) { + if s.event != nil { + s.event(EventTag{Key: key, Value: value}) + } +} +func (s *spanImpl) onLog(ld opentracing.LogData) { + if s.event != nil { + s.event(EventLog(ld)) + } +} +func (s *spanImpl) onLogFields(lr opentracing.LogRecord) { + if s.event != nil { + s.event(EventLogFields(lr)) + } +} +func (s *spanImpl) onBaggage(key, value string) { + if s.event != nil { + s.event(EventBaggage{Key: key, Value: value}) + } +} +func (s *spanImpl) onFinish(sp RawSpan) { + if s.event != nil { + s.event(EventFinish(sp)) + } +} diff --git a/vendor/github.com/ipfs/go-log/tracer/propagation.go b/vendor/github.com/ipfs/go-log/tracer/propagation.go new file mode 100644 index 0000000000..bb2106597a --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/propagation.go @@ -0,0 +1,61 @@ +package loggabletracer + +import opentracing "github.com/opentracing/opentracing-go" + +type accessorPropagator struct { + tracer *LoggableTracer +} + +// DelegatingCarrier is a flexible carrier interface which can be implemented +// by types which have a means of storing the trace metadata and already know +// how to serialize themselves (for example, protocol buffers). +type DelegatingCarrier interface { + SetState(traceID, spanID uint64, sampled bool) + State() (traceID, spanID uint64, sampled bool) + SetBaggageItem(key, value string) + GetBaggage(func(key, value string)) +} + +func (p *accessorPropagator) Inject( + spanContext opentracing.SpanContext, + carrier interface{}, +) error { + dc, ok := carrier.(DelegatingCarrier) + if !ok || dc == nil { + return opentracing.ErrInvalidCarrier + } + sc, ok := spanContext.(SpanContext) + if !ok { + return opentracing.ErrInvalidSpanContext + } + dc.SetState(sc.TraceID, sc.SpanID, sc.Sampled) + for k, v := range sc.Baggage { + dc.SetBaggageItem(k, v) + } + return nil +} + +func (p *accessorPropagator) Extract( + carrier interface{}, +) (opentracing.SpanContext, error) { + dc, ok := carrier.(DelegatingCarrier) + if !ok || dc == nil { + return nil, opentracing.ErrInvalidCarrier + } + + traceID, spanID, sampled := dc.State() + sc := SpanContext{ + TraceID: traceID, + SpanID: spanID, + Sampled: sampled, + Baggage: nil, + } + dc.GetBaggage(func(k, v string) { + if sc.Baggage == nil { + sc.Baggage = map[string]string{} + } + sc.Baggage[k] = v + }) + + return sc, nil +} diff --git a/vendor/github.com/ipfs/go-log/tracer/propagation_ot.go b/vendor/github.com/ipfs/go-log/tracer/propagation_ot.go new file mode 100644 index 0000000000..28cf526cf8 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/propagation_ot.go @@ -0,0 +1,178 @@ +package loggabletracer + +import ( + "encoding/binary" + "io" + "strconv" + "strings" + + "github.com/gogo/protobuf/proto" + "github.com/ipfs/go-log/tracer/wire" + opentracing "github.com/opentracing/opentracing-go" +) + +type textMapPropagator struct { +} +type binaryPropagator struct { +} + +const ( + prefixTracerState = "ot-tracer-" + prefixBaggage = "ot-baggage-" + + tracerStateFieldCount = 3 + fieldNameTraceID = prefixTracerState + "traceid" + fieldNameSpanID = prefixTracerState + "spanid" + fieldNameSampled = prefixTracerState + "sampled" +) + +func (p *textMapPropagator) Inject( + spanContext opentracing.SpanContext, + opaqueCarrier interface{}, +) error { + sc, ok := spanContext.(SpanContext) + if !ok { + return opentracing.ErrInvalidSpanContext + } + carrier, ok := opaqueCarrier.(opentracing.TextMapWriter) + if !ok { + return opentracing.ErrInvalidCarrier + } + carrier.Set(fieldNameTraceID, strconv.FormatUint(sc.TraceID, 16)) + carrier.Set(fieldNameSpanID, strconv.FormatUint(sc.SpanID, 16)) + carrier.Set(fieldNameSampled, strconv.FormatBool(sc.Sampled)) + + for k, v := range sc.Baggage { + carrier.Set(prefixBaggage+k, v) + } + return nil +} + +func (p *textMapPropagator) Extract( + opaqueCarrier interface{}, +) (opentracing.SpanContext, error) { + carrier, ok := opaqueCarrier.(opentracing.TextMapReader) + if !ok { + return nil, opentracing.ErrInvalidCarrier + } + requiredFieldCount := 0 + var traceID, spanID uint64 + var sampled bool + var err error + decodedBaggage := make(map[string]string) + err = carrier.ForeachKey(func(k, v string) error { + switch strings.ToLower(k) { + case fieldNameTraceID: + traceID, err = strconv.ParseUint(v, 16, 64) + if err != nil { + return opentracing.ErrSpanContextCorrupted + } + case fieldNameSpanID: + spanID, err = strconv.ParseUint(v, 16, 64) + if err != nil { + return opentracing.ErrSpanContextCorrupted + } + case fieldNameSampled: + sampled, err = strconv.ParseBool(v) + if err != nil { + return opentracing.ErrSpanContextCorrupted + } + default: + lowercaseK := strings.ToLower(k) + if strings.HasPrefix(lowercaseK, prefixBaggage) { + decodedBaggage[strings.TrimPrefix(lowercaseK, prefixBaggage)] = v + } + // Balance off the requiredFieldCount++ just below... + requiredFieldCount-- + } + requiredFieldCount++ + return nil + }) + if err != nil { + return nil, err + } + if requiredFieldCount < tracerStateFieldCount { + if requiredFieldCount == 0 { + return nil, opentracing.ErrSpanContextNotFound + } + return nil, opentracing.ErrSpanContextCorrupted + } + + return SpanContext{ + TraceID: traceID, + SpanID: spanID, + Sampled: sampled, + Baggage: decodedBaggage, + }, nil +} + +func (p *binaryPropagator) Inject( + spanContext opentracing.SpanContext, + opaqueCarrier interface{}, +) error { + sc, ok := spanContext.(SpanContext) + if !ok { + return opentracing.ErrInvalidSpanContext + } + carrier, ok := opaqueCarrier.(io.Writer) + if !ok { + return opentracing.ErrInvalidCarrier + } + + state := wire.TracerState{} + state.TraceId = sc.TraceID + state.SpanId = sc.SpanID + state.Sampled = sc.Sampled + state.BaggageItems = sc.Baggage + + b, err := proto.Marshal(&state) + if err != nil { + return err + } + + // Write the length of the marshalled binary to the writer. + length := uint32(len(b)) + if err := binary.Write(carrier, binary.BigEndian, &length); err != nil { + return err + } + + _, err = carrier.Write(b) + return err +} + +func (p *binaryPropagator) Extract( + opaqueCarrier interface{}, +) (opentracing.SpanContext, error) { + carrier, ok := opaqueCarrier.(io.Reader) + if !ok { + return nil, opentracing.ErrInvalidCarrier + } + + // Read the length of marshalled binary. io.ReadAll isn't that performant + // since it keeps resizing the underlying buffer as it encounters more bytes + // to read. By reading the length, we can allocate a fixed sized buf and read + // the exact amount of bytes into it. + var length uint32 + if err := binary.Read(carrier, binary.BigEndian, &length); err != nil { + return nil, opentracing.ErrSpanContextCorrupted + } + buf := make([]byte, length) + if n, err := carrier.Read(buf); err != nil { + if n > 0 { + return nil, opentracing.ErrSpanContextCorrupted + } + return nil, opentracing.ErrSpanContextNotFound + } + + ctx := wire.TracerState{} + if err := proto.Unmarshal(buf, &ctx); err != nil { + return nil, opentracing.ErrSpanContextCorrupted + } + + return SpanContext{ + TraceID: ctx.TraceId, + SpanID: ctx.SpanId, + Sampled: ctx.Sampled, + Baggage: ctx.BaggageItems, + }, nil +} diff --git a/vendor/github.com/ipfs/go-log/tracer/raw.go b/vendor/github.com/ipfs/go-log/tracer/raw.go new file mode 100644 index 0000000000..759454274a --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/raw.go @@ -0,0 +1,34 @@ +package loggabletracer + +import ( + "time" + + opentracing "github.com/opentracing/opentracing-go" +) + +// RawSpan encapsulates all state associated with a (finished) Span. +type RawSpan struct { + // Those recording the RawSpan should also record the contents of its + // SpanContext. + Context SpanContext + + // The SpanID of this SpanContext's first intra-trace reference (i.e., + // "parent"), or 0 if there is no parent. + ParentSpanID uint64 + + // The name of the "operation" this span is an instance of. (Called a "span + // name" in some implementations) + Operation string + + // We store rather than so that only + // one of the timestamps has global clock uncertainty issues. + Start time.Time + Duration time.Duration + + // Essentially an extension mechanism. Can be used for many purposes, + // not to be enumerated here. + Tags opentracing.Tags + + // The span's "microlog". + Logs []opentracing.LogRecord +} diff --git a/vendor/github.com/ipfs/go-log/tracer/recorder.go b/vendor/github.com/ipfs/go-log/tracer/recorder.go new file mode 100644 index 0000000000..dbe055a18a --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/recorder.go @@ -0,0 +1,103 @@ +package loggabletracer + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "time" + + writer "github.com/ipfs/go-log/writer" + opentrace "github.com/opentracing/opentracing-go" +) + +// A SpanRecorder handles all of the `RawSpan` data generated via an +// associated `Tracer` (see `NewStandardTracer`) instance. It also names +// the containing process and provides access to a straightforward tag map. +type SpanRecorder interface { + // Implementations must determine whether and where to store `span`. + RecordSpan(span RawSpan) +} + +type LoggableSpanRecorder struct{} + +// NewLoggableRecorder creates new LoggableSpanRecorder +func NewLoggableRecorder() *LoggableSpanRecorder { + return new(LoggableSpanRecorder) +} + +// Loggable Representation of a span, treated as an event log +type LoggableSpan struct { + TraceID uint64 `json:"TraceID"` + SpanID uint64 `json:"SpanID"` + ParentSpanID uint64 `json:"ParentSpanID"` + Operation string `json:"Operation"` + Start time.Time `json:"Start"` + Duration time.Duration `json:"Duration"` + Tags opentrace.Tags `json:"Tags"` + Logs []SpanLog `json:"Logs"` +} + +type SpanLog struct { + Timestamp time.Time `json:"Timestamp"` + Field []SpanField `json:"Fields"` +} + +type SpanField struct { + Key string `json:"Key"` + Value string `json:"Value"` +} + +// RecordSpan implements the respective method of SpanRecorder. +func (r *LoggableSpanRecorder) RecordSpan(span RawSpan) { + // short circuit if theres nothing to write to + if !writer.WriterGroup.Active() { + return + } + + sl := make([]SpanLog, len(span.Logs)) + for i := range span.Logs { + sl[i].Timestamp = span.Logs[i].Timestamp + sf := make([]SpanField, len(span.Logs[i].Fields)) + sl[i].Field = sf + for j := range span.Logs[i].Fields { + sf[j].Key = span.Logs[i].Fields[j].Key() + sf[j].Value = fmt.Sprint(span.Logs[i].Fields[j].Value()) + } + } + + tags := make(map[string]interface{}, len(span.Tags)) + for k, v := range span.Tags { + switch vt := v.(type) { + case bool, string, int, int8, int16, int32, int64, uint, uint8, uint16, uint64: + tags[k] = v + case []byte: + base64.StdEncoding.EncodeToString(vt) + default: + tags[k] = fmt.Sprint(v) + } + } + + spanlog := &LoggableSpan{ + TraceID: span.Context.TraceID, + SpanID: span.Context.SpanID, + ParentSpanID: span.ParentSpanID, + Operation: span.Operation, + Start: span.Start, + Duration: span.Duration, + Tags: tags, + Logs: sl, + } + + var buf bytes.Buffer + encoder := json.NewEncoder(&buf) + encoder.SetEscapeHTML(false) + err := encoder.Encode(spanlog) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR FORMATTING SPAN ENTRY: %s\n", err) + return + } + + _, _ = writer.WriterGroup.Write(buf.Bytes()) +} diff --git a/vendor/github.com/ipfs/go-log/tracer/span.go b/vendor/github.com/ipfs/go-log/tracer/span.go new file mode 100644 index 0000000000..a23a57c32b --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/span.go @@ -0,0 +1,274 @@ +package loggabletracer + +import ( + "sync" + "time" + + opentracing "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/opentracing/opentracing-go/log" +) + +// Span provides access to the essential details of the span, for use +// by loggabletracer consumers. These methods may only be called prior +// to (*opentracing.Span).Finish(). +type Span interface { + opentracing.Span + + // Operation names the work done by this span instance + Operation() string + + // Start indicates when the span began + Start() time.Time +} + +// Implements the `Span` interface. Created via LoggableTracer (see +// `loggabletracer.New()`). +type spanImpl struct { + tracer *LoggableTracer + event func(SpanEvent) + sync.Mutex // protects the fields below + raw RawSpan + // The number of logs dropped because of MaxLogsPerSpan. + numDroppedLogs int +} + +var spanPool = &sync.Pool{New: func() interface{} { + return &spanImpl{} +}} + +func (s *spanImpl) reset() { + s.tracer, s.event = nil, nil + // Note: Would like to do the following, but then the consumer of RawSpan + // (the recorder) needs to make sure that they're not holding on to the + // baggage or logs when they return (i.e. they need to copy if they care): + // + // logs, baggage := s.raw.Logs[:0], s.raw.Baggage + // for k := range baggage { + // delete(baggage, k) + // } + // s.raw.Logs, s.raw.Baggage = logs, baggage + // + // That's likely too much to ask for. But there is some magic we should + // be able to do with `runtime.SetFinalizer` to reclaim that memory into + // a buffer pool when GC considers them unreachable, which should ease + // some of the load. Hard to say how quickly that would be in practice + // though. + s.raw = RawSpan{ + Context: SpanContext{}, + } +} + +func (s *spanImpl) SetOperationName(operationName string) opentracing.Span { + s.Lock() + defer s.Unlock() + s.raw.Operation = operationName + return s +} + +func (s *spanImpl) trim() bool { + return !s.raw.Context.Sampled && s.tracer.options.TrimUnsampledSpans +} + +func (s *spanImpl) SetTag(key string, value interface{}) opentracing.Span { + defer s.onTag(key, value) + s.Lock() + defer s.Unlock() + if key == string(ext.SamplingPriority) { + if v, ok := value.(uint16); ok { + s.raw.Context.Sampled = v != 0 + return s + } + } + if s.trim() { + return s + } + + if s.raw.Tags == nil { + s.raw.Tags = opentracing.Tags{} + } + s.raw.Tags[key] = value + return s +} + +func (s *spanImpl) LogKV(keyValues ...interface{}) { + fields, err := log.InterleavedKVToFields(keyValues...) + if err != nil { + s.LogFields(log.Error(err), log.String("function", "LogKV")) + return + } + s.LogFields(fields...) +} + +func (s *spanImpl) appendLog(lr opentracing.LogRecord) { + maxLogs := s.tracer.options.MaxLogsPerSpan + if maxLogs == 0 || len(s.raw.Logs) < maxLogs { + s.raw.Logs = append(s.raw.Logs, lr) + return + } + + // We have too many logs. We don't touch the first numOld logs; we treat the + // rest as a circular buffer and overwrite the oldest log among those. + numOld := (maxLogs - 1) / 2 + numNew := maxLogs - numOld + s.raw.Logs[numOld+s.numDroppedLogs%numNew] = lr + s.numDroppedLogs++ +} + +func (s *spanImpl) LogFields(fields ...log.Field) { + lr := opentracing.LogRecord{ + Fields: fields, + } + defer s.onLogFields(lr) + s.Lock() + defer s.Unlock() + if s.trim() || s.tracer.options.DropAllLogs { + return + } + if lr.Timestamp.IsZero() { + lr.Timestamp = time.Now() + } + s.appendLog(lr) +} + +func (s *spanImpl) LogEvent(event string) { + s.Log(opentracing.LogData{ + Event: event, + }) +} + +func (s *spanImpl) LogEventWithPayload(event string, payload interface{}) { + s.Log(opentracing.LogData{ + Event: event, + Payload: payload, + }) +} + +func (s *spanImpl) Log(ld opentracing.LogData) { + defer s.onLog(ld) + s.Lock() + defer s.Unlock() + if s.trim() || s.tracer.options.DropAllLogs { + return + } + + if ld.Timestamp.IsZero() { + ld.Timestamp = time.Now() + } + + s.appendLog(ld.ToLogRecord()) +} + +func (s *spanImpl) Finish() { + s.FinishWithOptions(opentracing.FinishOptions{}) +} + +// rotateLogBuffer rotates the records in the buffer: records 0 to pos-1 move at +// the end (i.e. pos circular left shifts). +func rotateLogBuffer(buf []opentracing.LogRecord, pos int) { + // This algorithm is described in: + // http://www.cplusplus.com/reference/algorithm/rotate + for first, middle, next := 0, pos, pos; first != middle; { + buf[first], buf[next] = buf[next], buf[first] + first++ + next++ + if next == len(buf) { + next = middle + } else if first == middle { + middle = next + } + } +} + +func (s *spanImpl) FinishWithOptions(opts opentracing.FinishOptions) { + finishTime := opts.FinishTime + if finishTime.IsZero() { + finishTime = time.Now() + } + duration := finishTime.Sub(s.raw.Start) + + s.Lock() + defer s.Unlock() + + for _, lr := range opts.LogRecords { + s.appendLog(lr) + } + for _, ld := range opts.BulkLogData { + s.appendLog(ld.ToLogRecord()) + } + + if s.numDroppedLogs > 0 { + // We dropped some log events, which means that we used part of Logs as a + // circular buffer (see appendLog). De-circularize it. + numOld := (len(s.raw.Logs) - 1) / 2 + numNew := len(s.raw.Logs) - numOld + rotateLogBuffer(s.raw.Logs[numOld:], s.numDroppedLogs%numNew) + + // Replace the log in the middle (the oldest "new" log) with information + // about the dropped logs. This means that we are effectively dropping one + // more "new" log. + numDropped := s.numDroppedLogs + 1 + s.raw.Logs[numOld] = opentracing.LogRecord{ + // Keep the timestamp of the last dropped event. + Timestamp: s.raw.Logs[numOld].Timestamp, + Fields: []log.Field{ + log.String("event", "dropped Span logs"), + log.Int("dropped_log_count", numDropped), + log.String("component", "loggabletracer"), + }, + } + } + + s.raw.Duration = duration + + s.onFinish(s.raw) + s.tracer.options.Recorder.RecordSpan(s.raw) + + // Last chance to get options before the span is possibly reset. + poolEnabled := s.tracer.options.EnableSpanPool + if s.tracer.options.DebugAssertUseAfterFinish { + // This makes it much more likely to catch a panic on any subsequent + // operation since s.tracer is accessed on every call to `Lock`. + // We don't call `reset()` here to preserve the logs in the Span + // which are printed when the assertion triggers. + s.tracer = nil + } + + if poolEnabled { + spanPool.Put(s) + } +} + +func (s *spanImpl) Tracer() opentracing.Tracer { + return s.tracer +} + +func (s *spanImpl) Context() opentracing.SpanContext { + return s.raw.Context +} + +func (s *spanImpl) SetBaggageItem(key, val string) opentracing.Span { + s.onBaggage(key, val) + if s.trim() { + return s + } + + s.Lock() + defer s.Unlock() + s.raw.Context = s.raw.Context.WithBaggageItem(key, val) + return s +} + +func (s *spanImpl) BaggageItem(key string) string { + s.Lock() + defer s.Unlock() + return s.raw.Context.Baggage[key] +} + +func (s *spanImpl) Operation() string { + return s.raw.Operation +} + +func (s *spanImpl) Start() time.Time { + return s.raw.Start +} diff --git a/vendor/github.com/ipfs/go-log/tracer/tracer.go b/vendor/github.com/ipfs/go-log/tracer/tracer.go new file mode 100644 index 0000000000..a6ea3a22ed --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/tracer.go @@ -0,0 +1,280 @@ +package loggabletracer + +import ( + "time" + + writer "github.com/ipfs/go-log/writer" + opentracing "github.com/opentracing/opentracing-go" +) + +// Tracer extends the opentracing.Tracer interface with methods to +// probe implementation state, for use by loggabletracer consumers. +type Tracer interface { + opentracing.Tracer + + // Options gets the Options used in New() or NewWithOptions(). + Options() Options +} + +// Options allows creating a customized Tracer via NewWithOptions. The object +// must not be updated when there is an active tracer using it. +type Options struct { + // ShouldSample is a function which is called when creating a new Span and + // determines whether that Span is sampled. The randomized TraceID is supplied + // to allow deterministic sampling decisions to be made across different nodes. + // For example, + // + // func(traceID uint64) { return traceID % 64 == 0 } + // + // samples every 64th trace on average. + ShouldSample func(traceID uint64) bool + // TrimUnsampledSpans turns potentially expensive operations on unsampled + // Spans into no-ops. More precisely, tags and log events are silently + // discarded. If NewSpanEventListener is set, the callbacks will still fire. + TrimUnsampledSpans bool + // Recorder receives Spans which have been finished. + Recorder SpanRecorder + // NewSpanEventListener can be used to enhance the tracer by effectively + // attaching external code to trace events. See NetTraceIntegrator for a + // practical example, and event.go for the list of possible events. + NewSpanEventListener func() func(SpanEvent) + // DropAllLogs turns log events on all Spans into no-ops. + // If NewSpanEventListener is set, the callbacks will still fire. + DropAllLogs bool + // MaxLogsPerSpan limits the number of Logs in a span (if set to a nonzero + // value). If a span has more logs than this value, logs are dropped as + // necessary (and replaced with a log describing how many were dropped). + // + // About half of the MaxLogPerSpan logs kept are the oldest logs, and about + // half are the newest logs. + // + // If NewSpanEventListener is set, the callbacks will still fire for all log + // events. This value is ignored if DropAllLogs is true. + MaxLogsPerSpan int + // DebugAssertSingleGoroutine internally records the ID of the goroutine + // creating each Span and verifies that no operation is carried out on + // it on a different goroutine. + // Provided strictly for development purposes. + // Passing Spans between goroutine without proper synchronization often + // results in use-after-Finish() errors. For a simple example, consider the + // following pseudocode: + // + // func (s *Server) Handle(req http.Request) error { + // sp := s.StartSpan("server") + // defer sp.Finish() + // wait := s.queueProcessing(opentracing.ContextWithSpan(context.Background(), sp), req) + // select { + // case resp := <-wait: + // return resp.Error + // case <-time.After(10*time.Second): + // sp.LogEvent("timed out waiting for processing") + // return ErrTimedOut + // } + // } + // + // This looks reasonable at first, but a request which spends more than ten + // seconds in the queue is abandoned by the main goroutine and its trace + // finished, leading to use-after-finish when the request is finally + // processed. Note also that even joining on to a finished Span via + // StartSpanWithOptions constitutes an illegal operation. + // + // Code bases which do not require (or decide they do not want) Spans to + // be passed across goroutine boundaries can run with this flag enabled in + // tests to increase their chances of spotting wrong-doers. + DebugAssertSingleGoroutine bool + // DebugAssertUseAfterFinish is provided strictly for development purposes. + // When set, it attempts to exacerbate issues emanating from use of Spans + // after calling Finish by running additional assertions. + DebugAssertUseAfterFinish bool + // EnableSpanPool enables the use of a pool, so that the tracer reuses spans + // after Finish has been called on it. Adds a slight performance gain as it + // reduces allocations. However, if you have any use-after-finish race + // conditions the code may panic. + EnableSpanPool bool +} + +// DefaultOptions returns an Options object with a 1 in 64 sampling rate and +// all options disabled. A Recorder needs to be set manually before using the +// returned object with a Tracer. +func DefaultOptions() Options { + return Options{ + ShouldSample: func(traceID uint64) bool { return traceID%64 == 0 }, + MaxLogsPerSpan: 100, + } +} + +// NewWithOptions creates a customized Tracer. +func NewWithOptions(opts Options) opentracing.Tracer { + rval := &LoggableTracer{options: opts} + rval.accessorPropagator = &accessorPropagator{rval} + return rval +} + +// New creates and returns a standard Tracer which defers completed Spans to +// `recorder`. +// Spans created by this Tracer support the ext.SamplingPriority tag: Setting +// ext.SamplingPriority causes the Span to be Sampled from that point on. +func New(recorder SpanRecorder) opentracing.Tracer { + opts := DefaultOptions() + opts.Recorder = recorder + return NewWithOptions(opts) +} + +// Implements the `Tracer` interface. +type LoggableTracer struct { + options Options + textPropagator *textMapPropagator + binaryPropagator *binaryPropagator + accessorPropagator *accessorPropagator +} + +func (t *LoggableTracer) StartSpan( + operationName string, + opts ...opentracing.StartSpanOption, +) opentracing.Span { + + if !writer.WriterGroup.Active() { + return opentracing.NoopTracer.StartSpan(opentracing.NoopTracer{}, operationName) + } + + sso := opentracing.StartSpanOptions{} + for _, o := range opts { + o.Apply(&sso) + } + return t.StartSpanWithOptions(operationName, sso) +} + +func (t *LoggableTracer) getSpan() *spanImpl { + if t.options.EnableSpanPool { + sp := spanPool.Get().(*spanImpl) + sp.reset() + return sp + } + return &spanImpl{} +} + +func (t *LoggableTracer) StartSpanWithOptions( + operationName string, + opts opentracing.StartSpanOptions, +) opentracing.Span { + if !writer.WriterGroup.Active() { + return opentracing.NoopTracer.StartSpan(opentracing.NoopTracer{}, operationName) + } + // Start time. + startTime := opts.StartTime + if startTime.IsZero() { + startTime = time.Now() + } + + // Tags. + tags := opts.Tags + + // Build the new span. This is the only allocation: We'll return this as + // an opentracing.Span. + sp := t.getSpan() + // Look for a parent in the list of References. + // + // TODO: would be nice if loggabletracer did something with all + // References, not just the first one. +ReferencesLoop: + for _, ref := range opts.References { + switch ref.Type { + case opentracing.ChildOfRef, + opentracing.FollowsFromRef: + + refCtx, ok := ref.ReferencedContext.(SpanContext) + if !ok { + // Could be a noopSpanContext + // Ignore that parent. + continue + } + sp.raw.Context.TraceID = refCtx.TraceID + sp.raw.Context.SpanID = randomID() + sp.raw.Context.Sampled = refCtx.Sampled + sp.raw.ParentSpanID = refCtx.SpanID + + if l := len(refCtx.Baggage); l > 0 { + sp.raw.Context.Baggage = make(map[string]string, l) + for k, v := range refCtx.Baggage { + sp.raw.Context.Baggage[k] = v + } + } + break ReferencesLoop + } + } + if sp.raw.Context.TraceID == 0 { + // No parent Span found; allocate new trace and span ids and determine + // the Sampled status. + sp.raw.Context.TraceID, sp.raw.Context.SpanID = randomID2() + sp.raw.Context.Sampled = t.options.ShouldSample(sp.raw.Context.TraceID) + } + + return t.startSpanInternal( + sp, + operationName, + startTime, + tags, + ) +} + +func (t *LoggableTracer) startSpanInternal( + sp *spanImpl, + operationName string, + startTime time.Time, + tags opentracing.Tags, +) opentracing.Span { + sp.tracer = t + if t.options.NewSpanEventListener != nil { + sp.event = t.options.NewSpanEventListener() + } + sp.raw.Operation = operationName + sp.raw.Start = startTime + sp.raw.Duration = -1 + sp.raw.Tags = tags + if t.options.DebugAssertSingleGoroutine { + sp.SetTag(debugGoroutineIDTag, curGoroutineID()) + } + defer sp.onCreate(operationName) + return sp +} + +type delegatorType struct{} + +// Delegator is the format to use for DelegatingCarrier. +var Delegator delegatorType + +func (t *LoggableTracer) Inject(sc opentracing.SpanContext, format interface{}, carrier interface{}) error { + if !writer.WriterGroup.Active() { + return opentracing.NoopTracer.Inject(opentracing.NoopTracer{}, sc, format, carrier) + } + switch format { + case opentracing.TextMap, opentracing.HTTPHeaders: + return t.textPropagator.Inject(sc, carrier) + case opentracing.Binary: + return t.binaryPropagator.Inject(sc, carrier) + } + if _, ok := format.(delegatorType); ok { + return t.accessorPropagator.Inject(sc, carrier) + } + return opentracing.ErrUnsupportedFormat +} + +func (t *LoggableTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) { + if !writer.WriterGroup.Active() { + return opentracing.NoopTracer.Extract(opentracing.NoopTracer{}, format, carrier) + } + switch format { + case opentracing.TextMap, opentracing.HTTPHeaders: + return t.textPropagator.Extract(carrier) + case opentracing.Binary: + return t.binaryPropagator.Extract(carrier) + } + if _, ok := format.(delegatorType); ok { + return t.accessorPropagator.Extract(carrier) + } + return nil, opentracing.ErrUnsupportedFormat +} + +func (t *LoggableTracer) Options() Options { + return t.options +} diff --git a/vendor/github.com/ipfs/go-log/tracer/util.go b/vendor/github.com/ipfs/go-log/tracer/util.go new file mode 100644 index 0000000000..279e2acaad --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/util.go @@ -0,0 +1,25 @@ +package loggabletracer + +import ( + "math/rand" + "sync" + "time" +) + +var ( + seededIDGen = rand.New(rand.NewSource(time.Now().UnixNano())) + // The golang rand generators are *not* intrinsically thread-safe. + seededIDLock sync.Mutex +) + +func randomID() uint64 { + seededIDLock.Lock() + defer seededIDLock.Unlock() + return uint64(seededIDGen.Int63()) +} + +func randomID2() (uint64, uint64) { + seededIDLock.Lock() + defer seededIDLock.Unlock() + return uint64(seededIDGen.Int63()), uint64(seededIDGen.Int63()) +} diff --git a/vendor/github.com/ipfs/go-log/tracer/wire/Makefile b/vendor/github.com/ipfs/go-log/tracer/wire/Makefile new file mode 100644 index 0000000000..8677a37114 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/wire/Makefile @@ -0,0 +1,6 @@ +pbgos := $(patsubst %.proto,%.pb.go,$(wildcard *.proto)) + +all: $(pbgos) + +%.pb.go: %.proto + protoc --gogofaster_out=. --proto_path=$(GOPATH)/src:. $< diff --git a/vendor/github.com/ipfs/go-log/tracer/wire/carrier.go b/vendor/github.com/ipfs/go-log/tracer/wire/carrier.go new file mode 100644 index 0000000000..12ec98e906 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/wire/carrier.go @@ -0,0 +1,40 @@ +package wire + +// ProtobufCarrier is a DelegatingCarrier that uses protocol buffers as the +// the underlying datastructure. The reason for implementing DelagatingCarrier +// is to allow for end users to serialize the underlying protocol buffers using +// jsonpb or any other serialization forms they want. +type ProtobufCarrier TracerState + +// SetState set's the tracer state. +func (p *ProtobufCarrier) SetState(traceID, spanID uint64, sampled bool) { + p.TraceId = traceID + p.SpanId = spanID + p.Sampled = sampled +} + +// State returns the tracer state. +func (p *ProtobufCarrier) State() (traceID, spanID uint64, sampled bool) { + traceID = p.TraceId + spanID = p.SpanId + sampled = p.Sampled + return traceID, spanID, sampled +} + +// SetBaggageItem sets a baggage item. +func (p *ProtobufCarrier) SetBaggageItem(key, value string) { + if p.BaggageItems == nil { + p.BaggageItems = map[string]string{key: value} + return + } + + p.BaggageItems[key] = value +} + +// GetBaggage iterates over each baggage item and executes the callback with +// the key:value pair. +func (p *ProtobufCarrier) GetBaggage(f func(k, v string)) { + for k, v := range p.BaggageItems { + f(k, v) + } +} diff --git a/vendor/github.com/ipfs/go-log/tracer/wire/gen.go b/vendor/github.com/ipfs/go-log/tracer/wire/gen.go new file mode 100644 index 0000000000..7d951fa43f --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/wire/gen.go @@ -0,0 +1,6 @@ +package wire + +//go:generate protoc --gogofaster_out=$GOPATH/src/github.com/ipfs/go-log/tracer/wire wire.proto + +// Run `go get github.com/gogo/protobuf/protoc-gen-gogofaster` to install the +// gogofaster generator binary. diff --git a/vendor/github.com/ipfs/go-log/tracer/wire/wire.pb.go b/vendor/github.com/ipfs/go-log/tracer/wire/wire.pb.go new file mode 100644 index 0000000000..0bbf3f1b60 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/wire/wire.pb.go @@ -0,0 +1,531 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wire.proto + +package wire + +import ( + encoding_binary "encoding/binary" + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type TracerState struct { + TraceId uint64 `protobuf:"fixed64,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"` + SpanId uint64 `protobuf:"fixed64,2,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"` + Sampled bool `protobuf:"varint,3,opt,name=sampled,proto3" json:"sampled,omitempty"` + BaggageItems map[string]string `protobuf:"bytes,4,rep,name=baggage_items,json=baggageItems,proto3" json:"baggage_items,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (m *TracerState) Reset() { *m = TracerState{} } +func (m *TracerState) String() string { return proto.CompactTextString(m) } +func (*TracerState) ProtoMessage() {} +func (*TracerState) Descriptor() ([]byte, []int) { + return fileDescriptor_f2dcdddcdf68d8e0, []int{0} +} +func (m *TracerState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TracerState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TracerState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TracerState) XXX_Merge(src proto.Message) { + xxx_messageInfo_TracerState.Merge(m, src) +} +func (m *TracerState) XXX_Size() int { + return m.Size() +} +func (m *TracerState) XXX_DiscardUnknown() { + xxx_messageInfo_TracerState.DiscardUnknown(m) +} + +var xxx_messageInfo_TracerState proto.InternalMessageInfo + +func (m *TracerState) GetTraceId() uint64 { + if m != nil { + return m.TraceId + } + return 0 +} + +func (m *TracerState) GetSpanId() uint64 { + if m != nil { + return m.SpanId + } + return 0 +} + +func (m *TracerState) GetSampled() bool { + if m != nil { + return m.Sampled + } + return false +} + +func (m *TracerState) GetBaggageItems() map[string]string { + if m != nil { + return m.BaggageItems + } + return nil +} + +func init() { + proto.RegisterType((*TracerState)(nil), "loggabletracer.wire.TracerState") + proto.RegisterMapType((map[string]string)(nil), "loggabletracer.wire.TracerState.BaggageItemsEntry") +} + +func init() { proto.RegisterFile("wire.proto", fileDescriptor_f2dcdddcdf68d8e0) } + +var fileDescriptor_f2dcdddcdf68d8e0 = []byte{ + // 250 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0xcf, 0x2c, 0x4a, + 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xce, 0xc9, 0x4f, 0x4f, 0x4f, 0x4c, 0xca, 0x49, + 0x2d, 0x29, 0x4a, 0x4c, 0x4e, 0x2d, 0xd2, 0x03, 0x49, 0x29, 0x7d, 0x65, 0xe4, 0xe2, 0x0e, 0x01, + 0xf3, 0x83, 0x4b, 0x12, 0x4b, 0x52, 0x85, 0x24, 0xb9, 0x38, 0xc0, 0xd2, 0xf1, 0x99, 0x29, 0x12, + 0x8c, 0x0a, 0x8c, 0x1a, 0x6c, 0x41, 0xec, 0x60, 0xbe, 0x67, 0x8a, 0x90, 0x38, 0x17, 0x7b, 0x71, + 0x41, 0x62, 0x1e, 0x48, 0x86, 0x09, 0x2c, 0xc3, 0x06, 0xe2, 0x7a, 0xa6, 0x08, 0x49, 0x70, 0xb1, + 0x17, 0x27, 0xe6, 0x16, 0xe4, 0xa4, 0xa6, 0x48, 0x30, 0x2b, 0x30, 0x6a, 0x70, 0x04, 0xc1, 0xb8, + 0x42, 0xe1, 0x5c, 0xbc, 0x49, 0x89, 0xe9, 0xe9, 0x89, 0xe9, 0xa9, 0xf1, 0x99, 0x25, 0xa9, 0xb9, + 0xc5, 0x12, 0x2c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x46, 0x7a, 0x58, 0x9c, 0xa2, 0x87, 0xe4, 0x0c, + 0x3d, 0x27, 0x88, 0x2e, 0x4f, 0x90, 0x26, 0xd7, 0xbc, 0x92, 0xa2, 0xca, 0x20, 0x9e, 0x24, 0x24, + 0x21, 0x29, 0x7b, 0x2e, 0x41, 0x0c, 0x25, 0x42, 0x02, 0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x60, 0x67, + 0x73, 0x06, 0x81, 0x98, 0x42, 0x22, 0x5c, 0xac, 0x65, 0x89, 0x39, 0xa5, 0xa9, 0x60, 0x07, 0x73, + 0x06, 0x41, 0x38, 0x56, 0x4c, 0x16, 0x8c, 0x4e, 0x72, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, + 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, + 0x2c, 0xc7, 0x10, 0xc5, 0x02, 0x72, 0x4c, 0x12, 0x1b, 0x38, 0xcc, 0x8c, 0x01, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xe4, 0x48, 0xf4, 0xf8, 0x41, 0x01, 0x00, 0x00, +} + +func (m *TracerState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TracerState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TracerState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BaggageItems) > 0 { + for k := range m.BaggageItems { + v := m.BaggageItems[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintWire(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintWire(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintWire(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x22 + } + } + if m.Sampled { + i-- + if m.Sampled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.SpanId != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.SpanId)) + i-- + dAtA[i] = 0x11 + } + if m.TraceId != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.TraceId)) + i-- + dAtA[i] = 0x9 + } + return len(dAtA) - i, nil +} + +func encodeVarintWire(dAtA []byte, offset int, v uint64) int { + offset -= sovWire(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *TracerState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TraceId != 0 { + n += 9 + } + if m.SpanId != 0 { + n += 9 + } + if m.Sampled { + n += 2 + } + if len(m.BaggageItems) > 0 { + for k, v := range m.BaggageItems { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovWire(uint64(len(k))) + 1 + len(v) + sovWire(uint64(len(v))) + n += mapEntrySize + 1 + sovWire(uint64(mapEntrySize)) + } + } + return n +} + +func sovWire(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozWire(x uint64) (n int) { + return sovWire(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *TracerState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWire + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TracerState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TracerState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) + } + m.TraceId = 0 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + m.TraceId = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + case 2: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) + } + m.SpanId = 0 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + m.SpanId = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sampled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWire + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Sampled = bool(v != 0) + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaggageItems", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWire + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthWire + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthWire + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BaggageItems == nil { + m.BaggageItems = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWire + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWire + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthWire + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthWire + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWire + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthWire + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthWire + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipWire(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthWire + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.BaggageItems[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipWire(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthWire + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthWire + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipWire(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowWire + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowWire + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowWire + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthWire + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupWire + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthWire + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthWire = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowWire = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupWire = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/github.com/ipfs/go-log/tracer/wire/wire.proto b/vendor/github.com/ipfs/go-log/tracer/wire/wire.proto new file mode 100644 index 0000000000..496fa19817 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/tracer/wire/wire.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package loggabletracer.wire; +option go_package = "wire"; + +message TracerState { + fixed64 trace_id = 1; + fixed64 span_id = 2; + bool sampled = 3; + map baggage_items = 4; +} diff --git a/vendor/github.com/ipfs/go-log/v2/LICENSE b/vendor/github.com/ipfs/go-log/v2/LICENSE new file mode 100644 index 0000000000..c7386b3c94 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipfs/go-log/v2/README.md b/vendor/github.com/ipfs/go-log/v2/README.md new file mode 100644 index 0000000000..eb98f57770 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/README.md @@ -0,0 +1,66 @@ +# go-log + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/ipfs/go-log?status.svg)](https://godoc.org/github.com/ipfs/go-log) +[![Build Status](https://travis-ci.org/ipfs/go-log.svg?branch=master)](https://travis-ci.org/ipfs/go-log) + + + + +> The logging library used by go-ipfs + +go-log wraps [zap](https://github.com/uber-go/zap) to provide a logging facade. go-log manages logging +instances and allows for their levels to be controlled individually. + +## Install + +```sh +go get github.com/ipfs/go-log +``` + +## Usage + +Once the package is imported under the name `logging`, an instance of `EventLogger` can be created like so: + +```go +var log = logging.Logger("subsystem name") +``` + +It can then be used to emit log messages in plain printf-style messages at seven standard levels: + +Levels may be set for all loggers: + +```go +lvl, err := logging.LevelFromString("error") + if err != nil { + panic(err) + } +logging.SetAllLoggers(lvl) +``` + +or individually: + +```go +lvl, err := logging.LevelFromString("error") + if err != nil { + panic(err) + } +logging.SetLogLevel("foo", "info") +``` + +## Contribute + +Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-log/issues)! + +This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +### Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) + +## License + +MIT diff --git a/vendor/github.com/ipfs/go-log/v2/core.go b/vendor/github.com/ipfs/go-log/v2/core.go new file mode 100644 index 0000000000..87e7d9c262 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/core.go @@ -0,0 +1,120 @@ +package log + +import ( + "sync" + + "go.uber.org/multierr" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var _ zapcore.Core = (*lockedMultiCore)(nil) + +type lockedMultiCore struct { + mu sync.RWMutex // guards mutations to cores slice + cores []zapcore.Core +} + +func (l *lockedMultiCore) With(fields []zapcore.Field) zapcore.Core { + l.mu.RLock() + defer l.mu.RUnlock() + sub := &lockedMultiCore{ + cores: make([]zapcore.Core, len(l.cores)), + } + for i := range l.cores { + sub.cores[i] = l.cores[i].With(fields) + } + return sub +} + +func (l *lockedMultiCore) Enabled(lvl zapcore.Level) bool { + l.mu.RLock() + defer l.mu.RUnlock() + for i := range l.cores { + if l.cores[i].Enabled(lvl) { + return true + } + } + return false +} + +func (l *lockedMultiCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { + l.mu.RLock() + defer l.mu.RUnlock() + for i := range l.cores { + ce = l.cores[i].Check(ent, ce) + } + return ce +} + +func (l *lockedMultiCore) Write(ent zapcore.Entry, fields []zapcore.Field) error { + l.mu.RLock() + defer l.mu.RUnlock() + var err error + for i := range l.cores { + err = multierr.Append(err, l.cores[i].Write(ent, fields)) + } + return err +} + +func (l *lockedMultiCore) Sync() error { + l.mu.RLock() + defer l.mu.RUnlock() + var err error + for i := range l.cores { + err = multierr.Append(err, l.cores[i].Sync()) + } + return err +} + +func (l *lockedMultiCore) AddCore(core zapcore.Core) { + l.mu.Lock() + defer l.mu.Unlock() + + l.cores = append(l.cores, core) +} + +func (l *lockedMultiCore) DeleteCore(core zapcore.Core) { + l.mu.Lock() + defer l.mu.Unlock() + + w := 0 + for i := 0; i < len(l.cores); i++ { + if l.cores[i] == core { + continue + } + l.cores[w] = l.cores[i] + w++ + } + l.cores = l.cores[:w] +} + +func (l *lockedMultiCore) ReplaceCore(original, replacement zapcore.Core) { + l.mu.Lock() + defer l.mu.Unlock() + + for i := 0; i < len(l.cores); i++ { + if l.cores[i] == original { + l.cores[i] = replacement + } + } +} + +func newCore(format LogFormat, ws zapcore.WriteSyncer, level LogLevel) zapcore.Core { + encCfg := zap.NewProductionEncoderConfig() + encCfg.EncodeTime = zapcore.ISO8601TimeEncoder + + var encoder zapcore.Encoder + switch format { + case PlaintextOutput: + encCfg.EncodeLevel = zapcore.CapitalLevelEncoder + encoder = zapcore.NewConsoleEncoder(encCfg) + case JSONOutput: + encoder = zapcore.NewJSONEncoder(encCfg) + default: + encCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder + encoder = zapcore.NewConsoleEncoder(encCfg) + } + + return zapcore.NewCore(encoder, ws, zap.NewAtomicLevelAt(zapcore.Level(level))) +} diff --git a/vendor/github.com/ipfs/go-log/v2/go.mod b/vendor/github.com/ipfs/go-log/v2/go.mod new file mode 100644 index 0000000000..9688c5b574 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/go.mod @@ -0,0 +1,8 @@ +module github.com/ipfs/go-log/v2 + +require ( + go.uber.org/multierr v1.5.0 + go.uber.org/zap v1.14.1 +) + +go 1.12 diff --git a/vendor/github.com/ipfs/go-log/v2/go.sum b/vendor/github.com/ipfs/go-log/v2/go.sum new file mode 100644 index 0000000000..f07a2f686b --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/go.sum @@ -0,0 +1,60 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/ipfs/go-log/v2/levels.go b/vendor/github.com/ipfs/go-log/v2/levels.go new file mode 100644 index 0000000000..9d43a597a1 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/levels.go @@ -0,0 +1,30 @@ +package log + +import "go.uber.org/zap/zapcore" + +// LogLevel represents a log severity level. Use the package variables as an +// enum. +type LogLevel zapcore.Level + +var ( + LevelDebug = LogLevel(zapcore.DebugLevel) + LevelInfo = LogLevel(zapcore.InfoLevel) + LevelWarn = LogLevel(zapcore.WarnLevel) + LevelError = LogLevel(zapcore.ErrorLevel) + LevelDPanic = LogLevel(zapcore.DPanicLevel) + LevelPanic = LogLevel(zapcore.PanicLevel) + LevelFatal = LogLevel(zapcore.FatalLevel) +) + +// LevelFromString parses a string-based level and returns the corresponding +// LogLevel. +// +// Supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and +// their lower-case forms. +// +// The returned LogLevel must be discarded if error is not nil. +func LevelFromString(level string) (LogLevel, error) { + lvl := zapcore.InfoLevel // zero value + err := lvl.Set(level) + return LogLevel(lvl), err +} diff --git a/vendor/github.com/ipfs/go-log/v2/log.go b/vendor/github.com/ipfs/go-log/v2/log.go new file mode 100644 index 0000000000..784e9e5e4d --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/log.go @@ -0,0 +1,75 @@ +// Package log is the logging library used by IPFS & libp2p +// (https://github.com/ipfs/go-ipfs). +package log + +import ( + "time" + + "go.uber.org/zap" +) + +// StandardLogger provides API compatibility with standard printf loggers +// eg. go-logging +type StandardLogger interface { + Debug(args ...interface{}) + Debugf(format string, args ...interface{}) + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Info(args ...interface{}) + Infof(format string, args ...interface{}) + Panic(args ...interface{}) + Panicf(format string, args ...interface{}) + Warn(args ...interface{}) + Warnf(format string, args ...interface{}) +} + +// EventLogger extends the StandardLogger interface to allow for log items +// containing structured metadata +type EventLogger interface { + StandardLogger +} + +// Logger retrieves an event logger by name +func Logger(system string) *ZapEventLogger { + if len(system) == 0 { + setuplog := getLogger("setup-logger") + setuplog.Error("Missing name parameter") + system = "undefined" + } + + logger := getLogger(system) + skipLogger := logger.Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar() + + return &ZapEventLogger{ + system: system, + SugaredLogger: *logger, + skipLogger: *skipLogger, + } +} + +// ZapEventLogger implements the EventLogger and wraps a go-logging Logger +type ZapEventLogger struct { + zap.SugaredLogger + // used to fix the caller location when calling Warning and Warningf. + skipLogger zap.SugaredLogger + system string +} + +// Warning is for compatibility +// Deprecated: use Warn(args ...interface{}) instead +func (logger *ZapEventLogger) Warning(args ...interface{}) { + logger.skipLogger.Warn(args...) +} + +// Warningf is for compatibility +// Deprecated: use Warnf(format string, args ...interface{}) instead +func (logger *ZapEventLogger) Warningf(format string, args ...interface{}) { + logger.skipLogger.Warnf(format, args...) +} + +// FormatRFC3339 returns the given time in UTC with RFC3999Nano format. +func FormatRFC3339(t time.Time) string { + return t.UTC().Format(time.RFC3339Nano) +} diff --git a/vendor/github.com/ipfs/go-log/v2/package.json b/vendor/github.com/ipfs/go-log/v2/package.json new file mode 100644 index 0000000000..adcf8cd08e --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/package.json @@ -0,0 +1,41 @@ +{ + "bugs": { + "url": "https://github.com/ipfs/go-log" + }, + "gx": { + "dvcsimport": "github.com/ipfs/go-log" + }, + "gxDependencies": [ + { + "author": "whyrusleeping", + "hash": "QmcaSwFc5RBg8yCq54QURwEU4nwjfCpjbpmaAm4VbdGLKv", + "name": "go-logging", + "version": "0.0.0" + }, + { + "author": "frist", + "hash": "QmWLWmRVSiagqP15jczsGME1qpob6HDbtbHAY2he9W5iUo", + "name": "opentracing-go", + "version": "0.0.3" + }, + { + "author": "mattn", + "hash": "QmTsHcKgTQ4VeYZd8eKYpTXeLW7KNwkRD9wjnrwsV2sToq", + "name": "go-colorable", + "version": "0.2.0" + }, + { + "author": "whyrusleeping", + "hash": "QmddjPSGZb3ieihSseFeCfVRpZzcqczPNsD2DvarSwnjJB", + "name": "gogo-protobuf", + "version": "1.2.1" + } + ], + "gxVersion": "0.12.1", + "language": "go", + "license": "", + "name": "go-log", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "1.5.9" +} + diff --git a/vendor/github.com/ipfs/go-log/v2/path_other.go b/vendor/github.com/ipfs/go-log/v2/path_other.go new file mode 100644 index 0000000000..94d339878e --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/path_other.go @@ -0,0 +1,11 @@ +//+build !windows + +package log + +import ( + "path/filepath" +) + +func normalizePath(p string) (string, error) { + return filepath.Abs(p) +} diff --git a/vendor/github.com/ipfs/go-log/v2/path_windows.go b/vendor/github.com/ipfs/go-log/v2/path_windows.go new file mode 100644 index 0000000000..08bb1f2886 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/path_windows.go @@ -0,0 +1,35 @@ +//+build windows + +package log + +import ( + "fmt" + "path/filepath" + "strings" +) + +func normalizePath(p string) (string, error) { + if p == "" { + return "", fmt.Errorf("path empty") + } + p, err := filepath.Abs(p) + if err != nil { + return "", err + } + // Is this _really_ an absolute path? + if !strings.HasPrefix(p, "\\\\") { + // It's a drive: path! + // Return a UNC path. + p = "\\\\%3F\\" + p + } + + // This will return file:////?/c:/foobar + // + // Why? Because: + // 1. Go will choke on file://c:/ because the "domain" includes a :. + // 2. Windows will choke on file:///c:/ because the path will be + // /c:/... which is _relative_ to the current drive. + // + // This path (a) has no "domain" and (b) starts with a slash. Yay! + return "file://" + filepath.ToSlash(p), nil +} diff --git a/vendor/github.com/ipfs/go-log/v2/pipe.go b/vendor/github.com/ipfs/go-log/v2/pipe.go new file mode 100644 index 0000000000..7435b9dc72 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/pipe.go @@ -0,0 +1,90 @@ +package log + +import ( + "io" + + "go.uber.org/multierr" + "go.uber.org/zap/zapcore" +) + +// A PipeReader is a reader that reads from the logger. It is synchronous +// so blocking on read will affect logging performance. +type PipeReader struct { + r *io.PipeReader + closer io.Closer + core zapcore.Core +} + +// Read implements the standard Read interface +func (p *PipeReader) Read(data []byte) (int, error) { + return p.r.Read(data) +} + +// Close unregisters the reader from the logger. +func (p *PipeReader) Close() error { + if p.core != nil { + loggerCore.DeleteCore(p.core) + } + return multierr.Append(p.core.Sync(), p.closer.Close()) +} + +// NewPipeReader creates a new in-memory reader that reads from all loggers +// The caller must call Close on the returned reader when done. +// +// By default, it: +// +// 1. Logs JSON. This can be changed by passing the PipeFormat option. +// 2. Logs everything that would otherwise be logged to the "primary" log +// output. That is, everything enabled by SetLogLevel. The minimum log level +// can be increased by passing the PipeLevel option. +func NewPipeReader(opts ...PipeReaderOption) *PipeReader { + opt := pipeReaderOptions{ + format: JSONOutput, + level: LevelDebug, + } + + for _, o := range opts { + o.setOption(&opt) + } + + r, w := io.Pipe() + + p := &PipeReader{ + r: r, + closer: w, + core: newCore(opt.format, zapcore.AddSync(w), opt.level), + } + + loggerCore.AddCore(p.core) + + return p +} + +type pipeReaderOptions struct { + format LogFormat + level LogLevel +} + +type PipeReaderOption interface { + setOption(*pipeReaderOptions) +} + +type pipeReaderOptionFunc func(*pipeReaderOptions) + +func (p pipeReaderOptionFunc) setOption(o *pipeReaderOptions) { + p(o) +} + +// PipeFormat sets the output format of the pipe reader +func PipeFormat(format LogFormat) PipeReaderOption { + return pipeReaderOptionFunc(func(o *pipeReaderOptions) { + o.format = format + }) +} + +// PipeLevel sets the log level of logs sent to the pipe reader. +func PipeLevel(level LogLevel) PipeReaderOption { + return pipeReaderOptionFunc(func(o *pipeReaderOptions) { + o.level = level + }) +} diff --git a/vendor/github.com/ipfs/go-log/v2/setup.go b/vendor/github.com/ipfs/go-log/v2/setup.go new file mode 100644 index 0000000000..79ff0adbe3 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/v2/setup.go @@ -0,0 +1,267 @@ +package log + +import ( + "errors" + "fmt" + "os" + "regexp" + "sync" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func init() { + SetupLogging(configFromEnv()) +} + +// Logging environment variables +const ( + // IPFS_* prefixed env vars kept for backwards compatibility + // for this release. They will not be available in the next + // release. + // + // GOLOG_* env vars take precedences over IPFS_* env vars. + envIPFSLogging = "IPFS_LOGGING" + envIPFSLoggingFmt = "IPFS_LOGGING_FMT" + + envLogging = "GOLOG_LOG_LEVEL" + envLoggingFmt = "GOLOG_LOG_FMT" + + envLoggingFile = "GOLOG_FILE" // /path/to/file +) + +type LogFormat int + +const ( + ColorizedOutput LogFormat = iota + PlaintextOutput + JSONOutput +) + +type Config struct { + // Format overrides the format of the log output. Defaults to ColorizedOutput + Format LogFormat + + // Level is the minimum enabled logging level. + Level LogLevel + + // Stderr indicates whether logs should be written to stderr. + Stderr bool + + // Stdout indicates whether logs should be written to stdout. + Stdout bool + + // File is a path to a file that logs will be written to. + File string +} + +// ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger +var ErrNoSuchLogger = errors.New("Error: No such logger") + +var loggerMutex sync.RWMutex // guards access to global logger state + +// loggers is the set of loggers in the system +var loggers = make(map[string]*zap.SugaredLogger) +var levels = make(map[string]zap.AtomicLevel) + +// primaryFormat is the format of the primary core used for logging +var primaryFormat LogFormat = ColorizedOutput + +// defaultLevel is the default log level +var defaultLevel LogLevel = LevelError + +// primaryCore is the primary logging core +var primaryCore zapcore.Core + +// loggerCore is the base for all loggers created by this package +var loggerCore = &lockedMultiCore{} + +// SetupLogging will initialize the logger backend and set the flags. +// TODO calling this in `init` pushes all configuration to env variables +// - move it out of `init`? then we need to change all the code (js-ipfs, go-ipfs) to call this explicitly +// - have it look for a config file? need to define what that is +func SetupLogging(cfg Config) { + loggerMutex.Lock() + defer loggerMutex.Unlock() + + primaryFormat = cfg.Format + defaultLevel = cfg.Level + + outputPaths := []string{} + + if cfg.Stderr { + outputPaths = append(outputPaths, "stderr") + } + if cfg.Stdout { + outputPaths = append(outputPaths, "stdout") + } + + // check if we log to a file + if len(cfg.File) > 0 { + if path, err := normalizePath(cfg.File); err != nil { + fmt.Fprintf(os.Stderr, "failed to resolve log path '%q', logging to %s\n", cfg.File, outputPaths) + } else { + outputPaths = append(outputPaths, path) + } + } + + ws, _, err := zap.Open(outputPaths...) + if err != nil { + panic(fmt.Sprintf("unable to open logging output: %v", err)) + } + + newPrimaryCore := newCore(primaryFormat, ws, LevelDebug) // the main core needs to log everything. + if primaryCore != nil { + loggerCore.ReplaceCore(primaryCore, newPrimaryCore) + } else { + loggerCore.AddCore(newPrimaryCore) + } + primaryCore = newPrimaryCore + + setAllLoggers(defaultLevel) +} + +// SetDebugLogging calls SetAllLoggers with logging.DEBUG +func SetDebugLogging() { + SetAllLoggers(LevelDebug) +} + +// SetAllLoggers changes the logging level of all loggers to lvl +func SetAllLoggers(lvl LogLevel) { + loggerMutex.RLock() + defer loggerMutex.RUnlock() + + setAllLoggers(lvl) +} + +func setAllLoggers(lvl LogLevel) { + for _, l := range levels { + l.SetLevel(zapcore.Level(lvl)) + } +} + +// SetLogLevel changes the log level of a specific subsystem +// name=="*" changes all subsystems +func SetLogLevel(name, level string) error { + lvl, err := LevelFromString(level) + if err != nil { + return err + } + + // wildcard, change all + if name == "*" { + SetAllLoggers(lvl) + return nil + } + + loggerMutex.RLock() + defer loggerMutex.RUnlock() + + // Check if we have a logger by that name + if _, ok := levels[name]; !ok { + return ErrNoSuchLogger + } + + levels[name].SetLevel(zapcore.Level(lvl)) + + return nil +} + +// SetLogLevelRegex sets all loggers to level `l` that match expression `e`. +// An error is returned if `e` fails to compile. +func SetLogLevelRegex(e, l string) error { + lvl, err := LevelFromString(l) + if err != nil { + return err + } + + rem, err := regexp.Compile(e) + if err != nil { + return err + } + + loggerMutex.Lock() + defer loggerMutex.Unlock() + for name := range loggers { + if rem.MatchString(name) { + levels[name].SetLevel(zapcore.Level(lvl)) + } + } + return nil +} + +// GetSubsystems returns a slice containing the +// names of the current loggers +func GetSubsystems() []string { + loggerMutex.RLock() + defer loggerMutex.RUnlock() + subs := make([]string, 0, len(loggers)) + + for k := range loggers { + subs = append(subs, k) + } + return subs +} + +func getLogger(name string) *zap.SugaredLogger { + loggerMutex.Lock() + defer loggerMutex.Unlock() + log, ok := loggers[name] + if !ok { + levels[name] = zap.NewAtomicLevelAt(zapcore.Level(defaultLevel)) + log = zap.New(loggerCore). + WithOptions( + zap.IncreaseLevel(levels[name]), + zap.AddCaller(), + ). + Named(name). + Sugar() + + loggers[name] = log + } + + return log +} + +// configFromEnv returns a Config with defaults populated using environment variables. +func configFromEnv() Config { + cfg := Config{ + Format: ColorizedOutput, + Stderr: true, + Level: LevelError, + } + + format := os.Getenv(envLoggingFmt) + if format == "" { + format = os.Getenv(envIPFSLoggingFmt) + } + + switch format { + case "nocolor": + cfg.Format = PlaintextOutput + case "json": + cfg.Format = JSONOutput + } + + lvl := os.Getenv(envLogging) + if lvl == "" { + lvl = os.Getenv(envIPFSLogging) + } + if lvl != "" { + var err error + cfg.Level, err = LevelFromString(lvl) + if err != nil { + fmt.Fprintf(os.Stderr, "error setting log levels: %s\n", err) + } + } + + cfg.File = os.Getenv(envLoggingFile) + // Disable stderr logging when a file is specified + // https://github.com/ipfs/go-log/issues/83 + if cfg.File != "" { + cfg.Stderr = false + } + + return cfg +} diff --git a/vendor/github.com/ipfs/go-log/writer/option.go b/vendor/github.com/ipfs/go-log/writer/option.go new file mode 100644 index 0000000000..b65d3a0baa --- /dev/null +++ b/vendor/github.com/ipfs/go-log/writer/option.go @@ -0,0 +1,4 @@ +package log + +// WriterGroup is the global writer group for logs to output to +var WriterGroup = NewMirrorWriter() diff --git a/vendor/github.com/ipfs/go-log/writer/writer.go b/vendor/github.com/ipfs/go-log/writer/writer.go new file mode 100644 index 0000000000..c2e4f452d7 --- /dev/null +++ b/vendor/github.com/ipfs/go-log/writer/writer.go @@ -0,0 +1,251 @@ +package log + +import ( + "fmt" + "io" + "sync" + "sync/atomic" +) + +// MaxWriterBuffer specifies how big the writer buffer can get before +// killing the writer. +var MaxWriterBuffer = 512 * 1024 + +// MirrorWriter implements a WriteCloser which syncs incoming bytes to multiple +// [buffered] WriteClosers. They can be added with AddWriter(). +type MirrorWriter struct { + active uint32 + + // channel for incoming writers + writerAdd chan *writerAdd + + // slices of writer/sync-channel pairs + writers []*bufWriter + + // synchronization channel for incoming writes + msgSync chan []byte +} + +// NewMirrorWriter initializes and returns a MirrorWriter. +func NewMirrorWriter() *MirrorWriter { + mw := &MirrorWriter{ + msgSync: make(chan []byte, 64), // sufficiently large buffer to avoid callers waiting + writerAdd: make(chan *writerAdd), + } + + go mw.logRoutine() + + return mw +} + +// Write broadcasts the written bytes to all Writers. +func (mw *MirrorWriter) Write(b []byte) (int, error) { + mycopy := make([]byte, len(b)) + copy(mycopy, b) + mw.msgSync <- mycopy + return len(b), nil +} + +// Close closes the MirrorWriter +func (mw *MirrorWriter) Close() error { + // it is up to the caller to ensure that write is not called during or + // after close is called. + close(mw.msgSync) + return nil +} + +func (mw *MirrorWriter) doClose() { + for _, w := range mw.writers { + w.writer.Close() + } +} + +func (mw *MirrorWriter) logRoutine() { + // rebind to avoid races on nilling out struct fields + msgSync := mw.msgSync + writerAdd := mw.writerAdd + + defer mw.doClose() + + for { + select { + case b, ok := <-msgSync: + if !ok { + return + } + + // write to all writers + dropped := mw.broadcastMessage(b) + + // consolidate the slice + if dropped { + mw.clearDeadWriters() + } + case wa := <-writerAdd: + mw.writers = append(mw.writers, newBufWriter(wa.w)) + + atomic.StoreUint32(&mw.active, 1) + close(wa.done) + } + } +} + +// broadcastMessage sends the given message to every writer +// if any writer is killed during the send, 'true' is returned +func (mw *MirrorWriter) broadcastMessage(b []byte) bool { + var dropped bool + for i, w := range mw.writers { + _, err := w.Write(b) + if err != nil { + mw.writers[i] = nil + dropped = true + } + } + return dropped +} + +func (mw *MirrorWriter) clearDeadWriters() { + writers := mw.writers + mw.writers = nil + for _, w := range writers { + if w != nil { + mw.writers = append(mw.writers, w) + } + } + if len(mw.writers) == 0 { + atomic.StoreUint32(&mw.active, 0) + } +} + +type writerAdd struct { + w io.WriteCloser + done chan struct{} +} + +// AddWriter attaches a new WriteCloser to this MirrorWriter. +// The new writer will start getting any bytes written to the mirror. +func (mw *MirrorWriter) AddWriter(w io.WriteCloser) { + wa := &writerAdd{ + w: w, + done: make(chan struct{}), + } + mw.writerAdd <- wa + <-wa.done +} + +// Active returns if there is at least one Writer +// attached to this MirrorWriter +func (mw *MirrorWriter) Active() (active bool) { + return atomic.LoadUint32(&mw.active) == 1 +} + +func newBufWriter(w io.WriteCloser) *bufWriter { + bw := &bufWriter{ + writer: w, + incoming: make(chan []byte, 1), + } + + go bw.loop() + return bw +} + +// writes incoming messages to a buffer and when it fills +// up, writes them to the writer +type bufWriter struct { + writer io.WriteCloser + + incoming chan []byte + + deathLock sync.Mutex + dead bool +} + +var errDeadWriter = fmt.Errorf("writer is dead") + +func (bw *bufWriter) Write(b []byte) (int, error) { + bw.deathLock.Lock() + dead := bw.dead + bw.deathLock.Unlock() + if dead { + if bw.incoming != nil { + close(bw.incoming) + bw.incoming = nil + } + return 0, errDeadWriter + } + + bw.incoming <- b + return len(b), nil +} + +func (bw *bufWriter) die() { + bw.deathLock.Lock() + bw.dead = true + bw.writer.Close() + bw.deathLock.Unlock() +} + +func (bw *bufWriter) loop() { + bufsize := 0 + bufBase := make([][]byte, 0, 16) // some initial memory + buffered := bufBase + nextCh := make(chan []byte) + + var nextMsg []byte + + go func() { + for b := range nextCh { + _, err := bw.writer.Write(b) + if err != nil { + // TODO: need a way to notify there was an error here + // wouldn't want to log here as it could casue an infinite loop + bw.die() + return + } + } + }() + + // collect and buffer messages + incoming := bw.incoming + for { + if nextMsg == nil || nextCh == nil { + // nextCh == nil implies we are 'dead' and draining the incoming channel + // until the caller notices and closes it for us + b, ok := <-incoming + if !ok { + return + } + nextMsg = b + } + + select { + case b, ok := <-incoming: + if !ok { + return + } + bufsize += len(b) + buffered = append(buffered, b) + if bufsize > MaxWriterBuffer { + // if we have too many messages buffered, kill the writer + bw.die() + if nextCh != nil { + close(nextCh) + } + nextCh = nil + // explicity keep going here to drain incoming + } + case nextCh <- nextMsg: + nextMsg = nil + if len(buffered) > 0 { + nextMsg = buffered[0] + buffered = buffered[1:] + bufsize -= len(nextMsg) + } + + if len(buffered) == 0 { + // reset slice position + buffered = bufBase[:0] + } + } + } +} diff --git a/vendor/github.com/ipfs/go-metrics-interface/.gitignore b/vendor/github.com/ipfs/go-metrics-interface/.gitignore new file mode 100644 index 0000000000..daf913b1b3 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/ipfs/go-metrics-interface/.travis.yml b/vendor/github.com/ipfs/go-metrics-interface/.travis.yml new file mode 100644 index 0000000000..4cfe98c242 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-metrics-interface/LICENSE b/vendor/github.com/ipfs/go-metrics-interface/LICENSE new file mode 100644 index 0000000000..ff68748396 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 IPFS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ipfs/go-metrics-interface/context.go b/vendor/github.com/ipfs/go-metrics-interface/context.go new file mode 100644 index 0000000000..8796b8b988 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/context.go @@ -0,0 +1,26 @@ +package metrics + +import "context" + +const CtxScopeKey = "ipfs.metrics.scope" + +func CtxGetScope(ctx context.Context) string { + s := ctx.Value(CtxScopeKey) + if s == nil { + return "" + } + str, ok := s.(string) + if !ok { + return "" + } + return str +} + +func CtxScope(ctx context.Context, scope string) context.Context { + return context.WithValue(ctx, CtxScopeKey, scope) +} + +func CtxSubScope(ctx context.Context, subscope string) context.Context { + curscope := CtxGetScope(ctx) + return CtxScope(ctx, curscope+"."+subscope) +} diff --git a/vendor/github.com/ipfs/go-metrics-interface/ctor.go b/vendor/github.com/ipfs/go-metrics-interface/ctor.go new file mode 100644 index 0000000000..aac694e5f8 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/ctor.go @@ -0,0 +1,43 @@ +package metrics + +import ( + "context" + "errors" +) + +var ErrImplemented = errors.New("there is implemenation already injected") + +var ctorImpl InternalNew = nil + +// name is dot spearated path +// must be uniqe, use system naming, and unit postfix, examples: +// ipfs.blockstore.bloomcache.bloom.miss.total +// ipfs.routing.dht.notresuingstream.total +// +// both arguemnts are obligatory +func New(name, helptext string) Creator { + if ctorImpl == nil { + return &noop{} + } else { + return ctorImpl(name, helptext) + } +} + +func NewCtx(ctx context.Context, name, helptext string) Creator { + return New(CtxGetScope(ctx)+"."+name, helptext) +} + +type InternalNew func(string, string) Creator + +func InjectImpl(newimpl InternalNew) error { + if ctorImpl != nil { + return ErrImplemented + } else { + ctorImpl = newimpl + return nil + } +} + +func Active() bool { + return ctorImpl != nil +} diff --git a/vendor/github.com/ipfs/go-metrics-interface/go.mod b/vendor/github.com/ipfs/go-metrics-interface/go.mod new file mode 100644 index 0000000000..57654087aa --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/go.mod @@ -0,0 +1 @@ +module github.com/ipfs/go-metrics-interface diff --git a/vendor/github.com/ipfs/go-metrics-interface/interface.go b/vendor/github.com/ipfs/go-metrics-interface/interface.go new file mode 100644 index 0000000000..f1237593c5 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/interface.go @@ -0,0 +1,45 @@ +package metrics + +import ( + "time" +) + +// Increment only metric +type Counter interface { + Inc() + Add(float64) // Only positive +} + +// Increse and decrese metric +type Gauge interface { + Set(float64) // Introduced discontinuity + Inc() + Dec() + Add(float64) + Sub(float64) +} + +type Histogram interface { + Observe(float64) // Adds observation to Histogram +} + +type Summary interface { + Observe(float64) // Adds observation to Summary +} + +// Consult http://godoc.org/github.com/prometheus/client_golang/prometheus#SummaryOpts +type SummaryOpts struct { + Objectives map[float64]float64 + MaxAge time.Duration + AgeBuckets uint32 + BufCap uint32 +} + +type Creator interface { + Counter() Counter + Gauge() Gauge + Histogram(buckets []float64) Histogram + + // opts cannot be nil, use empty summary instance + Summary(opts SummaryOpts) Summary +} diff --git a/vendor/github.com/ipfs/go-metrics-interface/noop.go b/vendor/github.com/ipfs/go-metrics-interface/noop.go new file mode 100644 index 0000000000..5b59aa83c3 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/noop.go @@ -0,0 +1,46 @@ +package metrics + +// Also implements the Counter interface +type noop struct{} + +func (g *noop) Set(v float64) { + // Noop +} + +func (g *noop) Inc() { + // Noop +} + +func (g *noop) Dec() { + // Noop +} + +func (g *noop) Add(v float64) { + // Noop +} + +func (g *noop) Sub(v float64) { + // Noop +} + +func (g *noop) Observe(v float64) { + // Noop +} + +// Creator functions + +func (g *noop) Counter() Counter { + return g +} + +func (g *noop) Gauge() Gauge { + return g +} + +func (g *noop) Histogram(buckets []float64) Histogram { + return g +} + +func (g *noop) Summary(opts SummaryOpts) Summary { + return g +} diff --git a/vendor/github.com/ipfs/go-metrics-interface/package.json b/vendor/github.com/ipfs/go-metrics-interface/package.json new file mode 100644 index 0000000000..6ba42d7610 --- /dev/null +++ b/vendor/github.com/ipfs/go-metrics-interface/package.json @@ -0,0 +1,16 @@ +{ + "author": "ipfs", + "bugs": { + "URL": "https://github.com/ipfs/go-metrics-interface/issues", + "url": "https://github.com/ipfs/go-metrics-interface/issues" + }, + "gx": { + "dvcsimport": "github.com/ipfs/go-metrics-interface" + }, + "gxVersion": "0.9.0", + "language": "go", + "license": "MIT", + "name": "go-metrics-interface", + "version": "0.2.0" +} + diff --git a/vendor/github.com/ipfs/go-verifcid/.travis.yml b/vendor/github.com/ipfs/go-verifcid/.travis.yml new file mode 100644 index 0000000000..4cfe98c242 --- /dev/null +++ b/vendor/github.com/ipfs/go-verifcid/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/ipfs/go-verifcid/go.mod b/vendor/github.com/ipfs/go-verifcid/go.mod new file mode 100644 index 0000000000..5db3e877f3 --- /dev/null +++ b/vendor/github.com/ipfs/go-verifcid/go.mod @@ -0,0 +1,6 @@ +module github.com/ipfs/go-verifcid + +require ( + github.com/ipfs/go-cid v0.0.1 + github.com/multiformats/go-multihash v0.0.1 +) diff --git a/vendor/github.com/ipfs/go-verifcid/go.sum b/vendor/github.com/ipfs/go-verifcid/go.sum new file mode 100644 index 0000000000..4525c37ee0 --- /dev/null +++ b/vendor/github.com/ipfs/go-verifcid/go.sum @@ -0,0 +1,22 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-cid v0.0.1 h1:GBjWPktLnNyX0JiQCNFpUuUSoMw5KMyqrsejHYlILBE= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/ipfs/go-verifcid/package.json b/vendor/github.com/ipfs/go-verifcid/package.json new file mode 100644 index 0000000000..a066b1d8a0 --- /dev/null +++ b/vendor/github.com/ipfs/go-verifcid/package.json @@ -0,0 +1,28 @@ +{ + "author": "why", + "bugs": {}, + "gx": { + "dvcsimport": "github.com/ipfs/go-verifcid" + }, + "gxDependencies": [ + { + "author": "multiformats", + "hash": "QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW", + "name": "go-multihash", + "version": "1.0.9" + }, + { + "author": "whyrusleeping", + "hash": "QmTbxNB1NwDesLmKTscr4udL2tVP7MaxvXnD1D9yX7g3PN", + "name": "go-cid", + "version": "0.9.3" + } + ], + "gxVersion": "0.12.1", + "language": "go", + "license": "", + "name": "go-verifcid", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "0.1.2" +} + diff --git a/vendor/github.com/ipfs/go-verifcid/validate.go b/vendor/github.com/ipfs/go-verifcid/validate.go new file mode 100644 index 0000000000..8a76e4933e --- /dev/null +++ b/vendor/github.com/ipfs/go-verifcid/validate.go @@ -0,0 +1,62 @@ +package verifcid + +import ( + "fmt" + + cid "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" +) + +var ErrPossiblyInsecureHashFunction = fmt.Errorf("potentially insecure hash functions not allowed") +var ErrBelowMinimumHashLength = fmt.Errorf("hashes must be at %d least bytes long", minimumHashLength) + +const minimumHashLength = 20 + +var goodset = map[uint64]bool{ + mh.SHA2_256: true, + mh.SHA2_512: true, + mh.SHA3_224: true, + mh.SHA3_256: true, + mh.SHA3_384: true, + mh.SHA3_512: true, + mh.SHAKE_256: true, + mh.DBL_SHA2_256: true, + mh.KECCAK_224: true, + mh.KECCAK_256: true, + mh.KECCAK_384: true, + mh.KECCAK_512: true, + mh.ID: true, + + mh.SHA1: true, // not really secure but still useful +} + +func IsGoodHash(code uint64) bool { + good, found := goodset[code] + if good { + return true + } + + if !found { + if code >= mh.BLAKE2B_MIN+19 && code <= mh.BLAKE2B_MAX { + return true + } + if code >= mh.BLAKE2S_MIN+19 && code <= mh.BLAKE2S_MAX { + return true + } + } + + return false +} + +func ValidateCid(c cid.Cid) error { + pref := c.Prefix() + if !IsGoodHash(pref.MhType) { + return ErrPossiblyInsecureHashFunction + } + + if pref.MhType != mh.ID && pref.MhLength < minimumHashLength { + return ErrBelowMinimumHashLength + } + + return nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/.gitmodules b/vendor/github.com/ipld/go-ipld-prime/.gitmodules new file mode 100644 index 0000000000..9326cf9f2d --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/.gitmodules @@ -0,0 +1,39 @@ +[submodule ".gopath/src/github.com/polydawn/refmt"] + path = .gopath/src/github.com/polydawn/refmt + url = https://github.com/polydawn/refmt +[submodule ".gopath/src/golang.org/x/sys"] + path = .gopath/src/golang.org/x/sys + url = https://go.googlesource.com/sys +[submodule ".gopath/src/golang.org/x/crypto"] + path = .gopath/src/golang.org/x/crypto + url = https://go.googlesource.com/crypto +[submodule ".gopath/src/github.com/ipfs/go-cid"] + path = .gopath/src/github.com/ipfs/go-cid + url = https://github.com/ipfs/go-cid +[submodule ".gopath/src/github.com/multiformats/go-multibase"] + path = .gopath/src/github.com/multiformats/go-multibase + url = https://github.com/multiformats/go-multibase +[submodule ".gopath/src/github.com/multiformats/go-multihash"] + path = .gopath/src/github.com/multiformats/go-multihash + url = https://github.com/multiformats/go-multihash +[submodule ".gopath/src/github.com/minio/sha256-simd"] + path = .gopath/src/github.com/minio/sha256-simd + url = https://github.com/minio/sha256-simd +[submodule ".gopath/src/github.com/minio/blake2b-simd"] + path = .gopath/src/github.com/minio/blake2b-simd + url = https://github.com/minio/blake2b-simd +[submodule ".gopath/src/github.com/gxed/hashland"] + path = .gopath/src/github.com/gxed/hashland + url = https://github.com/gxed/hashland +[submodule ".gopath/src/github.com/mr-tron/base58"] + path = .gopath/src/github.com/mr-tron/base58 + url = https://github.com/mr-tron/base58 +[submodule ".gopath/src/github.com/spaolacci/murmur3"] + path = .gopath/src/github.com/spaolacci/murmur3 + url = https://github.com/spaolacci/murmur3 +[submodule ".gopath/src/github.com/multiformats/go-base32"] + path = .gopath/src/github.com/multiformats/go-base32 + url = https://github.com/multiformats/go-base32 +[submodule ".gopath/src/github.com/warpfork/go-wish"] + path = .gopath/src/github.com/warpfork/go-wish + url = https://github.com/warpfork/go-wish diff --git a/vendor/github.com/ipld/go-ipld-prime/.travis.yml b/vendor/github.com/ipld/go-ipld-prime/.travis.yml new file mode 100644 index 0000000000..fd0164701e --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/.travis.yml @@ -0,0 +1,25 @@ +language: go + +go: + - 1.12.x + +env: + global: + - GO111MODULE=on + +notifications: + email: false + +install: +- go mod download + +before_script: +- go fmt ./... +- go build ./... +- go test -run xxxx ./... + +script: +- go test -race -short -coverprofile=coverage.txt ./... + +after_success: +- bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/ipld/go-ipld-prime/HACKME.md b/vendor/github.com/ipld/go-ipld-prime/HACKME.md new file mode 100644 index 0000000000..c952fa263b --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/HACKME.md @@ -0,0 +1,120 @@ +hackme +====== + +Design rational are documented here. + +This doc is not necessary reading for users of this package, +but if you're considering submitting patches -- or just trying to understand +why it was written this way, and check for reasoning that might be dated -- +then it might be useful reading. + +It may also be an incomplete doc. It's been written opportunistically. +If you don't understand the rationale for some things, try checking git history +(many of the commit messages are downright bookish), or get in touch via +a github issue, irc, matrix, etc and ask! + + +about NodeAssembler and NodeBuilder +----------------------------------- + +See the godoc on these types. + +In short, a `NodeBuilder` is for creating a new piece of memory; +a `NodeAssembler` is for instantiating some memory which you already have. + +Generally, you'll start any function using a `NodeBuilder`, but then continue +and recurse by passing on the `NodeAssembler`. + +See the `./HACKME_builderBehaviors.md` doc for more details on +high level rules and implementation patterns to look out for. + + + +about NodeStyle +--------------- + +### NodeStyle promises information without allocations + +You'll notice nearly every `ipld.NodeStyle` implementation is +a golang struct type with _zero fields_. + +This is important. +Getting a NodeStyle is generally expected to be "free" (i.e., zero allocations), +while `NewBuilder` is allowed to be costly (usually causes at least one allocation). +Zero-member structs can be referred to by an interface without requiring an allocation, +which is how it's possible ensure `NodeStyle` are always "free" to refer to. + +(Note that a `NodeStyle` that bundles some information like ADL configuration +will subvert this pattern -- but these are an exception, not the rule.) + +### NodeStyle reported by a Node + +`ipld.NodeStyle` is a type that opaquely represents some information about how +a node was constructed and is implemented. The general contract for what +should happen when asking a node for its style +(via the `ipld.Node.Style() NodeStyle` interface) is that style should be +effective instructions for how one could build a copy of that node, using +the same implementation details. + +By example, if something was made as a `plainString` -- i.e., +either via `String()` or via `Style__String{}.NewBuilder()` -- +then its `Style()` will be `Style__String`. + +Note there are also limits to this: if a node was built in a flexible way, +the style it reports later may only report what it is now, and not return +that same flexibility again. +By example, if something was made as an "any" -- i.e., +via `Style__Any{}.NewBuilder()`, and then *happened* to be assigned a string value -- +the resulting string node will carry a `Style()` property that returns +`Style__String` -- **not** `Style__Any`. + +#### NodeStyle meets generic transformation + +One of the core purposes of the `NodeStyle` interface (and all the different +ways you can get it from existing data) is to enable the `traversal` package +(or other user-written packages like it) to do transformations on data. + +// work-in-progress warning: generic transformations are not fully implemented. + +When implementating a transformation that works over unknown data, +the signiture of function a user provides is roughly: +`func(oldValue Node, acceptableValues NodeStyle) (Node, error)`. +(This signiture may vary by the strategy taken by the transformation -- this +signiture is useful because it's capable of no-op'ing; an alternative signiture +might give the user a `NodeAssembler` instead of the `NodeStyle`.) + +In this situation, the transformation system determines the `NodeStyle` +(or `NodeAssembler`) to use by asking the parent value of the one we're visiting. +This is because we want to give the update function the ability to create +any kind of value that would be accepted in this position -- not just create a +value of the same style as the one currently there! It is for this reason +the `oldValue.Style()` property can't be used directly. + +At the root of such a transformation, we use the `node.Style()` property to +determine how to get started building a new value. + +#### NodeStyle meets recursive assemblers + +Asking for a NodeStyle in a recursive assembly process tells you about what +kind of node would be accepted in an `AssignNode(Node)` call. +It does *not* make any remark on the fact it's a key assembler or value assembler +and might be wrapped with additional rules (such as map key uniqueness, field +name expectations, etc). + +(Note that it's also not an exclusive statement about what `AssignNode(Node)` will +accept; e.g. in many situations, while a `Style__MyStringType` might be the style +returned, any string kinded node can be used in `AssignNode(Node)` and will be +appropriately converted.) + +Any of these paths counts as "recursive assembly process": + +- `MapAssembler.KeyStyle()` +- `MapAssembler.ValueStyle(string)` +- `MapAssembler.AssembleKey().Style()` +- `MapAssembler.AssembleValue().Style()` +- `ListAssembler.ValueStyle()` +- `ListAssembler.AssembleValue().Style()` + +### NodeStyle for carrying ADL configuration + +// work-in-progress warning: this is an intention of the design, but not implemented. diff --git a/vendor/github.com/ipld/go-ipld-prime/HACKME_builderBehaviors.md b/vendor/github.com/ipld/go-ipld-prime/HACKME_builderBehaviors.md new file mode 100644 index 0000000000..c4c977b7db --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/HACKME_builderBehaviors.md @@ -0,0 +1,61 @@ +hackme: NodeBuilder and NodeAssembler behaviors +=============================================== + +high level rules of builders and assemblers +------------------------------------------- + +- Errors should be returned as soon as possible. + - That means an error like "repeated key in map" should be returned by the key assembler! + - Either 'NodeAssembler.AssignString' should return this (for simple keys on untyped maps, or on structs, etc)... + - ... or 'MapAssembler.Finish' (in the case of complex keys in a typed map). + +- Logical integrity checks must be done locally -- recursive types rely on their contained types to report errors, and the recursive type wraps the assemblers of their contained type in order to check and correctly invalidate/rollback the recursive construction. + +- Recursive types tend to have a value assembler that wraps the child type's assembler in order to intercept relevant "finish" methods. + - This is generally where that logic integrity check mentioned above is tracked; we need explicit confirmation that it *passes* before the parent's assembly should proceed. + - Implementations may also need this moment to complete any assignment of the child value into position in the parent value. But not all implementations need this -- some will have had all the child assembler effects applying directly to the final memory positions. + +- Assemblers should invalidate themselves as soon as they become "finished". + - For maps and lists, that means the "Finish" methods. + - For all the other scalars, the "Assign*" method itself means finished. + - Or in other words: whatever method returns an `error`, that's what makes that assembler "finished". + - The purpose of this is to prevent accidental mutation after any validations have been performed during the "finish" processing. + +- Many methods must be called in the right order, and the user must not hold onto references after calling "finish" methods on them. + - The reason this is important is to enable assembler systems to agressively reuse memory, thus increasing performance. + - Thus, if you hold onto NodeAssembler reference after being finished with it... you can't assume it'll explicitly error if you call further methods on it, because it might now be operating again... _on a different target_. + - In recursive structures, calling AssembleKey or AssembleValue might return pointer-identical assemblers (per warning in previous bullet), but the memory their assembly is targetted to should always advance -- it should never target already-assembled memory. + - (If you're thinking "the Rust memory model would be able to greatly enhance safety here!"... yes. Yes it would.) + - When misuses of order are detected, these may cause panics (rather than error returns) (not all methods that can be so misused have error returns). + + +detailed rules and expectations for implementers +------------------------------------------------ + +The expectations in the "happy path" are often clear. +Here are also collected some details of exactly what should happen when an error has been reached, +but the caller tries to continue anyway. + +- while building maps: + - assigning a key with 'AssembleKey': + - in case of success: clearly 'AssembleValue' should be ready to use next. + - in case of failure from repeated key: + - the error must be returned immediately from either the 'NodeAssembler.AssignString' or the 'MapAssembler.Finish' method. + - 'AssignString' for any simple keys; 'MapAssembler.Finish' may be relevant in the case of complex keys in a typed map. + - implementers take note: this implies the `NodeAssembler` returned by `AssembleKey` has some way to refer to the map assembler that spawned it. + - no side effect should be visible if 'AssembleKey' is called again next. + - (typically this doesn't require extra code for the string case, but it may require some active zeroing in the complex key case.) + - (remember to reset any internal flag for expecting 'AssembleValue' to be used next, and decrement any length pointers that were optimistically incremented!) + - n.b. the "no side effect" rule here is for keys, not for values. + - TODO/REVIEW: do we want the no-side-effect rule for values? it might require nontrivial volumes of zeroing, and often in practice, this might be wasteful. + +- invalidation of assemblers: + - is typically implemented by nil'ing the wip node they point to. + - this means you get nil pointer dereference panics when attempting to use an assembler after it's finished... which is not the greatest error message. + - but it does save us a lot of check code for a situation that the user certainly shouldn't get into in the first place. + - (worth review: can we add that check code without extra runtime cost? possibly, because the compiler might then skip its own implicit check branches. might still increase SLOC noticably in codegen output, though.) + - worth noting there's a limit to how good this can be anyway: it's "best effort" error reporting: see the remarks on reuse of assembler memory in "overall rules" above. + - it's systemically critical to not yield an assembler _ever again in the future_ that refers to some memory already considered finished. + - even though we no longer return intermediate nodes, there's still many ways this could produce problems. For example, complicating (if not outright breaking) COW sharing of segments of data. + - in most situations, we get this for free, because the child assembler methods only go "forward" -- there's no backing up, lists have no random index insertion or update support, and maps actively reject dupe keys. + - if you *do* make a system which exposes any of those features... be very careful; you will probably need to start tracking "freeze" flags on the data in order to retain systemic sanity. diff --git a/vendor/github.com/ipld/go-ipld-prime/LICENSE b/vendor/github.com/ipld/go-ipld-prime/LICENSE new file mode 100644 index 0000000000..80e1f8f672 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Eric Myhre + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/ipld/go-ipld-prime/README.md b/vendor/github.com/ipld/go-ipld-prime/README.md new file mode 100644 index 0000000000..22e5ca7e95 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/README.md @@ -0,0 +1,105 @@ +go-ipld-prime +============= + +`go-ipld-prime` is an implementation of the IPLD spec interfaces, +a batteries-included codec implementations of IPLD for CBOR and JSON, +and tooling for basic operations on IPLD objects (traversals, etc). + + + +API +--- + +The API is split into several packages based on responsibly of the code. +The most central interfaces are the base package, +but you'll certainly need to import additional packages to get concrete implementations into action. + +Roughly speaking, the core package interfaces are all about the IPLD Data Model; +the codec packages contain functions for parsing serial data into the IPLD Data Model, +and converting Data Model content back into serial formats; +the traversal package is an example of higher-order functions on the Data Model; +concrete 'Node' implementations ready to use can be found under 'impl/*'; +and several additional packages contain advanced features such as IPLD Schemas. + +(Because the codecs, as well as higher-order features like traversals, are +implemented in a separate package from the core interfaces or any of the Node implementations, +you can be sure they're not doing any funky "magic" -- all this stuff will work the same +if you want to write your own extensions, whether for new Node implementations +or new codecs, or new higher-order order functions!) + +- `github.com/ipld/go-ipld-prime` -- imported as just `ipld` -- contains the core interfaces for IPLD. The most important interfaces are `Node`, `NodeBuilder`, `Path`, and `Link`. +- `github.com/ipld/go-ipld-prime/impl/free` -- imported as `ipldfree` -- provides concrete implementations of `Node` and `NodeBuilder` which work for any kind of data. +- `github.com/ipld/go-ipld-prime/impl/cbor` -- imported as `ipldcbor` -- provides concrete implementations of `Node` and `NodeBuilder` which have some special features to accelerate certain workloads with CBOR. +- `github.com/ipld/go-ipld-prime/traversal` -- contains higher-order functions for traversing graphs of data easily. +- `github.com/ipld/go-ipld-prime/traversal/selector` -- contains selectors, which are sort of like regexps, but for trees and graphs of IPLD data! +- `github.com/ipld/go-ipld-prime/codec -- parent package of all the codec implementations! +- `github.com/ipld/go-ipld-prime/codec/dagcbor` -- implementations of marshalling and unmarshalling as CBOR (a fast, binary serialization format). +- `github.com/ipld/go-ipld-prime/codec/dagjson` -- implementations of marshalling and unmarshalling as JSON (a popular human readable format). +- `github.com/ipld/go-ipld-prime/linking/cid` -- imported as `cidlink` -- provides concrete implementations of `Link` as a CID. Also, the multicodec registry. +- `github.com/ipld/go-ipld-prime/schema` -- contains the `schema.Type` and `schema.TypedNode` interface declarations, which represent IPLD Schema type information. +- `github.com/ipld/go-ipld-prime/impl/typed` -- provides concrete implementations of `schema.TypedNode` which decorate a basic `Node` at runtime to have additional features described by IPLD Schemas. + + + +Other IPLD Libraries +-------------------- + +The IPLD specifications are designed to be language-agnostic. +Many implementations exist in a variety of languages. + +For overall behaviors and specifications, refer to the specs repo: + https://github.com/ipld/specs/ + + +### distinctions from go-ipld-interface&go-ipld-cbor + +This library ("go ipld prime") is the current head of development for golang IPLD, +but several other libraries exist which are widely deployed. + +This library is a clean take on the IPLD interfaces and addresses several design decisions very differently than existing libraries: + +- The Node interfaces are minimal (and match cleanly to the IPLD Data Model); +- Many features known to be legacy are dropped; +- The Link implementations are purely CIDs; +- The Path implementations are provided in the same box; +- The JSON and CBOR implementations are provided in the same box; +- And several odd dependencies on blockstore and other interfaces from the rest of the IPFS ecosystem are removed. + +Many of these changes had been discussed for the other IPLD codebases as well, +but we chose clean break v2 as a more viable project-management path. +Both the existing IPLD libraries and go-ipld-prime can co-exist on the same import path, and refer to the same kinds of serial data. +Projects wishing to migrate can do so smoothly and at their leisure. + +There is no explicit deprecation timeline for the earlier golang IPLD libraries, +but you should expect new features *here*, rather than in those libraries. + + + +Change Policy +------------- + +The go-ipld-prime library is already usable. We are also still in development, and may still change things. + +Using a commit hash when depending on this library is advisable (as it is with any other). + +We may sometimes tag releases, but it's just as acceptable to track commits on master without the indirection. + +The following are all norms you can expect of changes to this codebase: + +- The `master` branch will not be force-pushed. + - (exceptional circumstances may exist, but such exceptions will only be considered valid for about as long after push as the "$N-second-rule" about dropped food). + - Therefore, commit hashes on master are gold to link against. +- All other branches *will* be force-pushed. + - Therefore, commit hashes not reachable from the master branch are inadvisable to link against. +- If it's on master, it's understood to be good, in as much as we can tell. +- Development proceeds -- both starting from and ending on -- the `master` branch. + - There are no other long-running supported-but-not-master branches. + - The existence of tags at any particular commit do not indicate that we will consider starting a long running and supported diverged branch from that point, nor start doing backports, etc. +- All changes are presumed breaking until proven otherwise; and we don't have the time and attention budget at this point for doing the "proven otherwise". + - All consumers updating their libraries should run their own compiler, linking, and test suites before assuming the update applies cleanly -- as is good practice regardless. + - Any idea of semver indicating more or less breakage should be treated as a street vendor selling potions of levitation -- it's likely best disregarded. + +None of this is to say we'll go breaking things willy-nilly for fun; but it *is* to say: + +- Staying close to master is always better than not staying close to master; +- and trust your compiler and your tests rather than tea-leaf patterns in a tag string. diff --git a/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/common.go b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/common.go new file mode 100644 index 0000000000..2542d9ce9e --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/common.go @@ -0,0 +1,3 @@ +package dagcbor + +const linkTag = 42 diff --git a/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/marshal.go b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/marshal.go new file mode 100644 index 0000000000..40ba29a123 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/marshal.go @@ -0,0 +1,145 @@ +package dagcbor + +import ( + "fmt" + + "github.com/polydawn/refmt/shared" + "github.com/polydawn/refmt/tok" + + ipld "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" +) + +// This should be identical to the general feature in the parent package, +// except for the `case ipld.ReprKind_Link` block, +// which is dag-cbor's special sauce for schemafree links. +func Marshal(n ipld.Node, sink shared.TokenSink) error { + var tk tok.Token + return marshal(n, &tk, sink) +} + +func marshal(n ipld.Node, tk *tok.Token, sink shared.TokenSink) error { + switch n.ReprKind() { + case ipld.ReprKind_Invalid: + return fmt.Errorf("cannot traverse a node that is undefined") + case ipld.ReprKind_Null: + tk.Type = tok.TNull + _, err := sink.Step(tk) + return err + case ipld.ReprKind_Map: + // Emit start of map. + tk.Type = tok.TMapOpen + tk.Length = n.Length() + if _, err := sink.Step(tk); err != nil { + return err + } + // Emit map contents (and recurse). + for itr := n.MapIterator(); !itr.Done(); { + k, v, err := itr.Next() + if err != nil { + return err + } + tk.Type = tok.TString + tk.Str, err = k.AsString() + if err != nil { + return err + } + if _, err := sink.Step(tk); err != nil { + return err + } + if err := marshal(v, tk, sink); err != nil { + return err + } + } + // Emit map close. + tk.Type = tok.TMapClose + _, err := sink.Step(tk) + return err + case ipld.ReprKind_List: + // Emit start of list. + tk.Type = tok.TArrOpen + l := n.Length() + tk.Length = l + if _, err := sink.Step(tk); err != nil { + return err + } + // Emit list contents (and recurse). + for i := 0; i < l; i++ { + v, err := n.LookupIndex(i) + if err != nil { + return err + } + if err := marshal(v, tk, sink); err != nil { + return err + } + } + // Emit list close. + tk.Type = tok.TArrClose + _, err := sink.Step(tk) + return err + case ipld.ReprKind_Bool: + v, err := n.AsBool() + if err != nil { + return err + } + tk.Type = tok.TBool + tk.Bool = v + _, err = sink.Step(tk) + return err + case ipld.ReprKind_Int: + v, err := n.AsInt() + if err != nil { + return err + } + tk.Type = tok.TInt + tk.Int = int64(v) + _, err = sink.Step(tk) + return err + case ipld.ReprKind_Float: + v, err := n.AsFloat() + if err != nil { + return err + } + tk.Type = tok.TFloat64 + tk.Float64 = v + _, err = sink.Step(tk) + return err + case ipld.ReprKind_String: + v, err := n.AsString() + if err != nil { + return err + } + tk.Type = tok.TString + tk.Str = v + _, err = sink.Step(tk) + return err + case ipld.ReprKind_Bytes: + v, err := n.AsBytes() + if err != nil { + return err + } + tk.Type = tok.TBytes + tk.Bytes = v + _, err = sink.Step(tk) + return err + case ipld.ReprKind_Link: + v, err := n.AsLink() + if err != nil { + return err + } + switch lnk := v.(type) { + case cidlink.Link: + tk.Type = tok.TBytes + tk.Bytes = append([]byte{0}, lnk.Bytes()...) + tk.Tagged = true + tk.Tag = linkTag + _, err = sink.Step(tk) + tk.Tagged = false + return err + default: + return fmt.Errorf("schemafree link emission only supported by this codec for CID type links!") + } + default: + panic("unreachable") + } +} diff --git a/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/multicodec.go b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/multicodec.go new file mode 100644 index 0000000000..34b822ac3a --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/multicodec.go @@ -0,0 +1,46 @@ +package dagcbor + +import ( + "io" + + "github.com/polydawn/refmt/cbor" + + ipld "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" +) + +var ( + _ cidlink.MulticodecDecoder = Decoder + _ cidlink.MulticodecEncoder = Encoder +) + +func init() { + cidlink.RegisterMulticodecDecoder(0x71, Decoder) + cidlink.RegisterMulticodecEncoder(0x71, Encoder) +} + +func Decoder(na ipld.NodeAssembler, r io.Reader) error { + // Probe for a builtin fast path. Shortcut to that if possible. + // (ipldcbor.NodeBuilder supports this, for example.) + type detectFastPath interface { + DecodeDagCbor(io.Reader) error + } + if na2, ok := na.(detectFastPath); ok { + return na2.DecodeDagCbor(r) + } + // Okay, generic builder path. + return Unmarshal(na, cbor.NewDecoder(cbor.DecodeOptions{}, r)) +} + +func Encoder(n ipld.Node, w io.Writer) error { + // Probe for a builtin fast path. Shortcut to that if possible. + // (ipldcbor.Node supports this, for example.) + type detectFastPath interface { + EncodeDagCbor(io.Writer) error + } + if n2, ok := n.(detectFastPath); ok { + return n2.EncodeDagCbor(w) + } + // Okay, generic inspection path. + return Marshal(n, cbor.NewEncoder(w)) +} diff --git a/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/unmarshal.go b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/unmarshal.go new file mode 100644 index 0000000000..d22d40f993 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/codec/dagcbor/unmarshal.go @@ -0,0 +1,152 @@ +package dagcbor + +import ( + "errors" + "fmt" + "math" + + cid "github.com/ipfs/go-cid" + "github.com/polydawn/refmt/shared" + "github.com/polydawn/refmt/tok" + + ipld "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" +) + +var ( + ErrInvalidMultibase = errors.New("invalid multibase on IPLD link") +) + +// This should be identical to the general feature in the parent package, +// except for the `case tok.TBytes` block, +// which has dag-cbor's special sauce for detecting schemafree links. + +func Unmarshal(na ipld.NodeAssembler, tokSrc shared.TokenSource) error { + var tk tok.Token + done, err := tokSrc.Step(&tk) + if err != nil { + return err + } + if done && !tk.Type.IsValue() { + return fmt.Errorf("unexpected eof") + } + return unmarshal(na, tokSrc, &tk) +} + +// starts with the first token already primed. Necessary to get recursion +// to flow right without a peek+unpeek system. +func unmarshal(na ipld.NodeAssembler, tokSrc shared.TokenSource, tk *tok.Token) error { + // FUTURE: check for schema.TypedNodeBuilder that's going to parse a Link (they can slurp any token kind they want). + switch tk.Type { + case tok.TMapOpen: + expectLen := tk.Length + allocLen := tk.Length + if tk.Length == -1 { + expectLen = math.MaxInt32 + allocLen = 0 + } + ma, err := na.BeginMap(allocLen) + if err != nil { + return err + } + observedLen := 0 + for { + _, err := tokSrc.Step(tk) + if err != nil { + return err + } + switch tk.Type { + case tok.TMapClose: + if expectLen != math.MaxInt32 && observedLen != expectLen { + return fmt.Errorf("unexpected mapClose before declared length") + } + return ma.Finish() + case tok.TString: + // continue + default: + return fmt.Errorf("unexpected %s token while expecting map key", tk.Type) + } + observedLen++ + if observedLen > expectLen { + return fmt.Errorf("unexpected continuation of map elements beyond declared length") + } + mva, err := ma.AssembleEntry(tk.Str) + if err != nil { // return in error if the key was rejected + return err + } + err = Unmarshal(mva, tokSrc) + if err != nil { // return in error if some part of the recursion errored + return err + } + } + case tok.TMapClose: + return fmt.Errorf("unexpected mapClose token") + case tok.TArrOpen: + expectLen := tk.Length + allocLen := tk.Length + if tk.Length == -1 { + expectLen = math.MaxInt32 + allocLen = 0 + } + la, err := na.BeginList(allocLen) + if err != nil { + return err + } + observedLen := 0 + for { + _, err := tokSrc.Step(tk) + if err != nil { + return err + } + switch tk.Type { + case tok.TArrClose: + if expectLen != math.MaxInt32 && observedLen != expectLen { + return fmt.Errorf("unexpected arrClose before declared length") + } + return la.Finish() + default: + observedLen++ + if observedLen > expectLen { + return fmt.Errorf("unexpected continuation of array elements beyond declared length") + } + err := unmarshal(la.AssembleValue(), tokSrc, tk) + if err != nil { // return in error if some part of the recursion errored + return err + } + } + } + case tok.TArrClose: + return fmt.Errorf("unexpected arrClose token") + case tok.TNull: + return na.AssignNull() + case tok.TString: + return na.AssignString(tk.Str) + case tok.TBytes: + if !tk.Tagged { + return na.AssignBytes(tk.Bytes) + } + switch tk.Tag { + case linkTag: + if tk.Bytes[0] != 0 { + return ErrInvalidMultibase + } + elCid, err := cid.Cast(tk.Bytes[1:]) + if err != nil { + return err + } + return na.AssignLink(cidlink.Link{elCid}) + default: + return fmt.Errorf("unhandled cbor tag %d", tk.Tag) + } + case tok.TBool: + return na.AssignBool(tk.Bool) + case tok.TInt: + return na.AssignInt(int(tk.Int)) // FIXME overflow check + case tok.TUint: + return na.AssignInt(int(tk.Uint)) // FIXME overflow check + case tok.TFloat64: + return na.AssignFloat(tk.Float64) + default: + panic("unreachable") + } +} diff --git a/vendor/github.com/ipld/go-ipld-prime/doc.go b/vendor/github.com/ipld/go-ipld-prime/doc.go new file mode 100644 index 0000000000..f304558a19 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/doc.go @@ -0,0 +1,50 @@ +// go-ipld-prime is a series of go interfaces for manipulating IPLD data. +// +// See https://github.com/ipld/specs for more information about the basics +// of "What is IPLD?". +// +// See https://github.com/ipld/go-ipld-prime/tree/master/doc/README.md +// for more documentation about go-ipld-prime's architecture and usage. +// +// Here in the godoc, the first couple of types to look at should be: +// +// - Node +// - NodeBuilder (and NodeAssembler) +// +// These types provide a generic description of the data model. +// +// If working with linked data (data which is split into multiple +// trees of Nodes, loaded separately, and connected by some kind of +// "link" reference), the next types you should look at are: +// +// - Link +// - LinkBuilder +// - Loader +// - Storer +// +// All of these types are interfaces. There are several implementations you +// can choose; we've provided some in subpackages, or you can bring your own. +// +// Particularly interesting subpackages include: +// +// - node/* -- various Node + NodeBuilder implementations +// - node/basic -- the first Node implementation you should try +// - codec/* -- functions for serializing and deserializing Nodes +// - linking/* -- various Link + LinkBuilder implementations +// - traversal -- functions for walking Node graphs (including +// automatic link loading) and visiting +// - must -- helpful functions for streamlining error handling +// - fluent -- alternative Node interfaces that flip errors to panics +// - schema -- interfaces for working with IPLD Schemas and Nodes +// which use Schema types and constraints +// +// Note that since interfaces in this package are the core of the library, +// choices made here maximize correctness and performance -- these choices +// are *not* always the choices that would maximize ergonomics. +// (Ergonomics can come on top; performance generally can't.) +// You can check out the 'must' or 'fluent' packages for more ergonomics; +// 'traversal' provides some ergnomics features for certain uses; +// any use of schemas with codegen tooling will provide more ergnomic options; +// or you can make your own function decorators that do what *you* need. +// +package ipld diff --git a/vendor/github.com/ipld/go-ipld-prime/errors.go b/vendor/github.com/ipld/go-ipld-prime/errors.go new file mode 100644 index 0000000000..24511dfd74 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/errors.go @@ -0,0 +1,86 @@ +package ipld + +import ( + "fmt" +) + +// ErrWrongKind may be returned from functions on the Node interface when +// a method is invoked which doesn't make sense for the Kind and/or ReprKind +// that node concretely contains. +// +// For example, calling AsString on a map will return ErrWrongKind. +// Calling Lookup on an int will similarly return ErrWrongKind. +type ErrWrongKind struct { + // TypeName may optionally indicate the named type of a node the function + // was called on (if the node was typed!), or, may be the empty string. + TypeName string + + // MethodName is literally the string for the operation attempted, e.g. + // "AsString". + // + // For methods on nodebuilders, we say e.g. "NodeBuilder.CreateMap". + MethodName string + + // ApprorpriateKind describes which ReprKinds the erroring method would + // make sense for. + AppropriateKind ReprKindSet + + // ActualKind describes the ReprKind of the node the method was called on. + // + // In the case of typed nodes, this will typically refer to the 'natural' + // data-model kind for such a type (e.g., structs will say 'map' here). + ActualKind ReprKind +} + +func (e ErrWrongKind) Error() string { + if e.TypeName == "" { + return fmt.Sprintf("func called on wrong kind: %s called on a %s node, but only makes sense on %s", e.MethodName, e.ActualKind, e.AppropriateKind) + } else { + return fmt.Sprintf("func called on wrong kind: %s called on a %s node (kind: %s), but only makes sense on %s", e.MethodName, e.TypeName, e.ActualKind, e.AppropriateKind) + } +} + +// ErrNotExists may be returned from the lookup functions of the Node interface +// to indicate a missing value. +// +// Note that schema.ErrNoSuchField is another type of error which sometimes +// occurs in similar places as ErrNotExists. ErrNoSuchField is preferred +// when handling data with constraints provided by a schema that mean that +// a field can *never* exist (as differentiated from a map key which is +// simply absent in some data). +type ErrNotExists struct { + Segment PathSegment +} + +func (e ErrNotExists) Error() string { + return fmt.Sprintf("key not found: %q", e.Segment) +} + +// ErrRepeatedMapKey is an error indicating that a key was inserted +// into a map that already contains that key. +// +// This error may be returned by any methods that add data to a map -- +// any of the methods on a NodeAssembler that was yielded by MapAssembler.AssignKey(), +// or from the MapAssembler.AssignDirectly() method. +type ErrRepeatedMapKey struct { + Key Node +} + +func (e ErrRepeatedMapKey) Error() string { + return fmt.Sprintf("cannot repeat map key (\"%s\")", e.Key) +} + +// ErrIteratorOverread is returned when calling 'Next' on a MapIterator or +// ListIterator when it is already done. +type ErrIteratorOverread struct{} + +func (e ErrIteratorOverread) Error() string { + return "iterator overread" +} + +type ErrCannotBeNull struct{} // Review: arguably either ErrInvalidKindForNodeStyle. + +type ErrInvalidStructKey struct{} // only possible for typed nodes -- specifically, struct types. +type ErrMissingRequiredField struct{} // only possible for typed nodes -- specifically, struct types. +type ErrListOverrun struct{} // only possible for typed nodes -- specifically, struct types with list (aka tuple) representations. +type ErrInvalidUnionDiscriminant struct{} // only possible for typed nodes -- specifically, union types. diff --git a/vendor/github.com/ipld/go-ipld-prime/fluent/doc.go b/vendor/github.com/ipld/go-ipld-prime/fluent/doc.go new file mode 100644 index 0000000000..86c9768ccb --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/fluent/doc.go @@ -0,0 +1,15 @@ +/* + The fluent package offers helper utilities for using NodeAssembler + more tersely by providing an interface that handles all errors for you, + and allows use of closures for any recursive assembly + so that creating trees of data results in indentation for legibility. + + Note that the fluent package creates wrapper objects in order to provide + the API conveniences that it does, and this comes at some cost to performance. + If you're optimizing for performance, using the fluent interfaces may be inadvisable. + However, as with any performance questions, benchmark before making decisions; + its entirely possible that your performance bottlenecks will be elsewhere + and there's no reason to deny yourself syntactic sugar if the costs don't + detectably affect the bottom line. +*/ +package fluent diff --git a/vendor/github.com/ipld/go-ipld-prime/fluent/fluentBuilder.go b/vendor/github.com/ipld/go-ipld-prime/fluent/fluentBuilder.go new file mode 100644 index 0000000000..99b0e84149 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/fluent/fluentBuilder.go @@ -0,0 +1,179 @@ +package fluent + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +func Build(ns ipld.NodeStyle, fn func(NodeAssembler)) (ipld.Node, error) { + nb := ns.NewBuilder() + fna := WrapAssembler(nb) + err := Recover(func() { + fn(fna) + }) + return nb.Build(), err +} + +func MustBuild(ns ipld.NodeStyle, fn func(NodeAssembler)) ipld.Node { + nb := ns.NewBuilder() + fn(WrapAssembler(nb)) + return nb.Build() +} +func MustBuildMap(ns ipld.NodeStyle, sizeHint int, fn func(MapAssembler)) ipld.Node { + return MustBuild(ns, func(fna NodeAssembler) { fna.CreateMap(sizeHint, fn) }) +} +func MustBuildList(ns ipld.NodeStyle, sizeHint int, fn func(ListAssembler)) ipld.Node { + return MustBuild(ns, func(fna NodeAssembler) { fna.CreateList(sizeHint, fn) }) +} + +func WrapAssembler(na ipld.NodeAssembler) NodeAssembler { + return &nodeAssembler{na} +} + +// NodeAssembler is the same as the interface in the core package, except: +// instead of returning errors, any error will cause panic +// (and you can collect these with `fluent.Recover`); +// and all recursive operations take a function as a parameter, +// within which you will receive another {Map,List,}NodeAssembler. +type NodeAssembler interface { + CreateMap(sizeHint int, fn func(MapAssembler)) + CreateList(sizeHint int, fn func(ListAssembler)) + AssignNull() + AssignBool(bool) + AssignInt(int) + AssignFloat(float64) + AssignString(string) + AssignBytes([]byte) + AssignLink(ipld.Link) + AssignNode(ipld.Node) + + Style() ipld.NodeStyle +} + +// MapAssembler is the same as the interface in the core package, except: +// instead of returning errors, any error will cause panic +// (and you can collect these with `fluent.Recover`); +// and all recursive operations take a function as a parameter, +// within which you will receive another {Map,List,}NodeAssembler. +type MapAssembler interface { + AssembleKey() NodeAssembler + AssembleValue() NodeAssembler + + AssembleEntry(k string) NodeAssembler + + KeyStyle() ipld.NodeStyle + ValueStyle(k string) ipld.NodeStyle +} + +// ListAssembler is the same as the interface in the core package, except: +// instead of returning errors, any error will cause panic +// (and you can collect these with `fluent.Recover`); +// and all recursive operations take a function as a parameter, +// within which you will receive another {Map,List,}NodeAssembler. +type ListAssembler interface { + AssembleValue() NodeAssembler + + ValueStyle(idx int) ipld.NodeStyle +} + +type nodeAssembler struct { + na ipld.NodeAssembler +} + +func (fna *nodeAssembler) CreateMap(sizeHint int, fn func(MapAssembler)) { + if ma, err := fna.na.BeginMap(sizeHint); err != nil { + panic(Error{err}) + } else { + fn(&mapNodeAssembler{ma}) + if err := ma.Finish(); err != nil { + panic(Error{err}) + } + } +} +func (fna *nodeAssembler) CreateList(sizeHint int, fn func(ListAssembler)) { + if la, err := fna.na.BeginList(sizeHint); err != nil { + panic(Error{err}) + } else { + fn(&listNodeAssembler{la}) + if err := la.Finish(); err != nil { + panic(Error{err}) + } + } +} +func (fna *nodeAssembler) AssignNull() { + if err := fna.na.AssignNull(); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) AssignBool(v bool) { + if err := fna.na.AssignBool(v); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) AssignInt(v int) { + if err := fna.na.AssignInt(v); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) AssignFloat(v float64) { + if err := fna.na.AssignFloat(v); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) AssignString(v string) { + if err := fna.na.AssignString(v); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) AssignBytes(v []byte) { + if err := fna.na.AssignBytes(v); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) AssignLink(v ipld.Link) { + if err := fna.na.AssignLink(v); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) AssignNode(v ipld.Node) { + if err := fna.na.AssignNode(v); err != nil { + panic(Error{err}) + } +} +func (fna *nodeAssembler) Style() ipld.NodeStyle { + return fna.na.Style() +} + +type mapNodeAssembler struct { + ma ipld.MapAssembler +} + +func (fma *mapNodeAssembler) AssembleKey() NodeAssembler { + return &nodeAssembler{fma.ma.AssembleKey()} +} +func (fma *mapNodeAssembler) AssembleValue() NodeAssembler { + return &nodeAssembler{fma.ma.AssembleValue()} +} +func (fma *mapNodeAssembler) AssembleEntry(k string) NodeAssembler { + va, err := fma.ma.AssembleEntry(k) + if err != nil { + panic(Error{err}) + } + return &nodeAssembler{va} +} +func (fma *mapNodeAssembler) KeyStyle() ipld.NodeStyle { + return fma.ma.KeyStyle() +} +func (fma *mapNodeAssembler) ValueStyle(k string) ipld.NodeStyle { + return fma.ma.ValueStyle(k) +} + +type listNodeAssembler struct { + la ipld.ListAssembler +} + +func (fla *listNodeAssembler) AssembleValue() NodeAssembler { + return &nodeAssembler{fla.la.AssembleValue()} +} +func (fla *listNodeAssembler) ValueStyle(idx int) ipld.NodeStyle { + return fla.la.ValueStyle(idx) +} diff --git a/vendor/github.com/ipld/go-ipld-prime/fluent/fluentRecover.go b/vendor/github.com/ipld/go-ipld-prime/fluent/fluentRecover.go new file mode 100644 index 0000000000..dec9693a86 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/fluent/fluentRecover.go @@ -0,0 +1,30 @@ +package fluent + +type Error struct { + Err error +} + +func (e Error) Error() string { + return e.Err.Error() +} + +// Recover invokes a function within a panic-recovering context, and returns +// any raised fluent.Error values; any other values are re-panicked. +// +// This can be useful for writing large blocks of code using fluent nodes, +// and handling any errors at once at the end. +func Recover(fn func()) (err error) { + defer func() { + ei := recover() + switch e2 := ei.(type) { + case nil: + return + case Error: + err = e2 + default: + panic(ei) + } + }() + fn() + return +} diff --git a/vendor/github.com/ipld/go-ipld-prime/go.mod b/vendor/github.com/ipld/go-ipld-prime/go.mod new file mode 100644 index 0000000000..bd0c340b6d --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/go.mod @@ -0,0 +1,15 @@ +module github.com/ipld/go-ipld-prime + +go 1.12 + +require ( + github.com/gxed/hashland/keccakpg v0.0.1 // indirect + github.com/gxed/hashland/murmur3 v0.0.1 // indirect + github.com/ipfs/go-cid v0.0.4 + github.com/minio/sha256-simd v0.1.1 // indirect + github.com/mr-tron/base58 v1.1.3 // indirect + github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 + github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a + golang.org/x/crypto v0.0.0-20200117160349-530e935923ad // indirect + golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 // indirect +) diff --git a/vendor/github.com/ipld/go-ipld-prime/go.sum b/vendor/github.com/ipld/go-ipld-prime/go.sum new file mode 100644 index 0000000000..d6f66d6a92 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/go.sum @@ -0,0 +1,52 @@ +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-cid v0.0.2 h1:tuuKaZPU1M6HcejsO3AcYWW8sZ8MTvyxfc4uqB4eFE8= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4 h1:UlfXKrZx1DjZoBhQHmNHLC1fK1dUJDN20Y28A7s+gJ8= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14 h1:2m16U/rLwVaRdz7ANkHtHTodP3zTP3N451MADg64x5k= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 h1:CskT+S6Ay54OwxBGB0R3Rsx4Muto6UnEYTyKJbyRIAI= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/ipld/go-ipld-prime/kind.go b/vendor/github.com/ipld/go-ipld-prime/kind.go new file mode 100644 index 0000000000..886c2382b8 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/kind.go @@ -0,0 +1,78 @@ +package ipld + +// ReprKind represents the primitive kind in the IPLD data model. +// All of these kinds map directly onto serializable data. +// +// Note that ReprKind contains the concept of "map", but not "struct" +// or "object" -- those are a concepts that could be introduced in a +// type system layers, but are *not* present in the data model layer, +// and therefore they aren't included in the ReprKind enum. +type ReprKind uint8 + +const ( + ReprKind_Invalid ReprKind = 0 + ReprKind_Map ReprKind = '{' + ReprKind_List ReprKind = '[' + ReprKind_Null ReprKind = '0' + ReprKind_Bool ReprKind = 'b' + ReprKind_Int ReprKind = 'i' + ReprKind_Float ReprKind = 'f' + ReprKind_String ReprKind = 's' + ReprKind_Bytes ReprKind = 'x' + ReprKind_Link ReprKind = '/' +) + +func (k ReprKind) String() string { + switch k { + case ReprKind_Invalid: + return "Invalid" + case ReprKind_Map: + return "Map" + case ReprKind_List: + return "List" + case ReprKind_Null: + return "Null" + case ReprKind_Bool: + return "Bool" + case ReprKind_Int: + return "Int" + case ReprKind_Float: + return "Float" + case ReprKind_String: + return "String" + case ReprKind_Bytes: + return "Bytes" + case ReprKind_Link: + return "Link" + default: + panic("invalid enumeration value!") + } +} + +// ReprKindSet is a type with a few enumerated consts that are commonly used +// (mostly, in error messages). +type ReprKindSet []ReprKind + +var ( + ReprKindSet_Recursive = ReprKindSet{ReprKind_Map, ReprKind_List} + ReprKindSet_Scalar = ReprKindSet{ReprKind_Null, ReprKind_Bool, ReprKind_Int, ReprKind_Float, ReprKind_String, ReprKind_Bytes, ReprKind_Link} + + ReprKindSet_JustMap = ReprKindSet{ReprKind_Map} + ReprKindSet_JustList = ReprKindSet{ReprKind_List} + ReprKindSet_JustNull = ReprKindSet{ReprKind_Null} + ReprKindSet_JustBool = ReprKindSet{ReprKind_Bool} + ReprKindSet_JustInt = ReprKindSet{ReprKind_Int} + ReprKindSet_JustFloat = ReprKindSet{ReprKind_Float} + ReprKindSet_JustString = ReprKindSet{ReprKind_String} + ReprKindSet_JustBytes = ReprKindSet{ReprKind_Bytes} + ReprKindSet_JustLink = ReprKindSet{ReprKind_Link} +) + +func (x ReprKindSet) String() string { + s := "" + for i := 0; i < len(x)-1; i++ { + s += x[i].String() + " or " + } + s += x[len(x)-1].String() + return s +} diff --git a/vendor/github.com/ipld/go-ipld-prime/linking.go b/vendor/github.com/ipld/go-ipld-prime/linking.go new file mode 100644 index 0000000000..8ccc40e93c --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/linking.go @@ -0,0 +1,144 @@ +package ipld + +import ( + "context" + "io" +) + +// Link is a special kind of value in IPLD which can be "loaded" to access +// more nodes. +// +// Nodes can return a Link; this can be loaded manually, or, +// the traversal package contains powerful features for automatically +// traversing links through large trees of nodes. +// +// Links straddle somewhat awkwardly across the IPLD Layer Model: +// clearly not at the Schema layer (though schemas can define their parameters), +// partially at the Data Model layer (as they're recognizably in the Node interface), +// and also involved at some serial layer that we don't often talk about: +// linking -- since we're a content-addressed system at heart -- necessarily +// involves understanding of concrete serialization details: +// which encoding mechanisms to use, what string escaping, what hashing, etc, +// and indeed what concrete serial link representation itself to use. +// +// Link is an abstract interface so that we can describe Nodes without +// getting stuck on specific details of any link representation. +// In practice, you'll almost certainly use CIDs for linking. +// However, it's possible to bring your own Link implementations +// (though this'll almost certainly involve also bringing your own encoding +// systems; it's a lot of work). +// It's even possible to use IPLD *entirely without* any linking implementation, +// using it purely for json/cbor via the encoding packages and +// foregoing the advanced traversal features around transparent link loading. +type Link interface { + // Load consumes serial data from a Loader and funnels the parsed + // data into a NodeAssembler. + // + // The provided Loader function is used to get a reader for the raw + // serialized content; the Link contains an understanding of how to + // select a decoder (and hasher for verification, etc); and the + // NodeAssembler accumulates the final results (which you can + // presumably access from elsewhere; Load is designed not to know + // about this). + Load(context.Context, LinkContext, NodeAssembler, Loader) error + + // LinkBuilder returns a handle to any parameters of the Link which + // are needed to create a new Link of the same style but with new content. + // (It's much like the relationship of Node/NodeBuilder.) + // + // (If you're familiar with CIDs, you can think of this method as + // corresponding closely to `cid.Prefix()`, just more abstractly.) + LinkBuilder() LinkBuilder + + // String should return a reasonably human-readable debug-friendly + // representation of a Link. It should only be used for debug and + // log message purposes; there is no contract that requires that the + // string be able to be parsed back into a reified Link. + String() string +} + +// LinkBuilder encapsulates any implementation details and parameters +// necessary for taking a Node and converting it to a serial representation +// and returning a Link to that data. +// +// The serialized bytes will be routed through the provided Storer system, +// which is expected to store them in some way such that a related Loader +// system can later use the Link and an associated Loader to load nodes +// of identical content. +// +// LinkBuilder, like Link, is an abstract interface. +// If using CIDs as an implementation, LinkBuilder will encapsulate things +// like multihashType, multicodecType, and cidVersion, for example. +type LinkBuilder interface { + Build(context.Context, LinkContext, Node, Storer) (Link, error) +} + +// Loader functions are used to get a reader for raw serialized content +// based on the lookup information in a Link. +// A loader function is used by providing it to a Link.Load() call. +// +// Loaders typically have some filesystem or database handle contained +// within their closure which is used to satisfy read operations. +// +// LinkContext objects can be provided to give additional information +// to the loader, and will be automatically filled out when a Loader +// is used by systems in the traversal package; most Loader implementations +// should also work fine when given the zero value of LinkContext. +// +// Loaders are implicitly coupled to a Link implementation and have some +// "extra" knowledge of the concrete Link type. This necessary since there is +// no mandated standard for how to serially represent Link itself, and such +// a representation is typically needed by a Storer implementation. +type Loader func(lnk Link, lnkCtx LinkContext) (io.Reader, error) + +// Storer functions are used to a get a writer for raw serialized content, +// which will be committed to storage indexed by Link. +// A stoerer function is used by providing it to a LinkBuilder.Build() call. +// +// The storer system comes in two parts: the Storer itself *starts* a storage +// operation (presumably to some e.g. tempfile) and returns a writer; the +// StoreCommitter returned with the writer is used to *commit* the final storage +// (much like a 'Close' operation for the writer). +// +// Storers typically have some filesystem or database handle contained +// within their closure which is used to satisfy read operations. +// +// LinkContext objects can be provided to give additional information +// to the storer, and will be automatically filled out when a Storer +// is used by systems in the traversal package; most Storer implementations +// should also work fine when given the zero value of LinkContext. +// +// Storers are implicitly coupled to a Link implementation and have some +// "extra" knowledge of the concrete Link type. This necessary since there is +// no mandated standard for how to serially represent Link itself, and such +// a representation is typically needed by a Storer implementation. +type Storer func(lnkCtx LinkContext) (io.Writer, StoreCommitter, error) + +// StoreCommitter is a thunk returned by a Storer which is used to "commit" +// the storage operation. It should be called after the associated writer +// is finished, similar to a 'Close' method, but further takes a Link parameter, +// which is the identity of the content. Typically, this will cause an atomic +// operation in the storage system to move the already-written content into +// a final place (e.g. rename a tempfile) determined by the Link. +// (The Link parameter is necessarily only given at the end of the process +// rather than the beginning to so that we can have content-addressible +// semantics while also supporting streaming writes.) +type StoreCommitter func(Link) error + +// LinkContext is a parameter to Storer and Loader functions. +// +// An example use of LinkContext might be inspecting the LinkNode, and if +// it's a typed node, inspecting its Type property; then, a Loader might +// deciding on whether or not we want to load objects of that Type. +// This might be used to do a traversal which looks at all directory objects, +// but not file contents, for example. +type LinkContext struct { + LinkPath Path + LinkNode Node // has the Link again, but also might have type info // always zero for writing new nodes, for obvi reasons. + ParentNode Node +} + +// n.b. if I had java, this would all indeed be generic: +// `Link<$T>`, `LinkBuilder<$T>`, `Storer<$T>`, etc would be an explicit family. +// ... Then again, in java, that'd prevent composition of a Storer or Loader +// which could support more than one concrete type, so. ¯\_(ツ)_/¯ diff --git a/vendor/github.com/ipld/go-ipld-prime/linking/cid/cidLink.go b/vendor/github.com/ipld/go-ipld-prime/linking/cid/cidLink.go new file mode 100644 index 0000000000..e8561a4df5 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/linking/cid/cidLink.go @@ -0,0 +1,92 @@ +package cidlink + +import ( + "bytes" + "context" + "fmt" + "io" + + cid "github.com/ipfs/go-cid" + ipld "github.com/ipld/go-ipld-prime" +) + +var ( + _ ipld.Link = Link{} + _ ipld.LinkBuilder = LinkBuilder{} +) + +type Link struct { + cid.Cid +} + +func (lnk Link) Load(ctx context.Context, lnkCtx ipld.LinkContext, na ipld.NodeAssembler, loader ipld.Loader) error { + // Open the byte reader. + r, err := loader(lnk, lnkCtx) + if err != nil { + return err + } + // Tee into hash checking and unmarshalling. + mcDecoder, exists := multicodecDecodeTable[lnk.Prefix().Codec] + if !exists { + return fmt.Errorf("no decoder registered for multicodec %d", lnk.Prefix().Codec) + } + var hasher bytes.Buffer // multihash only exports bulk use, which is... really inefficient and should be fixed. + decodeErr := mcDecoder(na, io.TeeReader(r, &hasher)) + // Error checking order here is tricky. + // If decoding errored out, we should still run the reader to the end, to check the hash. + // (We still don't implement this by running the hash to the end first, because that would increase the high-water memory requirement.) + // ((Which we experience right now anyway because multihash's interface is silly, but we're acting as if that's fixed or will be soon.)) + // If the hash is rejected, we should return that error (and even if there was a decodeErr, it becomes irrelevant). + if decodeErr != nil { + _, err := io.Copy(&hasher, r) + if err != nil { + return err + } + } + cid, err := lnk.Prefix().Sum(hasher.Bytes()) + if err != nil { + return err + } + if cid != lnk.Cid { + return fmt.Errorf("hash mismatch! %q (actual) != %q (expected)", cid, lnk.Cid) + } + if decodeErr != nil { + return decodeErr + } + return nil +} +func (lnk Link) LinkBuilder() ipld.LinkBuilder { + return LinkBuilder{lnk.Cid.Prefix()} +} +func (lnk Link) String() string { + return lnk.Cid.String() +} + +type LinkBuilder struct { + cid.Prefix +} + +func (lb LinkBuilder) Build(ctx context.Context, lnkCtx ipld.LinkContext, node ipld.Node, storer ipld.Storer) (ipld.Link, error) { + // Open the byte writer. + w, commit, err := storer(lnkCtx) + if err != nil { + return nil, err + } + // Marshal, teeing into the storage writer and the hasher. + mcEncoder, exists := multicodecEncodeTable[lb.Prefix.Codec] + if !exists { + return nil, fmt.Errorf("no encoder registered for multicodec %d", lb.Prefix.Codec) + } + var hasher bytes.Buffer // multihash-via-cid only exports bulk use, which is... really inefficient and should be fixed. + w = io.MultiWriter(&hasher, w) + err = mcEncoder(node, w) + if err != nil { + return nil, err + } + cid, err := lb.Prefix.Sum(hasher.Bytes()) + lnk := Link{cid} + if err := commit(lnk); err != nil { + return lnk, err + } + return lnk, nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodec.go b/vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodec.go new file mode 100644 index 0000000000..510e041177 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodec.go @@ -0,0 +1,42 @@ +package cidlink + +import ( + "io" + + ipld "github.com/ipld/go-ipld-prime" +) + +type MulticodecDecodeTable map[uint64]MulticodecDecoder + +type MulticodecEncodeTable map[uint64]MulticodecEncoder + +// MulticodecDecoder builds an ipld.Node by unmarshalling bytes and funnelling +// the data tree into an ipld.NodeAssembler. The resulting Node is not +// returned; typically you call this function with an ipld.NodeBuilder, +// and you can extract the result from there. +// +// MulticodecDecoder are used by registering them in a MulticodecDecoderTable, +// which makes them available to be used internally by cidlink.Link.Load. +// +// Consider implementing decoders to probe their NodeBuilder to see if it +// has special features that may be able to do the job more efficiently. +// For example, ipldcbor.NodeBuilder has special unmarshaller functions +// that know how to fastpath their work *if* we're doing a cbor decode; +// if possible, detect and use that; if not, fall back to general generic +// NodeBuilder usage. +type MulticodecDecoder func(ipld.NodeAssembler, io.Reader) error + +// MulticodecEncoder marshals and ipld.Node into bytes and sends them to +// an io.Writer. +// +// MulticodecEncoder are used by registering them in a MulticodecEncoderTable, +// which makes them available to be used internally by cidlink.LinkBuilder. +// +// Tends to be implemented by probing the node to see if it matches a special +// interface that we know can do this particular kind of encoding +// (e.g. if you're using ipldgit.Node and making a MulticodecEncoder to register +// as the rawgit multicodec, you'll probe for that specific thing, since it's +// implemented on the node itself), +// but may also be able to work based on the ipld.Node interface alone +// (e.g. you can do dag-cbor to any kind of Node). +type MulticodecEncoder func(ipld.Node, io.Writer) error diff --git a/vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodecRegistry.go b/vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodecRegistry.go new file mode 100644 index 0000000000..f24f8decca --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/linking/cid/multicodecRegistry.go @@ -0,0 +1,35 @@ +package cidlink + +import "fmt" + +var ( + multicodecDecodeTable MulticodecDecodeTable + multicodecEncodeTable MulticodecEncodeTable +) + +func init() { + multicodecEncodeTable = make(MulticodecEncodeTable) + multicodecDecodeTable = make(MulticodecDecodeTable) +} + +// RegisterMulticodecDecoder is used to register multicodec features. +// It adjusts a global registry and may only be used at program init time; +// it is meant to provide a plugin system, not a configuration mechanism. +func RegisterMulticodecDecoder(hook uint64, fn MulticodecDecoder) { + _, exists := multicodecDecodeTable[hook] + if exists { + panic(fmt.Errorf("multicodec decoder already registered for %x", hook)) + } + multicodecDecodeTable[hook] = fn +} + +// RegisterMulticodecEncoder is used to register multicodec features. +// It adjusts a global registry and may only be used at program init time; +// it is meant to provide a plugin system, not a configuration mechanism. +func RegisterMulticodecEncoder(hook uint64, fn MulticodecEncoder) { + _, exists := multicodecEncodeTable[hook] + if exists { + panic(fmt.Errorf("multicodec encoder already registered for %x", hook)) + } + multicodecEncodeTable[hook] = fn +} diff --git a/vendor/github.com/ipld/go-ipld-prime/module.tl b/vendor/github.com/ipld/go-ipld-prime/module.tl new file mode 100644 index 0000000000..b4caed74ce --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/module.tl @@ -0,0 +1,24 @@ +{ + "imports": { + "base": "catalog:early.polydawn.io/monolith/busybash:v1:linux-amd64", + "go": "catalog:early.hyphae.polydawn.io/go:v1.10:linux-amd64", + "src": "ingest:git:.:HEAD" + }, + "steps": { + "test": { + "operation": { + "inputs": { + "/": "base" + "/app/go": "go" + "/task": "src" + }, + "action": { + "exec": [ + "/bin/bash", "-c", + "export PATH=$PATH:/app/go/go/bin && export GOPATH=$PWD/.gopath && go test ./..." + ] + } + } + } + } +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node.go b/vendor/github.com/ipld/go-ipld-prime/node.go new file mode 100644 index 0000000000..45834d12c2 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node.go @@ -0,0 +1,274 @@ +package ipld + +// Node represents a value in IPLD. Any point in a tree of data is a node: +// scalar values (like int, string, etc) are nodes, and +// so are recursive values (like map and list). +// +// Nodes and kinds are described in the IPLD specs at +// https://github.com/ipld/specs/blob/master/data-model-layer/data-model.md . +// +// Methods on the Node interface cover the superset of all possible methods for +// all possible kinds -- but some methods only make sense for particular kinds, +// and thus will only make sense to call on values of the appropriate kind. +// (For example, 'Length' on an int doesn't make sense, +// and 'AsInt' on a map certainly doesn't work either!) +// Use the ReprKind method to find out the kind of value before +// calling kind-specific methods. +// Individual method documentation state which kinds the method is valid for. +// (If you're familiar with the stdlib reflect package, you'll find +// the design of the Node interface very comparable to 'reflect.Value'.) +// +// The Node interface is read-only. All of the methods on the interface are +// for examining values, and implementations should be immutable. +// The companion interface, NodeBuilder, provides the matching writable +// methods, and should be use to create a (thence immutable) Node. +// +// Keeping Node immutable and separating mutation into NodeBuilder makes +// it possible to perform caching (or rather, memoization, since there's no +// such thing as cache invalidation for immutable systems) of computed +// properties of Node; use copy-on-write algorithms for memory efficiency; +// and to generally build pleasant APIs. +// Many library functions will rely on the immutability of Node (e.g., +// assuming that pointer-equal nodes do not change in value over time), +// so any user-defined Node implementations should be careful to uphold +// the immutability contract.) +// +// There are many different concrete types which implement Node. +// The primary purpose of various node implementations is to organize +// memory in the program in different ways -- some in-memory layouts may +// be more optimal for some programs than others, and changing the Node +// (and NodeBuilder) implementations lets the programmer choose. +// +// For concrete implementations of Node, check out the "./impl/" folder, +// and the packages within it. +// "impl/free" should probably be your first start; the Node and NodeBuilder +// implementations in that package work for any data. +// Other packages are optimized for specific use-cases. +// Codegen tools can also be used to produce concrete implementations of Node; +// these may be specific to certain data, but still conform to the Node +// interface for interoperability and to support higher-level functions. +// +// Nodes may also be *typed* -- see the 'schema' and 'impl/typed' packages. +// Typed nodes have additional constraints and behaviors (and have a +// `.Type().Kind()` in addition to their `.ReprKind()`!), but still behave +// as a regular Node in all the basic ways. +type Node interface { + // ReprKind returns a value from the ReprKind enum describing what the + // essential serializable kind of this node is (map, list, int, etc). + // Most other handling of a node requires first switching upon the kind. + ReprKind() ReprKind + + // LookupString looks up a child object in this node and returns it. + // The returned Node may be any of the ReprKind: + // a primitive (string, int, etc), a map, a list, or a link. + // + // If the Kind of this Node is not ReprKind_Map, a nil node and an error + // will be returned. + // + // If the key does not exist, a nil node and an error will be returned. + LookupString(key string) (Node, error) + + // Lookup is the equivalent of LookupString, but takes a reified Node + // as a parameter instead of a plain string. + // This mechanism is useful if working with typed maps (if the key types + // have constraints, and you already have a reified `schema.TypedNode` value, + // using that value can save parsing and validation costs); + // and may simply be convenient if you already have a Node value in hand. + // + // (When writing generic functions over Node, a good rule of thumb is: + // when handling a map, check for `schema.TypedNode`, and in this case prefer + // the Lookup(Node) method; otherwise, favor LookupString; typically + // implementations will have their fastest paths thusly.) + Lookup(key Node) (Node, error) + + // LookupIndex is the equivalent of LookupString but for indexing into a list. + // As with LookupString, the returned Node may be any of the ReprKind: + // a primitive (string, int, etc), a map, a list, or a link. + // + // If the Kind of this Node is not ReprKind_List, a nil node and an error + // will be returned. + // + // If idx is out of range, a nil node and an error will be returned. + LookupIndex(idx int) (Node, error) + + // LookupSegment is will act as either LookupString or LookupIndex, + // whichever is contextually appropriate. + // + // Using LookupSegment may imply an "atoi" conversion if used on a list node, + // or an "itoa" conversion if used on a map node. If an "itoa" conversion + // takes place, it may error, and this method may return that error. + LookupSegment(seg PathSegment) (Node, error) + + // Note that when using codegenerated types, there may be a fifth variant + // of lookup method on maps: `Get($GeneratedTypeKey) $GeneratedTypeValue`! + + // MapIterator returns an iterator which yields key-value pairs + // traversing the node. + // If the node kind is anything other than a map, nil will be returned. + // + // The iterator will yield every entry in the map; that is, it + // can be expected that itr.Next will be called node.Length times + // before itr.Done becomes true. + MapIterator() MapIterator + + // ListIterator returns an iterator which yields key-value pairs + // traversing the node. + // If the node kind is anything other than a list, nil will be returned. + // + // The iterator will yield every entry in the list; that is, it + // can be expected that itr.Next will be called node.Length times + // before itr.Done becomes true. + ListIterator() ListIterator + + // Length returns the length of a list, or the number of entries in a map, + // or -1 if the node is not of list nor map kind. + Length() int + + // Undefined nodes are returned when traversing a struct field that is + // defined by a schema but unset in the data. (Undefined nodes are not + // possible otherwise; you'll only see them from `schema.TypedNode`.) + // The undefined flag is necessary so iterating over structs can + // unambiguously make the distinction between values that are + // present-and-null versus values that are absent. + IsUndefined() bool + + IsNull() bool + AsBool() (bool, error) + AsInt() (int, error) + AsFloat() (float64, error) + AsString() (string, error) + AsBytes() ([]byte, error) + AsLink() (Link, error) + + // Style returns a NodeStyle which can describe some properties of this node's implementation, + // and also be used to get a NodeBuilder, + // which can be use to create new nodes with the same implementation as this one. + // + // For typed nodes, the NodeStyle will also implement schema.Type. + // + // For Advanced Data Layouts, the NodeStyle will encapsulate any additional + // parameters and configuration of the ADL, and will also (usually) + // implement NodeStyleSupportingAmend. + // + // Calling this method should not cause an allocation. + Style() NodeStyle +} + +// NodeStyle describes a node implementation (all Node have a NodeStyle), +// and a NodeStyle can always be used to get a NodeBuilder. +// +// A NodeStyle may also provide other information about implementation; +// such information is specific to this library ("style" isn't a concept +// you'll find in the IPLD Specifications), and is usually provided through +// feature-detection interfaces (for example, see NodeStyleSupportingAmend). +// +// Generic algorithms for working with IPLD Nodes make use of NodeStyle +// to get builders for new nodes when creating data, and can also use the +// feature-detection interfaces to help decide what kind of operations +// will be optimal to use on a given node implementation. +// +// Note that NodeStyle is not the same as schema.Type. +// NodeStyle is a (golang-specific!) way to reflect upon the implementation +// and in-memory layout of some IPLD data. +// schema.Type is information about how a group of nodes is related in a schema +// (if they have one!) and the rules that the type mandates the node must follow. +// (Every node must have a style; but schema types are an optional feature.) +type NodeStyle interface { + // NewBuilder returns a NodeBuilder that can be used to create a new Node. + // + // Note that calling NewBuilder often performs an allocation + // (while in contrast, getting a NodeStyle typically does not!) -- + // this may be consequential when writing high performance code. + NewBuilder() NodeBuilder +} + +// NodeStyleSupportingAmend is a feature-detection interface that can be +// used on a NodeStyle to see if it's possible to build new nodes of this style +// while sharing some internal data in a copy-on-write way. +// +// For example, Nodes using an Advanced Data Layout will typically +// support this behavior, and since ADLs are often used for handling large +// volumes of data, detecting and using this feature can result in significant +// performance savings. +type NodeStyleSupportingAmend interface { + AmendingBuilder(base Node) NodeBuilder + // FUTURE: probably also needs a `AmendingWithout(base Node, filter func(k,v) bool) NodeBuilder`, or similar. + // ("deletion" based APIs are also possible but both more complicated in interfaces added, and prone to accidentally quadratic usage.) + // FUTURE: there should be some stdlib `Copy` (?) methods that automatically look for this feature, and fallback if absent. + // Might include a wide range of point `Transform`, etc, methods. + // FUTURE: consider putting this (and others like it) in a `feature` package, if there begin to be enough of them and docs get crowded. +} + +// MapIterator is an interface for traversing map nodes. +// Sequential calls to Next() will yield key-value pairs; +// Done() describes whether iteration should continue. +// +// Iteration order is defined to be stable: two separate MapIterator +// created to iterate the same Node will yield the same key-value pairs +// in the same order. +// The order itself may be defined by the Node implementation: some +// Nodes may retain insertion order, and some may return iterators which +// always yield data in sorted order, for example. +type MapIterator interface { + // Next returns the next key-value pair. + // + // An error value can also be returned at any step: in the case of advanced + // data structures with incremental loading, it's possible to encounter + // cancellation or I/O errors at any point in iteration. + // If an error is returned, the boolean will always be false (so it's + // correct to check the bool first and short circuit to continuing if true). + // If an error is returned, the key and value may be nil. + Next() (key Node, value Node, err error) + + // Done returns false as long as there's at least one more entry to iterate. + // When Done returns true, iteration can stop. + // + // Note when implementing iterators for advanced data layouts (e.g. more than + // one chunk of backing data, which is loaded incrementally): if your + // implementation does any I/O during the Done method, and it encounters + // an error, it must return 'false', so that the following Next call + // has an opportunity to return the error. + Done() bool +} + +// ListIterator is an interface for traversing list nodes. +// Sequential calls to Next() will yield index-value pairs; +// Done() describes whether iteration should continue. +// +// A loop which iterates from 0 to Node.Length is a valid +// alternative to using a ListIterator. +type ListIterator interface { + // Next returns the next index and value. + // + // An error value can also be returned at any step: in the case of advanced + // data structures with incremental loading, it's possible to encounter + // cancellation or I/O errors at any point in iteration. + // If an error is returned, the boolean will always be false (so it's + // correct to check the bool first and short circuit to continuing if true). + // If an error is returned, the key and value may be nil. + Next() (idx int, value Node, err error) + + // Done returns false as long as there's at least one more entry to iterate. + // When Done returns false, iteration can stop. + // + // Note when implementing iterators for advanced data layouts (e.g. more than + // one chunk of backing data, which is loaded incrementally): if your + // implementation does any I/O during the Done method, and it encounters + // an error, it must return 'false', so that the following Next call + // has an opportunity to return the error. + Done() bool +} + +// REVIEW: immediate-mode AsBytes() method (as opposed to e.g. returning +// an io.Reader instance) might be problematic, esp. if we introduce +// AdvancedLayouts which support large bytes natively. +// +// Probable solution is having both immediate and iterator return methods. +// Returning a reader for bytes when you know you want a slice already +// is going to be high friction without purpose in many common uses. +// +// Unclear what SetByteStream() would look like for advanced layouts. +// One could try to encapsulate the chunking entirely within the advlay +// node impl... but would it be graceful? Not sure. Maybe. Hopefully! +// Yes? The advlay impl would still tend to use SetBytes for the raw +// data model layer nodes its composing, so overall, it shakes out nicely. diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/HACKME.md b/vendor/github.com/ipld/go-ipld-prime/node/basic/HACKME.md new file mode 100644 index 0000000000..fa090f9fef --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/HACKME.md @@ -0,0 +1,145 @@ +hackme +====== + +Design rationale are documented here. + +This doc is not necessary reading for users of this package, +but if you're considering submitting patches -- or just trying to understand +why it was written this way, and check for reasoning that might be dated -- +then it might be useful reading. + +### scalars are just typedefs + +This is noteworthy because in codegen, this is typically *not* the case: +in codegen, even scalar types are boxed in a struct, such that it prevents +casting values into those types. + +This casting is not a concern for ipldfree types, because +A) we don't have any kind of validation rules to make such casting worrying; and +B) since our types are unexported, casting is still blocked by this anyway. + +### about builders for scalars + +The assembler types for scalars (string, int, etc) are pretty funny-looking. +You might wish to make them work without any state at all! + +The reason this doesn't fly is that we have to keep the "wip" value in hand +just long enough to return it from the `NodeBuilder.Build` method -- the +`NodeAssembler` contract for `Assign*` methods doesn't permit just returning +their results immediately. + +(Another possible reason is if we expected to use these assemblers on +slab-style allocations (say, `[]plainString`)... +however, this is inapplicable at present, because +A) we don't (except places that have special-case internal paths anyway); and +B) the types aren't exported, so users can't either.) + +Does this mean that using `NodeBuilder` for scalars has a completely +unnecessary second allocation, which is laughably inefficient? Yes. +It's unfortunate the interfaces constrain us to this. +**But**: one typically doesn't actually use builders for scalars much; +they're just here for completeness. +So this is less of a problem in practice than it might at first seem. + +More often, one will use the "any" builder (which is has a whole different set +of design constraints and tradeoffs); +or, if one is writing code and knows which scalar they need, the exported +direct constructor function for that kind +(e.g., `String("foo")` instead of `Style__String{}.NewBuilder().AssignString("foo")`) +will do the right thing and do it in one allocation (and it's less to type, too). + +### maps and list keyAssembler and valueAssemblers have custom scalar handling + +Related to the above heading. + +Maps and lists in this package do their own internal handling of scalars, +using unexported features inside the package, because they can more efficient. + +### when to invalidate the 'w' pointers + +The 'w' pointer -- short for 'wip' node pointer -- has an interesting lifecycle. + +In a NodeAssembler, the 'w' pointer should be intialized before the assembler is used. +This means either the matching NodeBuilder type does so; or, +if we're inside recursive structure, the parent assembler did so. + +The 'w' pointer is used throughout the life of the assembler. + +Setting the 'w' pointer to nil is one of two mechanisms used internally +to mark that assembly has become "finished" (the other mechanism is using +an internal state enum field). +Setting the 'w' pointer to nil has two advantages: +one is that it makes it *impossible* to continue to mutate the target node; +the other is that we need no *additional* memory to track this state change. +However, we can't use the strategy of nilling 'w' in all cases: in particular, +when in the NodeBuilder at the root of some construction, +we need to continue to hold onto the node between when it becomes "finished" +and when Build is called; otherwise we can't actually return the value! +Different stratgies are therefore used in different parts of this package. + +Maps and lists use an internal state enum, because they already have one, +and so they might as well; there's no additional cost to this. +Since they can use this state to guard against additional mutations after "finish", +the map and list assemblers don't bother to nil their own 'w' at all. + +During recursion to assemble values _inside_ maps and lists, it's interesting: +the child assembler wrapper type takes reponsibility for nilling out +the 'w' pointer in the child assembler's state, doing this at the same time as +it updates the parent's state machine to clear proceeding with the next entry. + +In the case of scalars at the root of a build, we took a shortcut: +we actually don't fence against repeat mutations at all. +*You can actually use the assign method more than once*. +We can do this without breaking safety contracts because the scalars +all have a pass-by-value phase somewhere in their lifecycle +(calling `nb.AssignString("x")`, then `n := nb.Build()`, then `nb.AssignString("y")` +won't error if `nb` is a freestanding builder for strings... but it also +won't result in mutating `n` to contain `"y"`, so overall, it's safe). + +We could normalize the case with scalars at the root of a tree so that they +error more aggressively... but currently we haven't bothered, since this would +require adding another piece of memory to the scalar builders; and meanwhile +we're not in trouble on compositional correctness. + +Note that these remarks are for the `basicnode` package, but may also +apply to other implementations too (e.g., our codegen output follows similar +overall logic). + +### nodestyles are available through a singleton + +Every NodeStyle available from this package is exposed as a field +in a struct of which there's one public exported instance available, +called 'Style'. + +This means you can use it like this: + +```go +nbm := basicnode.Style.Map.NewBuilder() +nbs := basicnode.Style.String.NewBuilder() +nba := basicnode.Style.Any.NewBuilder() +// etc +``` + +(If you're interested in the performance of this: it's free! +Methods called at the end of the chain are inlinable. +Since all of the types of the structures on the way there are zero-member +structs, the compiler can effectively treat them as constants, +and thus freely elide any memory dereferences that would +otherwise be necessary to get methods on such a value.) + +### nodestyles are (also) available as exported concrete types + +The 'Style' singleton is one way to access the NodeStyle in this package; +their exported types are another equivalent way. + +```go +basicnode.Style.Map = basicnode.Style__Map{} +``` + +It is recommended to use the singleton style; +they compile to identical assembly, and the singleton is syntactically prettier. + +We may make these concrete types unexported in the future. +A decision on this is deferred until some time has passed and +we can accumulate reasonable certainty that there's no need for an exported type +(such as type assertions, etc). diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/any.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/any.go new file mode 100644 index 0000000000..708de6decf --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/any.go @@ -0,0 +1,200 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +var ( + //_ ipld.Node = &anyNode{} + _ ipld.NodeStyle = Style__Any{} + _ ipld.NodeBuilder = &anyBuilder{} + //_ ipld.NodeAssembler = &anyAssembler{} +) + +// anyNode is a union meant for alloc amortization; see anyAssembler. +// Note that anyBuilder doesn't use anyNode, because it's not aiming to amortize anything. +// +// REVIEW: if there's any point in keeping this around. It's here for completeness, +// but not currently used anywhere in package, and also not currently exported. +// type anyNode struct { +// kind ipld.ReprKind +// +// plainMap +// plainList +// plainBool +// plainInt +// plainFloat +// plainString +// plainBytes +// plainLink +// } + +// -- Node interface methods --> + +// Unimplemented at present -- see "REVIEW" comment on anyNode. + +// -- NodeStyle --> + +type Style__Any struct{} + +func (Style__Any) NewBuilder() ipld.NodeBuilder { + return &anyBuilder{} +} + +// -- NodeBuilder --> + +// anyBuilder is a builder for any kind of node. +// +// anyBuilder is a little unusual in its internal workings: +// unlike most builders, it doesn't embed the corresponding assembler, +// nor will it end up using anyNode, +// but instead embeds a builder for each of the kinds it might contain. +// This is because we want a more granular return at the end: +// if we used anyNode, and returned a pointer to just the relevant part of it, +// we'd have all the extra bytes of anyNode still reachable in GC terms +// for as long as that handle to the interior of it remains live. +type anyBuilder struct { + // kind is set on first interaction, and used to select which builder to delegate 'Build' to! + // As soon as it's been set to a value other than zero (being "Invalid"), all other Assign/Begin calls will fail since something is already in progress. + // May also be set to the magic value '99', which means "i dunno, I'm just carrying another node of unknown style". + kind ipld.ReprKind + + // Only one of the following ends up being used... + // but we don't know in advance which one, so all are embeded here. + // This uses excessive space, but amortizes allocations, and all will be + // freed as soon as the builder is done. + // Builders are only used for recursives; + // scalars are simple enough we just do them directly. + // 'scalarNode' may also hold another Node of unknown style (possibly not even from this package), + // in which case this is indicated by 'kind==99'. + + mapBuilder plainMap__Builder + listBuilder plainList__Builder + scalarNode ipld.Node +} + +func (nb *anyBuilder) Reset() { + *nb = anyBuilder{} +} + +func (nb *anyBuilder) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_Map + nb.mapBuilder.w = &plainMap{} + return nb.mapBuilder.BeginMap(sizeHint) +} +func (nb *anyBuilder) BeginList(sizeHint int) (ipld.ListAssembler, error) { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_List + nb.listBuilder.w = &plainList{} + return nb.listBuilder.BeginList(sizeHint) +} +func (nb *anyBuilder) AssignNull() error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_Null + return nil +} +func (nb *anyBuilder) AssignBool(v bool) error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_Bool + nb.scalarNode = NewBool(v) + return nil +} +func (nb *anyBuilder) AssignInt(v int) error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_Int + nb.scalarNode = NewInt(v) + return nil +} +func (nb *anyBuilder) AssignFloat(v float64) error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_Float + nb.scalarNode = NewFloat(v) + return nil +} +func (nb *anyBuilder) AssignString(v string) error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_String + nb.scalarNode = NewString(v) + return nil +} +func (nb *anyBuilder) AssignBytes(v []byte) error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_Bytes + nb.scalarNode = NewBytes(v) + return nil +} +func (nb *anyBuilder) AssignLink(v ipld.Link) error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = ipld.ReprKind_Link + nb.scalarNode = NewLink(v) + return nil +} +func (nb *anyBuilder) AssignNode(v ipld.Node) error { + if nb.kind != ipld.ReprKind_Invalid { + panic("misuse") + } + nb.kind = 99 + nb.scalarNode = v + return nil +} +func (anyBuilder) Style() ipld.NodeStyle { + return Style__Any{} +} + +func (nb *anyBuilder) Build() ipld.Node { + switch nb.kind { + case ipld.ReprKind_Invalid: + panic("misuse") + case ipld.ReprKind_Map: + return nb.mapBuilder.Build() + case ipld.ReprKind_List: + return nb.listBuilder.Build() + case ipld.ReprKind_Null: + return ipld.Null + case ipld.ReprKind_Bool: + return nb.scalarNode + case ipld.ReprKind_Int: + return nb.scalarNode + case ipld.ReprKind_Float: + return nb.scalarNode + case ipld.ReprKind_String: + return nb.scalarNode + case ipld.ReprKind_Bytes: + return nb.scalarNode + case ipld.ReprKind_Link: + return nb.scalarNode + case 99: + return nb.scalarNode + default: + panic("unreachable") + } +} + +// -- NodeAssembler --> + +// ... oddly enough, we seem to be able to put off implementing this +// until we also implement something that goes full-hog on amortization +// and actually has a slab of `anyNode`. Which so far, nothing does. +// See "REVIEW" comment on anyNode. +// type anyAssembler struct { +// w *anyNode +// } diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/bool.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/bool.go new file mode 100644 index 0000000000..bb2489ebed --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/bool.go @@ -0,0 +1,144 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = plainBool(false) + _ ipld.NodeStyle = Style__Bool{} + _ ipld.NodeBuilder = &plainBool__Builder{} + _ ipld.NodeAssembler = &plainBool__Assembler{} +) + +func NewBool(value bool) ipld.Node { + v := plainBool(value) + return &v +} + +// plainBool is a simple boxed boolean that complies with ipld.Node. +type plainBool bool + +// -- Node interface methods --> + +func (plainBool) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Bool +} +func (plainBool) LookupString(string) (ipld.Node, error) { + return mixins.Bool{"bool"}.LookupString("") +} +func (plainBool) Lookup(key ipld.Node) (ipld.Node, error) { + return mixins.Bool{"bool"}.Lookup(nil) +} +func (plainBool) LookupIndex(idx int) (ipld.Node, error) { + return mixins.Bool{"bool"}.LookupIndex(0) +} +func (plainBool) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + return mixins.Bool{"bool"}.LookupSegment(seg) +} +func (plainBool) MapIterator() ipld.MapIterator { + return nil +} +func (plainBool) ListIterator() ipld.ListIterator { + return nil +} +func (plainBool) Length() int { + return -1 +} +func (plainBool) IsUndefined() bool { + return false +} +func (plainBool) IsNull() bool { + return false +} +func (n plainBool) AsBool() (bool, error) { + return bool(n), nil +} +func (plainBool) AsInt() (int, error) { + return mixins.Bool{"bool"}.AsInt() +} +func (plainBool) AsFloat() (float64, error) { + return mixins.Bool{"bool"}.AsFloat() +} +func (plainBool) AsString() (string, error) { + return mixins.Bool{"bool"}.AsString() +} +func (plainBool) AsBytes() ([]byte, error) { + return mixins.Bool{"bool"}.AsBytes() +} +func (plainBool) AsLink() (ipld.Link, error) { + return mixins.Bool{"bool"}.AsLink() +} +func (plainBool) Style() ipld.NodeStyle { + return Style__Bool{} +} + +// -- NodeStyle --> + +type Style__Bool struct{} + +func (Style__Bool) NewBuilder() ipld.NodeBuilder { + var w plainBool + return &plainBool__Builder{plainBool__Assembler{w: &w}} +} + +// -- NodeBuilder --> + +type plainBool__Builder struct { + plainBool__Assembler +} + +func (nb *plainBool__Builder) Build() ipld.Node { + return nb.w +} +func (nb *plainBool__Builder) Reset() { + var w plainBool + *nb = plainBool__Builder{plainBool__Assembler{w: &w}} +} + +// -- NodeAssembler --> + +type plainBool__Assembler struct { + w *plainBool +} + +func (plainBool__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.BoolAssembler{"bool"}.BeginMap(0) +} +func (plainBool__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.BoolAssembler{"bool"}.BeginList(0) +} +func (plainBool__Assembler) AssignNull() error { + return mixins.BoolAssembler{"bool"}.AssignNull() +} +func (na *plainBool__Assembler) AssignBool(v bool) error { + *na.w = plainBool(v) + return nil +} +func (plainBool__Assembler) AssignInt(int) error { + return mixins.BoolAssembler{"bool"}.AssignInt(0) +} +func (plainBool__Assembler) AssignFloat(float64) error { + return mixins.BoolAssembler{"bool"}.AssignFloat(0) +} +func (plainBool__Assembler) AssignString(string) error { + return mixins.BoolAssembler{"bool"}.AssignString("") +} +func (plainBool__Assembler) AssignBytes([]byte) error { + return mixins.BoolAssembler{"bool"}.AssignBytes(nil) +} +func (plainBool__Assembler) AssignLink(ipld.Link) error { + return mixins.BoolAssembler{"bool"}.AssignLink(nil) +} +func (na *plainBool__Assembler) AssignNode(v ipld.Node) error { + if v2, err := v.AsBool(); err != nil { + return err + } else { + *na.w = plainBool(v2) + return nil + } +} +func (plainBool__Assembler) Style() ipld.NodeStyle { + return Style__Bool{} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/bytes.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/bytes.go new file mode 100644 index 0000000000..244520814f --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/bytes.go @@ -0,0 +1,144 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = plainBytes(nil) + _ ipld.NodeStyle = Style__Bytes{} + _ ipld.NodeBuilder = &plainBytes__Builder{} + _ ipld.NodeAssembler = &plainBytes__Assembler{} +) + +func NewBytes(value []byte) ipld.Node { + v := plainBytes(value) + return &v +} + +// plainBytes is a simple boxed byte slice that complies with ipld.Node. +type plainBytes []byte + +// -- Node interface methods --> + +func (plainBytes) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Bytes +} +func (plainBytes) LookupString(string) (ipld.Node, error) { + return mixins.Bytes{"bytes"}.LookupString("") +} +func (plainBytes) Lookup(key ipld.Node) (ipld.Node, error) { + return mixins.Bytes{"bytes"}.Lookup(nil) +} +func (plainBytes) LookupIndex(idx int) (ipld.Node, error) { + return mixins.Bytes{"bytes"}.LookupIndex(0) +} +func (plainBytes) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + return mixins.Bytes{"bytes"}.LookupSegment(seg) +} +func (plainBytes) MapIterator() ipld.MapIterator { + return nil +} +func (plainBytes) ListIterator() ipld.ListIterator { + return nil +} +func (plainBytes) Length() int { + return -1 +} +func (plainBytes) IsUndefined() bool { + return false +} +func (plainBytes) IsNull() bool { + return false +} +func (plainBytes) AsBool() (bool, error) { + return mixins.Bytes{"bytes"}.AsBool() +} +func (plainBytes) AsInt() (int, error) { + return mixins.Bytes{"bytes"}.AsInt() +} +func (plainBytes) AsFloat() (float64, error) { + return mixins.Bytes{"bytes"}.AsFloat() +} +func (plainBytes) AsString() (string, error) { + return mixins.Bytes{"bytes"}.AsString() +} +func (n plainBytes) AsBytes() ([]byte, error) { + return []byte(n), nil +} +func (plainBytes) AsLink() (ipld.Link, error) { + return mixins.Bytes{"bytes"}.AsLink() +} +func (plainBytes) Style() ipld.NodeStyle { + return Style__Bytes{} +} + +// -- NodeStyle --> + +type Style__Bytes struct{} + +func (Style__Bytes) NewBuilder() ipld.NodeBuilder { + var w plainBytes + return &plainBytes__Builder{plainBytes__Assembler{w: &w}} +} + +// -- NodeBuilder --> + +type plainBytes__Builder struct { + plainBytes__Assembler +} + +func (nb *plainBytes__Builder) Build() ipld.Node { + return nb.w +} +func (nb *plainBytes__Builder) Reset() { + var w plainBytes + *nb = plainBytes__Builder{plainBytes__Assembler{w: &w}} +} + +// -- NodeAssembler --> + +type plainBytes__Assembler struct { + w *plainBytes +} + +func (plainBytes__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.BytesAssembler{"bytes"}.BeginMap(0) +} +func (plainBytes__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.BytesAssembler{"bytes"}.BeginList(0) +} +func (plainBytes__Assembler) AssignNull() error { + return mixins.BytesAssembler{"bytes"}.AssignNull() +} +func (plainBytes__Assembler) AssignBool(bool) error { + return mixins.BytesAssembler{"bytes"}.AssignBool(false) +} +func (plainBytes__Assembler) AssignInt(int) error { + return mixins.BytesAssembler{"bytes"}.AssignInt(0) +} +func (plainBytes__Assembler) AssignFloat(float64) error { + return mixins.BytesAssembler{"bytes"}.AssignFloat(0) +} +func (plainBytes__Assembler) AssignString(string) error { + return mixins.BytesAssembler{"bytes"}.AssignString("") +} +func (na *plainBytes__Assembler) AssignBytes(v []byte) error { + *na.w = plainBytes(v) + return nil +} +func (plainBytes__Assembler) AssignLink(ipld.Link) error { + return mixins.BytesAssembler{"bytes"}.AssignLink(nil) +} +func (na *plainBytes__Assembler) AssignNode(v ipld.Node) error { + if v2, err := v.AsBytes(); err != nil { + return err + } else { + *na.w = plainBytes(v2) + return nil + } +} +func (plainBytes__Assembler) Style() ipld.NodeStyle { + return Style__Bytes{} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/float.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/float.go new file mode 100644 index 0000000000..f7c824f758 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/float.go @@ -0,0 +1,144 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = plainFloat(0) + _ ipld.NodeStyle = Style__Float{} + _ ipld.NodeBuilder = &plainFloat__Builder{} + _ ipld.NodeAssembler = &plainFloat__Assembler{} +) + +func NewFloat(value float64) ipld.Node { + v := plainFloat(value) + return &v +} + +// plainFloat is a simple boxed float that complies with ipld.Node. +type plainFloat float64 + +// -- Node interface methods --> + +func (plainFloat) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Float +} +func (plainFloat) LookupString(string) (ipld.Node, error) { + return mixins.Float{"float"}.LookupString("") +} +func (plainFloat) Lookup(key ipld.Node) (ipld.Node, error) { + return mixins.Float{"float"}.Lookup(nil) +} +func (plainFloat) LookupIndex(idx int) (ipld.Node, error) { + return mixins.Float{"float"}.LookupIndex(0) +} +func (plainFloat) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + return mixins.Float{"float"}.LookupSegment(seg) +} +func (plainFloat) MapIterator() ipld.MapIterator { + return nil +} +func (plainFloat) ListIterator() ipld.ListIterator { + return nil +} +func (plainFloat) Length() int { + return -1 +} +func (plainFloat) IsUndefined() bool { + return false +} +func (plainFloat) IsNull() bool { + return false +} +func (plainFloat) AsBool() (bool, error) { + return mixins.Float{"float"}.AsBool() +} +func (plainFloat) AsInt() (int, error) { + return mixins.Float{"float"}.AsInt() +} +func (n plainFloat) AsFloat() (float64, error) { + return float64(n), nil +} +func (plainFloat) AsString() (string, error) { + return mixins.Float{"float"}.AsString() +} +func (plainFloat) AsBytes() ([]byte, error) { + return mixins.Float{"float"}.AsBytes() +} +func (plainFloat) AsLink() (ipld.Link, error) { + return mixins.Float{"float"}.AsLink() +} +func (plainFloat) Style() ipld.NodeStyle { + return Style__Float{} +} + +// -- NodeStyle --> + +type Style__Float struct{} + +func (Style__Float) NewBuilder() ipld.NodeBuilder { + var w plainFloat + return &plainFloat__Builder{plainFloat__Assembler{w: &w}} +} + +// -- NodeBuilder --> + +type plainFloat__Builder struct { + plainFloat__Assembler +} + +func (nb *plainFloat__Builder) Build() ipld.Node { + return nb.w +} +func (nb *plainFloat__Builder) Reset() { + var w plainFloat + *nb = plainFloat__Builder{plainFloat__Assembler{w: &w}} +} + +// -- NodeAssembler --> + +type plainFloat__Assembler struct { + w *plainFloat +} + +func (plainFloat__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.FloatAssembler{"float"}.BeginMap(0) +} +func (plainFloat__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.FloatAssembler{"float"}.BeginList(0) +} +func (plainFloat__Assembler) AssignNull() error { + return mixins.FloatAssembler{"float"}.AssignNull() +} +func (plainFloat__Assembler) AssignBool(bool) error { + return mixins.FloatAssembler{"float"}.AssignBool(false) +} +func (plainFloat__Assembler) AssignInt(int) error { + return mixins.FloatAssembler{"float"}.AssignInt(0) +} +func (na *plainFloat__Assembler) AssignFloat(v float64) error { + *na.w = plainFloat(v) + return nil +} +func (plainFloat__Assembler) AssignString(string) error { + return mixins.FloatAssembler{"float"}.AssignString("") +} +func (plainFloat__Assembler) AssignBytes([]byte) error { + return mixins.FloatAssembler{"float"}.AssignBytes(nil) +} +func (plainFloat__Assembler) AssignLink(ipld.Link) error { + return mixins.FloatAssembler{"float"}.AssignLink(nil) +} +func (na *plainFloat__Assembler) AssignNode(v ipld.Node) error { + if v2, err := v.AsFloat(); err != nil { + return err + } else { + *na.w = plainFloat(v2) + return nil + } +} +func (plainFloat__Assembler) Style() ipld.NodeStyle { + return Style__Float{} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/int.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/int.go new file mode 100644 index 0000000000..0d30612357 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/int.go @@ -0,0 +1,144 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = plainInt(0) + _ ipld.NodeStyle = Style__Int{} + _ ipld.NodeBuilder = &plainInt__Builder{} + _ ipld.NodeAssembler = &plainInt__Assembler{} +) + +func NewInt(value int) ipld.Node { + v := plainInt(value) + return &v +} + +// plainInt is a simple boxed int that complies with ipld.Node. +type plainInt int + +// -- Node interface methods --> + +func (plainInt) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Int +} +func (plainInt) LookupString(string) (ipld.Node, error) { + return mixins.Int{"int"}.LookupString("") +} +func (plainInt) Lookup(key ipld.Node) (ipld.Node, error) { + return mixins.Int{"int"}.Lookup(nil) +} +func (plainInt) LookupIndex(idx int) (ipld.Node, error) { + return mixins.Int{"int"}.LookupIndex(0) +} +func (plainInt) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + return mixins.Int{"int"}.LookupSegment(seg) +} +func (plainInt) MapIterator() ipld.MapIterator { + return nil +} +func (plainInt) ListIterator() ipld.ListIterator { + return nil +} +func (plainInt) Length() int { + return -1 +} +func (plainInt) IsUndefined() bool { + return false +} +func (plainInt) IsNull() bool { + return false +} +func (plainInt) AsBool() (bool, error) { + return mixins.Int{"int"}.AsBool() +} +func (n plainInt) AsInt() (int, error) { + return int(n), nil +} +func (plainInt) AsFloat() (float64, error) { + return mixins.Int{"int"}.AsFloat() +} +func (plainInt) AsString() (string, error) { + return mixins.Int{"int"}.AsString() +} +func (plainInt) AsBytes() ([]byte, error) { + return mixins.Int{"int"}.AsBytes() +} +func (plainInt) AsLink() (ipld.Link, error) { + return mixins.Int{"int"}.AsLink() +} +func (plainInt) Style() ipld.NodeStyle { + return Style__Int{} +} + +// -- NodeStyle --> + +type Style__Int struct{} + +func (Style__Int) NewBuilder() ipld.NodeBuilder { + var w plainInt + return &plainInt__Builder{plainInt__Assembler{w: &w}} +} + +// -- NodeBuilder --> + +type plainInt__Builder struct { + plainInt__Assembler +} + +func (nb *plainInt__Builder) Build() ipld.Node { + return nb.w +} +func (nb *plainInt__Builder) Reset() { + var w plainInt + *nb = plainInt__Builder{plainInt__Assembler{w: &w}} +} + +// -- NodeAssembler --> + +type plainInt__Assembler struct { + w *plainInt +} + +func (plainInt__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.IntAssembler{"int"}.BeginMap(0) +} +func (plainInt__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.IntAssembler{"int"}.BeginList(0) +} +func (plainInt__Assembler) AssignNull() error { + return mixins.IntAssembler{"int"}.AssignNull() +} +func (plainInt__Assembler) AssignBool(bool) error { + return mixins.IntAssembler{"int"}.AssignBool(false) +} +func (na *plainInt__Assembler) AssignInt(v int) error { + *na.w = plainInt(v) + return nil +} +func (plainInt__Assembler) AssignFloat(float64) error { + return mixins.IntAssembler{"int"}.AssignFloat(0) +} +func (plainInt__Assembler) AssignString(string) error { + return mixins.IntAssembler{"int"}.AssignString("") +} +func (plainInt__Assembler) AssignBytes([]byte) error { + return mixins.IntAssembler{"int"}.AssignBytes(nil) +} +func (plainInt__Assembler) AssignLink(ipld.Link) error { + return mixins.IntAssembler{"int"}.AssignLink(nil) +} +func (na *plainInt__Assembler) AssignNode(v ipld.Node) error { + if v2, err := v.AsInt(); err != nil { + return err + } else { + *na.w = plainInt(v2) + return nil + } +} +func (plainInt__Assembler) Style() ipld.NodeStyle { + return Style__Int{} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/link.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/link.go new file mode 100644 index 0000000000..bd6c47e8e1 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/link.go @@ -0,0 +1,145 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = &plainLink{} + _ ipld.NodeStyle = Style__Link{} + _ ipld.NodeBuilder = &plainLink__Builder{} + _ ipld.NodeAssembler = &plainLink__Assembler{} +) + +func NewLink(value ipld.Link) ipld.Node { + return &plainLink{value} +} + +// plainLink is a simple box around a Link that complies with ipld.Node. +type plainLink struct { + x ipld.Link +} + +// -- Node interface methods --> + +func (plainLink) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Link +} +func (plainLink) LookupString(string) (ipld.Node, error) { + return mixins.Link{"link"}.LookupString("") +} +func (plainLink) Lookup(key ipld.Node) (ipld.Node, error) { + return mixins.Link{"link"}.Lookup(nil) +} +func (plainLink) LookupIndex(idx int) (ipld.Node, error) { + return mixins.Link{"link"}.LookupIndex(0) +} +func (plainLink) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + return mixins.Link{"link"}.LookupSegment(seg) +} +func (plainLink) MapIterator() ipld.MapIterator { + return nil +} +func (plainLink) ListIterator() ipld.ListIterator { + return nil +} +func (plainLink) Length() int { + return -1 +} +func (plainLink) IsUndefined() bool { + return false +} +func (plainLink) IsNull() bool { + return false +} +func (plainLink) AsBool() (bool, error) { + return mixins.Link{"link"}.AsBool() +} +func (plainLink) AsInt() (int, error) { + return mixins.Link{"link"}.AsInt() +} +func (plainLink) AsFloat() (float64, error) { + return mixins.Link{"link"}.AsFloat() +} +func (plainLink) AsString() (string, error) { + return mixins.Link{"link"}.AsString() +} +func (plainLink) AsBytes() ([]byte, error) { + return mixins.Link{"link"}.AsBytes() +} +func (n *plainLink) AsLink() (ipld.Link, error) { + return n.x, nil +} +func (plainLink) Style() ipld.NodeStyle { + return Style__Link{} +} + +// -- NodeStyle --> + +type Style__Link struct{} + +func (Style__Link) NewBuilder() ipld.NodeBuilder { + var w plainLink + return &plainLink__Builder{plainLink__Assembler{w: &w}} +} + +// -- NodeBuilder --> + +type plainLink__Builder struct { + plainLink__Assembler +} + +func (nb *plainLink__Builder) Build() ipld.Node { + return nb.w +} +func (nb *plainLink__Builder) Reset() { + var w plainLink + *nb = plainLink__Builder{plainLink__Assembler{w: &w}} +} + +// -- NodeAssembler --> + +type plainLink__Assembler struct { + w *plainLink +} + +func (plainLink__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.LinkAssembler{"link"}.BeginMap(0) +} +func (plainLink__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.LinkAssembler{"link"}.BeginList(0) +} +func (plainLink__Assembler) AssignNull() error { + return mixins.LinkAssembler{"link"}.AssignNull() +} +func (plainLink__Assembler) AssignBool(bool) error { + return mixins.LinkAssembler{"link"}.AssignBool(false) +} +func (plainLink__Assembler) AssignInt(int) error { + return mixins.LinkAssembler{"link"}.AssignInt(0) +} +func (plainLink__Assembler) AssignFloat(float64) error { + return mixins.LinkAssembler{"link"}.AssignFloat(0) +} +func (plainLink__Assembler) AssignString(string) error { + return mixins.LinkAssembler{"link"}.AssignString("") +} +func (plainLink__Assembler) AssignBytes([]byte) error { + return mixins.LinkAssembler{"link"}.AssignBytes(nil) +} +func (na *plainLink__Assembler) AssignLink(v ipld.Link) error { + na.w.x = v + return nil +} +func (na *plainLink__Assembler) AssignNode(v ipld.Node) error { + if v2, err := v.AsLink(); err != nil { + return err + } else { + na.w.x = v2 + return nil + } +} +func (plainLink__Assembler) Style() ipld.NodeStyle { + return Style__Link{} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/list.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/list.go new file mode 100644 index 0000000000..c00875f2bc --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/list.go @@ -0,0 +1,359 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = &plainList{} + _ ipld.NodeStyle = Style__List{} + _ ipld.NodeBuilder = &plainList__Builder{} + _ ipld.NodeAssembler = &plainList__Assembler{} +) + +// plainList is a concrete type that provides a list-kind ipld.Node. +// It can contain any kind of value. +// plainList is also embedded in the 'any' struct and usable from there. +type plainList struct { + x []ipld.Node +} + +// -- Node interface methods --> + +func (plainList) ReprKind() ipld.ReprKind { + return ipld.ReprKind_List +} +func (plainList) LookupString(string) (ipld.Node, error) { + return mixins.List{"list"}.LookupString("") +} +func (plainList) Lookup(ipld.Node) (ipld.Node, error) { + return mixins.List{"list"}.Lookup(nil) +} +func (n *plainList) LookupIndex(idx int) (ipld.Node, error) { + if n.Length() <= idx { + return nil, ipld.ErrNotExists{ipld.PathSegmentOfInt(idx)} + } + return n.x[idx], nil +} +func (n *plainList) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + idx, err := seg.Index() + if err != nil { + panic("todo name this kind of error") + } + return n.LookupIndex(idx) +} +func (plainList) MapIterator() ipld.MapIterator { + return nil +} +func (n *plainList) ListIterator() ipld.ListIterator { + return &plainList_ListIterator{n, 0} +} +func (n *plainList) Length() int { + return len(n.x) +} +func (plainList) IsUndefined() bool { + return false +} +func (plainList) IsNull() bool { + return false +} +func (plainList) AsBool() (bool, error) { + return mixins.List{"list"}.AsBool() +} +func (plainList) AsInt() (int, error) { + return mixins.List{"list"}.AsInt() +} +func (plainList) AsFloat() (float64, error) { + return mixins.List{"list"}.AsFloat() +} +func (plainList) AsString() (string, error) { + return mixins.List{"list"}.AsString() +} +func (plainList) AsBytes() ([]byte, error) { + return mixins.List{"list"}.AsBytes() +} +func (plainList) AsLink() (ipld.Link, error) { + return mixins.List{"list"}.AsLink() +} +func (plainList) Style() ipld.NodeStyle { + return Style__List{} +} + +type plainList_ListIterator struct { + n *plainList + idx int +} + +func (itr *plainList_ListIterator) Next() (idx int, v ipld.Node, _ error) { + if itr.Done() { + return -1, nil, ipld.ErrIteratorOverread{} + } + v = itr.n.x[itr.idx] + idx = itr.idx + itr.idx++ + return +} +func (itr *plainList_ListIterator) Done() bool { + return itr.idx >= len(itr.n.x) +} + +// -- NodeStyle --> + +type Style__List struct{} + +func (Style__List) NewBuilder() ipld.NodeBuilder { + return &plainList__Builder{plainList__Assembler{w: &plainList{}}} +} + +// -- NodeBuilder --> + +type plainList__Builder struct { + plainList__Assembler +} + +func (nb *plainList__Builder) Build() ipld.Node { + if nb.state != laState_finished { + panic("invalid state: assembler must be 'finished' before Build can be called!") + } + return nb.w +} +func (nb *plainList__Builder) Reset() { + *nb = plainList__Builder{} + nb.w = &plainList{} +} + +// -- NodeAssembler --> + +type plainList__Assembler struct { + w *plainList + + va plainList__ValueAssembler + + state laState +} +type plainList__ValueAssembler struct { + la *plainList__Assembler +} + +// laState is an enum of the state machine for a list assembler. +// (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.) +// it's similar to maState for maps, but has fewer states because we never have keys to assemble. +type laState uint8 + +const ( + laState_initial laState = iota // also the 'expect value or finish' state + laState_midValue // waiting for a 'finished' state in the ValueAssembler. + laState_finished // 'w' will also be nil, but this is a politer statement +) + +func (plainList__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.ListAssembler{"list"}.BeginMap(0) +} +func (na *plainList__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + if sizeHint < 0 { + sizeHint = 0 + } + // Allocate storage space. + na.w.x = make([]ipld.Node, 0, sizeHint) + // That's it; return self as the ListAssembler. We already have all the right methods on this structure. + return na, nil +} +func (plainList__Assembler) AssignNull() error { + return mixins.ListAssembler{"list"}.AssignNull() +} +func (plainList__Assembler) AssignBool(bool) error { + return mixins.ListAssembler{"list"}.AssignBool(false) +} +func (plainList__Assembler) AssignInt(int) error { + return mixins.ListAssembler{"list"}.AssignInt(0) +} +func (plainList__Assembler) AssignFloat(float64) error { + return mixins.ListAssembler{"list"}.AssignFloat(0) +} +func (plainList__Assembler) AssignString(string) error { + return mixins.ListAssembler{"list"}.AssignString("") +} +func (plainList__Assembler) AssignBytes([]byte) error { + return mixins.ListAssembler{"list"}.AssignBytes(nil) +} +func (plainList__Assembler) AssignLink(ipld.Link) error { + return mixins.ListAssembler{"list"}.AssignLink(nil) +} +func (na *plainList__Assembler) AssignNode(v ipld.Node) error { + // Sanity check, then update, assembler state. + if na.state != laState_initial { + panic("misuse") + } + na.state = laState_finished + // Copy the content. + if v2, ok := v.(*plainList); ok { // if our own type: shortcut. + // Copy the structure by value. + // This means we'll have pointers into the same internal maps and slices; + // this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that. + *na.w = *v2 + return nil + } + // If the above shortcut didn't work, resort to a generic copy. + // We call AssignNode for all the child values, giving them a chance to hit shortcuts even if we didn't. + if v.ReprKind() != ipld.ReprKind_List { + return ipld.ErrWrongKind{TypeName: "list", MethodName: "AssignNode", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: v.ReprKind()} + } + itr := v.ListIterator() + for !itr.Done() { + _, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + // validators could run and report errors promptly, if this type had any -- same as for regular Finish. + return nil +} +func (plainList__Assembler) Style() ipld.NodeStyle { + return Style__List{} +} + +// -- ListAssembler --> + +// AssembleValue is part of conforming to ListAssembler, which we do on +// plainList__Assembler so that BeginList can just return a retyped pointer rather than new object. +func (la *plainList__Assembler) AssembleValue() ipld.NodeAssembler { + // Sanity check, then update, assembler state. + if la.state != laState_initial { + panic("misuse") + } + la.state = laState_midValue + // Make value assembler valid by giving it pointer back to whole 'la'; yield it. + la.va.la = la + return &la.va +} + +// Finish is part of conforming to ListAssembler, which we do on +// plainList__Assembler so that BeginList can just return a retyped pointer rather than new object. +func (la *plainList__Assembler) Finish() error { + // Sanity check, then update, assembler state. + if la.state != laState_initial { + panic("misuse") + } + la.state = laState_finished + // validators could run and report errors promptly, if this type had any. + return nil +} +func (plainList__Assembler) ValueStyle(_ int) ipld.NodeStyle { + return Style__Any{} +} + +// -- ListAssembler.ValueAssembler --> + +func (lva *plainList__ValueAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + ma := plainList__ValueAssemblerMap{} + ma.ca.w = &plainMap{} + ma.p = lva.la + _, err := ma.ca.BeginMap(sizeHint) + return &ma, err +} +func (lva *plainList__ValueAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + la := plainList__ValueAssemblerList{} + la.ca.w = &plainList{} + la.p = lva.la + _, err := la.ca.BeginList(sizeHint) + return &la, err +} +func (lva *plainList__ValueAssembler) AssignNull() error { + return lva.AssignNode(ipld.Null) +} +func (lva *plainList__ValueAssembler) AssignBool(v bool) error { + vb := plainBool(v) + return lva.AssignNode(&vb) +} +func (lva *plainList__ValueAssembler) AssignInt(v int) error { + vb := plainInt(v) + return lva.AssignNode(&vb) +} +func (lva *plainList__ValueAssembler) AssignFloat(v float64) error { + vb := plainFloat(v) + return lva.AssignNode(&vb) +} +func (lva *plainList__ValueAssembler) AssignString(v string) error { + vb := plainString(v) + return lva.AssignNode(&vb) +} +func (lva *plainList__ValueAssembler) AssignBytes(v []byte) error { + vb := plainBytes(v) + return lva.AssignNode(&vb) +} +func (lva *plainList__ValueAssembler) AssignLink(v ipld.Link) error { + vb := plainLink{v} + return lva.AssignNode(&vb) +} +func (lva *plainList__ValueAssembler) AssignNode(v ipld.Node) error { + lva.la.w.x = append(lva.la.w.x, v) + lva.la.state = laState_initial + lva.la = nil // invalidate self to prevent further incorrect use. + return nil +} +func (plainList__ValueAssembler) Style() ipld.NodeStyle { + return Style__Any{} +} + +type plainList__ValueAssemblerMap struct { + ca plainMap__Assembler + p *plainList__Assembler // pointer back to parent, for final insert and state bump +} + +// we briefly state only the methods we need to delegate here. +// just embedding plainMap__Assembler also behaves correctly, +// but causes a lot of unnecessary autogenerated functions in the final binary. + +func (ma *plainList__ValueAssemblerMap) AssembleEntry(k string) (ipld.NodeAssembler, error) { + return ma.ca.AssembleEntry(k) +} +func (ma *plainList__ValueAssemblerMap) AssembleKey() ipld.NodeAssembler { + return ma.ca.AssembleKey() +} +func (ma *plainList__ValueAssemblerMap) AssembleValue() ipld.NodeAssembler { + return ma.ca.AssembleValue() +} +func (plainList__ValueAssemblerMap) KeyStyle() ipld.NodeStyle { + return Style__String{} +} +func (plainList__ValueAssemblerMap) ValueStyle(_ string) ipld.NodeStyle { + return Style__Any{} +} + +func (ma *plainList__ValueAssemblerMap) Finish() error { + if err := ma.ca.Finish(); err != nil { + return err + } + w := ma.ca.w + ma.ca.w = nil + return ma.p.va.AssignNode(w) +} + +type plainList__ValueAssemblerList struct { + ca plainList__Assembler + p *plainList__Assembler // pointer back to parent, for final insert and state bump +} + +// we briefly state only the methods we need to delegate here. +// just embedding plainList__Assembler also behaves correctly, +// but causes a lot of unnecessary autogenerated functions in the final binary. + +func (la *plainList__ValueAssemblerList) AssembleValue() ipld.NodeAssembler { + return la.ca.AssembleValue() +} +func (plainList__ValueAssemblerList) ValueStyle(_ int) ipld.NodeStyle { + return Style__Any{} +} + +func (la *plainList__ValueAssemblerList) Finish() error { + if err := la.ca.Finish(); err != nil { + return err + } + w := la.ca.w + la.ca.w = nil + return la.p.va.AssignNode(w) +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/map.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/map.go new file mode 100644 index 0000000000..f6d2ef4593 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/map.go @@ -0,0 +1,470 @@ +package basicnode + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = &plainMap{} + _ ipld.NodeStyle = Style__Map{} + _ ipld.NodeBuilder = &plainMap__Builder{} + _ ipld.NodeAssembler = &plainMap__Assembler{} +) + +// plainMap is a concrete type that provides a map-kind ipld.Node. +// It can contain any kind of value. +// plainMap is also embedded in the 'any' struct and usable from there. +type plainMap struct { + m map[string]ipld.Node // string key -- even if a runtime schema wrapper is using us for storage, we must have a comparable type here, and string is all we know. + t []plainMap__Entry // table for fast iteration, order keeping, and yielding pointers to enable alloc/conv amortization. +} + +type plainMap__Entry struct { + k plainString // address of this used when we return keys as nodes, such as in iterators. Need in one place to amortize shifts to heap when ptr'ing for iface. + v ipld.Node // identical to map values. keeping them here simplifies iteration. (in codegen'd maps, this position is also part of amortization, but in this implementation, that's less useful.) + // note on alternate implementations: 'v' could also use the 'any' type, and thus amortize value allocations. the memory size trade would be large however, so we don't, here. +} + +// -- Node interface methods --> + +func (plainMap) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Map +} +func (n *plainMap) LookupString(key string) (ipld.Node, error) { + v, exists := n.m[key] + if !exists { + return nil, ipld.ErrNotExists{ipld.PathSegmentOfString(key)} + } + return v, nil +} +func (n *plainMap) Lookup(key ipld.Node) (ipld.Node, error) { + ks, err := key.AsString() + if err != nil { + return nil, err + } + return n.LookupString(ks) +} +func (plainMap) LookupIndex(idx int) (ipld.Node, error) { + return mixins.Map{"map"}.LookupIndex(0) +} +func (n *plainMap) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + return n.LookupString(seg.String()) +} +func (n *plainMap) MapIterator() ipld.MapIterator { + return &plainMap_MapIterator{n, 0} +} +func (plainMap) ListIterator() ipld.ListIterator { + return nil +} +func (n *plainMap) Length() int { + return len(n.t) +} +func (plainMap) IsUndefined() bool { + return false +} +func (plainMap) IsNull() bool { + return false +} +func (plainMap) AsBool() (bool, error) { + return mixins.Map{"map"}.AsBool() +} +func (plainMap) AsInt() (int, error) { + return mixins.Map{"map"}.AsInt() +} +func (plainMap) AsFloat() (float64, error) { + return mixins.Map{"map"}.AsFloat() +} +func (plainMap) AsString() (string, error) { + return mixins.Map{"map"}.AsString() +} +func (plainMap) AsBytes() ([]byte, error) { + return mixins.Map{"map"}.AsBytes() +} +func (plainMap) AsLink() (ipld.Link, error) { + return mixins.Map{"map"}.AsLink() +} +func (plainMap) Style() ipld.NodeStyle { + return Style__Map{} +} + +type plainMap_MapIterator struct { + n *plainMap + idx int +} + +func (itr *plainMap_MapIterator) Next() (k ipld.Node, v ipld.Node, _ error) { + if itr.Done() { + return nil, nil, ipld.ErrIteratorOverread{} + } + k = &itr.n.t[itr.idx].k + v = itr.n.t[itr.idx].v + itr.idx++ + return +} +func (itr *plainMap_MapIterator) Done() bool { + return itr.idx >= len(itr.n.t) +} + +// -- NodeStyle --> + +type Style__Map struct{} + +func (Style__Map) NewBuilder() ipld.NodeBuilder { + return &plainMap__Builder{plainMap__Assembler{w: &plainMap{}}} +} + +// -- NodeBuilder --> + +type plainMap__Builder struct { + plainMap__Assembler +} + +func (nb *plainMap__Builder) Build() ipld.Node { + if nb.state != maState_finished { + panic("invalid state: assembler must be 'finished' before Build can be called!") + } + return nb.w +} +func (nb *plainMap__Builder) Reset() { + *nb = plainMap__Builder{} + nb.w = &plainMap{} +} + +// -- NodeAssembler --> + +type plainMap__Assembler struct { + w *plainMap + + ka plainMap__KeyAssembler + va plainMap__ValueAssembler + + state maState +} +type plainMap__KeyAssembler struct { + ma *plainMap__Assembler +} +type plainMap__ValueAssembler struct { + ma *plainMap__Assembler +} + +// maState is an enum of the state machine for a map assembler. +// (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.) +type maState uint8 + +const ( + maState_initial maState = iota // also the 'expect key or finish' state + maState_midKey // waiting for a 'finished' state in the KeyAssembler. + maState_expectValue // 'AssembleValue' is the only valid next step + maState_midValue // waiting for a 'finished' state in the ValueAssembler. + maState_finished // 'w' will also be nil, but this is a politer statement +) + +func (na *plainMap__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + if sizeHint < 0 { + sizeHint = 0 + } + // Allocate storage space. + na.w.t = make([]plainMap__Entry, 0, sizeHint) + na.w.m = make(map[string]ipld.Node, sizeHint) + // That's it; return self as the MapAssembler. We already have all the right methods on this structure. + return na, nil +} +func (plainMap__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.MapAssembler{"map"}.BeginList(0) +} +func (plainMap__Assembler) AssignNull() error { + return mixins.MapAssembler{"map"}.AssignNull() +} +func (plainMap__Assembler) AssignBool(bool) error { + return mixins.MapAssembler{"map"}.AssignBool(false) +} +func (plainMap__Assembler) AssignInt(int) error { + return mixins.MapAssembler{"map"}.AssignInt(0) +} +func (plainMap__Assembler) AssignFloat(float64) error { + return mixins.MapAssembler{"map"}.AssignFloat(0) +} +func (plainMap__Assembler) AssignString(string) error { + return mixins.MapAssembler{"map"}.AssignString("") +} +func (plainMap__Assembler) AssignBytes([]byte) error { + return mixins.MapAssembler{"map"}.AssignBytes(nil) +} +func (plainMap__Assembler) AssignLink(ipld.Link) error { + return mixins.MapAssembler{"map"}.AssignLink(nil) +} +func (na *plainMap__Assembler) AssignNode(v ipld.Node) error { + // Sanity check, then update, assembler state. + if na.state != maState_initial { + panic("misuse") + } + na.state = maState_finished + // Copy the content. + if v2, ok := v.(*plainMap); ok { // if our own type: shortcut. + // Copy the structure by value. + // This means we'll have pointers into the same internal maps and slices; + // this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that. + *na.w = *v2 + return nil + } + // If the above shortcut didn't work, resort to a generic copy. + // We call AssignNode for all the child values, giving them a chance to hit shortcuts even if we didn't. + if v.ReprKind() != ipld.ReprKind_Map { + return ipld.ErrWrongKind{TypeName: "map", MethodName: "AssignNode", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: v.ReprKind()} + } + itr := v.MapIterator() + for !itr.Done() { + k, v, err := itr.Next() + if err != nil { + return err + } + if err := na.AssembleKey().AssignNode(k); err != nil { + return err + } + if err := na.AssembleValue().AssignNode(v); err != nil { + return err + } + } + // validators could run and report errors promptly, if this type had any -- same as for regular Finish. + return nil +} +func (plainMap__Assembler) Style() ipld.NodeStyle { + return Style__Map{} +} + +// -- MapAssembler --> + +// AssembleEntry is part of conforming to MapAssembler, which we do on +// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object. +func (ma *plainMap__Assembler) AssembleEntry(k string) (ipld.NodeAssembler, error) { + // Sanity check, then update, assembler state. + if ma.state != maState_initial { + panic("misuse") + } + ma.state = maState_midValue + // Check for dup keys; error if so. + _, exists := ma.w.m[k] + if exists { + return nil, ipld.ErrRepeatedMapKey{plainString(k)} + } + ma.w.t = append(ma.w.t, plainMap__Entry{k: plainString(k)}) + // Make value assembler valid by giving it pointer back to whole 'ma'; yield it. + ma.va.ma = ma + return &ma.va, nil +} + +// AssembleKey is part of conforming to MapAssembler, which we do on +// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object. +func (ma *plainMap__Assembler) AssembleKey() ipld.NodeAssembler { + // Sanity check, then update, assembler state. + if ma.state != maState_initial { + panic("misuse") + } + ma.state = maState_midKey + // Extend entry table. + ma.w.t = append(ma.w.t, plainMap__Entry{}) + // Make key assembler valid by giving it pointer back to whole 'ma'; yield it. + ma.ka.ma = ma + return &ma.ka +} + +// AssembleValue is part of conforming to MapAssembler, which we do on +// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object. +func (ma *plainMap__Assembler) AssembleValue() ipld.NodeAssembler { + // Sanity check, then update, assembler state. + if ma.state != maState_expectValue { + panic("misuse") + } + ma.state = maState_midValue + // Make value assembler valid by giving it pointer back to whole 'ma'; yield it. + ma.va.ma = ma + return &ma.va +} + +// Finish is part of conforming to MapAssembler, which we do on +// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object. +func (ma *plainMap__Assembler) Finish() error { + // Sanity check, then update, assembler state. + if ma.state != maState_initial { + panic("misuse") + } + ma.state = maState_finished + // validators could run and report errors promptly, if this type had any. + return nil +} +func (plainMap__Assembler) KeyStyle() ipld.NodeStyle { + return Style__String{} +} +func (plainMap__Assembler) ValueStyle(_ string) ipld.NodeStyle { + return Style__Any{} +} + +// -- MapAssembler.KeyAssembler --> + +func (plainMap__KeyAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.StringAssembler{"string"}.BeginMap(0) +} +func (plainMap__KeyAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.StringAssembler{"string"}.BeginList(0) +} +func (plainMap__KeyAssembler) AssignNull() error { + return mixins.StringAssembler{"string"}.AssignNull() +} +func (plainMap__KeyAssembler) AssignBool(bool) error { + return mixins.StringAssembler{"string"}.AssignBool(false) +} +func (plainMap__KeyAssembler) AssignInt(int) error { + return mixins.StringAssembler{"string"}.AssignInt(0) +} +func (plainMap__KeyAssembler) AssignFloat(float64) error { + return mixins.StringAssembler{"string"}.AssignFloat(0) +} +func (mka *plainMap__KeyAssembler) AssignString(v string) error { + // Check for dup keys; error if so. + _, exists := mka.ma.w.m[v] + if exists { + return ipld.ErrRepeatedMapKey{plainString(v)} + } + // Assign the key into the end of the entry table; + // we'll be doing map insertions after we get the value in hand. + // (There's no need to delegate to another assembler for the key type, + // because we're just at Data Model level here, which only regards plain strings.) + mka.ma.w.t[len(mka.ma.w.t)-1].k = plainString(v) + // Update parent assembler state: clear to proceed. + mka.ma.state = maState_expectValue + mka.ma = nil // invalidate self to prevent further incorrect use. + return nil +} +func (plainMap__KeyAssembler) AssignBytes([]byte) error { + return mixins.StringAssembler{"string"}.AssignBytes(nil) +} +func (plainMap__KeyAssembler) AssignLink(ipld.Link) error { + return mixins.StringAssembler{"string"}.AssignLink(nil) +} +func (mka *plainMap__KeyAssembler) AssignNode(v ipld.Node) error { + vs, err := v.AsString() + if err != nil { + return fmt.Errorf("cannot assign non-string node into map key assembler") // FIXME:errors: this doesn't quite fit in ErrWrongKind cleanly; new error type? + } + return mka.AssignString(vs) +} +func (plainMap__KeyAssembler) Style() ipld.NodeStyle { + return Style__String{} +} + +// -- MapAssembler.ValueAssembler --> + +func (mva *plainMap__ValueAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + ma := plainMap__ValueAssemblerMap{} + ma.ca.w = &plainMap{} + ma.p = mva.ma + _, err := ma.ca.BeginMap(sizeHint) + return &ma, err +} +func (mva *plainMap__ValueAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + la := plainMap__ValueAssemblerList{} + la.ca.w = &plainList{} + la.p = mva.ma + _, err := la.ca.BeginList(sizeHint) + return &la, err +} +func (mva *plainMap__ValueAssembler) AssignNull() error { + return mva.AssignNode(ipld.Null) +} +func (mva *plainMap__ValueAssembler) AssignBool(v bool) error { + vb := plainBool(v) + return mva.AssignNode(&vb) +} +func (mva *plainMap__ValueAssembler) AssignInt(v int) error { + vb := plainInt(v) + return mva.AssignNode(&vb) +} +func (mva *plainMap__ValueAssembler) AssignFloat(v float64) error { + vb := plainFloat(v) + return mva.AssignNode(&vb) +} +func (mva *plainMap__ValueAssembler) AssignString(v string) error { + vb := plainString(v) + return mva.AssignNode(&vb) +} +func (mva *plainMap__ValueAssembler) AssignBytes(v []byte) error { + vb := plainBytes(v) + return mva.AssignNode(&vb) +} +func (mva *plainMap__ValueAssembler) AssignLink(v ipld.Link) error { + vb := plainLink{v} + return mva.AssignNode(&vb) +} +func (mva *plainMap__ValueAssembler) AssignNode(v ipld.Node) error { + l := len(mva.ma.w.t) - 1 + mva.ma.w.t[l].v = v + mva.ma.w.m[string(mva.ma.w.t[l].k)] = v + mva.ma.state = maState_initial + mva.ma = nil // invalidate self to prevent further incorrect use. + return nil +} +func (plainMap__ValueAssembler) Style() ipld.NodeStyle { + return Style__Any{} +} + +type plainMap__ValueAssemblerMap struct { + ca plainMap__Assembler + p *plainMap__Assembler // pointer back to parent, for final insert and state bump +} + +// we briefly state only the methods we need to delegate here. +// just embedding plainMap__Assembler also behaves correctly, +// but causes a lot of unnecessary autogenerated functions in the final binary. + +func (ma *plainMap__ValueAssemblerMap) AssembleEntry(k string) (ipld.NodeAssembler, error) { + return ma.ca.AssembleEntry(k) +} +func (ma *plainMap__ValueAssemblerMap) AssembleKey() ipld.NodeAssembler { + return ma.ca.AssembleKey() +} +func (ma *plainMap__ValueAssemblerMap) AssembleValue() ipld.NodeAssembler { + return ma.ca.AssembleValue() +} +func (plainMap__ValueAssemblerMap) KeyStyle() ipld.NodeStyle { + return Style__String{} +} +func (plainMap__ValueAssemblerMap) ValueStyle(_ string) ipld.NodeStyle { + return Style__Any{} +} + +func (ma *plainMap__ValueAssemblerMap) Finish() error { + if err := ma.ca.Finish(); err != nil { + return err + } + w := ma.ca.w + ma.ca.w = nil + return ma.p.va.AssignNode(w) +} + +type plainMap__ValueAssemblerList struct { + ca plainList__Assembler + p *plainMap__Assembler // pointer back to parent, for final insert and state bump +} + +// we briefly state only the methods we need to delegate here. +// just embedding plainList__Assembler also behaves correctly, +// but causes a lot of unnecessary autogenerated functions in the final binary. + +func (la *plainMap__ValueAssemblerList) AssembleValue() ipld.NodeAssembler { + return la.ca.AssembleValue() +} +func (plainMap__ValueAssemblerList) ValueStyle(_ int) ipld.NodeStyle { + return Style__Any{} +} + +func (la *plainMap__ValueAssemblerList) Finish() error { + if err := la.ca.Finish(); err != nil { + return err + } + w := la.ca.w + la.ca.w = nil + return la.p.va.AssignNode(w) +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/string.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/string.go new file mode 100644 index 0000000000..7b05dd5e1e --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/string.go @@ -0,0 +1,149 @@ +package basicnode + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/node/mixins" +) + +var ( + _ ipld.Node = plainString("") + _ ipld.NodeStyle = Style__String{} + _ ipld.NodeBuilder = &plainString__Builder{} + _ ipld.NodeAssembler = &plainString__Assembler{} +) + +func NewString(value string) ipld.Node { + v := plainString(value) + return &v +} + +// plainString is a simple boxed string that complies with ipld.Node. +// It's useful for many things, such as boxing map keys. +// +// The implementation is a simple typedef of a string; +// handling it as a Node incurs 'runtime.convTstring', +// which is about the best we can do. +type plainString string + +// -- Node interface methods --> + +func (plainString) ReprKind() ipld.ReprKind { + return ipld.ReprKind_String +} +func (plainString) LookupString(string) (ipld.Node, error) { + return mixins.String{"string"}.LookupString("") +} +func (plainString) Lookup(key ipld.Node) (ipld.Node, error) { + return mixins.String{"string"}.Lookup(nil) +} +func (plainString) LookupIndex(idx int) (ipld.Node, error) { + return mixins.String{"string"}.LookupIndex(0) +} +func (plainString) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { + return mixins.String{"string"}.LookupSegment(seg) +} +func (plainString) MapIterator() ipld.MapIterator { + return nil +} +func (plainString) ListIterator() ipld.ListIterator { + return nil +} +func (plainString) Length() int { + return -1 +} +func (plainString) IsUndefined() bool { + return false +} +func (plainString) IsNull() bool { + return false +} +func (plainString) AsBool() (bool, error) { + return mixins.String{"string"}.AsBool() +} +func (plainString) AsInt() (int, error) { + return mixins.String{"string"}.AsInt() +} +func (plainString) AsFloat() (float64, error) { + return mixins.String{"string"}.AsFloat() +} +func (x plainString) AsString() (string, error) { + return string(x), nil +} +func (plainString) AsBytes() ([]byte, error) { + return mixins.String{"string"}.AsBytes() +} +func (plainString) AsLink() (ipld.Link, error) { + return mixins.String{"string"}.AsLink() +} +func (plainString) Style() ipld.NodeStyle { + return Style__String{} +} + +// -- NodeStyle --> + +type Style__String struct{} + +func (Style__String) NewBuilder() ipld.NodeBuilder { + var w plainString + return &plainString__Builder{plainString__Assembler{w: &w}} +} + +// -- NodeBuilder --> + +type plainString__Builder struct { + plainString__Assembler +} + +func (nb *plainString__Builder) Build() ipld.Node { + return nb.w +} +func (nb *plainString__Builder) Reset() { + var w plainString + *nb = plainString__Builder{plainString__Assembler{w: &w}} +} + +// -- NodeAssembler --> + +type plainString__Assembler struct { + w *plainString +} + +func (plainString__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return mixins.StringAssembler{"string"}.BeginMap(0) +} +func (plainString__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return mixins.StringAssembler{"string"}.BeginList(0) +} +func (plainString__Assembler) AssignNull() error { + return mixins.StringAssembler{"string"}.AssignNull() +} +func (plainString__Assembler) AssignBool(bool) error { + return mixins.StringAssembler{"string"}.AssignBool(false) +} +func (plainString__Assembler) AssignInt(int) error { + return mixins.StringAssembler{"string"}.AssignInt(0) +} +func (plainString__Assembler) AssignFloat(float64) error { + return mixins.StringAssembler{"string"}.AssignFloat(0) +} +func (na *plainString__Assembler) AssignString(v string) error { + *na.w = plainString(v) + return nil +} +func (plainString__Assembler) AssignBytes([]byte) error { + return mixins.StringAssembler{"string"}.AssignBytes(nil) +} +func (plainString__Assembler) AssignLink(ipld.Link) error { + return mixins.StringAssembler{"string"}.AssignLink(nil) +} +func (na *plainString__Assembler) AssignNode(v ipld.Node) error { + if v2, err := v.AsString(); err != nil { + return err + } else { + *na.w = plainString(v2) + return nil + } +} +func (plainString__Assembler) Style() ipld.NodeStyle { + return Style__String{} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/basic/style.go b/vendor/github.com/ipld/go-ipld-prime/node/basic/style.go new file mode 100644 index 0000000000..a5b87f553e --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/basic/style.go @@ -0,0 +1,26 @@ +package basicnode + +// Style embeds a NodeStyle for every kind of Node implementation in this package. +// You can use it like this: +// +// basicnode.Style.Map.NewBuilder().BeginMap() //... +// +// and: +// +// basicnode.Style.String.NewBuilder().AssignString("x") // ... +// +// Most of the styles here are for one particular Kind of node (e.g. string, int, etc); +// you can use the "Any" style if you want a builder that can accept any kind of data. +var Style style + +type style struct { + Any Style__Any + Map Style__Map + List Style__List + Bool Style__Bool + Int Style__Int + Float Style__Float + String Style__String + Bytes Style__Bytes + Link Style__Link +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/HACKME.md b/vendor/github.com/ipld/go-ipld-prime/node/mixins/HACKME.md new file mode 100644 index 0000000000..a000a7f638 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/HACKME.md @@ -0,0 +1,37 @@ +node mixins and how to use them +=============================== + +These mixins are here to: + +1. reduce the amount of code you need to write to create a new Node implementation, and +2. standardize a lot of the error handling for common cases (especially, around kinds). + +"Reduce the amount of code" also has an application in codegen, +where while it doesn't save any human effort, it does reduce GLOC size. +(Or more precisely, it doesn't save *lines*, since we use them in verbose style, +but it does make those lines an awful lot shorter.) + +Note that these mixins are _not_ particularly here to help with performance. + +- all `ErrWrongKind` error are returned by value, which means a `runtime.convT2I` which means a heap allocation. + The error paths will therefore never be "fast"; it will *always* be cheaper + to check `kind` in advance than to probe and handle errors, if efficiency is your goal. +- in general, there's really no way to improve upon the performance of having these methods simply writen directlyon your type. + +These mixins will affect struct size if you use them via embed. +They can also be used without any effect on struct size if used more verbosely. + +The binary/assembly output size is not affected by use of the mixins. +(If using them verbosely -- e.g. still declaring methods on your type +and using `return mixins.Kind{"TypeName"}.Method()` in the method body -- +the end result is the inliner kicks in, and the end result is almost +identical binary size.) + +Summary: + +- SLOC: good, or neutral depending on use +- GLOC: good +- standardized: good +- speed: neutral +- mem size: neutral if used verbosely, bad if used most tersely +- asm size: neutral diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/boolMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/boolMixin.go new file mode 100644 index 0000000000..cbe6be6574 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/boolMixin.go @@ -0,0 +1,97 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// Bool can be embedded in a struct to provide all the methods that +// have fixed output for any int-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type Bool struct { + TypeName string +} + +func (Bool) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Bool +} +func (x Bool) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Bool} +} +func (x Bool) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Bool} +} +func (x Bool) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Bool} +} +func (x Bool) LookupSegment(ipld.PathSegment) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupSegment", AppropriateKind: ipld.ReprKindSet_Recursive, ActualKind: ipld.ReprKind_Bool} +} +func (Bool) MapIterator() ipld.MapIterator { + return nil +} +func (Bool) ListIterator() ipld.ListIterator { + return nil +} +func (Bool) Length() int { + return -1 +} +func (Bool) IsUndefined() bool { + return false +} +func (Bool) IsNull() bool { + return false +} +func (x Bool) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Bool} +} +func (x Bool) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Bool} +} +func (x Bool) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Bool} +} +func (x Bool) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Bool} +} +func (x Bool) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Bool} +} + +// BoolAssembler has similar purpose as Bool, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type BoolAssembler struct { + TypeName string +} + +func (x BoolAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Bool} +} +func (x BoolAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Bool} +} +func (x BoolAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_Bool} +} +func (x BoolAssembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Bool} +} +func (x BoolAssembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Bool} +} +func (x BoolAssembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Bool} +} +func (x BoolAssembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Bool} +} +func (x BoolAssembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Bool} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/bytesMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/bytesMixin.go new file mode 100644 index 0000000000..ba798d1129 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/bytesMixin.go @@ -0,0 +1,97 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// Bytes can be embedded in a struct to provide all the methods that +// have fixed output for any int-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type Bytes struct { + TypeName string +} + +func (Bytes) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Bytes +} +func (x Bytes) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Bytes} +} +func (x Bytes) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Bytes} +} +func (x Bytes) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Bytes} +} +func (x Bytes) LookupSegment(ipld.PathSegment) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupSegment", AppropriateKind: ipld.ReprKindSet_Recursive, ActualKind: ipld.ReprKind_Bytes} +} +func (Bytes) MapIterator() ipld.MapIterator { + return nil +} +func (Bytes) ListIterator() ipld.ListIterator { + return nil +} +func (Bytes) Length() int { + return -1 +} +func (Bytes) IsUndefined() bool { + return false +} +func (Bytes) IsNull() bool { + return false +} +func (x Bytes) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Bytes} +} +func (x Bytes) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Bytes} +} +func (x Bytes) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Bytes} +} +func (x Bytes) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Bytes} +} +func (x Bytes) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Bytes} +} + +// BytesAssembler has similar purpose as Bytes, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type BytesAssembler struct { + TypeName string +} + +func (x BytesAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Bytes} +} +func (x BytesAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Bytes} +} +func (x BytesAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_Bytes} +} +func (x BytesAssembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Bytes} +} +func (x BytesAssembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Bytes} +} +func (x BytesAssembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Bytes} +} +func (x BytesAssembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Bytes} +} +func (x BytesAssembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Bytes} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/floatMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/floatMixin.go new file mode 100644 index 0000000000..28986fce95 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/floatMixin.go @@ -0,0 +1,97 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// Float can be embedded in a struct to provide all the methods that +// have fixed output for any int-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type Float struct { + TypeName string +} + +func (Float) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Float +} +func (x Float) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Float} +} +func (x Float) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Float} +} +func (x Float) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Float} +} +func (x Float) LookupSegment(ipld.PathSegment) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupSegment", AppropriateKind: ipld.ReprKindSet_Recursive, ActualKind: ipld.ReprKind_Float} +} +func (Float) MapIterator() ipld.MapIterator { + return nil +} +func (Float) ListIterator() ipld.ListIterator { + return nil +} +func (Float) Length() int { + return -1 +} +func (Float) IsUndefined() bool { + return false +} +func (Float) IsNull() bool { + return false +} +func (x Float) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Float} +} +func (x Float) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Float} +} +func (x Float) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Float} +} +func (x Float) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Float} +} +func (x Float) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Float} +} + +// FloatAssembler has similar purpose as Float, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type FloatAssembler struct { + TypeName string +} + +func (x FloatAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Float} +} +func (x FloatAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Float} +} +func (x FloatAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_Float} +} +func (x FloatAssembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Float} +} +func (x FloatAssembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Float} +} +func (x FloatAssembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Float} +} +func (x FloatAssembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Float} +} +func (x FloatAssembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Float} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/intMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/intMixin.go new file mode 100644 index 0000000000..f51d4f3017 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/intMixin.go @@ -0,0 +1,97 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// Int can be embedded in a struct to provide all the methods that +// have fixed output for any int-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type Int struct { + TypeName string +} + +func (Int) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Int +} +func (x Int) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Int} +} +func (x Int) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Int} +} +func (x Int) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Int} +} +func (x Int) LookupSegment(ipld.PathSegment) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupSegment", AppropriateKind: ipld.ReprKindSet_Recursive, ActualKind: ipld.ReprKind_Int} +} +func (Int) MapIterator() ipld.MapIterator { + return nil +} +func (Int) ListIterator() ipld.ListIterator { + return nil +} +func (Int) Length() int { + return -1 +} +func (Int) IsUndefined() bool { + return false +} +func (Int) IsNull() bool { + return false +} +func (x Int) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Int} +} +func (x Int) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Int} +} +func (x Int) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Int} +} +func (x Int) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Int} +} +func (x Int) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Int} +} + +// IntAssembler has similar purpose as Int, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type IntAssembler struct { + TypeName string +} + +func (x IntAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Int} +} +func (x IntAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Int} +} +func (x IntAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_Int} +} +func (x IntAssembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Int} +} +func (x IntAssembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Int} +} +func (x IntAssembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Int} +} +func (x IntAssembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Int} +} +func (x IntAssembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Int} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/linkMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/linkMixin.go new file mode 100644 index 0000000000..e4fb7606bd --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/linkMixin.go @@ -0,0 +1,97 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// Link can be embedded in a struct to provide all the methods that +// have fixed output for any int-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type Link struct { + TypeName string +} + +func (Link) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Link +} +func (x Link) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Link} +} +func (x Link) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Link} +} +func (x Link) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Link} +} +func (x Link) LookupSegment(ipld.PathSegment) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupSegment", AppropriateKind: ipld.ReprKindSet_Recursive, ActualKind: ipld.ReprKind_Link} +} +func (Link) MapIterator() ipld.MapIterator { + return nil +} +func (Link) ListIterator() ipld.ListIterator { + return nil +} +func (Link) Length() int { + return -1 +} +func (Link) IsUndefined() bool { + return false +} +func (Link) IsNull() bool { + return false +} +func (x Link) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Link} +} +func (x Link) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Link} +} +func (x Link) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Link} +} +func (x Link) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Link} +} +func (x Link) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Link} +} + +// LinkAssembler has similar purpose as Link, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type LinkAssembler struct { + TypeName string +} + +func (x LinkAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_Link} +} +func (x LinkAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Link} +} +func (x LinkAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_Link} +} +func (x LinkAssembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Link} +} +func (x LinkAssembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Link} +} +func (x LinkAssembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Link} +} +func (x LinkAssembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Link} +} +func (x LinkAssembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Link} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/listMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/listMixin.go new file mode 100644 index 0000000000..1286f30bf3 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/listMixin.go @@ -0,0 +1,88 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// List can be embedded in a struct to provide all the methods that +// have fixed output for any int-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type List struct { + TypeName string +} + +func (List) ReprKind() ipld.ReprKind { + return ipld.ReprKind_List +} +func (x List) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_List} +} +func (x List) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_List} +} +func (List) MapIterator() ipld.MapIterator { + return nil +} +func (List) IsUndefined() bool { + return false +} +func (List) IsNull() bool { + return false +} +func (x List) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_List} +} +func (x List) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_List} +} +func (x List) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_List} +} +func (x List) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_List} +} +func (x List) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_List} +} +func (x List) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_List} +} + +// ListAssembler has similar purpose as List, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type ListAssembler struct { + TypeName string +} + +func (x ListAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_List} +} +func (x ListAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_List} +} +func (x ListAssembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_List} +} +func (x ListAssembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_List} +} +func (x ListAssembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_List} +} +func (x ListAssembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_List} +} +func (x ListAssembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_List} +} +func (x ListAssembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_List} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/mapMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/mapMixin.go new file mode 100644 index 0000000000..a205ce2d67 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/mapMixin.go @@ -0,0 +1,85 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// Map can be embedded in a struct to provide all the methods that +// have fixed output for any map-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type Map struct { + TypeName string +} + +func (Map) ReprKind() ipld.ReprKind { + return ipld.ReprKind_Map +} +func (x Map) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Map} +} +func (Map) ListIterator() ipld.ListIterator { + return nil +} +func (Map) IsUndefined() bool { + return false +} +func (Map) IsNull() bool { + return false +} +func (x Map) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Map} +} +func (x Map) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Map} +} +func (x Map) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Map} +} +func (x Map) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Map} +} +func (x Map) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Map} +} +func (x Map) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Map} +} + +// MapAssembler has similar purpose as Map, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type MapAssembler struct { + TypeName string +} + +func (x MapAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_Map} +} +func (x MapAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_Map} +} +func (x MapAssembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_Map} +} +func (x MapAssembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_Map} +} +func (x MapAssembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_Map} +} +func (x MapAssembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_Map} +} +func (x MapAssembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_Map} +} +func (x MapAssembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_Map} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/stringMixin.go b/vendor/github.com/ipld/go-ipld-prime/node/mixins/stringMixin.go new file mode 100644 index 0000000000..2eb68a77fc --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/stringMixin.go @@ -0,0 +1,97 @@ +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// String can be embedded in a struct to provide all the methods that +// have fixed output for any string-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type String struct { + TypeName string +} + +func (String) ReprKind() ipld.ReprKind { + return ipld.ReprKind_String +} +func (x String) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_String} +} +func (x String) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_String} +} +func (x String) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_String} +} +func (x String) LookupSegment(ipld.PathSegment) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupSegment", AppropriateKind: ipld.ReprKindSet_Recursive, ActualKind: ipld.ReprKind_String} +} +func (String) MapIterator() ipld.MapIterator { + return nil +} +func (String) ListIterator() ipld.ListIterator { + return nil +} +func (String) Length() int { + return -1 +} +func (String) IsUndefined() bool { + return false +} +func (String) IsNull() bool { + return false +} +func (x String) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_String} +} +func (x String) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_String} +} +func (x String) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_String} +} +func (x String) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_String} +} +func (x String) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_String} +} + +// StringAssembler has similar purpose as String, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type StringAssembler struct { + TypeName string +} + +func (x StringAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_String} +} +func (x StringAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_String} +} +func (x StringAssembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_String} +} +func (x StringAssembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_String} +} +func (x StringAssembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_String} +} +func (x StringAssembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_String} +} +func (x StringAssembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_String} +} +func (x StringAssembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_String} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/node/mixins/tmplMixin.txt b/vendor/github.com/ipld/go-ipld-prime/node/mixins/tmplMixin.txt new file mode 100644 index 0000000000..cd4f6beb8b --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/node/mixins/tmplMixin.txt @@ -0,0 +1,107 @@ +// copy this and remove methods that aren't relevant to your kind. +// this has not been scripted. +// (the first part is trivial; the second part is not; and this updates rarely. https://xkcd.com/1205/ applies.) + +package mixins + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// @Kind@ can be embedded in a struct to provide all the methods that +// have fixed output for any int-kinded nodes. +// (Mostly this includes all the methods which simply return ErrWrongKind.) +// Other methods will still need to be implemented to finish conforming to Node. +// +// To conserve memory and get a TypeName in errors without embedding, +// write methods on your type with a body that simply initializes this struct +// and immediately uses the relevant method; +// this is more verbose in source, but compiles to a tighter result: +// in memory, there's no embed; and in runtime, the calls will be inlined +// and thus have no cost in execution time. +type @Kind@ struct { + TypeName string +} + +func (@Kind@) ReprKind() ipld.ReprKind { + return ipld.ReprKind_@Kind@ +} +func (x @Kind@) LookupString(string) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupString", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) Lookup(key ipld.Node) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "Lookup", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) LookupIndex(idx int) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupIndex", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) LookupSegment(ipld.PathSegment) (ipld.Node, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "LookupSegment", AppropriateKind: ipld.ReprKindSet_Recursive, ActualKind: ipld.ReprKind_@Kind@} +} +func (@Kind@) MapIterator() ipld.MapIterator { + return nil +} +func (@Kind@) ListIterator() ipld.ListIterator { + return nil +} +func (@Kind@) Length() int { + return -1 +} +func (@Kind@) IsUndefined() bool { + return false +} +func (@Kind@) IsNull() bool { + return false +} +func (x @Kind@) AsBool() (bool, error) { + return false, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) AsInt() (int, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) AsFloat() (float64, error) { + return 0, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) AsString() (string, error) { + return "", ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) AsBytes() ([]byte, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@) AsLink() (ipld.Link, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AsLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_@Kind@} +} + +// @Kind@Assembler has similar purpose as @Kind@, but for (you guessed it) +// the NodeAssembler interface rather than the Node interface. +type @Kind@Assembler struct { + TypeName string +} + +func (x @Kind@Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginMap", AppropriateKind: ipld.ReprKindSet_JustMap, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { + return nil, ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "BeginList", AppropriateKind: ipld.ReprKindSet_JustList, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) AssignNull() error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignNull", AppropriateKind: ipld.ReprKindSet_JustNull, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) AssignBool(bool) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBool", AppropriateKind: ipld.ReprKindSet_JustBool, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) AssignInt(int) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignInt", AppropriateKind: ipld.ReprKindSet_JustInt, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) AssignFloat(float64) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignFloat", AppropriateKind: ipld.ReprKindSet_JustFloat, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) AssignString(string) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignString", AppropriateKind: ipld.ReprKindSet_JustString, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) AssignBytes([]byte) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignBytes", AppropriateKind: ipld.ReprKindSet_JustBytes, ActualKind: ipld.ReprKind_@Kind@} +} +func (x @Kind@Assembler) AssignLink(ipld.Link) error { + return ipld.ErrWrongKind{TypeName: x.TypeName, MethodName: "AssignLink", AppropriateKind: ipld.ReprKindSet_JustLink, ActualKind: ipld.ReprKind_@Kind@} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/nodeBuilder.go b/vendor/github.com/ipld/go-ipld-prime/nodeBuilder.go new file mode 100644 index 0000000000..20d92957e4 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/nodeBuilder.go @@ -0,0 +1,137 @@ +package ipld + +// NodeAssembler is the interface that describes all the ways we can set values +// in a node that's under construction. +// +// To create a Node, you should start with a NodeBuilder (which contains a +// superset of the NodeAssembler methods, and can return the finished Node +// from its `Build` method). +// +// Why do both this and the NodeBuilder interface exist? +// When creating trees of nodes, recursion works over the NodeAssembler interface. +// This is important to efficient library internals, because avoiding the +// requirement to be able to return a Node at any random point in the process +// relieves internals from needing to implement 'freeze' features. +// (This is useful in turn because implementing those 'freeze' features in a +// language without first-class/compile-time support for them (as golang is) +// would tend to push complexity and costs to execution time; we'd rather not.) +type NodeAssembler interface { + BeginMap(sizeHint int) (MapAssembler, error) + BeginList(sizeHint int) (ListAssembler, error) + AssignNull() error + AssignBool(bool) error + AssignInt(int) error + AssignFloat(float64) error + AssignString(string) error + AssignBytes([]byte) error + AssignLink(Link) error + + AssignNode(Node) error // if you already have a completely constructed subtree, this method puts the whole thing in place at once. + + // Style returns a NodeStyle describing what kind of value we're assembling. + // + // You often don't need this (because you should be able to + // just feed data and check errors), but it's here. + // + // Using `this.Style().NewBuilder()` to produce a new `Node`, + // then giving that node to `this.AssignNode(n)` should always work. + // (Note that this is not necessarily an _exclusive_ statement on what + // sort of values will be accepted by `this.AssignNode(n)`.) + Style() NodeStyle +} + +// MapAssembler assembles a map node! (You guessed it.) +// +// Methods on MapAssembler must be called in a valid order: +// assemble a key, then assemble a value, then loop as long as desired; +// when finished, call 'Finish'. +// +// Incorrect order invocations will panic. +// Calling AssembleKey twice in a row will panic; +// calling AssembleValue before finishing using the NodeAssembler from AssembleKey will panic; +// calling AssembleValue twice in a row will panic; +// etc. +// +// Note that the NodeAssembler yielded from AssembleKey has additional behavior: +// if the node assembled there matches a key already present in the map, +// that assembler will emit the error! +type MapAssembler interface { + AssembleKey() NodeAssembler // must be followed by call to AssembleValue. + AssembleValue() NodeAssembler // must be called immediately after AssembleKey. + + AssembleEntry(k string) (NodeAssembler, error) // shortcut combining AssembleKey and AssembleValue into one step; valid when the key is a string kind. + + Finish() error + + // KeyStyle returns a NodeStyle that knows how to build keys of a type this map uses. + // + // You often don't need this (because you should be able to + // just feed data and check errors), but it's here. + // + // For all Data Model maps, this will answer with a basic concept of "string". + // For Schema typed maps, this may answer with a more complex type (potentially even a struct type). + KeyStyle() NodeStyle + + // ValueStyle returns a NodeStyle that knows how to build values this map can contain. + // + // You often don't need this (because you should be able to + // just feed data and check errors), but it's here. + // + // ValueStyle requires a parameter describing the key in order to say what + // NodeStyle will be acceptable as a value for that key, because when using + // struct types (or union types) from the Schemas system, they behave as maps + // but have different acceptable types for each field (or member, for unions). + // For plain maps (that is, not structs or unions masquerading as maps), + // the empty string can be used as a parameter, and the returned NodeStyle + // can be assumed applicable for all values. + // Using an empty string for a struct or union will return a nil NodeStyle. + // (Design note: a string is sufficient for the parameter here rather than + // a full Node, because the only cases where the value types vary are also + // cases where the keys may not be complex.) + ValueStyle(k string) NodeStyle +} + +type ListAssembler interface { + AssembleValue() NodeAssembler + + Finish() error + + // ValueStyle returns a NodeStyle that knows how to build values this map can contain. + // + // You often don't need this (because you should be able to + // just feed data and check errors), but it's here. + // + // ValueStyle, much like the matching method on the MapAssembler interface, + // requires a parameter specifying the index in the list in order to say + // what NodeStyle will be acceptable as a value at that position. + // For many lists (and *all* lists which operate exclusively at the Data Model level), + // this will return the same NodeStyle regardless of the value of 'idx'; + // the only time this value will vary is when operating with a Schema, + // and handling the representation NodeAssembler for a struct type with + // a representation of a list kind. + // If you know you are operating in a situation that won't have varying + // NodeStyles, it is acceptable to call `ValueStyle(0)` and use the + // resulting NodeStyle for all reasoning. + ValueStyle(idx int) NodeStyle +} + +type NodeBuilder interface { + NodeAssembler + + // Build returns the new value after all other assembly has been completed. + // + // A method on the NodeAssembler that finishes assembly of the data must + // be called first (e.g., any of the "Assign*" methods, or "Finish" if + // the assembly was for a map or a list); that finishing method still has + // all responsibility for validating the assembled data and returning + // any errors from that process. + // (Correspondingly, there is no error return from this method.) + Build() Node + + // Resets the builder. It can hereafter be used again. + // Reusing a NodeBuilder can reduce allocations and improve performance. + // + // Only call this if you're going to reuse the builder. + // (Otherwise, it's unnecessary, and may cause an unwanted allocation). + Reset() +} diff --git a/vendor/github.com/ipld/go-ipld-prime/path.go b/vendor/github.com/ipld/go-ipld-prime/path.go new file mode 100644 index 0000000000..fef7b8d66a --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/path.go @@ -0,0 +1,193 @@ +package ipld + +import ( + "strings" +) + +// Path describes a series of steps across a tree or DAG of Node, +// where each segment in the path is a map key or list index +// (literaly, Path is a slice of PathSegment values). +// Path is used in describing progress in a traversal; and +// can also be used as an instruction for traversing from one Node to another. +// Path values will also often be encountered as part of error messages. +// +// (Note that Paths are useful as an instruction for traversing from +// *one* Node to *one* other Node; to do a walk from one Node and visit +// *several* Nodes based on some sort of pattern, look to IPLD Selectors, +// and the 'traversal/selector' package in this project.) +// +// Path values are always relative. +// Observe how 'traversal.Focus' requires both a Node and a Path argument -- +// where to start, and where to go, respectively. +// Similarly, error values which include a Path will be speaking in reference +// to the "starting Node" in whatever context they arose from. +// +// The canonical form of a Path is as a list of PathSegment. +// Each PathSegment is a string; by convention, the string should be +// in UTF-8 encoding and use NFC normalization, but all operations +// will regard the string as its constituent eight-bit bytes. +// +// There are no illegal or magical characters in IPLD Paths +// (in particular, do not mistake them for UNIX system paths). +// IPLD Paths can only go down: that is, each segment must traverse one node. +// There is no ".." which means "go up"; +// and there is no "." which means "stay here". +// IPLD Paths have no magic behavior around characters such as "~". +// IPLD Paths do not have a concept of "globs" nor behave specially +// for a path segment string of "*" (but you may wish to see 'Selectors' +// for globbing-like features that traverse over IPLD data). +// +// An empty string is a valid PathSegment. +// (This leads to some unfortunate complications when wishing to represent +// paths in a simple string format; however, consider that maps do exist +// in serialized data in the wild where an empty string is used as the key: +// it is important we be able to correctly describe and address this!) +// +// A string containing "/" (or even being simply "/"!) is a valid PathSegment. +// (As with empty strings, this is unfortunate (in particular, because it +// very much doesn't match up well with expectations popularized by UNIX-like +// filesystems); but, as with empty strings, maps which contain such a key +// certainly exist, and it is important that we be able to regard them!) +// +// A string starting, ending, or otherwise containing the NUL (\x00) byte +// is also a valid PathSegment. This follows from the rule of "a string is +// regarded as its constituent eight-bit bytes": an all-zero byte is not exceptional. +// In golang, this doesn't pose particular difficulty, but note this would be +// of marked concern for languages which have "C-style nul-terminated strings". +// +// For an IPLD Path to be represented as a string, an encoding system +// including escaping is necessary. At present, there is not a single +// canonical specification for such an escaping; we expect to decide one +// in the future, but this is not yet settled and done. +// (This implementation has a 'String' method, but it contains caveats +// and may be ambiguous for some content. This may be fixed in the future.) +type Path struct { + segments []PathSegment +} + +// NewPath returns a Path composed of the given segments. +// +// This constructor function does a defensive copy, +// in case your segments slice should mutate in the future. +// (Use NewPathNocopy if this is a performance concern, +// and you're sure you know what you're doing.) +func NewPath(segments []PathSegment) Path { + p := Path{make([]PathSegment, len(segments))} + copy(p.segments, segments) + return p +} + +// NewPathNocopy is identical to NewPath but trusts that +// the segments slice you provide will not be mutated. +func NewPathNocopy(segments []PathSegment) Path { + return Path{segments} +} + +// ParsePath converts a string to an IPLD Path, doing a basic parsing of the +// string using "/" as a delimiter to produce a segmented Path. +// This is a handy, but not a general-purpose nor spec-compliant (!), +// way to create a Path: it cannot represent all valid paths. +// +// Multiple subsequent "/" characters will be silently collapsed. +// E.g., `"foo///bar"` will be treated equivalently to `"foo/bar"`. +// Prefixed and suffixed extraneous "/" characters are also discarded. +// This makes this constructor incapable of handling some possible Path values +// (specifically: paths with empty segements cannot be created with this constructor). +// +// There is no escaping mechanism used by this function. +// This makes this constructor incapable of handling some possible Path values +// (specifically, a path segment containing "/" cannot be created, because it +// will always be intepreted as a segment separator). +// +// No other "cleaning" of the path occurs. See the documentation of the Path struct; +// in particular, note that ".." does not mean "go up", nor does "." mean "stay here" -- +// correspondingly, there isn't anything to "clean" in the same sense as +// 'filepath.Clean' from the standard library filesystem path packages would. +// +// If the provided string contains unprintable characters, or non-UTF-8 +// or non-NFC-canonicalized bytes, no remark will be made about this, +// and those bytes will remain part of the PathSegments in the resulting Path. +func ParsePath(pth string) Path { + // FUTURE: we should probably have some escaping mechanism which makes + // it possible to encode a slash in a segment. Specification needed. + ss := strings.FieldsFunc(pth, func(r rune) bool { return r == '/' }) + ssl := len(ss) + p := Path{make([]PathSegment, ssl)} + for i := 0; i < ssl; i++ { + p.segments[i] = PathSegmentOfString(ss[i]) + } + return p +} + +// String representation of a Path is simply the join of each segment with '/'. +// It does not include a leading nor trailing slash. +// +// This is a handy, but not a general-purpose nor spec-compliant (!), +// way to reduce a Path to a string. +// There is no escaping mechanism used by this function, +// and as a result, not all possible valid Path values (such as those with +// empty segments or with segments containing "/") can be encoded unambiguously. +// For Path values containing these problematic segments, ParsePath applied +// to the string returned from this function may return a nonequal Path value. +// +// No escaping for unprintable characters is provided. +// No guarantee that the resulting string is UTF-8 nor NFC canonicalized +// is provided unless all the constituent PathSegment had those properties. +func (p Path) String() string { + l := len(p.segments) + if l == 0 { + return "" + } + sb := strings.Builder{} + for i := 0; i < l-1; i++ { + sb.WriteString(p.segments[i].String()) + sb.WriteByte('/') + } + sb.WriteString(p.segments[l-1].String()) + return sb.String() +} + +// Segements returns a slice of the path segment strings. +// +// It is not lawful to mutate nor append the returned slice. +func (p Path) Segments() []PathSegment { + return p.segments +} + +// Join creates a new path composed of the concatenation of this and the given path's segments. +func (p Path) Join(p2 Path) Path { + combinedSegments := make([]PathSegment, len(p.segments)+len(p2.segments)) + copy(combinedSegments, p.segments) + copy(combinedSegments[len(p.segments):], p2.segments) + p.segments = combinedSegments + return p +} + +// AppendSegmentString is as per Join, but a shortcut when appending single segments using strings. +func (p Path) AppendSegment(ps PathSegment) Path { + l := len(p.segments) + combinedSegments := make([]PathSegment, l+1) + copy(combinedSegments, p.segments) + combinedSegments[l] = ps + p.segments = combinedSegments + return p +} + +// AppendSegmentString is as per Join, but a shortcut when appending single segments using strings. +func (p Path) AppendSegmentString(ps string) Path { + return p.AppendSegment(PathSegmentOfString(ps)) +} + +// Parent returns a path with the last of its segments popped off (or +// the zero path if it's already empty). +func (p Path) Parent() Path { + if len(p.segments) == 0 { + return Path{} + } + return Path{p.segments[0 : len(p.segments)-1]} +} + +// Truncate returns a path with only as many segments remaining as requested. +func (p Path) Truncate(i int) Path { + return Path{p.segments[0:i]} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/pathSegment.go b/vendor/github.com/ipld/go-ipld-prime/pathSegment.go new file mode 100644 index 0000000000..fd0238c77d --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/pathSegment.go @@ -0,0 +1,136 @@ +package ipld + +import ( + "strconv" +) + +// PathSegment can describe either a key in a map, or an index in a list. +// +// Create a PathSegment via either ParsePathSegment, PathSegmentOfString, +// or PathSegmentOfInt; or, via one of the constructors of Path, +// which will implicitly create PathSegment internally. +// Using PathSegment's natural zero value directly is discouraged +// (it will act like ParsePathSegment("0"), which likely not what you'd expect). +// +// Path segments are "stringly typed" -- they may be interpreted as either strings or ints depending on context. +// A path segment of "123" will be used as a string when traversing a node of map kind; +// and it will be converted to an integer when traversing a node of list kind. +// (If a path segment string cannot be parsed to an int when traversing a node of list kind, then traversal will error.) +// It is not possible to ask which kind (string or integer) a PathSegment is, because that is not defined -- this is *only* intepreted contextually. +// +// Internally, PathSegment will store either a string or an integer, +// depending on how it was constructed, +// and will automatically convert to the other on request. +// (This means if two pieces of code communicate using PathSegment, +// one producing ints and the other expecting ints, +// then they will work together efficiently.) +// PathSegment in a Path produced by ParsePath generally have all strings internally, +// because there is no distinction possible when parsing a Path string +// (and attempting to pre-parse all strings into ints "just in case" would waste time in almost all cases). +// +// Be cautious of attempting to use PathSegment as a map key! +// Due to the implementation detail of internal storage, it's possible for +// PathSegment values which are "equal" per PathSegment.Equal's definition +// to still be unequal in the eyes of golang's native maps. +// You should probably use the string values of the PathSegment as map keys. +// (This has the additional bonus of hitting a special fastpath that the golang +// built-in maps have specifically for plain string keys.) +// +type PathSegment struct { + /* + A quick implementation note about the Go compiler and "union" semantics: + + There are roughly two ways to do "union" semantics in Go. + + The first is to make a struct with each of the values. + + The second is to make an interface and use an unexported method to keep it closed. + + The second tactic provides somewhat nicer semantics to the programmer. + (Namely, it's clearly impossible to have two inhabitants, which is... the point.) + The downside is... putting things in interfaces generally incurs an allocation + (grep your assembly output for "runtime.conv*"). + + The first tactic looks kludgier, and would seem to waste memory + (the struct reserves space for each possible value, even though the semantic is that only one may be non-zero). + However, in most cases, more *bytes* are cheaper than more *allocs* -- + garbage collection costs are domininated by alloc count, not alloc size. + + Because PathSegment is something we expect to put in fairly "hot" paths, + we're using the first tactic. + + (We also currently get away with having no extra discriminator bit + because we use a signed int for indexes, and negative values aren't valid there, + and thus we can use it as a sentinel value. + (Fun note: Empty strings were originally used for this sentinel, + but it turns out empty strings are valid PathSegment themselves, so!)) + */ + + s string + i int +} + +// ParsePathSegment parses a string into a PathSegment, +// handling any escaping if present. +// (Note: there is currently no escaping specified for PathSegments, +// so this is currently functionally equivalent to PathSegmentOfString.) +func ParsePathSegment(s string) PathSegment { + return PathSegment{s: s, i: -1} +} + +// PathSegmentOfString boxes a string into a PathSegment. +// It does not attempt to parse any escaping; use ParsePathSegment for that. +func PathSegmentOfString(s string) PathSegment { + return PathSegment{s: s, i: -1} +} + +// PathSegmentOfString boxes an int into a PathSegment. +func PathSegmentOfInt(i int) PathSegment { + return PathSegment{i: i} +} + +// containsString is unexported because we use it to see what our *storage* form is, +// but this is considered an implementation detail that's non-semantic. +// If it returns false, it implicitly means "containsInt", as these are the only options. +func (ps PathSegment) containsString() bool { + return ps.i < 0 +} + +// String returns the PathSegment as a string. +func (ps PathSegment) String() string { + switch ps.containsString() { + case true: + return ps.s + case false: + return strconv.Itoa(ps.i) + } + panic("unreachable") +} + +// Index returns the PathSegment as an int, +// or returns an error if the segment is a string that can't be parsed as an int. +func (ps PathSegment) Index() (int, error) { + switch ps.containsString() { + case true: + return strconv.Atoi(ps.s) + case false: + return ps.i, nil + } + panic("unreachable") +} + +// Equals checks if two PathSegment values are equal. +// +// Because PathSegment is "stringly typed", this comparison does not +// regard if one of the segments is stored as a string and one is stored as an int; +// if string values of two segments are equal, they are "equal" overall. +// In other words, `PathSegmentOfInt(2).Equals(PathSegmentOfString("2")) == true`! +// (You should still typically prefer this method over converting two segments +// to string and comparing those, because even though that may be functionally +// correct, this method will be faster if they're both ints internally.) +func (x PathSegment) Equals(o PathSegment) bool { + if !x.containsString() && !o.containsString() { + return x.i == o.i + } + return x.String() == o.String() +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/errors.go b/vendor/github.com/ipld/go-ipld-prime/schema/errors.go new file mode 100644 index 0000000000..d0f908ee01 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/errors.go @@ -0,0 +1,18 @@ +package schema + +import ( + "fmt" +) + +// ErrNoSuchField may be returned from lookup functions on the Node +// interface when a field is requested which doesn't exist, or from Insert +// on a MapBuilder when a key doesn't match a field name in the structure. +type ErrNoSuchField struct { + Type Type + + FieldName string +} + +func (e ErrNoSuchField) Error() string { + return fmt.Sprintf("no such field: %s.%s", e.Type.Name(), e.FieldName) +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/kind.go b/vendor/github.com/ipld/go-ipld-prime/schema/kind.go new file mode 100644 index 0000000000..604a82d247 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/kind.go @@ -0,0 +1,108 @@ +package schema + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +// Kind is an enum of kind in the IPLD Schema system. +// +// Note that schema.Kind is distinct from ipld.ReprKind! +// Schema kinds include concepts such as "struct" and "enum", which are +// concepts only introduced by the Schema layer, and not present in the +// Data Model layer. +type Kind uint8 + +const ( + Kind_Invalid Kind = 0 + Kind_Map Kind = '{' + Kind_List Kind = '[' + Kind_Unit Kind = '1' + Kind_Bool Kind = 'b' + Kind_Int Kind = 'i' + Kind_Float Kind = 'f' + Kind_String Kind = 's' + Kind_Bytes Kind = 'x' + Kind_Link Kind = '/' + Kind_Struct Kind = '$' + Kind_Union Kind = '^' + Kind_Enum Kind = '%' + // FUTURE: Kind_Any = '?'? +) + +func (k Kind) String() string { + switch k { + case Kind_Invalid: + return "Invalid" + case Kind_Map: + return "Map" + case Kind_List: + return "List" + case Kind_Unit: + return "Unit" + case Kind_Bool: + return "Bool" + case Kind_Int: + return "Int" + case Kind_Float: + return "Float" + case Kind_String: + return "String" + case Kind_Bytes: + return "Bytes" + case Kind_Link: + return "Link" + case Kind_Struct: + return "Struct" + case Kind_Union: + return "Union" + case Kind_Enum: + return "Enum" + default: + panic("invalid enumeration value!") + } +} + +// ActsLike returns a constant from the ipld.ReprKind enum describing what +// this schema.Kind acts like at the Data Model layer. +// +// Things with similar names are generally conserved +// (e.g. "map" acts like "map"); +// concepts added by the schema layer have to be mapped onto something +// (e.g. "struct" acts like "map"). +// +// Note that this mapping describes how a typed Node will *act*, programmatically; +// it does not necessarily describe how it will be *serialized* +// (for example, a struct will always act like a map, even if it has a tuple +// representation strategy and thus becomes a list when serialized). +func (k Kind) ActsLike() ipld.ReprKind { + switch k { + case Kind_Invalid: + return ipld.ReprKind_Invalid + case Kind_Map: + return ipld.ReprKind_Map + case Kind_List: + return ipld.ReprKind_List + case Kind_Unit: + return ipld.ReprKind_Bool // maps to 'true'. + case Kind_Bool: + return ipld.ReprKind_Bool + case Kind_Int: + return ipld.ReprKind_Int + case Kind_Float: + return ipld.ReprKind_Float + case Kind_String: + return ipld.ReprKind_String + case Kind_Bytes: + return ipld.ReprKind_Bytes + case Kind_Link: + return ipld.ReprKind_Link + case Kind_Struct: + return ipld.ReprKind_Map // clear enough: fields are keys. + case Kind_Union: + return ipld.ReprKind_Map // REVIEW: unions are tricky. + case Kind_Enum: + return ipld.ReprKind_String // 'AsString' is the one clear thing to define. + default: + panic("invalid enumeration value!") + } +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/maybe.go b/vendor/github.com/ipld/go-ipld-prime/schema/maybe.go new file mode 100644 index 0000000000..670a6bcf6c --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/maybe.go @@ -0,0 +1,9 @@ +package schema + +type Maybe uint8 + +const ( + Maybe_Value = Maybe(0) + Maybe_Null = Maybe(1) + Maybe_Absent = Maybe(2) +) diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/tmpBuilders.go b/vendor/github.com/ipld/go-ipld-prime/schema/tmpBuilders.go new file mode 100644 index 0000000000..ed12f1128d --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/tmpBuilders.go @@ -0,0 +1,44 @@ +package schema + +// Everything in this file is __a temporary hack__ and will be __removed__. +// +// These methods will only hang around until more of the "ast" packages are finished; +// thereafter, building schema.Type and schema.TypeSystem values will only be +// possible through first constructing a schema AST, and *then* using Reify(), +// which will validate things correctly, cycle-check, cross-link, etc. +// +// (Meanwhile, we're using these methods in the codegen prototypes.) + +func SpawnString(name TypeName) TypeString { + return TypeString{anyType{name, nil}} +} + +func SpawnInt(name TypeName) TypeInt { + return TypeInt{anyType{name, nil}} +} + +func SpawnBytes(name TypeName) TypeBytes { + return TypeBytes{anyType{name, nil}} +} + +func SpawnLink(name TypeName) TypeLink { + return TypeLink{anyType{name, nil}, nil, false} +} + +func SpawnLinkReference(name TypeName, referenceType Type) TypeLink { + return TypeLink{anyType{name, nil}, referenceType, true} +} +func SpawnList(name TypeName, typ Type, nullable bool) TypeList { + return TypeList{anyType{name, nil}, false, typ, nullable} +} + +func SpawnStruct(name TypeName, fields []StructField, repr StructRepresentation) TypeStruct { + fieldsMap := make(map[string]StructField, len(fields)) + for _, field := range fields { + fieldsMap[field.name] = field + } + return TypeStruct{anyType{name, nil}, fields, fieldsMap, repr} +} +func SpawnStructField(name string, typ Type, optional bool, nullable bool) StructField { + return StructField{name, typ, optional, nullable} +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/type.go b/vendor/github.com/ipld/go-ipld-prime/schema/type.go new file mode 100644 index 0000000000..dd6c622f13 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/type.go @@ -0,0 +1,188 @@ +package schema + +import ( + ipld "github.com/ipld/go-ipld-prime" +) + +type TypeName string // = ast.TypeName + +// typesystem.Type is an union interface; each of the `Type*` concrete types +// in this package are one of its members. +// +// Specifically, +// +// TypeBool +// TypeString +// TypeBytes +// TypeInt +// TypeFloat +// TypeMap +// TypeList +// TypeLink +// TypeUnion +// TypeStruct +// TypeEnum +// +// are all of the kinds of Type. +// +// This is a closed union; you can switch upon the above members without +// including a default case. The membership is closed by the unexported +// '_Type' method; you may use the BurntSushi/go-sumtype tool to check +// your switches for completeness. +// +// Many interesting properties of each Type are only defined for that specific +// type, so it's typical to use a type switch to handle each type of Type. +// (Your humble author is truly sorry for the word-mash that results from +// attempting to describe the types that describe the typesystem.Type.) +// +// For example, to inspect the kind of fields in a struct: you might +// cast a `Type` interface into `TypeStruct`, and then the `Fields()` on +// that `TypeStruct` can be inspected. (`Fields()` isn't defined for any +// other kind of Type.) +type Type interface { + // Unexported marker method to force the union closed. + _Type() + + // Returns a pointer to the TypeSystem this Type is a member of. + TypeSystem() *TypeSystem + + // Returns the string name of the Type. This name is unique within the + // universe this type is a member of, *unless* this type is Anonymous, + // in which case a string describing the type will still be returned, but + // that string will not be required to be unique. + Name() TypeName + + // Returns the Kind of this Type. + // + // The returned value is a 1:1 association with which of the concrete + // "schema.Type*" structs this interface can be cast to. + // + // Note that a schema.Kind is a different enum than ipld.ReprKind; + // and furthermore, there's no strict relationship between them. + // schema.TypedNode values can be described by *two* distinct ReprKinds: + // one which describes how the Node itself will act, + // and another which describes how the Node presents for serialization. + // For some combinations of Type and representation strategy, one or both + // of the ReprKinds can be determined statically; but not always: + // it can sometimes be necessary to inspect the value quite concretely + // (e.g., `schema.TypedNode{}.Representation().ReprKind()`) in order to find + // out exactly how a node will be serialized! This is because some types + // can vary in representation kind based on their value (specifically, + // kinded-representation unions have this property). + Kind() Kind +} + +var ( + _ Type = TypeBool{} + _ Type = TypeString{} + _ Type = TypeBytes{} + _ Type = TypeInt{} + _ Type = TypeFloat{} + _ Type = TypeMap{} + _ Type = TypeList{} + _ Type = TypeLink{} + _ Type = TypeUnion{} + _ Type = TypeStruct{} + _ Type = TypeEnum{} +) + +type anyType struct { + name TypeName + universe *TypeSystem +} + +type TypeBool struct { + anyType +} + +type TypeString struct { + anyType +} + +type TypeBytes struct { + anyType +} + +type TypeInt struct { + anyType +} + +type TypeFloat struct { + anyType +} + +type TypeMap struct { + anyType + anonymous bool + keyType Type // must be ReprKind==string (e.g. Type==String|Enum). + valueType Type + valueNullable bool +} + +type TypeList struct { + anyType + anonymous bool + valueType Type + valueNullable bool +} + +type TypeLink struct { + anyType + referencedType Type + hasReferencedType bool + // ...? +} + +type TypeUnion struct { + anyType + style UnionStyle + valuesKinded map[ipld.ReprKind]Type // for Style==Kinded + values map[string]Type // for Style!=Kinded (note, key is freetext, not necessarily TypeName of the value) + typeHintKey string // for Style==Envelope|Inline + contentKey string // for Style==Envelope +} + +type UnionStyle struct{ x string } + +var ( + UnionStyle_Kinded = UnionStyle{"kinded"} + UnionStyle_Keyed = UnionStyle{"keyed"} + UnionStyle_Envelope = UnionStyle{"envelope"} + UnionStyle_Inline = UnionStyle{"inline"} +) + +type TypeStruct struct { + anyType + // n.b. `Fields` is an (order-preserving!) map in the schema-schema; + // but it's a list here, with the keys denormalized into the value, + // because that's typically how we use it. + fields []StructField + fieldsMap map[string]StructField // same content, indexed for lookup. + representation StructRepresentation +} +type StructField struct { + name string + typ Type + optional bool + nullable bool +} + +type StructRepresentation interface{ _StructRepresentation() } + +func (StructRepresentation_Map) _StructRepresentation() {} +func (StructRepresentation_Tuple) _StructRepresentation() {} +func (StructRepresentation_StringPairs) _StructRepresentation() {} +func (StructRepresentation_StringJoin) _StructRepresentation() {} + +type StructRepresentation_Map struct { + renames map[string]string + implicits map[string]interface{} +} +type StructRepresentation_Tuple struct{} +type StructRepresentation_StringPairs struct{ sep1, sep2 string } +type StructRepresentation_StringJoin struct{ sep string } + +type TypeEnum struct { + anyType + members []string +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/typeMethods.go b/vendor/github.com/ipld/go-ipld-prime/schema/typeMethods.go new file mode 100644 index 0000000000..0e7d23fb8c --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/typeMethods.go @@ -0,0 +1,160 @@ +package schema + +/* cookie-cutter standard interface stuff */ + +func (anyType) _Type() {} +func (t anyType) TypeSystem() *TypeSystem { return t.universe } +func (t anyType) Name() TypeName { return t.name } + +func (TypeBool) Kind() Kind { return Kind_Bool } +func (TypeString) Kind() Kind { return Kind_String } +func (TypeBytes) Kind() Kind { return Kind_Bytes } +func (TypeInt) Kind() Kind { return Kind_Int } +func (TypeFloat) Kind() Kind { return Kind_Float } +func (TypeMap) Kind() Kind { return Kind_Map } +func (TypeList) Kind() Kind { return Kind_List } +func (TypeLink) Kind() Kind { return Kind_Link } +func (TypeUnion) Kind() Kind { return Kind_Union } +func (TypeStruct) Kind() Kind { return Kind_Struct } +func (TypeEnum) Kind() Kind { return Kind_Enum } + +/* interesting methods per Type type */ + +// IsAnonymous is returns true if the type was unnamed. Unnamed types will +// claim to have a Name property like `{Foo:Bar}`, and this is not guaranteed +// to be a unique string for all types in the universe. +func (t TypeMap) IsAnonymous() bool { + return t.anonymous +} + +// KeyType returns the Type of the map keys. +// +// Note that map keys will must always be some type which is representable as a +// string in the IPLD Data Model (e.g. either TypeString or TypeEnum). +func (t TypeMap) KeyType() Type { + return t.keyType +} + +// ValueType returns to the Type of the map values. +func (t TypeMap) ValueType() Type { + return t.valueType +} + +// ValueIsNullable returns a bool describing if the map values are permitted +// to be null. +func (t TypeMap) ValueIsNullable() bool { + return t.valueNullable +} + +// IsAnonymous is returns true if the type was unnamed. Unnamed types will +// claim to have a Name property like `[Foo]`, and this is not guaranteed +// to be a unique string for all types in the universe. +func (t TypeList) IsAnonymous() bool { + return t.anonymous +} + +// ValueType returns to the Type of the list values. +func (t TypeList) ValueType() Type { + return t.valueType +} + +// ValueIsNullable returns a bool describing if the list values are permitted +// to be null. +func (t TypeList) ValueIsNullable() bool { + return t.valueNullable +} + +// UnionMembers returns a set of all the types that can inhabit this Union. +func (t TypeUnion) UnionMembers() map[Type]struct{} { + m := make(map[Type]struct{}, len(t.values)+len(t.valuesKinded)) + switch t.style { + case UnionStyle_Kinded: + for _, v := range t.valuesKinded { + m[v] = struct{}{} + } + default: + for _, v := range t.values { + m[v] = struct{}{} + } + } + return m +} + +// Fields returns a slice of descriptions of the object's fields. +func (t TypeStruct) Fields() []StructField { + a := make([]StructField, len(t.fields)) + for i := range t.fields { + a[i] = t.fields[i] + } + return a +} + +// Field looks up a StructField by name, or returns nil if no such field. +func (t TypeStruct) Field(name string) *StructField { + if v, ok := t.fieldsMap[name]; ok { + return &v + } + return nil +} + +// Name returns the string name of this field. The name is the string that +// will be used as a map key if the structure this field is a member of is +// serialized as a map representation. +func (f StructField) Name() string { return f.name } + +// Type returns the Type of this field's value. Note the field may +// also be unset if it is either Optional or Nullable. +func (f StructField) Type() Type { return f.typ } + +// IsOptional returns true if the field is allowed to be absent from the object. +// If IsOptional is false, the field may be absent from the serial representation +// of the object entirely. +// +// Note being optional is different than saying the value is permitted to be null! +// A field may be both nullable and optional simultaneously, or either, or neither. +func (f StructField) IsOptional() bool { return f.optional } + +// IsNullable returns true if the field value is allowed to be null. +// +// If is Nullable is false, note that it's still possible that the field value +// will be absent if the field is Optional! Being nullable is unrelated to +// whether the field's presence is optional as a whole. +// +// Note that a field may be both nullable and optional simultaneously, +// or either, or neither. +func (f StructField) IsNullable() bool { return f.nullable } + +func (t TypeStruct) RepresentationStrategy() StructRepresentation { + return t.representation +} + +func (r StructRepresentation_Map) GetFieldKey(field StructField) string { + if n, ok := r.renames[field.name]; ok { + return n + } + return field.name +} + +// Members returns a slice the strings which are valid inhabitants of this enum. +func (t TypeEnum) Members() []string { + a := make([]string, len(t.members)) + for i := range t.members { + a[i] = t.members[i] + } + return a +} + +// Links can keep a referenced type, which is a hint only about the data on the +// other side of the link, no something that can be explicitly validated without +// loading the link + +// HasReferencedType returns true if the link has a hint about the type it references +// false if it's generic +func (t TypeLink) HasReferencedType() bool { + return t.hasReferencedType +} + +// ReferencedType returns the type hint for the node on the other side of the link +func (t TypeLink) ReferencedType() Type { + return t.referencedType +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/typedNode.go b/vendor/github.com/ipld/go-ipld-prime/schema/typedNode.go new file mode 100644 index 0000000000..2e608c83b5 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/typedNode.go @@ -0,0 +1,73 @@ +package schema + +import ( + "github.com/ipld/go-ipld-prime" +) + +// schema.TypedNode is a superset of the ipld.Node interface, and has additional behaviors. +// +// A schema.TypedNode can be inspected for its schema.Type and schema.Kind, +// which conveys much more and richer information than the Data Model layer +// ipld.ReprKind. +// +// There are many different implementations of schema.TypedNode. +// One implementation can wrap any other existing ipld.Node (i.e., it's zero-copy) +// and promises that it has *already* been validated to match the typesystem.Type; +// another implementation similarly wraps any other existing ipld.Node, but +// defers to the typesystem validation checking to fields that are accessed; +// and when using code generation tools, all of the generated native Golang +// types produced by the codegen will each individually implement schema.TypedNode. +// +// Typed nodes sometimes have slightly different behaviors than plain nodes: +// For example, when looking up fields on a typed node that's a struct, +// the error returned for a lookup with a key that's not a field name will +// be ErrNoSuchField (instead of ErrNotExists). +// These behaviors apply to the schema.TypedNode only and not their representations; +// continuing the example, the .Representation().LookupString() method on +// that same node for the same key as plain `.LookupString()` will still +// return ErrNotExists, because the representation isn't a schema.TypedNode! +type TypedNode interface { + // schema.TypedNode acts just like a regular Node for almost all purposes; + // which ipld.ReprKind it acts as is determined by the TypeKind. + // (Note that the representation strategy of the type does *not* affect + // the ReprKind of schema.TypedNode -- rather, the representation strategy + // affects the `.Representation().ReprKind()`.) + // + // For example: if the `.Type().Kind()` of this node is "struct", + // it will act like ReprKind() == "map" + // (even if Type().(Struct).ReprStrategy() is "tuple"). + ipld.Node + + // Type returns a reference to the reified schema.Type value. + Type() Type + + // Representation returns an ipld.Node which sees the data in this node + // in its representation form. + // + // For example: if the `.Type().Kind()` of this node is "struct", + // `.Representation().Kind()` may vary based on its representation strategy: + // if the representation strategy is "map", then it will be ReprKind=="map"; + // if the streatgy is "tuple", then it will be ReprKind=="list". + Representation() ipld.Node +} + +// schema.TypedLinkNode is a superset of the schema.TypedNode interface, and has one additional behavior. +// +// A schema.TypedLinkNode contains a hint for the appropriate node builder to use for loading data +// on the other side of the link contained within the node, so that it can be assembled +// into a node representation and validated against the schema as quickly as possible +// +// So, for example, if you wanted to support loading the other side of a link +// with a code-gen'd node builder while utilizing the automatic loading facilities +// of the traversal package, you could write a LinkNodeBuilderChooser as follows: +// +// func LinkNodeBuilderChooser(lnk ipld.Link, lnkCtx ipld.LinkContext) ipld.NodeStyle { +// if tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok { +// return tlnkNd.LinkTargetNodeStyle() +// } +// return basicnode.Style__Any{} +// } +// +type TypedLinkNode interface { + LinkTargetNodeStyle() ipld.NodeStyle +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/typesystem.go b/vendor/github.com/ipld/go-ipld-prime/schema/typesystem.go new file mode 100644 index 0000000000..8e1420c2c6 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/typesystem.go @@ -0,0 +1,14 @@ +package schema + +type TypeSystem struct { + // namedTypes is the set of all named types in this universe. + // The map's key is the value's Name() property and must be unique. + // + // The IsAnonymous property is false for all values in this map that + // support the IsAnonymous property. + // + // Each Type in the universe may only refer to other types in their + // definition if those type are either A) in this namedTypes map, + // or B) are IsAnonymous==true. + namedTypes map[TypeName]Type +} diff --git a/vendor/github.com/ipld/go-ipld-prime/schema/validate.go b/vendor/github.com/ipld/go-ipld-prime/schema/validate.go new file mode 100644 index 0000000000..c9465261dc --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/schema/validate.go @@ -0,0 +1,70 @@ +package schema + +/* + Okay, so. There are several fun considerations for a "validate" method. + + --- + + There's two radically different approaches to "validate"/"reify": + + - Option 1: Look at the schema.Type info and check if a data node seems + to match it -- recursing on the type info. + - Option 2: Use the schema.Type{}.RepresentationNodeBuilder() to feed data + into it -- recursing on what the nodebuilder already expresses. + + (Option 2 also need to take a `memStorage ipld.NodeBuilder` param, btw, + for handling all the cases where we *aren't* doing codegen.) + + Option 1 provides a little more opportunity for returning multiple errors. + Option 2 will generally have a hard time with that (nodebuilers are not + necessarily in a valid state after their first error encounter). + + As a result of having these two options at all, we may indeed end up with + at least two very different functions -- despite seeming to do similar + things, their interior will radically diverge. + + --- + + We may also need to consider distinct reification paths: we may want one + that returns a new node tree which is eagerly converted to schema.TypedNode + recursively; and another that returns a lazyNode which wraps things + with their typed node constraints only as they're requested. + (Note that the latter would have interesting implications for any code + which has expectations about pointer equality consistency.) + + --- + + A further fun issue which needs consideration: well, I'll just save a snip + of prospective docs I wrote while trying to iterate on these functions: + + // Note that using Validate on a node that's already a schema.TypedNode is likely + // to be nonsensical. In many schemas, the schema.TypedNode tree is actually a + // different depth than its representational tree (e.g. unions can cause this), + + ... and that's ... that's a fairly sizable issue that needs resolving. + There's a couple of different ways to handle some of the behaviors around + unions, and some of them make the tradeoff described above, and I'm really + unsure if all the implications have been sussed out yet. We should defer + writing code that depends on this issue until gathering some more info. + + --- + + One more note: about returning multiple errors from a Validate function: + there's an upper bound of the utility of the thing. Going farther than the + first parse error is nice, but it will still hit limits: for example, + upon encountering a union and failing to match it, we can't generally + produce further errors from anywhere deeper in the tree without them being + combinatorial "if previous juncture X was type Y, then..." nonsense. + (This applies to all recursive kinds to some degree, but it's especially + rough with unions. For most of the others, it's flatly a missing field, + or an excessive field, or a leaf error; with unions it can be hard to tell.) + + --- + + And finally: both "Validate" and "Reify" methods might actually belong + in the schema.TypedNode package -- if they make *any* reference to `schema.TypedNode`, + then they have no choice (otherwise, cyclic imports would occur). + If we make a "Validate" that works purely on the schema.Type info, and + returns *only* errors: only then we can have it in the schema package. + +*/ diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/common.go b/vendor/github.com/ipld/go-ipld-prime/traversal/common.go new file mode 100644 index 0000000000..5f5e472554 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/common.go @@ -0,0 +1,47 @@ +package traversal + +import ( + "context" + "fmt" + "io" + + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/schema" +) + +// init sets all the values in TraveralConfig to reasonable defaults +// if they're currently the zero value. +// +// Note that you're absolutely going to need to replace the +// LinkLoader and LinkNodeBuilderChooser if you want automatic link traversal; +// the defaults return error and/or panic. +func (tc *Config) init() { + if tc.Ctx == nil { + tc.Ctx = context.Background() + } + if tc.LinkLoader == nil { + tc.LinkLoader = func(ipld.Link, ipld.LinkContext) (io.Reader, error) { + return nil, fmt.Errorf("no link loader configured") + } + } + if tc.LinkTargetNodeStyleChooser == nil { + tc.LinkTargetNodeStyleChooser = func(lnk ipld.Link, lnkCtx ipld.LinkContext) (ipld.NodeStyle, error) { + if tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok { + return tlnkNd.LinkTargetNodeStyle(), nil + } + return nil, fmt.Errorf("no LinkTargetNodeStyleChooser configured") + } + } + if tc.LinkStorer == nil { + tc.LinkStorer = func(ipld.LinkContext) (io.Writer, ipld.StoreCommitter, error) { + return nil, nil, fmt.Errorf("no link storer configured") + } + } +} + +func (prog *Progress) init() { + if prog.Cfg == nil { + prog.Cfg = &Config{} + } + prog.Cfg.init() +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/doc.go b/vendor/github.com/ipld/go-ipld-prime/traversal/doc.go new file mode 100644 index 0000000000..822a9ec760 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/doc.go @@ -0,0 +1,57 @@ +// This package provides functional utilities for traversing and transforming +// IPLD nodes. +// +// The traversal.Path type provides a description of how to perform +// several steps across a Node tree. These are dual purpose: +// Paths can be used as instructions to do some traversal, and +// Paths are accumulated during traversals as a log of progress. +// +// "Focus" functions provide syntactic sugar for using ipld.Path to jump +// to a Node deep in a tree of other Nodes. +// +// "FocusedTransform" functions can do the same such deep jumps, and support +// mutation as well! +// (Of course, since ipld.Node is an immutable interface, more precisely +// speaking, "transformations" are implemented rebuilding trees of nodes to +// emulate mutation in a copy-on-write way.) +// +// "Walk" functions perform a walk of a Node graph, and apply visitor +// functions multiple Nodes. The more advanced Walk functions can be guided +// by Selectors, which provide a declarative mechanism for guiding the +// traversal and filtering which Nodes are of interest. +// (See the selector sub-package for more detail.) +// +// "WalkTransforming" is similar to Traverse, but with support for mutations. +// Like "FocusTransform", "WalkTransforming" operates in a copy-on-write way. +// +// All of these functions -- the "Focus*" and "Walk*" family alike -- +// work via callbacks: they do the traversal, and call a user-provided function +// with a handle to the reached Node. Further "Focus" and "Walk" can be used +// recursively within this callback. +// +// All of these functions -- the "Focus*" and "Walk*" family alike -- +// include support for automatic resolution and loading of new Node trees +// whenever IPLD Links are encountered. This can be configured freely +// by providing LinkLoader interfaces to the traversal.Config. +// +// Some notes on the limits of usage: +// +// The "*Transform" family of methods is most appropriate for patterns of usage +// which resemble point mutations. +// More general transformations -- zygohylohistomorphisms, etc -- will be best +// implemented by composing the read-only systems (e.g. Focus, Traverse) and +// handling the accumulation in the visitor functions. +// +// (Why? The "point mutation" use-case gets core library support because +// it's both high utility and highly clear how to implement it. +// More advanced transformations are nontrivial to provide generalized support +// for, for three reasons: efficiency is hard; not all existing research into +// categorical recursion schemes is necessarily applicable without modification +// (efficient behavior in a merkle-tree context is not the same as efficient +// behavior on uniform memory!); and we have the further compounding complexity +// of the range of choices available for underlying Node implementation. +// Therefore, attempts at generalization are not included here; handling these +// issues in concrete cases is easy, so we call it an application logic concern. +// However, exploring categorical recursion schemes as a library is encouraged!) +// +package traversal diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/fns.go b/vendor/github.com/ipld/go-ipld-prime/traversal/fns.go new file mode 100644 index 0000000000..b67ba6f2de --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/fns.go @@ -0,0 +1,69 @@ +package traversal + +import ( + "context" + + ipld "github.com/ipld/go-ipld-prime" +) + +// This file defines interfaces for things users provide, +// plus a few of the parameters they'll need to receieve. +//-------------------------------------------------------- + +// VisitFn is a read-only visitor. +type VisitFn func(Progress, ipld.Node) error + +// TransformFn is like a visitor that can also return a new Node to replace the visited one. +type TransformFn func(Progress, ipld.Node) (ipld.Node, error) + +// AdvVisitFn is like VisitFn, but for use with AdvTraversal: it gets additional arguments describing *why* this node is visited. +type AdvVisitFn func(Progress, ipld.Node, VisitReason) error + +// VisitReason provides additional information to traversals using AdvVisitFn. +type VisitReason byte + +const ( + VisitReason_SelectionMatch VisitReason = 'm' // Tells AdvVisitFn that this node was explicitly selected. (This is the set of nodes that VisitFn is called for.) + VisitReason_SelectionParent VisitReason = 'p' // Tells AdvVisitFn that this node is a parent of one that will be explicitly selected. (These calls only happen if the feature is enabled -- enabling parent detection requires a different algorithm and adds some overhead.) + VisitReason_SelectionCandidate VisitReason = 'x' // Tells AdvVisitFn that this node was visited while searching for selection matches. It is not necessarily implied that any explicit match will be a child of this node; only that we had to consider it. (Merkle-proofs generally need to include any node in this group.) +) + +type Progress struct { + Cfg *Config + Path ipld.Path // Path is how we reached the current point in the traversal. + LastBlock struct { // LastBlock stores the Path and Link of the last block edge we had to load. (It will always be zero in traversals with no linkloader.) + Path ipld.Path + Link ipld.Link + } +} + +type Config struct { + Ctx context.Context // Context carried through a traversal. Optional; use it if you need cancellation. + LinkLoader ipld.Loader // Loader used for automatic link traversal. + LinkTargetNodeStyleChooser LinkTargetNodeStyleChooser // Chooser for Node implementations to produce during automatic link traversal. + LinkStorer ipld.Storer // Storer used if any mutation features (e.g. traversal.Transform) are used. +} + +// LinkTargetNodeStyleChooser is a function that returns a NodeStyle based on +// the information in a Link and/or its LinkContext. +// +// A LinkTargetNodeStyleChooser can be used in a traversal.Config to be clear about +// what kind of Node implementation to use when loading a Link. +// In a simple example, it could constantly return a `basicnode.Style__Any{}`. +// In a more complex example, a program using `bind` over native Go types +// could decide what kind of native type is expected, and return a +// `bind.NodeBuilder` for that specific concrete native type. +type LinkTargetNodeStyleChooser func(ipld.Link, ipld.LinkContext) (ipld.NodeStyle, error) + +// SkipMe is a signalling "error" which can be used to tell traverse to skip some data. +// +// SkipMe can be returned by the Config.LinkLoader to skip entire blocks without aborting the walk. +// (This can be useful if you know you don't have data on hand, +// but want to continue the walk in other areas anyway; +// or, if you're doing a way where you know that it's valid to memoize seen +// areas based on Link alone.) +type SkipMe struct{} + +func (SkipMe) Error() string { + return "skip" +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/focus.go b/vendor/github.com/ipld/go-ipld-prime/traversal/focus.go new file mode 100644 index 0000000000..30c6f62043 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/focus.go @@ -0,0 +1,142 @@ +package traversal + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// Focus traverses a Node graph according to a path, reaches a single Node, +// and calls the given VisitFn on that reached node. +// +// This function is a helper function which starts a new traversal with default configuration. +// It cannot cross links automatically (since this requires configuration). +// Use the equivalent Focus function on the Progress structure +// for more advanced and configurable walks. +func Focus(n ipld.Node, p ipld.Path, fn VisitFn) error { + return Progress{}.Focus(n, p, fn) +} + +// FocusedTransform traverses an ipld.Node graph, reaches a single Node, +// and calls the given TransformFn to decide what new node to replace the visited node with. +// A new Node tree will be returned (the original is unchanged). +// +// This function is a helper function which starts a new traversal with default configuration. +// It cannot cross links automatically (since this requires configuration). +// Use the equivalent FocusedTransform function on the Progress structure +// for more advanced and configurable walks. +func FocusedTransform(n ipld.Node, p ipld.Path, fn TransformFn) (ipld.Node, error) { + return Progress{}.FocusedTransform(n, p, fn) +} + +// Focus traverses a Node graph according to a path, reaches a single Node, +// and calls the given VisitFn on that reached node. +// +// Focus is a read-only traversal. +// See FocusedTransform if looking for a way to do an "update" to a Node. +// +// Provide configuration to this process using the Config field in the Progress object. +// +// This walk will automatically cross links, but requires some configuration +// with link loading functions to do so. +// +// Focus (and the other traversal functions) can be used again again inside the VisitFn! +// By using the traversal.Progress handed to the VisitFn, +// the Path recorded of the traversal so far will continue to be extended, +// and thus continued nested uses of Walk and Focus will see the fully contextualized Path. +func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error { + prog.init() + segments := p.Segments() + var prev ipld.Node // for LinkContext + for i, seg := range segments { + // Traverse the segment. + switch n.ReprKind() { + case ipld.ReprKind_Invalid: + return fmt.Errorf("cannot traverse node at %q: it is undefined", p.Truncate(i)) + case ipld.ReprKind_Map: + next, err := n.LookupString(seg.String()) + if err != nil { + return fmt.Errorf("error traversing segment %q on node at %q: %s", seg, p.Truncate(i), err) + } + prev, n = n, next + case ipld.ReprKind_List: + intSeg, err := seg.Index() + if err != nil { + return fmt.Errorf("error traversing segment %q on node at %q: the segment cannot be parsed as a number and the node is a list", seg, p.Truncate(i)) + } + next, err := n.LookupIndex(intSeg) + if err != nil { + return fmt.Errorf("error traversing segment %q on node at %q: %s", seg, p.Truncate(i), err) + } + prev, n = n, next + default: + return fmt.Errorf("cannot traverse node at %q: %s", p.Truncate(i), fmt.Errorf("cannot traverse terminals")) + } + // Dereference any links. + for n.ReprKind() == ipld.ReprKind_Link { + lnk, _ := n.AsLink() + // Assemble the LinkContext in case the Loader or NBChooser want it. + lnkCtx := ipld.LinkContext{ + LinkPath: p.Truncate(i), + LinkNode: n, + ParentNode: prev, + } + // Pick what in-memory format we will build. + ns, err := prog.Cfg.LinkTargetNodeStyleChooser(lnk, lnkCtx) + if err != nil { + return fmt.Errorf("error traversing node at %q: could not load link %q: %s", p.Truncate(i+1), lnk, err) + } + nb := ns.NewBuilder() + // Load link! + err = lnk.Load( + prog.Cfg.Ctx, + lnkCtx, + nb, + prog.Cfg.LinkLoader, + ) + if err != nil { + return fmt.Errorf("error traversing node at %q: could not load link %q: %s", p.Truncate(i+1), lnk, err) + } + prog.LastBlock.Path = p.Truncate(i + 1) + prog.LastBlock.Link = lnk + prev, n = n, nb.Build() + } + } + prog.Path = prog.Path.Join(p) + return fn(prog, n) +} + +// FocusedTransform traverses an ipld.Node graph, reaches a single Node, +// and calls the given TransformFn to decide what new node to replace the visited node with. +// A new Node tree will be returned (the original is unchanged). +// +// If the TransformFn returns the same Node which it was called with, +// then the transform is a no-op, and the Node returned from the +// FocusedTransform call as a whole will also be the same as its starting Node. +// +// Otherwise, the reached node will be "replaced" with the new Node -- meaning +// that new intermediate nodes will be constructed to also replace each +// parent Node that was traversed to get here, thus propagating the changes in +// a copy-on-write fashion -- and the FocusedTransform function as a whole will +// return a new Node containing identical children except for those replaced. +// +// FocusedTransform can be used again inside the applied function! +// This kind of composition can be useful for doing batches of updates. +// E.g. if have a large Node graph which contains a 100-element list, and +// you want to replace elements 12, 32, and 95 of that list: +// then you should FocusedTransform to the list first, and inside that +// TransformFn's body, you can replace the entire list with a new one +// that is composed of copies of everything but those elements -- including +// using more TransformFn calls as desired to produce the replacement elements +// if it so happens that those replacement elements are easiest to construct +// by regarding them as incremental updates to the previous values. +// +// Note that anything you can do with the Transform function, you can also +// do with regular Node and NodeBuilder usage directly. Transform just +// does a large amount of the intermediate bookkeeping that's useful when +// creating new values which are partial updates to existing values. +// +// This feature is not yet implemented. +func (prog Progress) FocusedTransform(n ipld.Node, p ipld.Path, fn TransformFn) (ipld.Node, error) { + panic("TODO") // TODO surprisingly different from Focus -- need to store nodes we traversed, and able do building. +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/builder/builder.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/builder/builder.go new file mode 100644 index 0000000000..39c4cf2f39 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/builder/builder.go @@ -0,0 +1,167 @@ +package builder + +import ( + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/fluent" + selector "github.com/ipld/go-ipld-prime/traversal/selector" +) + +// SelectorSpec is a specification for a selector that can build +// a selector ipld.Node or an actual parsed Selector +type SelectorSpec interface { + Node() ipld.Node + Selector() (selector.Selector, error) +} + +// SelectorSpecBuilder is a utility interface to build selector ipld nodes +// quickly. +// +// It serves two purposes: +// 1. Save the user of go-ipld-prime time and mental overhead with an easy +// interface for making selector nodes in much less code without having to remember +// the selector sigils +// 2. Provide a level of protection from selector schema changes, at least in terms +// of naming, if not structure +type SelectorSpecBuilder interface { + ExploreRecursiveEdge() SelectorSpec + ExploreRecursive(limit selector.RecursionLimit, sequence SelectorSpec) SelectorSpec + ExploreUnion(...SelectorSpec) SelectorSpec + ExploreAll(next SelectorSpec) SelectorSpec + ExploreIndex(index int, next SelectorSpec) SelectorSpec + ExploreRange(start int, end int, next SelectorSpec) SelectorSpec + ExploreFields(ExploreFieldsSpecBuildingClosure) SelectorSpec + Matcher() SelectorSpec +} + +// ExploreFieldsSpecBuildingClosure is a function that provided to SelectorSpecBuilder's +// ExploreFields method that assembles the fields map in the selector using +// an ExploreFieldsSpecBuilder +type ExploreFieldsSpecBuildingClosure func(ExploreFieldsSpecBuilder) + +// ExploreFieldsSpecBuilder is an interface for assemble the map of fields to +// selectors in ExploreFields +type ExploreFieldsSpecBuilder interface { + Insert(k string, v SelectorSpec) +} + +type selectorSpecBuilder struct { + ns ipld.NodeStyle +} + +type selectorSpec struct { + n ipld.Node +} + +func (ss selectorSpec) Node() ipld.Node { + return ss.n +} + +func (ss selectorSpec) Selector() (selector.Selector, error) { + return selector.ParseSelector(ss.n) +} + +// NewSelectorSpecBuilder creates a SelectorSpecBuilder which will store +// data in the format determined by the given ipld.NodeStyle. +func NewSelectorSpecBuilder(ns ipld.NodeStyle) SelectorSpecBuilder { + return &selectorSpecBuilder{ns} +} + +func (ssb *selectorSpecBuilder) ExploreRecursiveEdge() SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_ExploreRecursiveEdge).CreateMap(0, func(na fluent.MapAssembler) {}) + }), + } +} + +func (ssb *selectorSpecBuilder) ExploreRecursive(limit selector.RecursionLimit, sequence SelectorSpec) SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_ExploreRecursive).CreateMap(2, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_Limit).CreateMap(1, func(na fluent.MapAssembler) { + switch limit.Mode() { + case selector.RecursionLimit_Depth: + na.AssembleEntry(selector.SelectorKey_LimitDepth).AssignInt(limit.Depth()) + case selector.RecursionLimit_None: + na.AssembleEntry(selector.SelectorKey_LimitNone).CreateMap(0, func(na fluent.MapAssembler) {}) + default: + panic("Unsupported recursion limit type") + } + }) + na.AssembleEntry(selector.SelectorKey_Sequence).AssignNode(sequence.Node()) + }) + }), + } +} + +func (ssb *selectorSpecBuilder) ExploreAll(next SelectorSpec) SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_ExploreAll).CreateMap(1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node()) + }) + }), + } +} +func (ssb *selectorSpecBuilder) ExploreIndex(index int, next SelectorSpec) SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_ExploreIndex).CreateMap(2, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_Index).AssignInt(index) + na.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node()) + }) + }), + } +} + +func (ssb *selectorSpecBuilder) ExploreRange(start int, end int, next SelectorSpec) SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_ExploreRange).CreateMap(3, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_Start).AssignInt(start) + na.AssembleEntry(selector.SelectorKey_End).AssignInt(end) + na.AssembleEntry(selector.SelectorKey_Next).AssignNode(next.Node()) + }) + }), + } +} + +func (ssb *selectorSpecBuilder) ExploreUnion(members ...SelectorSpec) SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_ExploreUnion).CreateList(len(members), func(na fluent.ListAssembler) { + for _, member := range members { + na.AssembleValue().AssignNode(member.Node()) + } + }) + }), + } +} + +func (ssb *selectorSpecBuilder) ExploreFields(specBuilder ExploreFieldsSpecBuildingClosure) SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_ExploreFields).CreateMap(1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_Fields).CreateMap(-1, func(na fluent.MapAssembler) { + specBuilder(exploreFieldsSpecBuilder{na}) + }) + }) + }), + } +} + +func (ssb *selectorSpecBuilder) Matcher() SelectorSpec { + return selectorSpec{ + fluent.MustBuildMap(ssb.ns, 1, func(na fluent.MapAssembler) { + na.AssembleEntry(selector.SelectorKey_Matcher).CreateMap(0, func(na fluent.MapAssembler) {}) + }), + } +} + +type exploreFieldsSpecBuilder struct { + na fluent.MapAssembler +} + +func (efsb exploreFieldsSpecBuilder) Insert(field string, s SelectorSpec) { + efsb.na.AssembleEntry(field).AssignNode(s.Node()) +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreAll.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreAll.go new file mode 100644 index 0000000000..f324a549bd --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreAll.go @@ -0,0 +1,44 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// ExploreAll is similar to a `*` -- it traverses all elements of an array, +// or all entries in a map, and applies a next selector to the reached nodes. +type ExploreAll struct { + next Selector // selector for element we're interested in +} + +// Interests for ExploreAll is nil (meaning traverse everything) +func (s ExploreAll) Interests() []ipld.PathSegment { + return nil +} + +// Explore returns the node's selector for all fields +func (s ExploreAll) Explore(n ipld.Node, p ipld.PathSegment) Selector { + return s.next +} + +// Decide always returns false because this is not a matcher +func (s ExploreAll) Decide(n ipld.Node) bool { + return false +} + +// ParseExploreAll assembles a Selector from a ExploreAll selector node +func (pc ParseContext) ParseExploreAll(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map") + } + next, err := n.LookupString(SelectorKey_Next) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: next field must be present in ExploreAll selector") + } + selector, err := pc.ParseSelector(next) + if err != nil { + return nil, err + } + return ExploreAll{selector}, nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreFields.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreFields.go new file mode 100644 index 0000000000..1a93afb284 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreFields.go @@ -0,0 +1,72 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// ExploreFields traverses named fields in a map (or equivalently, struct, if +// traversing on typed/schema nodes) and applies a next selector to the +// reached nodes. +// +// Note that a concept of "ExplorePath" (e.g. "foo/bar/baz") can be represented +// as a set of three nexted ExploreFields selectors, each specifying one field. +// (For this reason, we don't have a special "ExplorePath" feature; use this.) +// +// ExploreFields also works for selecting specific elements out of a list; +// if a "field" is a base-10 int, it will be coerced and do the right thing. +// ExploreIndex or ExploreRange is more appropriate, however, and should be preferred. +type ExploreFields struct { + selections map[string]Selector + interests []ipld.PathSegment // keys of above; already boxed as that's the only way we consume them +} + +// Interests for ExploreFields are the fields listed in the selector node +func (s ExploreFields) Interests() []ipld.PathSegment { + return s.interests +} + +// Explore returns the selector for the given path if it is a field in +// the selector node or nil if not +func (s ExploreFields) Explore(n ipld.Node, p ipld.PathSegment) Selector { + return s.selections[p.String()] +} + +// Decide always returns false because this is not a matcher +func (s ExploreFields) Decide(n ipld.Node) bool { + return false +} + +// ParseExploreFields assembles a Selector +// from a ExploreFields selector node +func (pc ParseContext) ParseExploreFields(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map") + } + fields, err := n.LookupString(SelectorKey_Fields) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be present") + } + if fields.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: fields in ExploreFields selector must be a map") + } + x := ExploreFields{ + make(map[string]Selector, fields.Length()), + make([]ipld.PathSegment, 0, fields.Length()), + } + for itr := fields.MapIterator(); !itr.Done(); { + kn, v, err := itr.Next() + if err != nil { + return nil, fmt.Errorf("error during selector spec parse: %s", err) + } + + kstr, _ := kn.AsString() + x.interests = append(x.interests, ipld.PathSegmentOfString(kstr)) + x.selections[kstr], err = pc.ParseSelector(v) + if err != nil { + return nil, err + } + } + return x, nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreIndex.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreIndex.go new file mode 100644 index 0000000000..173ecba282 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreIndex.go @@ -0,0 +1,63 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// ExploreIndex traverses a specific index in a list, and applies a next +// selector to the reached node. +type ExploreIndex struct { + next Selector // selector for element we're interested in + interest [1]ipld.PathSegment // index of element we're interested in +} + +// Interests for ExploreIndex is just the index specified by the selector node +func (s ExploreIndex) Interests() []ipld.PathSegment { + return s.interest[:] +} + +// Explore returns the node's selector if +// the path matches the index the index for this selector or nil if not +func (s ExploreIndex) Explore(n ipld.Node, p ipld.PathSegment) Selector { + if n.ReprKind() != ipld.ReprKind_List { + return nil + } + expectedIndex, expectedErr := p.Index() + actualIndex, actualErr := s.interest[0].Index() + if expectedErr != nil || actualErr != nil || expectedIndex != actualIndex { + return nil + } + return s.next +} + +// Decide always returns false because this is not a matcher +func (s ExploreIndex) Decide(n ipld.Node) bool { + return false +} + +// ParseExploreIndex assembles a Selector +// from a ExploreIndex selector node +func (pc ParseContext) ParseExploreIndex(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map") + } + indexNode, err := n.LookupString(SelectorKey_Index) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: index field must be present in ExploreIndex selector") + } + indexValue, err := indexNode.AsInt() + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: index field must be a number in ExploreIndex selector") + } + next, err := n.LookupString(SelectorKey_Next) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: next field must be present in ExploreIndex selector") + } + selector, err := pc.ParseSelector(next) + if err != nil { + return nil, err + } + return ExploreIndex{selector, [1]ipld.PathSegment{ipld.PathSegmentOfInt(indexValue)}}, nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRange.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRange.go new file mode 100644 index 0000000000..e20df09f7a --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRange.go @@ -0,0 +1,87 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// ExploreRange traverses a list, and for each element in the range specified, +// will apply a next selector to those reached nodes. +type ExploreRange struct { + next Selector // selector for element we're interested in + start int + end int + interest []ipld.PathSegment // index of element we're interested in +} + +// Interests for ExploreRange are all path segments within the iteration range +func (s ExploreRange) Interests() []ipld.PathSegment { + return s.interest +} + +// Explore returns the node's selector if +// the path matches an index in the range of this selector +func (s ExploreRange) Explore(n ipld.Node, p ipld.PathSegment) Selector { + if n.ReprKind() != ipld.ReprKind_List { + return nil + } + index, err := p.Index() + if err != nil { + return nil + } + if index < s.start || index >= s.end { + return nil + } + return s.next +} + +// Decide always returns false because this is not a matcher +func (s ExploreRange) Decide(n ipld.Node) bool { + return false +} + +// ParseExploreRange assembles a Selector +// from a ExploreRange selector node +func (pc ParseContext) ParseExploreRange(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map") + } + startNode, err := n.LookupString(SelectorKey_Start) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: start field must be present in ExploreRange selector") + } + startValue, err := startNode.AsInt() + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: start field must be a number in ExploreRange selector") + } + endNode, err := n.LookupString(SelectorKey_End) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: end field must be present in ExploreRange selector") + } + endValue, err := endNode.AsInt() + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: end field must be a number in ExploreRange selector") + } + if startValue >= endValue { + return nil, fmt.Errorf("selector spec parse rejected: end field must be greater than start field in ExploreRange selector") + } + next, err := n.LookupString(SelectorKey_Next) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: next field must be present in ExploreRange selector") + } + selector, err := pc.ParseSelector(next) + if err != nil { + return nil, err + } + x := ExploreRange{ + selector, + startValue, + endValue, + make([]ipld.PathSegment, 0, endValue-startValue), + } + for i := startValue; i < endValue; i++ { + x.interest = append(x.interest, ipld.PathSegmentOfInt(i)) + } + return x, nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursive.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursive.go new file mode 100644 index 0000000000..0c8e400a0d --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursive.go @@ -0,0 +1,219 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// ExploreRecursive traverses some structure recursively. +// To guide this exploration, it uses a "sequence", which is another Selector +// tree; some leaf node in this sequence should contain an ExploreRecursiveEdge +// selector, which denotes the place recursion should occur. +// +// In implementation, whenever evaluation reaches an ExploreRecursiveEdge marker +// in the recursion sequence's Selector tree, the implementation logically +// produces another new Selector which is a copy of the original +// ExploreRecursive selector, but with a decremented maxDepth parameter, and +// continues evaluation thusly. +// +// It is not valid for an ExploreRecursive selector's sequence to contain +// no instances of ExploreRecursiveEdge; it *is* valid for it to contain +// more than one ExploreRecursiveEdge. +// +// ExploreRecursive can contain a nested ExploreRecursive! +// This is comparable to a nested for-loop. +// In these cases, any ExploreRecursiveEdge instance always refers to the +// nearest parent ExploreRecursive (in other words, ExploreRecursiveEdge can +// be thought of like the 'continue' statement, or end of a for-loop body; +// it is *not* a 'goto' statement). +// +// Be careful when using ExploreRecursive with a large maxDepth parameter; +// it can easily cause very large traversals (especially if used in combination +// with selectors like ExploreAll inside the sequence). +type ExploreRecursive struct { + sequence Selector // selector for element we're interested in + current Selector // selector to apply to the current node + limit RecursionLimit // the limit for this recursive selector +} + +// RecursionLimit_Mode is an enum that represents the type of a recursion limit +// -- either "depth" or "none" for now +type RecursionLimit_Mode uint8 + +const ( + // RecursionLimit_None means there is no recursion limit + RecursionLimit_None RecursionLimit_Mode = 0 + // RecursionLimit_Depth mean recursion stops after the recursive selector + // is copied to a given depth + RecursionLimit_Depth RecursionLimit_Mode = 1 +) + +// RecursionLimit is a union type that captures all data about the recursion +// limit (both its type and data specific to the type) +type RecursionLimit struct { + mode RecursionLimit_Mode + depth int +} + +// Mode returns the type for this recursion limit +func (rl RecursionLimit) Mode() RecursionLimit_Mode { + return rl.mode +} + +// Depth returns the depth for a depth recursion limit, or 0 otherwise +func (rl RecursionLimit) Depth() int { + if rl.mode != RecursionLimit_Depth { + return 0 + } + return rl.depth +} + +// RecursionLimitDepth returns a depth limited recursion to the given depth +func RecursionLimitDepth(depth int) RecursionLimit { + return RecursionLimit{RecursionLimit_Depth, depth} +} + +// RecursionLimitNone return recursion with no limit +func RecursionLimitNone() RecursionLimit { + return RecursionLimit{RecursionLimit_None, 0} +} + +// Interests for ExploreRecursive is empty (meaning traverse everything) +func (s ExploreRecursive) Interests() []ipld.PathSegment { + return s.current.Interests() +} + +// Explore returns the node's selector for all fields +func (s ExploreRecursive) Explore(n ipld.Node, p ipld.PathSegment) Selector { + nextSelector := s.current.Explore(n, p) + limit := s.limit + + if nextSelector == nil { + return nil + } + if !s.hasRecursiveEdge(nextSelector) { + return ExploreRecursive{s.sequence, nextSelector, limit} + } + switch limit.mode { + case RecursionLimit_Depth: + if limit.depth < 2 { + return s.replaceRecursiveEdge(nextSelector, nil) + } + return ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), RecursionLimit{RecursionLimit_Depth, limit.depth - 1}} + case RecursionLimit_None: + return ExploreRecursive{s.sequence, s.replaceRecursiveEdge(nextSelector, s.sequence), limit} + default: + panic("Unsupported recursion limit type") + } +} + +func (s ExploreRecursive) hasRecursiveEdge(nextSelector Selector) bool { + _, isRecursiveEdge := nextSelector.(ExploreRecursiveEdge) + if isRecursiveEdge { + return true + } + exploreUnion, isUnion := nextSelector.(ExploreUnion) + if isUnion { + for _, selector := range exploreUnion.Members { + if s.hasRecursiveEdge(selector) { + return true + } + } + } + return false +} + +func (s ExploreRecursive) replaceRecursiveEdge(nextSelector Selector, replacement Selector) Selector { + _, isRecursiveEdge := nextSelector.(ExploreRecursiveEdge) + if isRecursiveEdge { + return replacement + } + exploreUnion, isUnion := nextSelector.(ExploreUnion) + if isUnion { + replacementMembers := make([]Selector, 0, len(exploreUnion.Members)) + for _, selector := range exploreUnion.Members { + newSelector := s.replaceRecursiveEdge(selector, replacement) + if newSelector != nil { + replacementMembers = append(replacementMembers, newSelector) + } + } + if len(replacementMembers) == 0 { + return nil + } + if len(replacementMembers) == 1 { + return replacementMembers[0] + } + return ExploreUnion{replacementMembers} + } + return nextSelector +} + +// Decide always returns false because this is not a matcher +func (s ExploreRecursive) Decide(n ipld.Node) bool { + return s.current.Decide(n) +} + +type exploreRecursiveContext struct { + edgesFound int +} + +func (erc *exploreRecursiveContext) Link(s Selector) bool { + _, ok := s.(ExploreRecursiveEdge) + if ok { + erc.edgesFound++ + } + return ok +} + +// ParseExploreRecursive assembles a Selector from a ExploreRecursive selector node +func (pc ParseContext) ParseExploreRecursive(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map") + } + + limitNode, err := n.LookupString(SelectorKey_Limit) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: limit field must be present in ExploreRecursive selector") + } + limit, err := parseLimit(limitNode) + if err != nil { + return nil, err + } + sequence, err := n.LookupString(SelectorKey_Sequence) + if err != nil { + return nil, fmt.Errorf("selector spec parse rejected: sequence field must be present in ExploreRecursive selector") + } + erc := &exploreRecursiveContext{} + selector, err := pc.PushParent(erc).ParseSelector(sequence) + if err != nil { + return nil, err + } + if erc.edgesFound == 0 { + return nil, fmt.Errorf("selector spec parse rejected: ExploreRecursive must have at least one ExploreRecursiveEdge") + } + return ExploreRecursive{selector, selector, limit}, nil +} + +func parseLimit(n ipld.Node) (RecursionLimit, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return RecursionLimit{}, fmt.Errorf("selector spec parse rejected: limit in ExploreRecursive is a keyed union and thus must be a map") + } + if n.Length() != 1 { + return RecursionLimit{}, fmt.Errorf("selector spec parse rejected: limit in ExploreRecursive is a keyed union and thus must be a single-entry map") + } + kn, v, _ := n.MapIterator().Next() + kstr, _ := kn.AsString() + switch kstr { + case SelectorKey_LimitDepth: + maxDepthValue, err := v.AsInt() + if err != nil { + return RecursionLimit{}, fmt.Errorf("selector spec parse rejected: limit field of type depth must be a number in ExploreRecursive selector") + } + return RecursionLimit{RecursionLimit_Depth, maxDepthValue}, nil + case SelectorKey_LimitNone: + return RecursionLimit{RecursionLimit_None, 0}, nil + default: + return RecursionLimit{}, fmt.Errorf("selector spec parse rejected: %q is not a known member of the limit union in ExploreRecursive", kstr) + } +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursiveEdge.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursiveEdge.go new file mode 100644 index 0000000000..2ff62e5ea2 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreRecursiveEdge.go @@ -0,0 +1,47 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// ExploreRecursiveEdge is a special sentinel value which is used to mark +// the end of a sequence started by an ExploreRecursive selector: the recursion +// goes back to the initial state of the earlier ExploreRecursive selector, +// and proceeds again (with a decremented maxDepth value). +// +// An ExploreRecursive selector that doesn't contain an ExploreRecursiveEdge +// is nonsensical. Containing more than one ExploreRecursiveEdge is valid. +// An ExploreRecursiveEdge without an enclosing ExploreRecursive is an error. +type ExploreRecursiveEdge struct{} + +// Interests should ultimately never get called for an ExploreRecursiveEdge selector +func (s ExploreRecursiveEdge) Interests() []ipld.PathSegment { + panic("Traversed Explore Recursive Edge Node With No Parent") +} + +// Explore should ultimately never get called for an ExploreRecursiveEdge selector +func (s ExploreRecursiveEdge) Explore(n ipld.Node, p ipld.PathSegment) Selector { + panic("Traversed Explore Recursive Edge Node With No Parent") +} + +// Decide should ultimately never get called for an ExploreRecursiveEdge selector +func (s ExploreRecursiveEdge) Decide(n ipld.Node) bool { + panic("Traversed Explore Recursive Edge Node With No Parent") +} + +// ParseExploreRecursiveEdge assembles a Selector +// from a exploreRecursiveEdge selector node +func (pc ParseContext) ParseExploreRecursiveEdge(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map") + } + s := ExploreRecursiveEdge{} + for _, parent := range pc.parentStack { + if parent.Link(s) { + return s, nil + } + } + return nil, fmt.Errorf("selector spec parse rejected: ExploreRecursiveEdge must be beneath ExploreRecursive") +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreUnion.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreUnion.go new file mode 100644 index 0000000000..4261693f32 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/exploreUnion.go @@ -0,0 +1,95 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// ExploreUnion allows selection to continue with two or more distinct selectors +// while exploring the same tree of data. +// +// ExploreUnion can be used to apply a Matcher on one node (causing it to +// be considered part of a (possibly labelled) result set), while simultaneously +// continuing to explore deeper parts of the tree with another selector, +// for example. +type ExploreUnion struct { + Members []Selector +} + +// Interests for ExploreUnion is: +// - nil (aka all) if any member selector has nil interests +// - the union of values returned by all member selectors otherwise +func (s ExploreUnion) Interests() []ipld.PathSegment { + // Check for any high-cardinality selectors first; if so, shortcircuit. + // (n.b. we're assuming the 'Interests' method is cheap here.) + for _, m := range s.Members { + if m.Interests() == nil { + return nil + } + } + // Accumulate the whitelist of interesting path segments. + // TODO: Dedup? + v := []ipld.PathSegment{} + for _, m := range s.Members { + v = append(v, m.Interests()...) + } + return v +} + +// Explore for a Union selector calls explore for each member selector +// and returns: +// - a new union selector if more than one member returns a selector +// - if exactly one member returns a selector, that selector +// - nil if no members return a selector +func (s ExploreUnion) Explore(n ipld.Node, p ipld.PathSegment) Selector { + // TODO: memory efficient? + nonNilResults := make([]Selector, 0, len(s.Members)) + for _, member := range s.Members { + resultSelector := member.Explore(n, p) + if resultSelector != nil { + nonNilResults = append(nonNilResults, resultSelector) + } + } + if len(nonNilResults) == 0 { + return nil + } + if len(nonNilResults) == 1 { + return nonNilResults[0] + } + return ExploreUnion{nonNilResults} +} + +// Decide returns true for a Union selector if any of the member selectors +// return true +func (s ExploreUnion) Decide(n ipld.Node) bool { + for _, m := range s.Members { + if m.Decide(n) { + return true + } + } + return false +} + +// ParseExploreUnion assembles a Selector +// from an ExploreUnion selector node +func (pc ParseContext) ParseExploreUnion(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_List { + return nil, fmt.Errorf("selector spec parse rejected: explore union selector must be a list") + } + x := ExploreUnion{ + make([]Selector, 0, n.Length()), + } + for itr := n.ListIterator(); !itr.Done(); { + _, v, err := itr.Next() + if err != nil { + return nil, fmt.Errorf("error during selector spec parse: %s", err) + } + member, err := pc.ParseSelector(v) + if err != nil { + return nil, err + } + x.Members = append(x.Members, member) + } + return x, nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/fieldKeys.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/fieldKeys.go new file mode 100644 index 0000000000..ba222d56b3 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/fieldKeys.go @@ -0,0 +1,25 @@ +package selector + +const ( + SelectorKey_Matcher = "." + SelectorKey_ExploreAll = "a" + SelectorKey_ExploreFields = "f" + SelectorKey_ExploreIndex = "i" + SelectorKey_ExploreRange = "r" + SelectorKey_ExploreRecursive = "R" + SelectorKey_ExploreUnion = "|" + SelectorKey_ExploreConditional = "&" + SelectorKey_ExploreRecursiveEdge = "@" + SelectorKey_Next = ">" + SelectorKey_Fields = "f>" + SelectorKey_Index = "i" + SelectorKey_Start = "^" + SelectorKey_End = "$" + SelectorKey_Sequence = ":>" + SelectorKey_Limit = "l" + SelectorKey_LimitDepth = "depth" + SelectorKey_LimitNone = "none" + SelectorKey_StopAt = "!" + SelectorKey_Condition = "&" + // not filling conditional keys since it's not complete +) diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/matcher.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/matcher.go new file mode 100644 index 0000000000..b2305ef863 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/matcher.go @@ -0,0 +1,46 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// Matcher marks a node to be included in the "result" set. +// (All nodes traversed by a selector are in the "covered" set (which is a.k.a. +// "the merkle proof"); the "result" set is a subset of the "covered" set.) +// +// In libraries using selectors, the "result" set is typically provided to +// some user-specified callback. +// +// A selector tree with only "explore*"-type selectors and no Matcher selectors +// is valid; it will just generate a "covered" set of nodes and no "result" set. +// TODO: From spec: implement conditions and labels +type Matcher struct{} + +// Interests are empty for a matcher (for now) because +// It is always just there to match, not explore further +func (s Matcher) Interests() []ipld.PathSegment { + return []ipld.PathSegment{} +} + +// Explore will return nil because a matcher is a terminal selector +func (s Matcher) Explore(n ipld.Node, p ipld.PathSegment) Selector { + return nil +} + +// Decide is always true for a match cause it's in the result set +// TODO: Implement boolean logic for conditionals +func (s Matcher) Decide(n ipld.Node) bool { + return true +} + +// ParseMatcher assembles a Selector +// from a matcher selector node +// TODO: Parse labels and conditions +func (pc ParseContext) ParseMatcher(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector body must be a map") + } + return Matcher{}, nil +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/selector/selector.go b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/selector.go new file mode 100644 index 0000000000..b410cefa3d --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/selector/selector.go @@ -0,0 +1,119 @@ +package selector + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" +) + +// Selector is the programmatic representation of an IPLD Selector Node +// and can be applied to traverse a given IPLD DAG +type Selector interface { + Interests() []ipld.PathSegment // returns the segments we're likely interested in **or nil** if we're a high-cardinality or expression based matcher and need all segments proposed to us. + Explore(ipld.Node, ipld.PathSegment) Selector // explore one step -- iteration comes from outside (either whole node, or by following suggestions of Interests). returns nil if no interest. you have to traverse to the next node yourself (the selector doesn't do it for you because you might be considering multiple selection reasons at the same time). + Decide(ipld.Node) bool +} + +// ParsedParent is created whenever you are parsing a selector node that may have +// child selectors nodes that need to know it +type ParsedParent interface { + Link(s Selector) bool +} + +// ParseContext tracks the progress when parsing a selector +type ParseContext struct { + parentStack []ParsedParent +} + +// ParseSelector creates a Selector that can be traversed from an IPLD Selector node +func ParseSelector(n ipld.Node) (Selector, error) { + return ParseContext{}.ParseSelector(n) +} + +// ParseSelector creates a Selector from an IPLD Selector Node with the given context +func (pc ParseContext) ParseSelector(n ipld.Node) (Selector, error) { + if n.ReprKind() != ipld.ReprKind_Map { + return nil, fmt.Errorf("selector spec parse rejected: selector is a keyed union and thus must be a map") + } + if n.Length() != 1 { + return nil, fmt.Errorf("selector spec parse rejected: selector is a keyed union and thus must be single-entry map") + } + kn, v, _ := n.MapIterator().Next() + kstr, _ := kn.AsString() + // Switch over the single key to determine which selector body comes next. + // (This switch is where the keyed union discriminators concretely happen.) + switch kstr { + case SelectorKey_ExploreFields: + return pc.ParseExploreFields(v) + case SelectorKey_ExploreAll: + return pc.ParseExploreAll(v) + case SelectorKey_ExploreIndex: + return pc.ParseExploreIndex(v) + case SelectorKey_ExploreRange: + return pc.ParseExploreRange(v) + case SelectorKey_ExploreUnion: + return pc.ParseExploreUnion(v) + case SelectorKey_ExploreRecursive: + return pc.ParseExploreRecursive(v) + case SelectorKey_ExploreRecursiveEdge: + return pc.ParseExploreRecursiveEdge(v) + case SelectorKey_Matcher: + return pc.ParseMatcher(v) + default: + return nil, fmt.Errorf("selector spec parse rejected: %q is not a known member of the selector union", kstr) + } +} + +// PushParent puts a parent onto the stack of parents for a parse context +func (pc ParseContext) PushParent(parent ParsedParent) ParseContext { + l := len(pc.parentStack) + parents := make([]ParsedParent, 0, l+1) + parents = append(parents, parent) + parents = append(parents, pc.parentStack...) + return ParseContext{parents} +} + +// SegmentIterator iterates either a list or a map, generating PathSegments +// instead of indexes or keys +type SegmentIterator interface { + Next() (pathSegment ipld.PathSegment, value ipld.Node, err error) + Done() bool +} + +// NewSegmentIterator generates a new iterator based on the node type +func NewSegmentIterator(n ipld.Node) SegmentIterator { + if n.ReprKind() == ipld.ReprKind_List { + return listSegmentIterator{n.ListIterator()} + } + return mapSegmentIterator{n.MapIterator()} +} + +type listSegmentIterator struct { + ipld.ListIterator +} + +func (lsi listSegmentIterator) Next() (pathSegment ipld.PathSegment, value ipld.Node, err error) { + i, v, err := lsi.ListIterator.Next() + return ipld.PathSegmentOfInt(i), v, err +} + +func (lsi listSegmentIterator) Done() bool { + return lsi.ListIterator.Done() +} + +type mapSegmentIterator struct { + ipld.MapIterator +} + +func (msi mapSegmentIterator) Next() (pathSegment ipld.PathSegment, value ipld.Node, err error) { + k, v, err := msi.MapIterator.Next() + if err != nil { + return ipld.PathSegment{}, v, err + } + kstr, _ := k.AsString() + return ipld.PathSegmentOfString(kstr), v, err +} + +func (msi mapSegmentIterator) Done() bool { + return msi.MapIterator.Done() +} diff --git a/vendor/github.com/ipld/go-ipld-prime/traversal/walk.go b/vendor/github.com/ipld/go-ipld-prime/traversal/walk.go new file mode 100644 index 0000000000..bcd173d085 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/traversal/walk.go @@ -0,0 +1,229 @@ +package traversal + +import ( + "fmt" + + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/traversal/selector" +) + +// WalkMatching walks a graph of Nodes, deciding which to visit by applying a Selector, +// and calling the given VisitFn on those that the Selector deems a match. +// +// This function is a helper function which starts a new walk with default configuration. +// It cannot cross links automatically (since this requires configuration). +// Use the equivalent WalkMatching function on the Progress structure +// for more advanced and configurable walks. +func WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn) error { + return Progress{}.WalkMatching(n, s, fn) +} + +// WalkAdv is identical to WalkMatching, except it is called for *all* nodes +// visited (not just matching nodes), together with the reason for the visit. +// An AdvVisitFn is used instead of a VisitFn, so that the reason can be provided. +// +// This function is a helper function which starts a new walk with default configuration. +// It cannot cross links automatically (since this requires configuration). +// Use the equivalent WalkAdv function on the Progress structure +// for more advanced and configurable walks. +func WalkAdv(n ipld.Node, s selector.Selector, fn AdvVisitFn) error { + return Progress{}.WalkAdv(n, s, fn) +} + +// WalkTransforming walks a graph of Nodes, deciding which to alter by applying a Selector, +// and calls the given TransformFn to decide what new node to replace the visited node with. +// A new Node tree will be returned (the original is unchanged). +// +// This function is a helper function which starts a new walk with default configuration. +// It cannot cross links automatically (since this requires configuration). +// Use the equivalent WalkTransforming function on the Progress structure +// for more advanced and configurable walks. +func WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.Node, error) { + return Progress{}.WalkTransforming(n, s, fn) +} + +// WalkMatching walks a graph of Nodes, deciding which to visit by applying a Selector, +// and calling the given VisitFn on those that the Selector deems a match. +// +// WalkMatching is a read-only traversal. +// See WalkTransforming if looking for a way to do "updates" to a tree of nodes. +// +// Provide configuration to this process using the Config field in the Progress object. +// +// This walk will automatically cross links, but requires some configuration +// with link loading functions to do so. +// +// Traversals are defined as visiting a (node,path) tuple. +// This is important to note because when walking DAGs with Links, +// it means you may visit the same node multiple times +// due to having reached it via a different path. +// (You can prevent this by using a LinkLoader function which memoizes a set of +// already-visited Links, and returns a SkipMe when encountering them again.) +// +// WalkMatching (and the other traversal functions) can be used again again inside the VisitFn! +// By using the traversal.Progress handed to the VisitFn, +// the Path recorded of the traversal so far will continue to be extended, +// and thus continued nested uses of Walk and Focus will see the fully contextualized Path. +// +func (prog Progress) WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn) error { + prog.init() + return prog.walkAdv(n, s, func(prog Progress, n ipld.Node, tr VisitReason) error { + if tr != VisitReason_SelectionMatch { + return nil + } + return fn(prog, n) + }) +} + +// WalkAdv is identical to WalkMatching, except it is called for *all* nodes +// visited (not just matching nodes), together with the reason for the visit. +// An AdvVisitFn is used instead of a VisitFn, so that the reason can be provided. +// +func (prog Progress) WalkAdv(n ipld.Node, s selector.Selector, fn AdvVisitFn) error { + prog.init() + return prog.walkAdv(n, s, fn) +} + +func (prog Progress) walkAdv(n ipld.Node, s selector.Selector, fn AdvVisitFn) error { + if s.Decide(n) { + if err := fn(prog, n, VisitReason_SelectionMatch); err != nil { + return err + } + } else { + if err := fn(prog, n, VisitReason_SelectionCandidate); err != nil { + return err + } + } + nk := n.ReprKind() + switch nk { + case ipld.ReprKind_Map, ipld.ReprKind_List: // continue + default: + return nil + } + attn := s.Interests() + if attn == nil { + return prog.walkAdv_iterateAll(n, s, fn) + } + return prog.walkAdv_iterateSelective(n, attn, s, fn) + +} + +func (prog Progress) walkAdv_iterateAll(n ipld.Node, s selector.Selector, fn AdvVisitFn) error { + for itr := selector.NewSegmentIterator(n); !itr.Done(); { + ps, v, err := itr.Next() + if err != nil { + return err + } + sNext := s.Explore(n, ps) + if sNext != nil { + progNext := prog + progNext.Path = prog.Path.AppendSegment(ps) + if v.ReprKind() == ipld.ReprKind_Link { + lnk, _ := v.AsLink() + progNext.LastBlock.Path = progNext.Path + progNext.LastBlock.Link = lnk + v, err = progNext.loadLink(v, n) + if err != nil { + if _, ok := err.(SkipMe); ok { + return nil + } + return err + } + } + + err = progNext.walkAdv(v, sNext, fn) + if err != nil { + return err + } + } + } + return nil +} + +func (prog Progress) walkAdv_iterateSelective(n ipld.Node, attn []ipld.PathSegment, s selector.Selector, fn AdvVisitFn) error { + for _, ps := range attn { + v, err := n.LookupSegment(ps) + if err != nil { + continue + } + sNext := s.Explore(n, ps) + if sNext != nil { + progNext := prog + progNext.Path = prog.Path.AppendSegment(ps) + if v.ReprKind() == ipld.ReprKind_Link { + lnk, _ := v.AsLink() + progNext.LastBlock.Path = progNext.Path + progNext.LastBlock.Link = lnk + v, err = progNext.loadLink(v, n) + if err != nil { + if _, ok := err.(SkipMe); ok { + return nil + } + return err + } + } + + err = progNext.walkAdv(v, sNext, fn) + if err != nil { + return err + } + } + } + return nil +} + +func (prog Progress) loadLink(v ipld.Node, parent ipld.Node) (ipld.Node, error) { + lnk, err := v.AsLink() + if err != nil { + return nil, err + } + // Assemble the LinkContext in case the Loader or NBChooser want it. + lnkCtx := ipld.LinkContext{ + LinkPath: prog.Path, + LinkNode: v, + ParentNode: parent, + } + // Pick what in-memory format we will build. + ns, err := prog.Cfg.LinkTargetNodeStyleChooser(lnk, lnkCtx) + if err != nil { + return nil, fmt.Errorf("error traversing node at %q: could not load link %q: %s", prog.Path, lnk, err) + } + nb := ns.NewBuilder() + // Load link! + err = lnk.Load( + prog.Cfg.Ctx, + lnkCtx, + nb, + prog.Cfg.LinkLoader, + ) + if err != nil { + if _, ok := err.(SkipMe); ok { + return nil, err + } + return nil, fmt.Errorf("error traversing node at %q: could not load link %q: %s", prog.Path, lnk, err) + } + return nb.Build(), nil +} + +// WalkTransforming walks a graph of Nodes, deciding which to alter by applying a Selector, +// and calls the given TransformFn to decide what new node to replace the visited node with. +// A new Node tree will be returned (the original is unchanged). +// +// If the TransformFn returns the same Node which it was called with, +// then the transform is a no-op; if every visited node is a no-op, +// then the root node returned from the walk as a whole will also be +// the same as its starting Node (no new memory will be used). +// +// When a Node is replaced, no further recursion of this walk will occur on its contents. +// (You can certainly do a additional traversals, including transforms, +// from inside the TransformFn while building the replacement node.) +// +// The style (that is, implementation) of Node returned will be the same as the +// styles of the Nodes at the same positions in the existing tree +// (literally, builders used to construct any new needed intermediate nodes +// are chosen by asking the existing nodes about their style). +// +// This feature is not yet implemented. +func (prog Progress) WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.Node, error) { + panic("TODO") +} diff --git a/vendor/github.com/ipld/go-ipld-prime/unit.go b/vendor/github.com/ipld/go-ipld-prime/unit.go new file mode 100644 index 0000000000..14f856cbb1 --- /dev/null +++ b/vendor/github.com/ipld/go-ipld-prime/unit.go @@ -0,0 +1,125 @@ +package ipld + +var Null Node = nullNode{} + +type nullNode struct{} + +func (nullNode) ReprKind() ReprKind { + return ReprKind_Null +} +func (nullNode) LookupString(key string) (Node, error) { + return nil, ErrWrongKind{TypeName: "null", MethodName: "LookupString", AppropriateKind: ReprKindSet_JustMap, ActualKind: ReprKind_Null} +} +func (nullNode) Lookup(key Node) (Node, error) { + return nil, ErrWrongKind{TypeName: "null", MethodName: "Lookup", AppropriateKind: ReprKindSet_JustMap, ActualKind: ReprKind_Null} +} +func (nullNode) LookupIndex(idx int) (Node, error) { + return nil, ErrWrongKind{TypeName: "null", MethodName: "LookupIndex", AppropriateKind: ReprKindSet_JustList, ActualKind: ReprKind_Null} +} +func (nullNode) LookupSegment(seg PathSegment) (Node, error) { + return nil, ErrWrongKind{TypeName: "null", MethodName: "LookupSegment", AppropriateKind: ReprKindSet_Recursive, ActualKind: ReprKind_Null} +} +func (nullNode) MapIterator() MapIterator { + return nil +} +func (nullNode) ListIterator() ListIterator { + return nil +} +func (nullNode) Length() int { + return -1 +} +func (nullNode) IsUndefined() bool { + return false +} +func (nullNode) IsNull() bool { + return true +} +func (nullNode) AsBool() (bool, error) { + return false, ErrWrongKind{TypeName: "null", MethodName: "AsBool", AppropriateKind: ReprKindSet_JustBool, ActualKind: ReprKind_Null} +} +func (nullNode) AsInt() (int, error) { + return 0, ErrWrongKind{TypeName: "null", MethodName: "AsInt", AppropriateKind: ReprKindSet_JustInt, ActualKind: ReprKind_Null} +} +func (nullNode) AsFloat() (float64, error) { + return 0, ErrWrongKind{TypeName: "null", MethodName: "AsFloat", AppropriateKind: ReprKindSet_JustFloat, ActualKind: ReprKind_Null} +} +func (nullNode) AsString() (string, error) { + return "", ErrWrongKind{TypeName: "null", MethodName: "AsString", AppropriateKind: ReprKindSet_JustString, ActualKind: ReprKind_Null} +} +func (nullNode) AsBytes() ([]byte, error) { + return nil, ErrWrongKind{TypeName: "null", MethodName: "AsBytes", AppropriateKind: ReprKindSet_JustBytes, ActualKind: ReprKind_Null} +} +func (nullNode) AsLink() (Link, error) { + return nil, ErrWrongKind{TypeName: "null", MethodName: "AsLink", AppropriateKind: ReprKindSet_JustLink, ActualKind: ReprKind_Null} +} +func (nullNode) Style() NodeStyle { + return nullStyle{} +} + +type nullStyle struct{} + +func (nullStyle) NewBuilder() NodeBuilder { + panic("cannot build null nodes") // TODO: okay, fine, we could grind out a simple closing of the loop here. +} + +var Undef Node = undefNode{} + +type undefNode struct{} + +func (undefNode) ReprKind() ReprKind { + return ReprKind_Null +} +func (undefNode) LookupString(key string) (Node, error) { + return nil, ErrWrongKind{TypeName: "undef", MethodName: "LookupString", AppropriateKind: ReprKindSet_JustMap, ActualKind: ReprKind_Null} +} +func (undefNode) Lookup(key Node) (Node, error) { + return nil, ErrWrongKind{TypeName: "undef", MethodName: "Lookup", AppropriateKind: ReprKindSet_JustMap, ActualKind: ReprKind_Null} +} +func (undefNode) LookupIndex(idx int) (Node, error) { + return nil, ErrWrongKind{TypeName: "undef", MethodName: "LookupIndex", AppropriateKind: ReprKindSet_JustList, ActualKind: ReprKind_Null} +} +func (undefNode) LookupSegment(seg PathSegment) (Node, error) { + return nil, ErrWrongKind{TypeName: "undef", MethodName: "LookupSegment", AppropriateKind: ReprKindSet_Recursive, ActualKind: ReprKind_Null} +} +func (undefNode) MapIterator() MapIterator { + return nil +} +func (undefNode) ListIterator() ListIterator { + return nil +} +func (undefNode) Length() int { + return -1 +} +func (undefNode) IsUndefined() bool { + return true +} +func (undefNode) IsNull() bool { + return false +} +func (undefNode) AsBool() (bool, error) { + return false, ErrWrongKind{TypeName: "undef", MethodName: "AsBool", AppropriateKind: ReprKindSet_JustBool, ActualKind: ReprKind_Null} +} +func (undefNode) AsInt() (int, error) { + return 0, ErrWrongKind{TypeName: "undef", MethodName: "AsInt", AppropriateKind: ReprKindSet_JustInt, ActualKind: ReprKind_Null} +} +func (undefNode) AsFloat() (float64, error) { + return 0, ErrWrongKind{TypeName: "undef", MethodName: "AsFloat", AppropriateKind: ReprKindSet_JustFloat, ActualKind: ReprKind_Null} +} +func (undefNode) AsString() (string, error) { + return "", ErrWrongKind{TypeName: "undef", MethodName: "AsString", AppropriateKind: ReprKindSet_JustString, ActualKind: ReprKind_Null} +} +func (undefNode) AsBytes() ([]byte, error) { + return nil, ErrWrongKind{TypeName: "undef", MethodName: "AsBytes", AppropriateKind: ReprKindSet_JustBytes, ActualKind: ReprKind_Null} +} +func (undefNode) AsLink() (Link, error) { + return nil, ErrWrongKind{TypeName: "undef", MethodName: "AsLink", AppropriateKind: ReprKindSet_JustLink, ActualKind: ReprKind_Null} +} +func (undefNode) Style() NodeStyle { + return undefStyle{} +} + +type undefStyle struct{} + +func (undefStyle) NewBuilder() NodeBuilder { + panic("cannot build undef nodes") // this definitely stays true. +} diff --git a/vendor/github.com/libp2p/go-buffer-pool/.travis.yml b/vendor/github.com/libp2p/go-buffer-pool/.travis.yml new file mode 100644 index 0000000000..5163d693fc --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/.travis.yml @@ -0,0 +1,30 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/pkg/mod + - $HOME/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/libp2p/go-buffer-pool/LICENSE b/vendor/github.com/libp2p/go-buffer-pool/LICENSE new file mode 100644 index 0000000000..c7386b3c94 --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/libp2p/go-buffer-pool/LICENSE-BSD b/vendor/github.com/libp2p/go-buffer-pool/LICENSE-BSD new file mode 100644 index 0000000000..97ece7897d --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/LICENSE-BSD @@ -0,0 +1,29 @@ +### Applies to buffer.go and buffer_test.go ### + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/libp2p/go-buffer-pool/README.md b/vendor/github.com/libp2p/go-buffer-pool/README.md new file mode 100644 index 0000000000..830cb56268 --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/README.md @@ -0,0 +1,53 @@ +go-buffer-pool +================== + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai) +[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](https://libp2p.io/) +[![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23libp2p) +[![codecov](https://codecov.io/gh/libp2p/go-buffer-pool/branch/master/graph/badge.svg)](https://codecov.io/gh/libp2p/go-buffer-pool) +[![Travis CI](https://travis-ci.org/libp2p/go-buffer-pool.svg?branch=master)](https://travis-ci.org/libp2p/go-buffer-pool) +[![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io) + +> A variable size buffer pool for go. + +## Table of Contents + +- [Use Case](#use-case) + - [Advantages over GC](#advantages-over-gc) + - [Disadvantages over GC:](#disadvantages-over-gc) +- [Contribute](#contribute) +- [License](#license) + +## Use Case + +Use this when you need to repeatedly allocate and free a bunch of temporary buffers of approximately the same size. + +### Advantages over GC + +* Reduces Memory Usage: + * We don't have to wait for a GC to run before we can reuse memory. This is essential if you're repeatedly allocating large short-lived buffers. + +* Reduces CPU usage: + * It takes some load off of the GC (due to buffer reuse). + * We don't have to zero buffers (fewer wasteful memory writes). + +### Disadvantages over GC: + +* Can leak memory contents. Unlike the go GC, we *don't* zero memory. +* All buffers have a capacity of a power of 2. This is fine if you either (a) actually need buffers with this size or (b) expect these buffers to be temporary. +* Requires that buffers be returned explicitly. This can lead to race conditions and memory corruption if the buffer is released while it's still in use. + +## Contribute + +PRs are welcome! + +Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +MIT © Protocol Labs +BSD © The Go Authors + +--- + +The last gx published version of this module was: 0.1.3: QmQDvJoB6aJWN3sjr3xsgXqKCXf4jU5zdMXpDMsBkYVNqa diff --git a/vendor/github.com/libp2p/go-buffer-pool/buffer.go b/vendor/github.com/libp2p/go-buffer-pool/buffer.go new file mode 100644 index 0000000000..2e4645a97d --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/buffer.go @@ -0,0 +1,302 @@ +// This is a derivitive work of Go's bytes.Buffer implementation. +// +// Originally copyright 2009 The Go Authors. All rights reserved. +// +// Modifications copyright 2018 Steven Allen. All rights reserved. +// +// Use of this source code is governed by both a BSD-style and an MIT-style +// license that can be found in the LICENSE_BSD and LICENSE files. + +package pool + +import ( + "io" +) + +// Buffer is a buffer like bytes.Buffer that: +// +// 1. Uses a buffer pool. +// 2. Frees memory on read. +// +// If you only have a few buffers and read/write at a steady rate, *don't* use +// this package, it'll be slower. +// +// However: +// +// 1. If you frequently create/destroy buffers, this implementation will be +// significantly nicer to the allocator. +// 2. If you have many buffers with bursty traffic, this implementation will use +// significantly less memory. +type Buffer struct { + // Pool is the buffer pool to use. If nil, this Buffer will use the + // global buffer pool. + Pool *BufferPool + + buf []byte + rOff int + + // Preallocated slice for samll reads/writes. + // This is *really* important for performance and only costs 8 words. + bootstrap [64]byte +} + +// NewBuffer constructs a new buffer initialized to `buf`. +// Unlike `bytes.Buffer`, we *copy* the buffer but don't reuse it (to ensure +// that we *only* use buffers from the pool). +func NewBuffer(buf []byte) *Buffer { + b := new(Buffer) + if len(buf) > 0 { + b.buf = b.getBuf(len(buf)) + copy(b.buf, buf) + } + return b +} + +// NewBufferString is identical to NewBuffer *except* that it allows one to +// initialize the buffer from a string (without having to allocate an +// intermediate bytes slice). +func NewBufferString(buf string) *Buffer { + b := new(Buffer) + if len(buf) > 0 { + b.buf = b.getBuf(len(buf)) + copy(b.buf, buf) + } + return b +} + +func (b *Buffer) grow(n int) int { + wOff := len(b.buf) + bCap := cap(b.buf) + + if bCap >= wOff+n { + b.buf = b.buf[:wOff+n] + return wOff + } + + bSize := b.Len() + + minCap := 2*bSize + n + + // Slide if cap >= minCap. + // Reallocate otherwise. + if bCap >= minCap { + copy(b.buf, b.buf[b.rOff:]) + } else { + // Needs new buffer. + newBuf := b.getBuf(minCap) + copy(newBuf, b.buf[b.rOff:]) + b.returnBuf() + b.buf = newBuf + } + + b.rOff = 0 + b.buf = b.buf[:bSize+n] + return bSize +} + +func (b *Buffer) getPool() *BufferPool { + if b.Pool == nil { + return GlobalPool + } + return b.Pool +} + +func (b *Buffer) returnBuf() { + if cap(b.buf) > len(b.bootstrap) { + b.getPool().Put(b.buf) + } + b.buf = nil +} + +func (b *Buffer) getBuf(n int) []byte { + if n <= len(b.bootstrap) { + return b.bootstrap[:n] + } + return b.getPool().Get(n) +} + +// Len returns the number of bytes that can be read from this buffer. +func (b *Buffer) Len() int { + return len(b.buf) - b.rOff +} + +// Cap returns the current capacity of the buffer. +// +// Note: Buffer *may* re-allocate when writing (or growing by) `n` bytes even if +// `Cap() < Len() + n` to avoid excessive copying. +func (b *Buffer) Cap() int { + return cap(b.buf) +} + +// Bytes returns the slice of bytes currently buffered in the Buffer. +// +// The buffer returned by Bytes is valid until the next call grow, truncate, +// read, or write. Really, just don't touch the Buffer until you're done with +// the return value of this function. +func (b *Buffer) Bytes() []byte { + return b.buf[b.rOff:] +} + +// String returns the string representation of the buffer. +// +// It returns `` the buffer is a nil pointer. +func (b *Buffer) String() string { + if b == nil { + return "" + } + return string(b.buf[b.rOff:]) +} + +// WriteString writes a string to the buffer. +// +// This function is identical to Write except that it allows one to write a +// string directly without allocating an intermediate byte slice. +func (b *Buffer) WriteString(buf string) (int, error) { + wOff := b.grow(len(buf)) + return copy(b.buf[wOff:], buf), nil +} + +// Truncate truncates the Buffer. +// +// Panics if `n > b.Len()`. +// +// This function may free memory by shrinking the internal buffer. +func (b *Buffer) Truncate(n int) { + if n < 0 || n > b.Len() { + panic("truncation out of range") + } + b.buf = b.buf[:b.rOff+n] + b.shrink() +} + +// Reset is equivalent to Truncate(0). +func (b *Buffer) Reset() { + b.returnBuf() + b.rOff = 0 +} + +// ReadByte reads a single byte from the Buffer. +func (b *Buffer) ReadByte() (byte, error) { + if b.rOff >= len(b.buf) { + return 0, io.EOF + } + c := b.buf[b.rOff] + b.rOff++ + return c, nil +} + +// WriteByte writes a single byte to the Buffer. +func (b *Buffer) WriteByte(c byte) error { + wOff := b.grow(1) + b.buf[wOff] = c + return nil +} + +// Grow grows the internal buffer such that `n` bytes can be written without +// reallocating. +func (b *Buffer) Grow(n int) { + wOff := b.grow(n) + b.buf = b.buf[:wOff] +} + +// Next is an alternative to `Read` that returns a byte slice instead of taking +// one. +// +// The returned byte slice is valid until the next read, write, grow, or +// truncate. +func (b *Buffer) Next(n int) []byte { + m := b.Len() + if m < n { + n = m + } + data := b.buf[b.rOff : b.rOff+n] + b.rOff += n + return data +} + +// Write writes the byte slice to the buffer. +func (b *Buffer) Write(buf []byte) (int, error) { + wOff := b.grow(len(buf)) + return copy(b.buf[wOff:], buf), nil +} + +// WriteTo copies from the buffer into the given writer until the buffer is +// empty. +func (b *Buffer) WriteTo(w io.Writer) (int64, error) { + if b.rOff < len(b.buf) { + n, err := w.Write(b.buf[b.rOff:]) + b.rOff += n + if b.rOff > len(b.buf) { + panic("invalid write count") + } + b.shrink() + return int64(n), err + } + return 0, nil +} + +// MinRead is the minimum slice size passed to a Read call by +// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond +// what is required to hold the contents of r, ReadFrom will not grow the +// underlying buffer. +const MinRead = 512 + +// ReadFrom reads from the given reader into the buffer. +func (b *Buffer) ReadFrom(r io.Reader) (int64, error) { + n := int64(0) + for { + wOff := b.grow(MinRead) + // Use *entire* buffer. + b.buf = b.buf[:cap(b.buf)] + + read, err := r.Read(b.buf[wOff:]) + b.buf = b.buf[:wOff+read] + n += int64(read) + switch err { + case nil: + case io.EOF: + err = nil + fallthrough + default: + b.shrink() + return n, err + } + } +} + +// Read reads at most `len(buf)` bytes from the internal buffer into the given +// buffer. +func (b *Buffer) Read(buf []byte) (int, error) { + if len(buf) == 0 { + return 0, nil + } + if b.rOff >= len(b.buf) { + return 0, io.EOF + } + n := copy(buf, b.buf[b.rOff:]) + b.rOff += n + b.shrink() + return n, nil +} + +func (b *Buffer) shrink() { + c := b.Cap() + // Either nil or bootstrap. + if c <= len(b.bootstrap) { + return + } + + l := b.Len() + if l == 0 { + // Shortcut if empty. + b.returnBuf() + b.rOff = 0 + } else if l*8 < c { + // Only shrink when capacity > 8x length. Avoids shrinking too aggressively. + newBuf := b.getBuf(l) + copy(newBuf, b.buf[b.rOff:]) + b.returnBuf() + b.rOff = 0 + b.buf = newBuf[:l] + } +} diff --git a/vendor/github.com/libp2p/go-buffer-pool/codecov.yml b/vendor/github.com/libp2p/go-buffer-pool/codecov.yml new file mode 100644 index 0000000000..5f88a9ea27 --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/codecov.yml @@ -0,0 +1,3 @@ +coverage: + range: "50...100" +comment: off diff --git a/vendor/github.com/libp2p/go-buffer-pool/go.mod b/vendor/github.com/libp2p/go-buffer-pool/go.mod new file mode 100644 index 0000000000..02b140dddb --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/go.mod @@ -0,0 +1,3 @@ +module github.com/libp2p/go-buffer-pool + +go 1.12 diff --git a/vendor/github.com/libp2p/go-buffer-pool/pool.go b/vendor/github.com/libp2p/go-buffer-pool/pool.go new file mode 100644 index 0000000000..d812840aaa --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/pool.go @@ -0,0 +1,115 @@ +// Package pool provides a sync.Pool equivalent that buckets incoming +// requests to one of 32 sub-pools, one for each power of 2, 0-32. +// +// import (pool "github.com/libp2p/go-buffer-pool") +// var p pool.BufferPool +// +// small := make([]byte, 1024) +// large := make([]byte, 4194304) +// p.Put(small) +// p.Put(large) +// +// small2 := p.Get(1024) +// large2 := p.Get(4194304) +// fmt.Println("small2 len:", len(small2)) +// fmt.Println("large2 len:", len(large2)) +// +// // Output: +// // small2 len: 1024 +// // large2 len: 4194304 +// +package pool + +import ( + "math" + "math/bits" + "sync" +) + +// GlobalPool is a static Pool for reusing byteslices of various sizes. +var GlobalPool = new(BufferPool) + +// MaxLength is the maximum length of an element that can be added to the Pool. +const MaxLength = math.MaxInt32 + +// BufferPool is a pool to handle cases of reusing elements of varying sizes. It +// maintains 32 internal pools, for each power of 2 in 0-32. +// +// You should generally just call the package level Get and Put methods or use +// the GlobalPool BufferPool instead of constructing your own. +// +// You MUST NOT copy Pool after using. +type BufferPool struct { + pools [32]sync.Pool // a list of singlePools + ptrs sync.Pool +} + +type bufp struct { + buf []byte +} + +// Get retrieves a buffer of the appropriate length from the buffer pool or +// allocates a new one. Get may choose to ignore the pool and treat it as empty. +// Callers should not assume any relation between values passed to Put and the +// values returned by Get. +// +// If no suitable buffer exists in the pool, Get creates one. +func (p *BufferPool) Get(length int) []byte { + if length == 0 { + return nil + } + if length > MaxLength { + return make([]byte, length) + } + idx := nextLogBase2(uint32(length)) + if ptr := p.pools[idx].Get(); ptr != nil { + bp := ptr.(*bufp) + buf := bp.buf[:uint32(length)] + bp.buf = nil + p.ptrs.Put(ptr) + return buf + } + return make([]byte, 1< MaxLength { + return // drop it + } + idx := prevLogBase2(uint32(capacity)) + var bp *bufp + if ptr := p.ptrs.Get(); ptr != nil { + bp = ptr.(*bufp) + } else { + bp = new(bufp) + } + bp.buf = buf + p.pools[idx].Put(bp) +} + +// Get retrieves a buffer of the appropriate length from the global buffer pool +// (or allocates a new one). +func Get(length int) []byte { + return GlobalPool.Get(length) +} + +// Put returns a buffer to the global buffer pool. +func Put(slice []byte) { + GlobalPool.Put(slice) +} + +// Log of base two, round up (for v > 0). +func nextLogBase2(v uint32) uint32 { + return uint32(bits.Len32(v - 1)) +} + +// Log of base two, round down (for v > 0) +func prevLogBase2(num uint32) uint32 { + next := nextLogBase2(num) + if num == (1 << uint32(next)) { + return next + } + return next - 1 +} diff --git a/vendor/github.com/libp2p/go-buffer-pool/writer.go b/vendor/github.com/libp2p/go-buffer-pool/writer.go new file mode 100644 index 0000000000..cea83f9237 --- /dev/null +++ b/vendor/github.com/libp2p/go-buffer-pool/writer.go @@ -0,0 +1,119 @@ +package pool + +import ( + "bufio" + "io" + "sync" +) + +const WriterBufferSize = 4096 + +var bufioWriterPool = sync.Pool{ + New: func() interface{} { + return bufio.NewWriterSize(nil, WriterBufferSize) + }, +} + +// Writer is a buffered writer that returns its internal buffer in a pool when +// not in use. +type Writer struct { + W io.Writer + bufw *bufio.Writer +} + +func (w *Writer) ensureBuffer() { + if w.bufw == nil { + w.bufw = bufioWriterPool.Get().(*bufio.Writer) + w.bufw.Reset(w.W) + } +} + +// Write writes the given byte slice to the underlying connection. +// +// Note: Write won't return the write buffer to the pool even if it ends up +// being empty after the write. You must call Flush() to do that. +func (w *Writer) Write(b []byte) (int, error) { + if w.bufw == nil { + if len(b) >= WriterBufferSize { + return w.W.Write(b) + } + w.bufw = bufioWriterPool.Get().(*bufio.Writer) + w.bufw.Reset(w.W) + } + return w.bufw.Write(b) +} + +// Size returns the size of the underlying buffer. +func (w *Writer) Size() int { + return WriterBufferSize +} + +// Available returns the amount buffer space available. +func (w *Writer) Available() int { + if w.bufw != nil { + return w.bufw.Available() + } + return WriterBufferSize +} + +// Buffered returns the amount of data buffered. +func (w *Writer) Buffered() int { + if w.bufw != nil { + return w.bufw.Buffered() + } + return 0 +} + +// WriteByte writes a single byte. +func (w *Writer) WriteByte(b byte) error { + w.ensureBuffer() + return w.bufw.WriteByte(b) +} + +// WriteRune writes a single rune, returning the number of bytes written. +func (w *Writer) WriteRune(r rune) (int, error) { + w.ensureBuffer() + return w.bufw.WriteRune(r) +} + +// WriteString writes a string, returning the number of bytes written. +func (w *Writer) WriteString(s string) (int, error) { + w.ensureBuffer() + return w.bufw.WriteString(s) +} + +// Flush flushes the write buffer, if any, and returns it to the pool. +func (w *Writer) Flush() error { + if w.bufw == nil { + return nil + } + if err := w.bufw.Flush(); err != nil { + return err + } + w.bufw.Reset(nil) + bufioWriterPool.Put(w.bufw) + w.bufw = nil + return nil +} + +// Close flushes the underlying writer and closes it if it implements the +// io.Closer interface. +// +// Note: Close() closes the writer even if Flush() fails to avoid leaking system +// resources. If you want to make sure Flush() succeeds, call it first. +func (w *Writer) Close() error { + var ( + ferr, cerr error + ) + ferr = w.Flush() + + // always close even if flush fails. + if closer, ok := w.W.(io.Closer); ok { + cerr = closer.Close() + } + + if ferr != nil { + return ferr + } + return cerr +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/LICENSE b/vendor/github.com/libp2p/go-libp2p-core/LICENSE new file mode 100644 index 0000000000..770d1744d1 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/LICENSE @@ -0,0 +1,4 @@ +Dual-licensed under MIT and ASLv2, by way of the [Permissive License Stack](https://protocol.ai/blog/announcing-the-permissive-license-stack/). + +Apache-2.0: https://www.apache.org/licenses/license-2.0 +MIT: https://www.opensource.org/licenses/mit diff --git a/vendor/github.com/libp2p/go-libp2p-core/LICENSE-APACHE b/vendor/github.com/libp2p/go-libp2p-core/LICENSE-APACHE new file mode 100644 index 0000000000..546514363d --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2019. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/libp2p/go-libp2p-core/LICENSE-MIT b/vendor/github.com/libp2p/go-libp2p-core/LICENSE-MIT new file mode 100644 index 0000000000..ea532a8305 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2019. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/ecdsa.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/ecdsa.go new file mode 100644 index 0000000000..3b7a425a5d --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/ecdsa.go @@ -0,0 +1,177 @@ +package crypto + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/asn1" + "errors" + "io" + "math/big" + + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + + sha256 "github.com/minio/sha256-simd" +) + +// ECDSAPrivateKey is an implementation of an ECDSA private key +type ECDSAPrivateKey struct { + priv *ecdsa.PrivateKey +} + +// ECDSAPublicKey is an implementation of an ECDSA public key +type ECDSAPublicKey struct { + pub *ecdsa.PublicKey +} + +// ECDSASig holds the r and s values of an ECDSA signature +type ECDSASig struct { + R, S *big.Int +} + +var ( + // ErrNotECDSAPubKey is returned when the public key passed is not an ecdsa public key + ErrNotECDSAPubKey = errors.New("not an ecdsa public key") + // ErrNilSig is returned when the signature is nil + ErrNilSig = errors.New("sig is nil") + // ErrNilPrivateKey is returned when a nil private key is provided + ErrNilPrivateKey = errors.New("private key is nil") + // ErrNilPublicKey is returned when a nil public key is provided + ErrNilPublicKey = errors.New("public key is nil") + // ECDSACurve is the default ecdsa curve used + ECDSACurve = elliptic.P256() +) + +// GenerateECDSAKeyPair generates a new ecdsa private and public key +func GenerateECDSAKeyPair(src io.Reader) (PrivKey, PubKey, error) { + return GenerateECDSAKeyPairWithCurve(ECDSACurve, src) +} + +// GenerateECDSAKeyPairWithCurve generates a new ecdsa private and public key with a speicified curve +func GenerateECDSAKeyPairWithCurve(curve elliptic.Curve, src io.Reader) (PrivKey, PubKey, error) { + priv, err := ecdsa.GenerateKey(curve, src) + if err != nil { + return nil, nil, err + } + + return &ECDSAPrivateKey{priv}, &ECDSAPublicKey{&priv.PublicKey}, nil +} + +// ECDSAKeyPairFromKey generates a new ecdsa private and public key from an input private key +func ECDSAKeyPairFromKey(priv *ecdsa.PrivateKey) (PrivKey, PubKey, error) { + if priv == nil { + return nil, nil, ErrNilPrivateKey + } + + return &ECDSAPrivateKey{priv}, &ECDSAPublicKey{&priv.PublicKey}, nil +} + +// MarshalECDSAPrivateKey returns x509 bytes from a private key +func MarshalECDSAPrivateKey(ePriv ECDSAPrivateKey) ([]byte, error) { + return x509.MarshalECPrivateKey(ePriv.priv) +} + +// MarshalECDSAPublicKey returns x509 bytes from a public key +func MarshalECDSAPublicKey(ePub ECDSAPublicKey) ([]byte, error) { + return x509.MarshalPKIXPublicKey(ePub.pub) +} + +// UnmarshalECDSAPrivateKey returns a private key from x509 bytes +func UnmarshalECDSAPrivateKey(data []byte) (PrivKey, error) { + priv, err := x509.ParseECPrivateKey(data) + if err != nil { + return nil, err + } + + return &ECDSAPrivateKey{priv}, nil +} + +// UnmarshalECDSAPublicKey returns the public key from x509 bytes +func UnmarshalECDSAPublicKey(data []byte) (PubKey, error) { + pubIfc, err := x509.ParsePKIXPublicKey(data) + if err != nil { + return nil, err + } + + pub, ok := pubIfc.(*ecdsa.PublicKey) + if !ok { + return nil, ErrNotECDSAPubKey + } + + return &ECDSAPublicKey{pub}, nil +} + +// Bytes returns the private key as protobuf bytes +func (ePriv *ECDSAPrivateKey) Bytes() ([]byte, error) { + return MarshalPrivateKey(ePriv) +} + +// Type returns the key type +func (ePriv *ECDSAPrivateKey) Type() pb.KeyType { + return pb.KeyType_ECDSA +} + +// Raw returns x509 bytes from a private key +func (ePriv *ECDSAPrivateKey) Raw() ([]byte, error) { + return x509.MarshalECPrivateKey(ePriv.priv) +} + +// Equals compares two private keys +func (ePriv *ECDSAPrivateKey) Equals(o Key) bool { + return basicEquals(ePriv, o) +} + +// Sign returns the signature of the input data +func (ePriv *ECDSAPrivateKey) Sign(data []byte) ([]byte, error) { + hash := sha256.Sum256(data) + r, s, err := ecdsa.Sign(rand.Reader, ePriv.priv, hash[:]) + if err != nil { + return nil, err + } + + return asn1.Marshal(ECDSASig{ + R: r, + S: s, + }) +} + +// GetPublic returns a public key +func (ePriv *ECDSAPrivateKey) GetPublic() PubKey { + return &ECDSAPublicKey{&ePriv.priv.PublicKey} +} + +// Bytes returns the public key as protobuf bytes +func (ePub *ECDSAPublicKey) Bytes() ([]byte, error) { + return MarshalPublicKey(ePub) +} + +// Type returns the key type +func (ePub *ECDSAPublicKey) Type() pb.KeyType { + return pb.KeyType_ECDSA +} + +// Raw returns x509 bytes from a public key +func (ePub *ECDSAPublicKey) Raw() ([]byte, error) { + return x509.MarshalPKIXPublicKey(ePub.pub) +} + +// Equals compares to public keys +func (ePub *ECDSAPublicKey) Equals(o Key) bool { + return basicEquals(ePub, o) +} + +// Verify compares data to a signature +func (ePub *ECDSAPublicKey) Verify(data, sigBytes []byte) (bool, error) { + sig := new(ECDSASig) + if _, err := asn1.Unmarshal(sigBytes, sig); err != nil { + return false, err + } + if sig == nil { + return false, ErrNilSig + } + + hash := sha256.Sum256(data) + + return ecdsa.Verify(ePub.pub, hash[:], sig.R, sig.S), nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/ed25519.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/ed25519.go new file mode 100644 index 0000000000..1707e7509f --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/ed25519.go @@ -0,0 +1,155 @@ +package crypto + +import ( + "bytes" + "crypto/ed25519" + "crypto/subtle" + "errors" + "fmt" + "io" + + pb "github.com/libp2p/go-libp2p-core/crypto/pb" +) + +// Ed25519PrivateKey is an ed25519 private key. +type Ed25519PrivateKey struct { + k ed25519.PrivateKey +} + +// Ed25519PublicKey is an ed25519 public key. +type Ed25519PublicKey struct { + k ed25519.PublicKey +} + +// GenerateEd25519Key generates a new ed25519 private and public key pair. +func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) { + pub, priv, err := ed25519.GenerateKey(src) + if err != nil { + return nil, nil, err + } + + return &Ed25519PrivateKey{ + k: priv, + }, + &Ed25519PublicKey{ + k: pub, + }, + nil +} + +// Type of the private key (Ed25519). +func (k *Ed25519PrivateKey) Type() pb.KeyType { + return pb.KeyType_Ed25519 +} + +// Bytes marshals an ed25519 private key to protobuf bytes. +func (k *Ed25519PrivateKey) Bytes() ([]byte, error) { + return MarshalPrivateKey(k) +} + +// Raw private key bytes. +func (k *Ed25519PrivateKey) Raw() ([]byte, error) { + // The Ed25519 private key contains two 32-bytes curve points, the private + // key and the public key. + // It makes it more efficient to get the public key without re-computing an + // elliptic curve multiplication. + buf := make([]byte, len(k.k)) + copy(buf, k.k) + + return buf, nil +} + +func (k *Ed25519PrivateKey) pubKeyBytes() []byte { + return k.k[ed25519.PrivateKeySize-ed25519.PublicKeySize:] +} + +// Equals compares two ed25519 private keys. +func (k *Ed25519PrivateKey) Equals(o Key) bool { + edk, ok := o.(*Ed25519PrivateKey) + if !ok { + return basicEquals(k, o) + } + + return subtle.ConstantTimeCompare(k.k, edk.k) == 1 +} + +// GetPublic returns an ed25519 public key from a private key. +func (k *Ed25519PrivateKey) GetPublic() PubKey { + return &Ed25519PublicKey{k: k.pubKeyBytes()} +} + +// Sign returns a signature from an input message. +func (k *Ed25519PrivateKey) Sign(msg []byte) ([]byte, error) { + return ed25519.Sign(k.k, msg), nil +} + +// Type of the public key (Ed25519). +func (k *Ed25519PublicKey) Type() pb.KeyType { + return pb.KeyType_Ed25519 +} + +// Bytes returns a ed25519 public key as protobuf bytes. +func (k *Ed25519PublicKey) Bytes() ([]byte, error) { + return MarshalPublicKey(k) +} + +// Raw public key bytes. +func (k *Ed25519PublicKey) Raw() ([]byte, error) { + return k.k, nil +} + +// Equals compares two ed25519 public keys. +func (k *Ed25519PublicKey) Equals(o Key) bool { + edk, ok := o.(*Ed25519PublicKey) + if !ok { + return basicEquals(k, o) + } + + return bytes.Equal(k.k, edk.k) +} + +// Verify checks a signature agains the input data. +func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (bool, error) { + return ed25519.Verify(k.k, data, sig), nil +} + +// UnmarshalEd25519PublicKey returns a public key from input bytes. +func UnmarshalEd25519PublicKey(data []byte) (PubKey, error) { + if len(data) != 32 { + return nil, errors.New("expect ed25519 public key data size to be 32") + } + + return &Ed25519PublicKey{ + k: ed25519.PublicKey(data), + }, nil +} + +// UnmarshalEd25519PrivateKey returns a private key from input bytes. +func UnmarshalEd25519PrivateKey(data []byte) (PrivKey, error) { + switch len(data) { + case ed25519.PrivateKeySize + ed25519.PublicKeySize: + // Remove the redundant public key. See issue #36. + redundantPk := data[ed25519.PrivateKeySize:] + pk := data[ed25519.PrivateKeySize-ed25519.PublicKeySize : ed25519.PrivateKeySize] + if subtle.ConstantTimeCompare(pk, redundantPk) == 0 { + return nil, errors.New("expected redundant ed25519 public key to be redundant") + } + + // No point in storing the extra data. + newKey := make([]byte, ed25519.PrivateKeySize) + copy(newKey, data[:ed25519.PrivateKeySize]) + data = newKey + case ed25519.PrivateKeySize: + default: + return nil, fmt.Errorf( + "expected ed25519 data size to be %d or %d, got %d", + ed25519.PrivateKeySize, + ed25519.PrivateKeySize+ed25519.PublicKeySize, + len(data), + ) + } + + return &Ed25519PrivateKey{ + k: ed25519.PrivateKey(data), + }, nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/key.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/key.go new file mode 100644 index 0000000000..090338810f --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/key.go @@ -0,0 +1,399 @@ +// Package crypto implements various cryptographic utilities used by libp2p. +// This includes a Public and Private key interface and key implementations +// for supported key algorithms. +package crypto + +import ( + "crypto/elliptic" + "crypto/hmac" + "crypto/rand" + "crypto/sha1" + "crypto/sha512" + "crypto/subtle" + "encoding/base64" + "errors" + "fmt" + "hash" + "io" + + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + + "github.com/gogo/protobuf/proto" + sha256 "github.com/minio/sha256-simd" +) + +const ( + // RSA is an enum for the supported RSA key type + RSA = iota + // Ed25519 is an enum for the supported Ed25519 key type + Ed25519 + // Secp256k1 is an enum for the supported Secp256k1 key type + Secp256k1 + // ECDSA is an enum for the supported ECDSA key type + ECDSA +) + +var ( + // ErrBadKeyType is returned when a key is not supported + ErrBadKeyType = errors.New("invalid or unsupported key type") + // KeyTypes is a list of supported keys + KeyTypes = []int{ + RSA, + Ed25519, + Secp256k1, + ECDSA, + } +) + +// PubKeyUnmarshaller is a func that creates a PubKey from a given slice of bytes +type PubKeyUnmarshaller func(data []byte) (PubKey, error) + +// PrivKeyUnmarshaller is a func that creates a PrivKey from a given slice of bytes +type PrivKeyUnmarshaller func(data []byte) (PrivKey, error) + +// PubKeyUnmarshallers is a map of unmarshallers by key type +var PubKeyUnmarshallers = map[pb.KeyType]PubKeyUnmarshaller{ + pb.KeyType_RSA: UnmarshalRsaPublicKey, + pb.KeyType_Ed25519: UnmarshalEd25519PublicKey, + pb.KeyType_Secp256k1: UnmarshalSecp256k1PublicKey, + pb.KeyType_ECDSA: UnmarshalECDSAPublicKey, +} + +// PrivKeyUnmarshallers is a map of unmarshallers by key type +var PrivKeyUnmarshallers = map[pb.KeyType]PrivKeyUnmarshaller{ + pb.KeyType_RSA: UnmarshalRsaPrivateKey, + pb.KeyType_Ed25519: UnmarshalEd25519PrivateKey, + pb.KeyType_Secp256k1: UnmarshalSecp256k1PrivateKey, + pb.KeyType_ECDSA: UnmarshalECDSAPrivateKey, +} + +// Key represents a crypto key that can be compared to another key +type Key interface { + // Bytes returns a serialized, storeable representation of this key + // DEPRECATED in favor of Marshal / Unmarshal + Bytes() ([]byte, error) + + // Equals checks whether two PubKeys are the same + Equals(Key) bool + + // Raw returns the raw bytes of the key (not wrapped in the + // libp2p-crypto protobuf). + // + // This function is the inverse of {Priv,Pub}KeyUnmarshaler. + Raw() ([]byte, error) + + // Type returns the protobof key type. + Type() pb.KeyType +} + +// PrivKey represents a private key that can be used to generate a public key and sign data +type PrivKey interface { + Key + + // Cryptographically sign the given bytes + Sign([]byte) ([]byte, error) + + // Return a public key paired with this private key + GetPublic() PubKey +} + +// PubKey is a public key that can be used to verifiy data signed with the corresponding private key +type PubKey interface { + Key + + // Verify that 'sig' is the signed hash of 'data' + Verify(data []byte, sig []byte) (bool, error) +} + +// GenSharedKey generates the shared key from a given private key +type GenSharedKey func([]byte) ([]byte, error) + +// GenerateKeyPair generates a private and public key +func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) { + return GenerateKeyPairWithReader(typ, bits, rand.Reader) +} + +// GenerateKeyPairWithReader returns a keypair of the given type and bitsize +func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, error) { + switch typ { + case RSA: + return GenerateRSAKeyPair(bits, src) + case Ed25519: + return GenerateEd25519Key(src) + case Secp256k1: + return GenerateSecp256k1Key(src) + case ECDSA: + return GenerateECDSAKeyPair(src) + default: + return nil, nil, ErrBadKeyType + } +} + +// GenerateEKeyPair returns an ephemeral public key and returns a function that will compute +// the shared secret key. Used in the identify module. +// +// Focuses only on ECDH now, but can be made more general in the future. +func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) { + var curve elliptic.Curve + + switch curveName { + case "P-256": + curve = elliptic.P256() + case "P-384": + curve = elliptic.P384() + case "P-521": + curve = elliptic.P521() + default: + return nil, nil, fmt.Errorf("unknown curve name") + } + + priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, nil, err + } + + pubKey := elliptic.Marshal(curve, x, y) + + done := func(theirPub []byte) ([]byte, error) { + // Verify and unpack node's public key. + x, y := elliptic.Unmarshal(curve, theirPub) + if x == nil { + return nil, fmt.Errorf("malformed public key: %d %v", len(theirPub), theirPub) + } + + if !curve.IsOnCurve(x, y) { + return nil, errors.New("invalid public key") + } + + // Generate shared secret. + secret, _ := curve.ScalarMult(x, y, priv) + + return secret.Bytes(), nil + } + + return pubKey, done, nil +} + +// StretchedKeys ... +type StretchedKeys struct { + IV []byte + MacKey []byte + CipherKey []byte +} + +// PENDING DEPRECATION: KeyStretcher() will be deprecated with secio; for new +// code, please use PBKDF2 (golang.org/x/crypto/pbkdf2) instead. +// KeyStretcher returns a set of keys for each party by stretching the shared key. +// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey). +// This function accepts the following cipher types: +// - AES-128 +// - AES-256 +// The function will panic upon receiving an unknown cipherType +func KeyStretcher(cipherType string, hashType string, secret []byte) (StretchedKeys, StretchedKeys) { + var cipherKeySize int + var ivSize int + switch cipherType { + case "AES-128": + ivSize = 16 + cipherKeySize = 16 + case "AES-256": + ivSize = 16 + cipherKeySize = 32 + default: + panic("Unrecognized cipher, programmer error?") + } + + hmacKeySize := 20 + + seed := []byte("key expansion") + + result := make([]byte, 2*(ivSize+cipherKeySize+hmacKeySize)) + + var h func() hash.Hash + + switch hashType { + case "SHA1": + h = sha1.New + case "SHA256": + h = sha256.New + case "SHA512": + h = sha512.New + default: + panic("Unrecognized hash function, programmer error?") + } + + m := hmac.New(h, secret) + // note: guaranteed to never return an error + m.Write(seed) + + a := m.Sum(nil) + + j := 0 + for j < len(result) { + m.Reset() + + // note: guaranteed to never return an error. + m.Write(a) + m.Write(seed) + + b := m.Sum(nil) + + todo := len(b) + + if j+todo > len(result) { + todo = len(result) - j + } + + copy(result[j:j+todo], b) + + j += todo + + m.Reset() + + // note: guaranteed to never return an error. + m.Write(a) + + a = m.Sum(nil) + } + + half := len(result) / 2 + r1 := result[:half] + r2 := result[half:] + + var k1 StretchedKeys + var k2 StretchedKeys + + k1.IV = r1[0:ivSize] + k1.CipherKey = r1[ivSize : ivSize+cipherKeySize] + k1.MacKey = r1[ivSize+cipherKeySize:] + + k2.IV = r2[0:ivSize] + k2.CipherKey = r2[ivSize : ivSize+cipherKeySize] + k2.MacKey = r2[ivSize+cipherKeySize:] + + return k1, k2 +} + +// UnmarshalPublicKey converts a protobuf serialized public key into its +// representative object +func UnmarshalPublicKey(data []byte) (PubKey, error) { + pmes := new(pb.PublicKey) + err := proto.Unmarshal(data, pmes) + if err != nil { + return nil, err + } + + return PublicKeyFromProto(pmes) +} + +// PublicKeyFromProto converts an unserialized protobuf PublicKey message +// into its representative object. +func PublicKeyFromProto(pmes *pb.PublicKey) (PubKey, error) { + um, ok := PubKeyUnmarshallers[pmes.GetType()] + if !ok { + return nil, ErrBadKeyType + } + + data := pmes.GetData() + + pk, err := um(data) + if err != nil { + return nil, err + } + + switch tpk := pk.(type) { + case *RsaPublicKey: + tpk.cached, _ = pmes.Marshal() + } + + return pk, nil +} + +// MarshalPublicKey converts a public key object into a protobuf serialized +// public key +func MarshalPublicKey(k PubKey) ([]byte, error) { + pbmes, err := PublicKeyToProto(k) + if err != nil { + return nil, err + } + + return proto.Marshal(pbmes) +} + +// PublicKeyToProto converts a public key object into an unserialized +// protobuf PublicKey message. +func PublicKeyToProto(k PubKey) (*pb.PublicKey, error) { + pbmes := new(pb.PublicKey) + pbmes.Type = k.Type() + data, err := k.Raw() + if err != nil { + return nil, err + } + pbmes.Data = data + return pbmes, nil +} + +// UnmarshalPrivateKey converts a protobuf serialized private key into its +// representative object +func UnmarshalPrivateKey(data []byte) (PrivKey, error) { + pmes := new(pb.PrivateKey) + err := proto.Unmarshal(data, pmes) + if err != nil { + return nil, err + } + + um, ok := PrivKeyUnmarshallers[pmes.GetType()] + if !ok { + return nil, ErrBadKeyType + } + + return um(pmes.GetData()) +} + +// MarshalPrivateKey converts a key object into its protobuf serialized form. +func MarshalPrivateKey(k PrivKey) ([]byte, error) { + pbmes := new(pb.PrivateKey) + pbmes.Type = k.Type() + data, err := k.Raw() + if err != nil { + return nil, err + } + + pbmes.Data = data + return proto.Marshal(pbmes) +} + +// ConfigDecodeKey decodes from b64 (for config file) to a byte array that can be unmarshalled. +func ConfigDecodeKey(b string) ([]byte, error) { + return base64.StdEncoding.DecodeString(b) +} + +// ConfigEncodeKey encodes a marshalled key to b64 (for config file). +func ConfigEncodeKey(b []byte) string { + return base64.StdEncoding.EncodeToString(b) +} + +// KeyEqual checks whether two Keys are equivalent (have identical byte representations). +func KeyEqual(k1, k2 Key) bool { + if k1 == k2 { + return true + } + + return k1.Equals(k2) +} + +func basicEquals(k1, k2 Key) bool { + if k1.Type() != k2.Type() { + return false + } + + a, err := k1.Raw() + if err != nil { + return false + } + b, err := k2.Raw() + if err != nil { + return false + } + return subtle.ConstantTimeCompare(a, b) == 1 +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/key_not_openssl.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/key_not_openssl.go new file mode 100644 index 0000000000..1499feaab7 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/key_not_openssl.go @@ -0,0 +1,80 @@ +// +build !openssl + +package crypto + +import ( + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + + btcec "github.com/btcsuite/btcd/btcec" +) + +// KeyPairFromStdKey wraps standard library (and secp256k1) private keys in libp2p/go-libp2p-core/crypto keys +func KeyPairFromStdKey(priv crypto.PrivateKey) (PrivKey, PubKey, error) { + if priv == nil { + return nil, nil, ErrNilPrivateKey + } + + switch p := priv.(type) { + case *rsa.PrivateKey: + return &RsaPrivateKey{*p}, &RsaPublicKey{k: p.PublicKey}, nil + + case *ecdsa.PrivateKey: + return &ECDSAPrivateKey{p}, &ECDSAPublicKey{&p.PublicKey}, nil + + case *ed25519.PrivateKey: + pubIfc := p.Public() + pub, _ := pubIfc.(ed25519.PublicKey) + return &Ed25519PrivateKey{*p}, &Ed25519PublicKey{pub}, nil + + case *btcec.PrivateKey: + sPriv := Secp256k1PrivateKey(*p) + sPub := Secp256k1PublicKey(*p.PubKey()) + return &sPriv, &sPub, nil + + default: + return nil, nil, ErrBadKeyType + } +} + +// PrivKeyToStdKey converts libp2p/go-libp2p-core/crypto private keys to standard library (and secp256k1) private keys +func PrivKeyToStdKey(priv PrivKey) (crypto.PrivateKey, error) { + if priv == nil { + return nil, ErrNilPrivateKey + } + + switch p := priv.(type) { + case *RsaPrivateKey: + return &p.sk, nil + case *ECDSAPrivateKey: + return p.priv, nil + case *Ed25519PrivateKey: + return &p.k, nil + case *Secp256k1PrivateKey: + return p, nil + default: + return nil, ErrBadKeyType + } +} + +// PubKeyToStdKey converts libp2p/go-libp2p-core/crypto private keys to standard library (and secp256k1) public keys +func PubKeyToStdKey(pub PubKey) (crypto.PublicKey, error) { + if pub == nil { + return nil, ErrNilPublicKey + } + + switch p := pub.(type) { + case *RsaPublicKey: + return &p.k, nil + case *ECDSAPublicKey: + return p.pub, nil + case *Ed25519PublicKey: + return p.k, nil + case *Secp256k1PublicKey: + return p, nil + default: + return nil, ErrBadKeyType + } +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/key_openssl.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/key_openssl.go new file mode 100644 index 0000000000..8d7810ce6c --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/key_openssl.go @@ -0,0 +1,94 @@ +// +build openssl + +package crypto + +import ( + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + + btcec "github.com/btcsuite/btcd/btcec" + openssl "github.com/libp2p/go-openssl" +) + +// KeyPairFromStdKey wraps standard library (and secp256k1) private keys in libp2p/go-libp2p-core/crypto keys +func KeyPairFromStdKey(priv crypto.PrivateKey) (PrivKey, PubKey, error) { + if priv == nil { + return nil, nil, ErrNilPrivateKey + } + + switch p := priv.(type) { + case *rsa.PrivateKey: + pk, err := openssl.LoadPrivateKeyFromDER(x509.MarshalPKCS1PrivateKey(p)) + if err != nil { + return nil, nil, err + } + + return &opensslPrivateKey{pk}, &opensslPublicKey{key: pk}, nil + + case *ecdsa.PrivateKey: + return &ECDSAPrivateKey{p}, &ECDSAPublicKey{&p.PublicKey}, nil + + case *ed25519.PrivateKey: + pubIfc := p.Public() + pub, _ := pubIfc.(ed25519.PublicKey) + return &Ed25519PrivateKey{*p}, &Ed25519PublicKey{pub}, nil + + case *btcec.PrivateKey: + sPriv := Secp256k1PrivateKey(*p) + sPub := Secp256k1PublicKey(*p.PubKey()) + return &sPriv, &sPub, nil + + default: + return nil, nil, ErrBadKeyType + } +} + +// PrivKeyToStdKey converts libp2p/go-libp2p-core/crypto private keys to standard library (and secp256k1) private keys +func PrivKeyToStdKey(priv PrivKey) (crypto.PrivateKey, error) { + if priv == nil { + return nil, ErrNilPrivateKey + } + switch p := priv.(type) { + case *opensslPrivateKey: + raw, err := p.Raw() + if err != nil { + return nil, err + } + return x509.ParsePKCS1PrivateKey(raw) + case *ECDSAPrivateKey: + return p.priv, nil + case *Ed25519PrivateKey: + return &p.k, nil + case *Secp256k1PrivateKey: + return p, nil + default: + return nil, ErrBadKeyType + } +} + +// PubKeyToStdKey converts libp2p/go-libp2p-core/crypto private keys to standard library (and secp256k1) public keys +func PubKeyToStdKey(pub PubKey) (crypto.PublicKey, error) { + if pub == nil { + return nil, ErrNilPublicKey + } + + switch p := pub.(type) { + case *opensslPublicKey: + raw, err := p.Raw() + if err != nil { + return nil, err + } + return x509.ParsePKIXPublicKey(raw) + case *ECDSAPublicKey: + return p.pub, nil + case *Ed25519PublicKey: + return p.k, nil + case *Secp256k1PublicKey: + return p, nil + default: + return nil, ErrBadKeyType + } +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/openssl_common.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/openssl_common.go new file mode 100644 index 0000000000..88807cafd7 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/openssl_common.go @@ -0,0 +1,119 @@ +// +build openssl + +package crypto + +import ( + "sync" + + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + + openssl "github.com/libp2p/go-openssl" +) + +// define these as separate types so we can add more key types later and reuse +// code. + +type opensslPublicKey struct { + key openssl.PublicKey + + cacheLk sync.Mutex + cached []byte +} + +type opensslPrivateKey struct { + key openssl.PrivateKey +} + +func unmarshalOpensslPrivateKey(b []byte) (opensslPrivateKey, error) { + sk, err := openssl.LoadPrivateKeyFromDER(b) + if err != nil { + return opensslPrivateKey{}, err + } + return opensslPrivateKey{sk}, nil +} + +func unmarshalOpensslPublicKey(b []byte) (opensslPublicKey, error) { + sk, err := openssl.LoadPublicKeyFromDER(b) + if err != nil { + return opensslPublicKey{}, err + } + return opensslPublicKey{key: sk, cached: b}, nil +} + +// Verify compares a signature against input data +func (pk *opensslPublicKey) Verify(data, sig []byte) (bool, error) { + err := pk.key.VerifyPKCS1v15(openssl.SHA256_Method, data, sig) + return err == nil, err +} + +func (pk *opensslPublicKey) Type() pb.KeyType { + switch pk.key.KeyType() { + case openssl.KeyTypeRSA: + return pb.KeyType_RSA + default: + return -1 + } +} + +// Bytes returns protobuf bytes of a public key +func (pk *opensslPublicKey) Bytes() ([]byte, error) { + pk.cacheLk.Lock() + var err error + if pk.cached == nil { + pk.cached, err = MarshalPublicKey(pk) + } + pk.cacheLk.Unlock() + return pk.cached, err +} + +func (pk *opensslPublicKey) Raw() ([]byte, error) { + return pk.key.MarshalPKIXPublicKeyDER() +} + +// Equals checks whether this key is equal to another +func (pk *opensslPublicKey) Equals(k Key) bool { + k0, ok := k.(*RsaPublicKey) + if !ok { + return basicEquals(pk, k) + } + + return pk.key.Equal(k0.opensslPublicKey.key) +} + +// Sign returns a signature of the input data +func (sk *opensslPrivateKey) Sign(message []byte) ([]byte, error) { + return sk.key.SignPKCS1v15(openssl.SHA256_Method, message) +} + +// GetPublic returns a public key +func (sk *opensslPrivateKey) GetPublic() PubKey { + return &opensslPublicKey{key: sk.key} +} + +func (sk *opensslPrivateKey) Type() pb.KeyType { + switch sk.key.KeyType() { + case openssl.KeyTypeRSA: + return pb.KeyType_RSA + default: + return -1 + } +} + +// Bytes returns protobuf bytes from a private key +func (sk *opensslPrivateKey) Bytes() ([]byte, error) { + return MarshalPrivateKey(sk) +} + +func (sk *opensslPrivateKey) Raw() ([]byte, error) { + return sk.key.MarshalPKCS1PrivateKeyDER() +} + +// Equals checks whether this key is equal to another +func (sk *opensslPrivateKey) Equals(k Key) bool { + k0, ok := k.(*RsaPrivateKey) + if !ok { + return basicEquals(sk, k) + } + + return sk.key.Equal(k0.opensslPrivateKey.key) +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/Makefile b/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/Makefile new file mode 100644 index 0000000000..8af2dd8177 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/Makefile @@ -0,0 +1,11 @@ +PB = $(wildcard *.proto) +GO = $(PB:.proto=.pb.go) + +all: $(GO) + +%.pb.go: %.proto + protoc --proto_path=$(PWD)/../..:. --gogofaster_out=. $< + +clean: + rm -f *.pb.go + rm -f *.go diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.pb.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.pb.go new file mode 100644 index 0000000000..072fad9c93 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.pb.go @@ -0,0 +1,625 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: crypto.proto + +package crypto_pb + +import ( + fmt "fmt" + github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type KeyType int32 + +const ( + KeyType_RSA KeyType = 0 + KeyType_Ed25519 KeyType = 1 + KeyType_Secp256k1 KeyType = 2 + KeyType_ECDSA KeyType = 3 +) + +var KeyType_name = map[int32]string{ + 0: "RSA", + 1: "Ed25519", + 2: "Secp256k1", + 3: "ECDSA", +} + +var KeyType_value = map[string]int32{ + "RSA": 0, + "Ed25519": 1, + "Secp256k1": 2, + "ECDSA": 3, +} + +func (x KeyType) Enum() *KeyType { + p := new(KeyType) + *p = x + return p +} + +func (x KeyType) String() string { + return proto.EnumName(KeyType_name, int32(x)) +} + +func (x *KeyType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(KeyType_value, data, "KeyType") + if err != nil { + return err + } + *x = KeyType(value) + return nil +} + +func (KeyType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_527278fb02d03321, []int{0} +} + +type PublicKey struct { + Type KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type"` + Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data"` +} + +func (m *PublicKey) Reset() { *m = PublicKey{} } +func (m *PublicKey) String() string { return proto.CompactTextString(m) } +func (*PublicKey) ProtoMessage() {} +func (*PublicKey) Descriptor() ([]byte, []int) { + return fileDescriptor_527278fb02d03321, []int{0} +} +func (m *PublicKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PublicKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PublicKey.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PublicKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_PublicKey.Merge(m, src) +} +func (m *PublicKey) XXX_Size() int { + return m.Size() +} +func (m *PublicKey) XXX_DiscardUnknown() { + xxx_messageInfo_PublicKey.DiscardUnknown(m) +} + +var xxx_messageInfo_PublicKey proto.InternalMessageInfo + +func (m *PublicKey) GetType() KeyType { + if m != nil { + return m.Type + } + return KeyType_RSA +} + +func (m *PublicKey) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type PrivateKey struct { + Type KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type"` + Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data"` +} + +func (m *PrivateKey) Reset() { *m = PrivateKey{} } +func (m *PrivateKey) String() string { return proto.CompactTextString(m) } +func (*PrivateKey) ProtoMessage() {} +func (*PrivateKey) Descriptor() ([]byte, []int) { + return fileDescriptor_527278fb02d03321, []int{1} +} +func (m *PrivateKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PrivateKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PrivateKey.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PrivateKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_PrivateKey.Merge(m, src) +} +func (m *PrivateKey) XXX_Size() int { + return m.Size() +} +func (m *PrivateKey) XXX_DiscardUnknown() { + xxx_messageInfo_PrivateKey.DiscardUnknown(m) +} + +var xxx_messageInfo_PrivateKey proto.InternalMessageInfo + +func (m *PrivateKey) GetType() KeyType { + if m != nil { + return m.Type + } + return KeyType_RSA +} + +func (m *PrivateKey) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func init() { + proto.RegisterEnum("crypto.pb.KeyType", KeyType_name, KeyType_value) + proto.RegisterType((*PublicKey)(nil), "crypto.pb.PublicKey") + proto.RegisterType((*PrivateKey)(nil), "crypto.pb.PrivateKey") +} + +func init() { proto.RegisterFile("crypto.proto", fileDescriptor_527278fb02d03321) } + +var fileDescriptor_527278fb02d03321 = []byte{ + // 203 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x2e, 0xaa, 0x2c, + 0x28, 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0xf1, 0x92, 0x94, 0x82, 0xb9, + 0x38, 0x03, 0x4a, 0x93, 0x72, 0x32, 0x93, 0xbd, 0x53, 0x2b, 0x85, 0x74, 0xb8, 0x58, 0x42, 0x2a, + 0x0b, 0x52, 0x25, 0x18, 0x15, 0x98, 0x34, 0xf8, 0x8c, 0x84, 0xf4, 0xe0, 0xca, 0xf4, 0xbc, 0x53, + 0x2b, 0x41, 0x32, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, 0x81, 0x55, 0x09, 0x49, 0x70, 0xb1, + 0xb8, 0x24, 0x96, 0x24, 0x4a, 0x30, 0x29, 0x30, 0x69, 0xf0, 0xc0, 0x64, 0x40, 0x22, 0x4a, 0x21, + 0x5c, 0x5c, 0x01, 0x45, 0x99, 0x65, 0x89, 0x25, 0xa9, 0x54, 0x34, 0x55, 0xcb, 0x92, 0x8b, 0x1d, + 0xaa, 0x41, 0x88, 0x9d, 0x8b, 0x39, 0x28, 0xd8, 0x51, 0x80, 0x41, 0x88, 0x9b, 0x8b, 0xdd, 0x35, + 0xc5, 0xc8, 0xd4, 0xd4, 0xd0, 0x52, 0x80, 0x51, 0x88, 0x97, 0x8b, 0x33, 0x38, 0x35, 0xb9, 0xc0, + 0xc8, 0xd4, 0x2c, 0xdb, 0x50, 0x80, 0x49, 0x88, 0x93, 0x8b, 0xd5, 0xd5, 0xd9, 0x25, 0xd8, 0x51, + 0x80, 0xd9, 0x49, 0xe2, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, + 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0x00, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x13, 0xbe, 0xd4, 0xff, 0x19, 0x01, 0x00, 0x00, +} + +func (m *PublicKey) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PublicKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PublicKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Data != nil { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + +func (m *PrivateKey) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PrivateKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PrivateKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Data != nil { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x12 + } + i = encodeVarintCrypto(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + +func encodeVarintCrypto(dAtA []byte, offset int, v uint64) int { + offset -= sovCrypto(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PublicKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovCrypto(uint64(m.Type)) + if m.Data != nil { + l = len(m.Data) + n += 1 + l + sovCrypto(uint64(l)) + } + return n +} + +func (m *PrivateKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovCrypto(uint64(m.Type)) + if m.Data != nil { + l = len(m.Data) + n += 1 + l + sovCrypto(uint64(l)) + } + return n +} + +func sovCrypto(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCrypto(x uint64) (n int) { + return sovCrypto(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PublicKey) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PublicKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PublicKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= KeyType(b&0x7F) << shift + if b < 0x80 { + break + } + } + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCrypto + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCrypto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000002) + default: + iNdEx = preIndex + skippy, err := skipCrypto(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCrypto + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCrypto + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Type") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Data") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PrivateKey) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PrivateKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PrivateKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= KeyType(b&0x7F) << shift + if b < 0x80 { + break + } + } + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrypto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCrypto + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCrypto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + hasFields[0] |= uint64(0x00000002) + default: + iNdEx = preIndex + skippy, err := skipCrypto(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCrypto + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthCrypto + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Type") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("Data") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCrypto(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCrypto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCrypto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCrypto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthCrypto + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCrypto + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCrypto + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCrypto = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCrypto = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCrypto = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.proto b/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.proto new file mode 100644 index 0000000000..182b0d4847 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/pb/crypto.proto @@ -0,0 +1,22 @@ +syntax = "proto2"; + +package crypto.pb; + +option go_package = "github.com/libp2p/go-libp2p-core/crypto/pb"; + +enum KeyType { + RSA = 0; + Ed25519 = 1; + Secp256k1 = 2; + ECDSA = 3; +} + +message PublicKey { + required KeyType Type = 1; + required bytes Data = 2; +} + +message PrivateKey { + required KeyType Type = 1; + required bytes Data = 2; +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_common.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_common.go new file mode 100644 index 0000000000..c7e305439a --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_common.go @@ -0,0 +1,25 @@ +package crypto + +import ( + "fmt" + "os" +) + +// WeakRsaKeyEnv is an environment variable which, when set, lowers the +// minimum required bits of RSA keys to 512. This should be used exclusively in +// test situations. +const WeakRsaKeyEnv = "LIBP2P_ALLOW_WEAK_RSA_KEYS" + +var MinRsaKeyBits = 2048 + +// ErrRsaKeyTooSmall is returned when trying to generate or parse an RSA key +// that's smaller than MinRsaKeyBits bits. In test +var ErrRsaKeyTooSmall error + +func init() { + if _, ok := os.LookupEnv(WeakRsaKeyEnv); ok { + MinRsaKeyBits = 512 + } + + ErrRsaKeyTooSmall = fmt.Errorf("rsa keys must be >= %d bits to be useful", MinRsaKeyBits) +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_go.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_go.go new file mode 100644 index 0000000000..f28a327b83 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_go.go @@ -0,0 +1,152 @@ +// +build !openssl + +package crypto + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "errors" + "io" + "sync" + + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + + "github.com/minio/sha256-simd" +) + +// RsaPrivateKey is an rsa private key +type RsaPrivateKey struct { + sk rsa.PrivateKey +} + +// RsaPublicKey is an rsa public key +type RsaPublicKey struct { + k rsa.PublicKey + + cacheLk sync.Mutex + cached []byte +} + +// GenerateRSAKeyPair generates a new rsa private and public key +func GenerateRSAKeyPair(bits int, src io.Reader) (PrivKey, PubKey, error) { + if bits < MinRsaKeyBits { + return nil, nil, ErrRsaKeyTooSmall + } + priv, err := rsa.GenerateKey(src, bits) + if err != nil { + return nil, nil, err + } + pk := priv.PublicKey + return &RsaPrivateKey{sk: *priv}, &RsaPublicKey{k: pk}, nil +} + +// Verify compares a signature against input data +func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) { + hashed := sha256.Sum256(data) + err := rsa.VerifyPKCS1v15(&pk.k, crypto.SHA256, hashed[:], sig) + if err != nil { + return false, err + } + return true, nil +} + +func (pk *RsaPublicKey) Type() pb.KeyType { + return pb.KeyType_RSA +} + +// Bytes returns protobuf bytes of a public key +func (pk *RsaPublicKey) Bytes() ([]byte, error) { + pk.cacheLk.Lock() + var err error + if pk.cached == nil { + pk.cached, err = MarshalPublicKey(pk) + } + pk.cacheLk.Unlock() + return pk.cached, err +} + +func (pk *RsaPublicKey) Raw() ([]byte, error) { + return x509.MarshalPKIXPublicKey(&pk.k) +} + +// Equals checks whether this key is equal to another +func (pk *RsaPublicKey) Equals(k Key) bool { + // make sure this is an rsa public key + other, ok := (k).(*RsaPublicKey) + if !ok { + return basicEquals(pk, k) + } + + return pk.k.N.Cmp(other.k.N) == 0 && pk.k.E == other.k.E +} + +// Sign returns a signature of the input data +func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) { + hashed := sha256.Sum256(message) + return rsa.SignPKCS1v15(rand.Reader, &sk.sk, crypto.SHA256, hashed[:]) +} + +// GetPublic returns a public key +func (sk *RsaPrivateKey) GetPublic() PubKey { + return &RsaPublicKey{k: sk.sk.PublicKey} +} + +func (sk *RsaPrivateKey) Type() pb.KeyType { + return pb.KeyType_RSA +} + +// Bytes returns protobuf bytes from a private key +func (sk *RsaPrivateKey) Bytes() ([]byte, error) { + return MarshalPrivateKey(sk) +} + +func (sk *RsaPrivateKey) Raw() ([]byte, error) { + b := x509.MarshalPKCS1PrivateKey(&sk.sk) + return b, nil +} + +// Equals checks whether this key is equal to another +func (sk *RsaPrivateKey) Equals(k Key) bool { + // make sure this is an rsa public key + other, ok := (k).(*RsaPrivateKey) + if !ok { + return basicEquals(sk, k) + } + + a := sk.sk + b := other.sk + + // Don't care about constant time. We're only comparing the public half. + return a.PublicKey.N.Cmp(b.PublicKey.N) == 0 && a.PublicKey.E == b.PublicKey.E +} + +// UnmarshalRsaPrivateKey returns a private key from the input x509 bytes +func UnmarshalRsaPrivateKey(b []byte) (PrivKey, error) { + sk, err := x509.ParsePKCS1PrivateKey(b) + if err != nil { + return nil, err + } + if sk.N.BitLen() < MinRsaKeyBits { + return nil, ErrRsaKeyTooSmall + } + return &RsaPrivateKey{sk: *sk}, nil +} + +// UnmarshalRsaPublicKey returns a public key from the input x509 bytes +func UnmarshalRsaPublicKey(b []byte) (PubKey, error) { + pub, err := x509.ParsePKIXPublicKey(b) + if err != nil { + return nil, err + } + pk, ok := pub.(*rsa.PublicKey) + if !ok { + return nil, errors.New("not actually an rsa public key") + } + if pk.N.BitLen() < MinRsaKeyBits { + return nil, ErrRsaKeyTooSmall + } + + return &RsaPublicKey{k: *pk}, nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_openssl.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_openssl.go new file mode 100644 index 0000000000..8e7fb74315 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/rsa_openssl.go @@ -0,0 +1,68 @@ +// +build openssl + +package crypto + +import ( + "errors" + "io" + + openssl "github.com/libp2p/go-openssl" +) + +// RsaPrivateKey is an rsa private key +type RsaPrivateKey struct { + opensslPrivateKey +} + +// RsaPublicKey is an rsa public key +type RsaPublicKey struct { + opensslPublicKey +} + +// GenerateRSAKeyPair generates a new rsa private and public key +func GenerateRSAKeyPair(bits int, _ io.Reader) (PrivKey, PubKey, error) { + if bits < MinRsaKeyBits { + return nil, nil, ErrRsaKeyTooSmall + } + + key, err := openssl.GenerateRSAKey(bits) + if err != nil { + return nil, nil, err + } + return &RsaPrivateKey{opensslPrivateKey{key}}, &RsaPublicKey{opensslPublicKey{key: key}}, nil +} + +// GetPublic returns a public key +func (sk *RsaPrivateKey) GetPublic() PubKey { + return &RsaPublicKey{opensslPublicKey{key: sk.opensslPrivateKey.key}} +} + +// UnmarshalRsaPrivateKey returns a private key from the input x509 bytes +func UnmarshalRsaPrivateKey(b []byte) (PrivKey, error) { + key, err := unmarshalOpensslPrivateKey(b) + if err != nil { + return nil, err + } + if 8*key.key.Size() < MinRsaKeyBits { + return nil, ErrRsaKeyTooSmall + } + if key.Type() != RSA { + return nil, errors.New("not actually an rsa public key") + } + return &RsaPrivateKey{key}, nil +} + +// UnmarshalRsaPublicKey returns a public key from the input x509 bytes +func UnmarshalRsaPublicKey(b []byte) (PubKey, error) { + key, err := unmarshalOpensslPublicKey(b) + if err != nil { + return nil, err + } + if 8*key.key.Size() < MinRsaKeyBits { + return nil, ErrRsaKeyTooSmall + } + if key.Type() != RSA { + return nil, errors.New("not actually an rsa public key") + } + return &RsaPublicKey{key}, nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/crypto/secp256k1.go b/vendor/github.com/libp2p/go-libp2p-core/crypto/secp256k1.go new file mode 100644 index 0000000000..6e98ea6bf7 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/crypto/secp256k1.go @@ -0,0 +1,125 @@ +package crypto + +import ( + "fmt" + "io" + + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + + btcec "github.com/btcsuite/btcd/btcec" + sha256 "github.com/minio/sha256-simd" +) + +// Secp256k1PrivateKey is an Secp256k1 private key +type Secp256k1PrivateKey btcec.PrivateKey + +// Secp256k1PublicKey is an Secp256k1 public key +type Secp256k1PublicKey btcec.PublicKey + +// GenerateSecp256k1Key generates a new Secp256k1 private and public key pair +func GenerateSecp256k1Key(src io.Reader) (PrivKey, PubKey, error) { + privk, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + return nil, nil, err + } + + k := (*Secp256k1PrivateKey)(privk) + return k, k.GetPublic(), nil +} + +// UnmarshalSecp256k1PrivateKey returns a private key from bytes +func UnmarshalSecp256k1PrivateKey(data []byte) (PrivKey, error) { + if len(data) != btcec.PrivKeyBytesLen { + return nil, fmt.Errorf("expected secp256k1 data size to be %d", btcec.PrivKeyBytesLen) + } + + privk, _ := btcec.PrivKeyFromBytes(btcec.S256(), data) + return (*Secp256k1PrivateKey)(privk), nil +} + +// UnmarshalSecp256k1PublicKey returns a public key from bytes +func UnmarshalSecp256k1PublicKey(data []byte) (PubKey, error) { + k, err := btcec.ParsePubKey(data, btcec.S256()) + if err != nil { + return nil, err + } + + return (*Secp256k1PublicKey)(k), nil +} + +// Bytes returns protobuf bytes from a private key +func (k *Secp256k1PrivateKey) Bytes() ([]byte, error) { + return MarshalPrivateKey(k) +} + +// Type returns the private key type +func (k *Secp256k1PrivateKey) Type() pb.KeyType { + return pb.KeyType_Secp256k1 +} + +// Raw returns the bytes of the key +func (k *Secp256k1PrivateKey) Raw() ([]byte, error) { + return (*btcec.PrivateKey)(k).Serialize(), nil +} + +// Equals compares two private keys +func (k *Secp256k1PrivateKey) Equals(o Key) bool { + sk, ok := o.(*Secp256k1PrivateKey) + if !ok { + return basicEquals(k, o) + } + + return k.GetPublic().Equals(sk.GetPublic()) +} + +// Sign returns a signature from input data +func (k *Secp256k1PrivateKey) Sign(data []byte) ([]byte, error) { + hash := sha256.Sum256(data) + sig, err := (*btcec.PrivateKey)(k).Sign(hash[:]) + if err != nil { + return nil, err + } + + return sig.Serialize(), nil +} + +// GetPublic returns a public key +func (k *Secp256k1PrivateKey) GetPublic() PubKey { + return (*Secp256k1PublicKey)((*btcec.PrivateKey)(k).PubKey()) +} + +// Bytes returns protobuf bytes from a public key +func (k *Secp256k1PublicKey) Bytes() ([]byte, error) { + return MarshalPublicKey(k) +} + +// Type returns the public key type +func (k *Secp256k1PublicKey) Type() pb.KeyType { + return pb.KeyType_Secp256k1 +} + +// Raw returns the bytes of the key +func (k *Secp256k1PublicKey) Raw() ([]byte, error) { + return (*btcec.PublicKey)(k).SerializeCompressed(), nil +} + +// Equals compares two public keys +func (k *Secp256k1PublicKey) Equals(o Key) bool { + sk, ok := o.(*Secp256k1PublicKey) + if !ok { + return basicEquals(k, o) + } + + return (*btcec.PublicKey)(k).IsEqual((*btcec.PublicKey)(sk)) +} + +// Verify compares a signature against the input data +func (k *Secp256k1PublicKey) Verify(data []byte, sigStr []byte) (bool, error) { + sig, err := btcec.ParseDERSignature(sigStr, btcec.S256()) + if err != nil { + return false, err + } + + hash := sha256.Sum256(data) + return sig.Verify(hash[:], (*btcec.PublicKey)(k)), nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo.go b/vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo.go new file mode 100644 index 0000000000..5cbfe8c3ae --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo.go @@ -0,0 +1,98 @@ +package peer + +import ( + "fmt" + + ma "github.com/multiformats/go-multiaddr" +) + +// AddrInfo is a small struct used to pass around a peer with +// a set of addresses (and later, keys?). +type AddrInfo struct { + ID ID + Addrs []ma.Multiaddr +} + +var _ fmt.Stringer = AddrInfo{} + +func (pi AddrInfo) String() string { + return fmt.Sprintf("{%v: %v}", pi.ID, pi.Addrs) +} + +var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr") + +// AddrInfosFromP2pAddrs converts a set of Multiaddrs to a set of AddrInfos. +func AddrInfosFromP2pAddrs(maddrs ...ma.Multiaddr) ([]AddrInfo, error) { + m := make(map[ID][]ma.Multiaddr) + for _, maddr := range maddrs { + transport, id := SplitAddr(maddr) + if id == "" { + return nil, ErrInvalidAddr + } + if transport == nil { + if _, ok := m[id]; !ok { + m[id] = nil + } + } else { + m[id] = append(m[id], transport) + } + } + ais := make([]AddrInfo, 0, len(m)) + for id, maddrs := range m { + ais = append(ais, AddrInfo{ID: id, Addrs: maddrs}) + } + return ais, nil +} + +// SplitAddr splits a p2p Multiaddr into a transport multiaddr and a peer ID. +// +// * Returns a nil transport if the address only contains a /p2p part. +// * Returns a empty peer ID if the address doesn't contain a /p2p part. +func SplitAddr(m ma.Multiaddr) (transport ma.Multiaddr, id ID) { + if m == nil { + return nil, "" + } + + transport, p2ppart := ma.SplitLast(m) + if p2ppart == nil || p2ppart.Protocol().Code != ma.P_P2P { + return m, "" + } + id = ID(p2ppart.RawValue()) // already validated by the multiaddr library. + return transport, id +} + +// AddrInfoFromP2pAddr converts a Multiaddr to an AddrInfo. +func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) { + transport, id := SplitAddr(m) + if id == "" { + return nil, ErrInvalidAddr + } + info := &AddrInfo{ID: id} + if transport != nil { + info.Addrs = []ma.Multiaddr{transport} + } + return info, nil +} + +// AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs. +func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) { + var addrs []ma.Multiaddr + p2ppart, err := ma.NewComponent("p2p", IDB58Encode(pi.ID)) + if err != nil { + return nil, err + } + if len(pi.Addrs) == 0 { + return []ma.Multiaddr{p2ppart}, nil + } + for _, addr := range pi.Addrs { + addrs = append(addrs, addr.Encapsulate(p2ppart)) + } + return addrs, nil +} + +func (pi *AddrInfo) Loggable() map[string]interface{} { + return map[string]interface{}{ + "peerID": pi.ID.Pretty(), + "addrs": pi.Addrs, + } +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo_serde.go b/vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo_serde.go new file mode 100644 index 0000000000..1df24e2b73 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/addrinfo_serde.go @@ -0,0 +1,38 @@ +package peer + +import ( + "encoding/json" + + ma "github.com/multiformats/go-multiaddr" +) + +func (pi AddrInfo) MarshalJSON() ([]byte, error) { + out := make(map[string]interface{}) + out["ID"] = pi.ID.Pretty() + var addrs []string + for _, a := range pi.Addrs { + addrs = append(addrs, a.String()) + } + out["Addrs"] = addrs + return json.Marshal(out) +} + +func (pi *AddrInfo) UnmarshalJSON(b []byte) error { + var data map[string]interface{} + err := json.Unmarshal(b, &data) + if err != nil { + return err + } + pid, err := IDB58Decode(data["ID"].(string)) + if err != nil { + return err + } + pi.ID = pid + addrs, ok := data["Addrs"].([]interface{}) + if ok { + for _, a := range addrs { + pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string))) + } + } + return nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/pb/Makefile b/vendor/github.com/libp2p/go-libp2p-core/peer/pb/Makefile new file mode 100644 index 0000000000..7cf8222f89 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/pb/Makefile @@ -0,0 +1,11 @@ +PB = $(wildcard *.proto) +GO = $(PB:.proto=.pb.go) + +all: $(GO) + +%.pb.go: %.proto + protoc --proto_path=$(PWD):$(PWD)/../.. --gogofaster_out=. $< + +clean: + rm -f *.pb.go + rm -f *.go diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.pb.go b/vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.pb.go new file mode 100644 index 0000000000..dd0755ef72 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.pb.go @@ -0,0 +1,606 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: peer_record.proto + +package peer_pb + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// PeerRecord messages contain information that is useful to share with other peers. +// Currently, a PeerRecord contains the public listen addresses for a peer, but this +// is expected to expand to include other information in the future. +// +// PeerRecords are designed to be serialized to bytes and placed inside of +// SignedEnvelopes before sharing with other peers. +// See https://github.com/libp2p/go-libp2p-core/record/pb/envelope.proto for +// the SignedEnvelope definition. +type PeerRecord struct { + // peer_id contains a libp2p peer id in its binary representation. + PeerId []byte `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` + // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. + Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` + // addresses is a list of public listen addresses for the peer. + Addresses []*PeerRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (m *PeerRecord) Reset() { *m = PeerRecord{} } +func (m *PeerRecord) String() string { return proto.CompactTextString(m) } +func (*PeerRecord) ProtoMessage() {} +func (*PeerRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_dc0d8059ab0ad14d, []int{0} +} +func (m *PeerRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PeerRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PeerRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PeerRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeerRecord.Merge(m, src) +} +func (m *PeerRecord) XXX_Size() int { + return m.Size() +} +func (m *PeerRecord) XXX_DiscardUnknown() { + xxx_messageInfo_PeerRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_PeerRecord proto.InternalMessageInfo + +func (m *PeerRecord) GetPeerId() []byte { + if m != nil { + return m.PeerId + } + return nil +} + +func (m *PeerRecord) GetSeq() uint64 { + if m != nil { + return m.Seq + } + return 0 +} + +func (m *PeerRecord) GetAddresses() []*PeerRecord_AddressInfo { + if m != nil { + return m.Addresses + } + return nil +} + +// AddressInfo is a wrapper around a binary multiaddr. It is defined as a +// separate message to allow us to add per-address metadata in the future. +type PeerRecord_AddressInfo struct { + Multiaddr []byte `protobuf:"bytes,1,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` +} + +func (m *PeerRecord_AddressInfo) Reset() { *m = PeerRecord_AddressInfo{} } +func (m *PeerRecord_AddressInfo) String() string { return proto.CompactTextString(m) } +func (*PeerRecord_AddressInfo) ProtoMessage() {} +func (*PeerRecord_AddressInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_dc0d8059ab0ad14d, []int{0, 0} +} +func (m *PeerRecord_AddressInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PeerRecord_AddressInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PeerRecord_AddressInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PeerRecord_AddressInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_PeerRecord_AddressInfo.Merge(m, src) +} +func (m *PeerRecord_AddressInfo) XXX_Size() int { + return m.Size() +} +func (m *PeerRecord_AddressInfo) XXX_DiscardUnknown() { + xxx_messageInfo_PeerRecord_AddressInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_PeerRecord_AddressInfo proto.InternalMessageInfo + +func (m *PeerRecord_AddressInfo) GetMultiaddr() []byte { + if m != nil { + return m.Multiaddr + } + return nil +} + +func init() { + proto.RegisterType((*PeerRecord)(nil), "peer.pb.PeerRecord") + proto.RegisterType((*PeerRecord_AddressInfo)(nil), "peer.pb.PeerRecord.AddressInfo") +} + +func init() { proto.RegisterFile("peer_record.proto", fileDescriptor_dc0d8059ab0ad14d) } + +var fileDescriptor_dc0d8059ab0ad14d = []byte{ + // 189 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0x48, 0x4d, 0x2d, + 0x8a, 0x2f, 0x4a, 0x4d, 0xce, 0x2f, 0x4a, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x07, + 0x09, 0xe9, 0x15, 0x24, 0x29, 0x2d, 0x66, 0xe4, 0xe2, 0x0a, 0x48, 0x4d, 0x2d, 0x0a, 0x02, 0xcb, + 0x0a, 0x89, 0x73, 0x81, 0x65, 0xe2, 0x33, 0x53, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0xd8, + 0x40, 0x5c, 0xcf, 0x14, 0x21, 0x01, 0x2e, 0xe6, 0xe2, 0xd4, 0x42, 0x09, 0x26, 0x05, 0x46, 0x0d, + 0x96, 0x20, 0x10, 0x53, 0xc8, 0x96, 0x8b, 0x33, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb5, + 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x5e, 0x0f, 0x6a, 0xac, 0x1e, 0xc2, 0x48, 0x3d, + 0x47, 0x88, 0x22, 0xcf, 0xbc, 0xb4, 0xfc, 0x20, 0x84, 0x0e, 0x29, 0x6d, 0x2e, 0x6e, 0x24, 0x19, + 0x21, 0x19, 0x2e, 0xce, 0xdc, 0xd2, 0x9c, 0x92, 0x4c, 0x90, 0x02, 0xa8, 0xd5, 0x08, 0x01, 0x27, + 0x89, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, + 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xfb, 0xc7, 0x18, + 0x10, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0x56, 0x19, 0xe4, 0x00, 0x00, 0x00, +} + +func (m *PeerRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PeerRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PeerRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Addresses) > 0 { + for iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Addresses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPeerRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.Seq != 0 { + i = encodeVarintPeerRecord(dAtA, i, uint64(m.Seq)) + i-- + dAtA[i] = 0x10 + } + if len(m.PeerId) > 0 { + i -= len(m.PeerId) + copy(dAtA[i:], m.PeerId) + i = encodeVarintPeerRecord(dAtA, i, uint64(len(m.PeerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PeerRecord_AddressInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PeerRecord_AddressInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PeerRecord_AddressInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Multiaddr) > 0 { + i -= len(m.Multiaddr) + copy(dAtA[i:], m.Multiaddr) + i = encodeVarintPeerRecord(dAtA, i, uint64(len(m.Multiaddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintPeerRecord(dAtA []byte, offset int, v uint64) int { + offset -= sovPeerRecord(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PeerRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PeerId) + if l > 0 { + n += 1 + l + sovPeerRecord(uint64(l)) + } + if m.Seq != 0 { + n += 1 + sovPeerRecord(uint64(m.Seq)) + } + if len(m.Addresses) > 0 { + for _, e := range m.Addresses { + l = e.Size() + n += 1 + l + sovPeerRecord(uint64(l)) + } + } + return n +} + +func (m *PeerRecord_AddressInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Multiaddr) + if l > 0 { + n += 1 + l + sovPeerRecord(uint64(l)) + } + return n +} + +func sovPeerRecord(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozPeerRecord(x uint64) (n int) { + return sovPeerRecord(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PeerRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PeerRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PeerRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PeerId", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPeerRecord + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPeerRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PeerId = append(m.PeerId[:0], dAtA[iNdEx:postIndex]...) + if m.PeerId == nil { + m.PeerId = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Seq", wireType) + } + m.Seq = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Seq |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPeerRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPeerRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addresses = append(m.Addresses, &PeerRecord_AddressInfo{}) + if err := m.Addresses[len(m.Addresses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPeerRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PeerRecord_AddressInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddressInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddressInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Multiaddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPeerRecord + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPeerRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Multiaddr = append(m.Multiaddr[:0], dAtA[iNdEx:postIndex]...) + if m.Multiaddr == nil { + m.Multiaddr = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPeerRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPeerRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPeerRecord(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPeerRecord + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthPeerRecord + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPeerRecord + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthPeerRecord + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthPeerRecord = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPeerRecord = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPeerRecord = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.proto b/vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.proto new file mode 100644 index 0000000000..fb2835d8e6 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/pb/peer_record.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package peer.pb; + +// PeerRecord messages contain information that is useful to share with other peers. +// Currently, a PeerRecord contains the public listen addresses for a peer, but this +// is expected to expand to include other information in the future. +// +// PeerRecords are designed to be serialized to bytes and placed inside of +// SignedEnvelopes before sharing with other peers. +// See https://github.com/libp2p/go-libp2p-core/record/pb/envelope.proto for +// the SignedEnvelope definition. +message PeerRecord { + + // AddressInfo is a wrapper around a binary multiaddr. It is defined as a + // separate message to allow us to add per-address metadata in the future. + message AddressInfo { + bytes multiaddr = 1; + } + + // peer_id contains a libp2p peer id in its binary representation. + bytes peer_id = 1; + + // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. + uint64 seq = 2; + + // addresses is a list of public listen addresses for the peer. + repeated AddressInfo addresses = 3; +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/peer.go b/vendor/github.com/libp2p/go-libp2p-core/peer/peer.go new file mode 100644 index 0000000000..176b9dffa7 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/peer.go @@ -0,0 +1,245 @@ +// Package peer implements an object used to represent peers in the libp2p network. +package peer + +import ( + "encoding/hex" + "errors" + "fmt" + "strings" + + cid "github.com/ipfs/go-cid" + ic "github.com/libp2p/go-libp2p-core/crypto" + b58 "github.com/mr-tron/base58/base58" + mh "github.com/multiformats/go-multihash" +) + +var ( + // ErrEmptyPeerID is an error for empty peer ID. + ErrEmptyPeerID = errors.New("empty peer ID") + // ErrNoPublicKey is an error for peer IDs that don't embed public keys + ErrNoPublicKey = errors.New("public key is not embedded in peer ID") +) + +// AdvancedEnableInlining enables automatically inlining keys shorter than +// 42 bytes into the peer ID (using the "identity" multihash function). +// +// WARNING: This flag will likely be set to false in the future and eventually +// be removed in favor of using a hash function specified by the key itself. +// See: https://github.com/libp2p/specs/issues/138 +// +// DO NOT change this flag unless you know what you're doing. +// +// This currently defaults to true for backwards compatibility but will likely +// be set to false by default when an upgrade path is determined. +var AdvancedEnableInlining = true + +const maxInlineKeyLength = 42 + +// ID is a libp2p peer identity. +// +// Peer IDs are derived by hashing a peer's public key and encoding the +// hash output as a multihash. See IDFromPublicKey for details. +type ID string + +// Pretty returns a base58-encoded string representation of the ID. +func (id ID) Pretty() string { + return IDB58Encode(id) +} + +// Loggable returns a pretty peer ID string in loggable JSON format. +func (id ID) Loggable() map[string]interface{} { + return map[string]interface{}{ + "peerID": id.Pretty(), + } +} + +func (id ID) String() string { + return id.Pretty() +} + +// ShortString prints out the peer ID. +// +// TODO(brian): ensure correctness at ID generation and +// enforce this by only exposing functions that generate +// IDs safely. Then any peer.ID type found in the +// codebase is known to be correct. +func (id ID) ShortString() string { + pid := id.Pretty() + if len(pid) <= 10 { + return fmt.Sprintf("", pid) + } + return fmt.Sprintf("", pid[:2], pid[len(pid)-6:]) +} + +// MatchesPrivateKey tests whether this ID was derived from the secret key sk. +func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool { + return id.MatchesPublicKey(sk.GetPublic()) +} + +// MatchesPublicKey tests whether this ID was derived from the public key pk. +func (id ID) MatchesPublicKey(pk ic.PubKey) bool { + oid, err := IDFromPublicKey(pk) + if err != nil { + return false + } + return oid == id +} + +// ExtractPublicKey attempts to extract the public key from an ID. +// +// This method returns ErrNoPublicKey if the peer ID looks valid but it can't extract +// the public key. +func (id ID) ExtractPublicKey() (ic.PubKey, error) { + decoded, err := mh.Decode([]byte(id)) + if err != nil { + return nil, err + } + if decoded.Code != mh.IDENTITY { + return nil, ErrNoPublicKey + } + pk, err := ic.UnmarshalPublicKey(decoded.Digest) + if err != nil { + return nil, err + } + return pk, nil +} + +// Validate checks if ID is empty or not. +func (id ID) Validate() error { + if id == ID("") { + return ErrEmptyPeerID + } + + return nil +} + +// IDFromString casts a string to the ID type, and validates +// the value to make sure it is a multihash. +func IDFromString(s string) (ID, error) { + if _, err := mh.Cast([]byte(s)); err != nil { + return ID(""), err + } + return ID(s), nil +} + +// IDFromBytes casts a byte slice to the ID type, and validates +// the value to make sure it is a multihash. +func IDFromBytes(b []byte) (ID, error) { + if _, err := mh.Cast(b); err != nil { + return ID(""), err + } + return ID(b), nil +} + +// IDB58Decode decodes a peer ID. +// +// Deprecated: Use Decode. +func IDB58Decode(s string) (ID, error) { + return Decode(s) +} + +// IDB58Encode returns the base58-encoded multihash representation of the ID. +// +// Deprecated: Use Encode. +func IDB58Encode(id ID) string { + return b58.Encode([]byte(id)) +} + +// IDHexDecode accepts a hex-encoded multihash representing a peer ID +// and returns the decoded ID if the input is valid. +// +// Deprecated: Don't raw-hex encode peer IDs, use base16 CIDs. +func IDHexDecode(s string) (ID, error) { + m, err := mh.FromHexString(s) + if err != nil { + return "", err + } + return ID(m), err +} + +// IDHexEncode returns the hex-encoded multihash representation of the ID. +// +// Deprecated: Don't raw-hex encode peer IDs, use base16 CIDs. +func IDHexEncode(id ID) string { + return hex.EncodeToString([]byte(id)) +} + +// Decode accepts an encoded peer ID and returns the decoded ID if the input is +// valid. +// +// The encoded peer ID can either be a CID of a key or a raw multihash (identity +// or sha256-256). +func Decode(s string) (ID, error) { + if strings.HasPrefix(s, "Qm") || strings.HasPrefix(s, "1") { + // base58 encoded sha256 or identity multihash + m, err := mh.FromB58String(s) + if err != nil { + return "", fmt.Errorf("failed to parse peer ID: %s", err) + } + return ID(m), nil + } + + c, err := cid.Decode(s) + if err != nil { + return "", fmt.Errorf("failed to parse peer ID: %s", err) + } + return FromCid(c) +} + +// Encode encodes a peer ID as a string. +// +// At the moment, it base58 encodes the peer ID but, in the future, it will +// switch to encoding it as a CID by default. +func Encode(id ID) string { + return IDB58Encode(id) +} + +// FromCid converts a CID to a peer ID, if possible. +func FromCid(c cid.Cid) (ID, error) { + ty := c.Type() + if ty != cid.Libp2pKey { + s := cid.CodecToStr[ty] + if s == "" { + s = fmt.Sprintf("[unknown multicodec %d]", ty) + } + return "", fmt.Errorf("can't convert CID of type %s to a peer ID", s) + } + return ID(c.Hash()), nil +} + +// ToCid encodes a peer ID as a CID of the public key. +// +// If the peer ID is invalid (e.g., empty), this will return the empty CID. +func ToCid(id ID) cid.Cid { + m, err := mh.Cast([]byte(id)) + if err != nil { + return cid.Cid{} + } + return cid.NewCidV1(cid.Libp2pKey, m) +} + +// IDFromPublicKey returns the Peer ID corresponding to the public key pk. +func IDFromPublicKey(pk ic.PubKey) (ID, error) { + b, err := pk.Bytes() + if err != nil { + return "", err + } + var alg uint64 = mh.SHA2_256 + if AdvancedEnableInlining && len(b) <= maxInlineKeyLength { + alg = mh.ID + } + hash, _ := mh.Sum(b, alg, -1) + return ID(hash), nil +} + +// IDFromPrivateKey returns the Peer ID corresponding to the secret key sk. +func IDFromPrivateKey(sk ic.PrivKey) (ID, error) { + return IDFromPublicKey(sk.GetPublic()) +} + +// IDSlice for sorting peers. +type IDSlice []ID + +func (es IDSlice) Len() int { return len(es) } +func (es IDSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] } +func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) } diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/peer_serde.go b/vendor/github.com/libp2p/go-libp2p-core/peer/peer_serde.go new file mode 100644 index 0000000000..e401fbbb79 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/peer_serde.go @@ -0,0 +1,75 @@ +// Package peer contains Protobuf and JSON serialization/deserialization methods for peer IDs. +package peer + +import ( + "encoding" + "encoding/json" +) + +// Interface assertions commented out to avoid introducing hard dependencies to protobuf. +// var _ proto.Marshaler = (*ID)(nil) +// var _ proto.Unmarshaler = (*ID)(nil) +var _ json.Marshaler = (*ID)(nil) +var _ json.Unmarshaler = (*ID)(nil) + +var _ encoding.BinaryMarshaler = (*ID)(nil) +var _ encoding.BinaryUnmarshaler = (*ID)(nil) +var _ encoding.TextMarshaler = (*ID)(nil) +var _ encoding.TextUnmarshaler = (*ID)(nil) + +func (id ID) Marshal() ([]byte, error) { + return []byte(id), nil +} + +// MarshalBinary returns the byte representation of the peer ID. +func (id ID) MarshalBinary() ([]byte, error) { + return id.Marshal() +} + +func (id ID) MarshalTo(data []byte) (n int, err error) { + return copy(data, []byte(id)), nil +} + +func (id *ID) Unmarshal(data []byte) (err error) { + *id, err = IDFromBytes(data) + return err +} + +// UnmarshalBinary sets the ID from its binary representation. +func (id *ID) UnmarshalBinary(data []byte) error { + return id.Unmarshal(data) +} + +// Size implements Gogo's proto.Sizer, but we omit the compile-time assertion to avoid introducing a hard +// dependency on gogo. +func (id ID) Size() int { + return len([]byte(id)) +} + +func (id ID) MarshalJSON() ([]byte, error) { + return json.Marshal(IDB58Encode(id)) +} + +func (id *ID) UnmarshalJSON(data []byte) (err error) { + var v string + if err = json.Unmarshal(data, &v); err != nil { + return err + } + *id, err = IDB58Decode(v) + return err +} + +// MarshalText returns the text encoding of the ID. +func (id ID) MarshalText() ([]byte, error) { + return []byte(IDB58Encode(id)), nil +} + +// UnmarshalText restores the ID from its text encoding. +func (id *ID) UnmarshalText(data []byte) error { + pid, err := IDB58Decode(string(data)) + if err != nil { + return err + } + *id = pid + return nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/record.go b/vendor/github.com/libp2p/go-libp2p-core/peer/record.go new file mode 100644 index 0000000000..3638c337f3 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/record.go @@ -0,0 +1,232 @@ +package peer + +import ( + "fmt" + "time" + + pb "github.com/libp2p/go-libp2p-core/peer/pb" + "github.com/libp2p/go-libp2p-core/record" + + ma "github.com/multiformats/go-multiaddr" + + "github.com/gogo/protobuf/proto" +) + +var _ record.Record = (*PeerRecord)(nil) + +func init() { + record.RegisterType(&PeerRecord{}) +} + +// PeerRecordEnvelopeDomain is the domain string used for peer records contained in a Envelope. +const PeerRecordEnvelopeDomain = "libp2p-peer-record" + +// PeerRecordEnvelopePayloadType is the type hint used to identify peer records in a Envelope. +// Defined in https://github.com/multiformats/multicodec/blob/master/table.csv +// with name "libp2p-peer-record". +var PeerRecordEnvelopePayloadType = []byte{0x03, 0x01} + +// PeerRecord contains information that is broadly useful to share with other peers, +// either through a direct exchange (as in the libp2p identify protocol), or through +// a Peer Routing provider, such as a DHT. +// +// Currently, a PeerRecord contains the public listen addresses for a peer, but this +// is expected to expand to include other information in the future. +// +// PeerRecords are ordered in time by their Seq field. Newer PeerRecords must have +// greater Seq values than older records. The NewPeerRecord function will create +// a PeerRecord with a timestamp-based Seq value. The other PeerRecord fields should +// be set by the caller: +// +// rec := peer.NewPeerRecord() +// rec.PeerID = aPeerID +// rec.Addrs = someAddrs +// +// Alternatively, you can construct a PeerRecord struct directly and use the TimestampSeq +// helper to set the Seq field: +// +// rec := peer.PeerRecord{PeerID: aPeerID, Addrs: someAddrs, Seq: peer.TimestampSeq()} +// +// Failing to set the Seq field will not result in an error, however, a PeerRecord with a +// Seq value of zero may be ignored or rejected by other peers. +// +// PeerRecords are intended to be shared with other peers inside a signed +// routing.Envelope, and PeerRecord implements the routing.Record interface +// to facilitate this. +// +// To share a PeerRecord, first call Sign to wrap the record in a Envelope +// and sign it with the local peer's private key: +// +// rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs} +// envelope, err := rec.Sign(myPrivateKey) +// +// The resulting record.Envelope can be marshalled to a []byte and shared +// publicly. As a convenience, the MarshalSigned method will produce the +// Envelope and marshal it to a []byte in one go: +// +// rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs} +// recordBytes, err := rec.MarshalSigned(myPrivateKey) +// +// To validate and unmarshal a signed PeerRecord from a remote peer, +// "consume" the containing envelope, which will return both the +// routing.Envelope and the inner Record. The Record must be cast to +// a PeerRecord pointer before use: +// +// envelope, untypedRecord, err := ConsumeEnvelope(envelopeBytes, PeerRecordEnvelopeDomain) +// if err != nil { +// handleError(err) +// return +// } +// peerRec := untypedRecord.(*PeerRecord) +// +type PeerRecord struct { + // PeerID is the ID of the peer this record pertains to. + PeerID ID + + // Addrs contains the public addresses of the peer this record pertains to. + Addrs []ma.Multiaddr + + // Seq is a monotonically-increasing sequence counter that's used to order + // PeerRecords in time. The interval between Seq values is unspecified, + // but newer PeerRecords MUST have a greater Seq value than older records + // for the same peer. + Seq uint64 +} + +// NewPeerRecord returns a PeerRecord with a timestamp-based sequence number. +// The returned record is otherwise empty and should be populated by the caller. +func NewPeerRecord() *PeerRecord { + return &PeerRecord{Seq: TimestampSeq()} +} + +// PeerRecordFromAddrInfo creates a PeerRecord from an AddrInfo struct. +// The returned record will have a timestamp-based sequence number. +func PeerRecordFromAddrInfo(info AddrInfo) *PeerRecord { + rec := NewPeerRecord() + rec.PeerID = info.ID + rec.Addrs = info.Addrs + return rec +} + +// PeerRecordFromProtobuf creates a PeerRecord from a protobuf PeerRecord +// struct. +func PeerRecordFromProtobuf(msg *pb.PeerRecord) (*PeerRecord, error) { + record := &PeerRecord{} + + var id ID + if err := id.UnmarshalBinary(msg.PeerId); err != nil { + return nil, err + } + + record.PeerID = id + record.Addrs = addrsFromProtobuf(msg.Addresses) + record.Seq = msg.Seq + + return record, nil +} + +// TimestampSeq is a helper to generate a timestamp-based sequence number for a PeerRecord. +func TimestampSeq() uint64 { + return uint64(time.Now().UnixNano()) +} + +// Domain is used when signing and validating PeerRecords contained in Envelopes. +// It is constant for all PeerRecord instances. +func (r *PeerRecord) Domain() string { + return PeerRecordEnvelopeDomain +} + +// Codec is a binary identifier for the PeerRecord type. It is constant for all PeerRecord instances. +func (r *PeerRecord) Codec() []byte { + return PeerRecordEnvelopePayloadType +} + +// UnmarshalRecord parses a PeerRecord from a byte slice. +// This method is called automatically when consuming a record.Envelope +// whose PayloadType indicates that it contains a PeerRecord. +// It is generally not necessary or recommended to call this method directly. +func (r *PeerRecord) UnmarshalRecord(bytes []byte) error { + if r == nil { + return fmt.Errorf("cannot unmarshal PeerRecord to nil receiver") + } + + var msg pb.PeerRecord + err := proto.Unmarshal(bytes, &msg) + if err != nil { + return err + } + + rPtr, err := PeerRecordFromProtobuf(&msg) + if err != nil { + return err + } + *r = *rPtr + + return nil +} + +// MarshalRecord serializes a PeerRecord to a byte slice. +// This method is called automatically when constructing a routing.Envelope +// using Seal or PeerRecord.Sign. +func (r *PeerRecord) MarshalRecord() ([]byte, error) { + msg, err := r.ToProtobuf() + if err != nil { + return nil, err + } + return proto.Marshal(msg) +} + +// Equal returns true if the other PeerRecord is identical to this one. +func (r *PeerRecord) Equal(other *PeerRecord) bool { + if other == nil { + return r == nil + } + if r.PeerID != other.PeerID { + return false + } + if r.Seq != other.Seq { + return false + } + if len(r.Addrs) != len(other.Addrs) { + return false + } + for i, _ := range r.Addrs { + if !r.Addrs[i].Equal(other.Addrs[i]) { + return false + } + } + return true +} + +// ToProtobuf returns the equivalent Protocol Buffer struct object of a PeerRecord. +func (r *PeerRecord) ToProtobuf() (*pb.PeerRecord, error) { + idBytes, err := r.PeerID.MarshalBinary() + if err != nil { + return nil, err + } + return &pb.PeerRecord{ + PeerId: idBytes, + Addresses: addrsToProtobuf(r.Addrs), + Seq: r.Seq, + }, nil +} + +func addrsFromProtobuf(addrs []*pb.PeerRecord_AddressInfo) []ma.Multiaddr { + var out []ma.Multiaddr + for _, addr := range addrs { + a, err := ma.NewMultiaddrBytes(addr.Multiaddr) + if err != nil { + continue + } + out = append(out, a) + } + return out +} + +func addrsToProtobuf(addrs []ma.Multiaddr) []*pb.PeerRecord_AddressInfo { + var out []*pb.PeerRecord_AddressInfo + for _, addr := range addrs { + out = append(out, &pb.PeerRecord_AddressInfo{Multiaddr: addr.Bytes()}) + } + return out +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/peer/set.go b/vendor/github.com/libp2p/go-libp2p-core/peer/set.go new file mode 100644 index 0000000000..2251a677e2 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/peer/set.go @@ -0,0 +1,71 @@ +package peer + +import ( + "sync" +) + +// PeerSet is a threadsafe set of peers. +type Set struct { + lk sync.RWMutex + ps map[ID]struct{} + + size int +} + +func NewSet() *Set { + ps := new(Set) + ps.ps = make(map[ID]struct{}) + ps.size = -1 + return ps +} + +func NewLimitedSet(size int) *Set { + ps := new(Set) + ps.ps = make(map[ID]struct{}) + ps.size = size + return ps +} + +func (ps *Set) Add(p ID) { + ps.lk.Lock() + ps.ps[p] = struct{}{} + ps.lk.Unlock() +} + +func (ps *Set) Contains(p ID) bool { + ps.lk.RLock() + _, ok := ps.ps[p] + ps.lk.RUnlock() + return ok +} + +func (ps *Set) Size() int { + ps.lk.RLock() + defer ps.lk.RUnlock() + return len(ps.ps) +} + +// TryAdd Attempts to add the given peer into the set. +// This operation can fail for one of two reasons: +// 1) The given peer is already in the set +// 2) The number of peers in the set is equal to size +func (ps *Set) TryAdd(p ID) bool { + var success bool + ps.lk.Lock() + if _, ok := ps.ps[p]; !ok && (len(ps.ps) < ps.size || ps.size == -1) { + success = true + ps.ps[p] = struct{}{} + } + ps.lk.Unlock() + return success +} + +func (ps *Set) Peers() []ID { + ps.lk.Lock() + out := make([]ID, 0, len(ps.ps)) + for p, _ := range ps.ps { + out = append(out, p) + } + ps.lk.Unlock() + return out +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/protocol/id.go b/vendor/github.com/libp2p/go-libp2p-core/protocol/id.go new file mode 100644 index 0000000000..9df3b5bcf1 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/protocol/id.go @@ -0,0 +1,29 @@ +package protocol + +// ID is an identifier used to write protocol headers in streams. +type ID string + +// These are reserved protocol.IDs. +const ( + TestingID ID = "/p2p/_testing" +) + +// ConvertFromStrings is a convenience function that takes a slice of strings and +// converts it to a slice of protocol.ID. +func ConvertFromStrings(ids []string) (res []ID) { + res = make([]ID, 0, len(ids)) + for _, id := range ids { + res = append(res, ID(id)) + } + return res +} + +// ConvertToStrings is a convenience function that takes a slice of protocol.ID and +// converts it to a slice of strings. +func ConvertToStrings(ids []ID) (res []string) { + res = make([]string, 0, len(ids)) + for _, id := range ids { + res = append(res, string(id)) + } + return res +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/protocol/switch.go b/vendor/github.com/libp2p/go-libp2p-core/protocol/switch.go new file mode 100644 index 0000000000..f3ac369bec --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/protocol/switch.go @@ -0,0 +1,81 @@ +// Package protocol provides core interfaces for protocol routing and negotiation in libp2p. +package protocol + +import ( + "io" +) + +// HandlerFunc is a user-provided function used by the Router to +// handle a protocol/stream. +// +// Will be invoked with the protocol ID string as the first argument, +// which may differ from the ID used for registration if the handler +// was registered using a match function. +type HandlerFunc = func(protocol string, rwc io.ReadWriteCloser) error + +// Router is an interface that allows users to add and remove protocol handlers, +// which will be invoked when incoming stream requests for registered protocols +// are accepted. +// +// Upon receiving an incoming stream request, the Router will check all registered +// protocol handlers to determine which (if any) is capable of handling the stream. +// The handlers are checked in order of registration; if multiple handlers are +// eligible, only the first to be registered will be invoked. +type Router interface { + + // AddHandler registers the given handler to be invoked for + // an exact literal match of the given protocol ID string. + AddHandler(protocol string, handler HandlerFunc) + + // AddHandlerWithFunc registers the given handler to be invoked + // when the provided match function returns true. + // + // The match function will be invoked with an incoming protocol + // ID string, and should return true if the handler supports + // the protocol. Note that the protocol ID argument is not + // used for matching; if you want to match the protocol ID + // string exactly, you must check for it in your match function. + AddHandlerWithFunc(protocol string, match func(string) bool, handler HandlerFunc) + + // RemoveHandler removes the registered handler (if any) for the + // given protocol ID string. + RemoveHandler(protocol string) + + // Protocols returns a list of all registered protocol ID strings. + // Note that the Router may be able to handle protocol IDs not + // included in this list if handlers were added with match functions + // using AddHandlerWithFunc. + Protocols() []string +} + +// Negotiator is a component capable of reaching agreement over what protocols +// to use for inbound streams of communication. +type Negotiator interface { + + // NegotiateLazy will return the registered protocol handler to use + // for a given inbound stream, returning as soon as the protocol has been + // determined. Returns an error if negotiation fails. + // + // NegotiateLazy may return before all protocol negotiation responses have been + // written to the stream. This is in contrast to Negotiate, which will block until + // the Negotiator is finished with the stream. + NegotiateLazy(rwc io.ReadWriteCloser) (io.ReadWriteCloser, string, HandlerFunc, error) + + // Negotiate will return the registered protocol handler to use for a given + // inbound stream, returning after the protocol has been determined and the + // Negotiator has finished using the stream for negotiation. Returns an + // error if negotiation fails. + Negotiate(rwc io.ReadWriteCloser) (string, HandlerFunc, error) + + // Handle calls Negotiate to determine which protocol handler to use for an + // inbound stream, then invokes the protocol handler function, passing it + // the protocol ID and the stream. Returns an error if negotiation fails. + Handle(rwc io.ReadWriteCloser) error +} + +// Switch is the component responsible for "dispatching" incoming stream requests to +// their corresponding stream handlers. It is both a Negotiator and a Router. +type Switch interface { + Router + Negotiator +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/record/envelope.go b/vendor/github.com/libp2p/go-libp2p-core/record/envelope.go new file mode 100644 index 0000000000..bdc33abdf1 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/record/envelope.go @@ -0,0 +1,297 @@ +package record + +import ( + "bytes" + "errors" + "fmt" + "sync" + + "github.com/libp2p/go-libp2p-core/crypto" + pb "github.com/libp2p/go-libp2p-core/record/pb" + + pool "github.com/libp2p/go-buffer-pool" + + "github.com/gogo/protobuf/proto" + "github.com/multiformats/go-varint" +) + +// Envelope contains an arbitrary []byte payload, signed by a libp2p peer. +// +// Envelopes are signed in the context of a particular "domain", which is a +// string specified when creating and verifying the envelope. You must know the +// domain string used to produce the envelope in order to verify the signature +// and access the payload. +type Envelope struct { + // The public key that can be used to verify the signature and derive the peer id of the signer. + PublicKey crypto.PubKey + + // A binary identifier that indicates what kind of data is contained in the payload. + // TODO(yusef): enforce multicodec prefix + PayloadType []byte + + // The envelope payload. + RawPayload []byte + + // The signature of the domain string :: type hint :: payload. + signature []byte + + // the unmarshalled payload as a Record, cached on first access via the Record accessor method + cached Record + unmarshalError error + unmarshalOnce sync.Once +} + +var ErrEmptyDomain = errors.New("envelope domain must not be empty") +var ErrEmptyPayloadType = errors.New("payloadType must not be empty") +var ErrInvalidSignature = errors.New("invalid signature or incorrect domain") + +// Seal marshals the given Record, places the marshaled bytes inside an Envelope, +// and signs with the given private key. +func Seal(rec Record, privateKey crypto.PrivKey) (*Envelope, error) { + payload, err := rec.MarshalRecord() + if err != nil { + return nil, fmt.Errorf("error marshaling record: %v", err) + } + + domain := rec.Domain() + payloadType := rec.Codec() + if domain == "" { + return nil, ErrEmptyDomain + } + + if len(payloadType) == 0 { + return nil, ErrEmptyPayloadType + } + + unsigned, err := makeUnsigned(domain, payloadType, payload) + if err != nil { + return nil, err + } + defer pool.Put(unsigned) + + sig, err := privateKey.Sign(unsigned) + if err != nil { + return nil, err + } + + return &Envelope{ + PublicKey: privateKey.GetPublic(), + PayloadType: payloadType, + RawPayload: payload, + signature: sig, + }, nil +} + +// ConsumeEnvelope unmarshals a serialized Envelope and validates its +// signature using the provided 'domain' string. If validation fails, an error +// is returned, along with the unmarshalled envelope so it can be inspected. +// +// On success, ConsumeEnvelope returns the Envelope itself, as well as the inner payload, +// unmarshalled into a concrete Record type. The actual type of the returned Record depends +// on what has been registered for the Envelope's PayloadType (see RegisterType for details). +// +// You can type assert on the returned Record to convert it to an instance of the concrete +// Record type: +// +// envelope, rec, err := ConsumeEnvelope(envelopeBytes, peer.PeerRecordEnvelopeDomain) +// if err != nil { +// handleError(envelope, err) // envelope may be non-nil, even if errors occur! +// return +// } +// peerRec, ok := rec.(*peer.PeerRecord) +// if ok { +// doSomethingWithPeerRecord(peerRec) +// } +// +// Important: you MUST check the error value before using the returned Envelope. In some error +// cases, including when the envelope signature is invalid, both the Envelope and an error will +// be returned. This allows you to inspect the unmarshalled but invalid Envelope. As a result, +// you must not assume that any non-nil Envelope returned from this function is valid. +// +// If the Envelope signature is valid, but no Record type is registered for the Envelope's +// PayloadType, ErrPayloadTypeNotRegistered will be returned, along with the Envelope and +// a nil Record. +func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record, err error) { + e, err := UnmarshalEnvelope(data) + if err != nil { + return nil, nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) + } + + err = e.validate(domain) + if err != nil { + return e, nil, fmt.Errorf("failed to validate envelope: %w", err) + } + + rec, err = e.Record() + if err != nil { + return e, nil, fmt.Errorf("failed to unmarshal envelope payload: %w", err) + } + return e, rec, nil +} + +// ConsumeTypedEnvelope unmarshals a serialized Envelope and validates its +// signature. If validation fails, an error is returned, along with the unmarshalled +// envelope so it can be inspected. +// +// Unlike ConsumeEnvelope, ConsumeTypedEnvelope does not try to automatically determine +// the type of Record to unmarshal the Envelope's payload into. Instead, the caller provides +// a destination Record instance, which will unmarshal the Envelope payload. It is the caller's +// responsibility to determine whether the given Record type is able to unmarshal the payload +// correctly. +// +// rec := &MyRecordType{} +// envelope, err := ConsumeTypedEnvelope(envelopeBytes, rec) +// if err != nil { +// handleError(envelope, err) +// } +// doSomethingWithRecord(rec) +// +// Important: you MUST check the error value before using the returned Envelope. In some error +// cases, including when the envelope signature is invalid, both the Envelope and an error will +// be returned. This allows you to inspect the unmarshalled but invalid Envelope. As a result, +// you must not assume that any non-nil Envelope returned from this function is valid. +func ConsumeTypedEnvelope(data []byte, destRecord Record) (envelope *Envelope, err error) { + e, err := UnmarshalEnvelope(data) + if err != nil { + return nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err) + } + + err = e.validate(destRecord.Domain()) + if err != nil { + return e, fmt.Errorf("failed to validate envelope: %w", err) + } + + err = destRecord.UnmarshalRecord(e.RawPayload) + if err != nil { + return e, fmt.Errorf("failed to unmarshal envelope payload: %w", err) + } + e.cached = destRecord + return e, nil +} + +// UnmarshalEnvelope unmarshals a serialized Envelope protobuf message, +// without validating its contents. Most users should use ConsumeEnvelope. +func UnmarshalEnvelope(data []byte) (*Envelope, error) { + var e pb.Envelope + if err := proto.Unmarshal(data, &e); err != nil { + return nil, err + } + + key, err := crypto.PublicKeyFromProto(e.PublicKey) + if err != nil { + return nil, err + } + + return &Envelope{ + PublicKey: key, + PayloadType: e.PayloadType, + RawPayload: e.Payload, + signature: e.Signature, + }, nil +} + +// Marshal returns a byte slice containing a serialized protobuf representation +// of a Envelope. +func (e *Envelope) Marshal() ([]byte, error) { + key, err := crypto.PublicKeyToProto(e.PublicKey) + if err != nil { + return nil, err + } + + msg := pb.Envelope{ + PublicKey: key, + PayloadType: e.PayloadType, + Payload: e.RawPayload, + Signature: e.signature, + } + return proto.Marshal(&msg) +} + +// Equal returns true if the other Envelope has the same public key, +// payload, payload type, and signature. This implies that they were also +// created with the same domain string. +func (e *Envelope) Equal(other *Envelope) bool { + if other == nil { + return e == nil + } + return e.PublicKey.Equals(other.PublicKey) && + bytes.Compare(e.PayloadType, other.PayloadType) == 0 && + bytes.Compare(e.signature, other.signature) == 0 && + bytes.Compare(e.RawPayload, other.RawPayload) == 0 +} + +// Record returns the Envelope's payload unmarshalled as a Record. +// The concrete type of the returned Record depends on which Record +// type was registered for the Envelope's PayloadType - see record.RegisterType. +// +// Once unmarshalled, the Record is cached for future access. +func (e *Envelope) Record() (Record, error) { + e.unmarshalOnce.Do(func() { + if e.cached != nil { + return + } + e.cached, e.unmarshalError = unmarshalRecordPayload(e.PayloadType, e.RawPayload) + }) + return e.cached, e.unmarshalError +} + +// TypedRecord unmarshals the Envelope's payload to the given Record instance. +// It is the caller's responsibility to ensure that the Record type is capable +// of unmarshalling the Envelope payload. Callers can inspect the Envelope's +// PayloadType field to determine the correct type of Record to use. +// +// This method will always unmarshal the Envelope payload even if a cached record +// exists. +func (e *Envelope) TypedRecord(dest Record) error { + return dest.UnmarshalRecord(e.RawPayload) +} + +// validate returns nil if the envelope signature is valid for the given 'domain', +// or an error if signature validation fails. +func (e *Envelope) validate(domain string) error { + unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload) + if err != nil { + return err + } + defer pool.Put(unsigned) + + valid, err := e.PublicKey.Verify(unsigned, e.signature) + if err != nil { + return fmt.Errorf("failed while verifying signature: %w", err) + } + if !valid { + return ErrInvalidSignature + } + return nil +} + +// makeUnsigned is a helper function that prepares a buffer to sign or verify. +// It returns a byte slice from a pool. The caller MUST return this slice to the +// pool. +func makeUnsigned(domain string, payloadType []byte, payload []byte) ([]byte, error) { + var ( + fields = [][]byte{[]byte(domain), payloadType, payload} + + // fields are prefixed with their length as an unsigned varint. we + // compute the lengths before allocating the sig buffer so we know how + // much space to add for the lengths + flen = make([][]byte, len(fields)) + size = 0 + ) + + for i, f := range fields { + l := len(f) + flen[i] = varint.ToUvarint(uint64(l)) + size += l + len(flen[i]) + } + + b := pool.Get(size) + + var s int + for i, f := range fields { + s += copy(b[s:], flen[i]) + s += copy(b[s:], f) + } + + return b[:s], nil +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/record/pb/Makefile b/vendor/github.com/libp2p/go-libp2p-core/record/pb/Makefile new file mode 100644 index 0000000000..7cf8222f89 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/record/pb/Makefile @@ -0,0 +1,11 @@ +PB = $(wildcard *.proto) +GO = $(PB:.proto=.pb.go) + +all: $(GO) + +%.pb.go: %.proto + protoc --proto_path=$(PWD):$(PWD)/../.. --gogofaster_out=. $< + +clean: + rm -f *.pb.go + rm -f *.go diff --git a/vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.pb.go b/vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.pb.go new file mode 100644 index 0000000000..412809f13a --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.pb.go @@ -0,0 +1,504 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: envelope.proto + +package record_pb + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + pb "github.com/libp2p/go-libp2p-core/crypto/pb" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Envelope encloses a signed payload produced by a peer, along with the public +// key of the keypair it was signed with so that it can be statelessly validated +// by the receiver. +// +// The payload is prefixed with a byte string that determines the type, so it +// can be deserialized deterministically. Often, this byte string is a +// multicodec. +type Envelope struct { + // public_key is the public key of the keypair the enclosed payload was + // signed with. + PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + // payload_type encodes the type of payload, so that it can be deserialized + // deterministically. + PayloadType []byte `protobuf:"bytes,2,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"` + // payload is the actual payload carried inside this envelope. + Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + // signature is the signature produced by the private key corresponding to + // the enclosed public key, over the payload, prefixing a domain string for + // additional security. + Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (m *Envelope) Reset() { *m = Envelope{} } +func (m *Envelope) String() string { return proto.CompactTextString(m) } +func (*Envelope) ProtoMessage() {} +func (*Envelope) Descriptor() ([]byte, []int) { + return fileDescriptor_ee266e8c558e9dc5, []int{0} +} +func (m *Envelope) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Envelope) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Envelope.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Envelope) XXX_Merge(src proto.Message) { + xxx_messageInfo_Envelope.Merge(m, src) +} +func (m *Envelope) XXX_Size() int { + return m.Size() +} +func (m *Envelope) XXX_DiscardUnknown() { + xxx_messageInfo_Envelope.DiscardUnknown(m) +} + +var xxx_messageInfo_Envelope proto.InternalMessageInfo + +func (m *Envelope) GetPublicKey() *pb.PublicKey { + if m != nil { + return m.PublicKey + } + return nil +} + +func (m *Envelope) GetPayloadType() []byte { + if m != nil { + return m.PayloadType + } + return nil +} + +func (m *Envelope) GetPayload() []byte { + if m != nil { + return m.Payload + } + return nil +} + +func (m *Envelope) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +func init() { + proto.RegisterType((*Envelope)(nil), "record.pb.Envelope") +} + +func init() { proto.RegisterFile("envelope.proto", fileDescriptor_ee266e8c558e9dc5) } + +var fileDescriptor_ee266e8c558e9dc5 = []byte{ + // 205 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0xcd, 0x2b, 0x4b, + 0xcd, 0xc9, 0x2f, 0x48, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2c, 0x4a, 0x4d, 0xce, + 0x2f, 0x4a, 0xd1, 0x2b, 0x48, 0x92, 0x12, 0x4b, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x48, + 0xd2, 0x87, 0xb0, 0x20, 0x4a, 0x94, 0x66, 0x31, 0x72, 0x71, 0xb8, 0x42, 0x75, 0x09, 0x19, 0x73, + 0x71, 0x15, 0x94, 0x26, 0xe5, 0x64, 0x26, 0xc7, 0x67, 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, + 0x70, 0x1b, 0x89, 0xe8, 0xc1, 0xd4, 0x27, 0xe9, 0x05, 0x80, 0x25, 0xbd, 0x53, 0x2b, 0x83, 0x38, + 0x0b, 0x60, 0x4c, 0x21, 0x45, 0x2e, 0x9e, 0x82, 0xc4, 0xca, 0x9c, 0xfc, 0xc4, 0x94, 0xf8, 0x92, + 0xca, 0x82, 0x54, 0x09, 0x26, 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x6e, 0xa8, 0x58, 0x48, 0x65, 0x41, + 0xaa, 0x90, 0x04, 0x17, 0x3b, 0x94, 0x2b, 0xc1, 0x0c, 0x96, 0x85, 0x71, 0x85, 0x64, 0xb8, 0x38, + 0x8b, 0x33, 0xd3, 0xf3, 0x12, 0x4b, 0x4a, 0x8b, 0x52, 0x25, 0x58, 0xc1, 0x72, 0x08, 0x01, 0x27, + 0x89, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, + 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0xbb, 0xde, 0x18, + 0x10, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x0b, 0xd9, 0x6d, 0xf2, 0x00, 0x00, 0x00, +} + +func (m *Envelope) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Envelope) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Envelope) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0x2a + } + if len(m.Payload) > 0 { + i -= len(m.Payload) + copy(dAtA[i:], m.Payload) + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.Payload))) + i-- + dAtA[i] = 0x1a + } + if len(m.PayloadType) > 0 { + i -= len(m.PayloadType) + copy(dAtA[i:], m.PayloadType) + i = encodeVarintEnvelope(dAtA, i, uint64(len(m.PayloadType))) + i-- + dAtA[i] = 0x12 + } + if m.PublicKey != nil { + { + size, err := m.PublicKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEnvelope(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintEnvelope(dAtA []byte, offset int, v uint64) int { + offset -= sovEnvelope(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Envelope) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PublicKey != nil { + l = m.PublicKey.Size() + n += 1 + l + sovEnvelope(uint64(l)) + } + l = len(m.PayloadType) + if l > 0 { + n += 1 + l + sovEnvelope(uint64(l)) + } + l = len(m.Payload) + if l > 0 { + n += 1 + l + sovEnvelope(uint64(l)) + } + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovEnvelope(uint64(l)) + } + return n +} + +func sovEnvelope(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEnvelope(x uint64) (n int) { + return sovEnvelope(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Envelope) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Envelope: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Envelope: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PublicKey == nil { + m.PublicKey = &pb.PublicKey{} + } + if err := m.PublicKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PayloadType", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PayloadType = append(m.PayloadType[:0], dAtA[iNdEx:postIndex]...) + if m.PayloadType == nil { + m.PayloadType = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Payload", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Payload = append(m.Payload[:0], dAtA[iNdEx:postIndex]...) + if m.Payload == nil { + m.Payload = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEnvelope + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEnvelope + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEnvelope + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) + if m.Signature == nil { + m.Signature = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEnvelope(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthEnvelope + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthEnvelope + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEnvelope(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEnvelope + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEnvelope + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEnvelope + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEnvelope + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEnvelope + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEnvelope + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEnvelope = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEnvelope = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEnvelope = fmt.Errorf("proto: unexpected end of group") +) diff --git a/vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.proto b/vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.proto new file mode 100644 index 0000000000..ca3555fbf7 --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/record/pb/envelope.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package record.pb; + +import "crypto/pb/crypto.proto"; + +// Envelope encloses a signed payload produced by a peer, along with the public +// key of the keypair it was signed with so that it can be statelessly validated +// by the receiver. +// +// The payload is prefixed with a byte string that determines the type, so it +// can be deserialized deterministically. Often, this byte string is a +// multicodec. +message Envelope { + // public_key is the public key of the keypair the enclosed payload was + // signed with. + crypto.pb.PublicKey public_key = 1; + + // payload_type encodes the type of payload, so that it can be deserialized + // deterministically. + bytes payload_type = 2; + + // payload is the actual payload carried inside this envelope. + bytes payload = 3; + + // signature is the signature produced by the private key corresponding to + // the enclosed public key, over the payload, prefixing a domain string for + // additional security. + bytes signature = 5; +} diff --git a/vendor/github.com/libp2p/go-libp2p-core/record/record.go b/vendor/github.com/libp2p/go-libp2p-core/record/record.go new file mode 100644 index 0000000000..212005780e --- /dev/null +++ b/vendor/github.com/libp2p/go-libp2p-core/record/record.go @@ -0,0 +1,102 @@ +package record + +import ( + "errors" + "reflect" +) + +var ( + // ErrPayloadTypeNotRegistered is returned from ConsumeEnvelope when the Envelope's + // PayloadType does not match any registered Record types. + ErrPayloadTypeNotRegistered = errors.New("payload type is not registered") + + payloadTypeRegistry = make(map[string]reflect.Type) +) + +// Record represents a data type that can be used as the payload of an Envelope. +// The Record interface defines the methods used to marshal and unmarshal a Record +// type to a byte slice. +// +// Record types may be "registered" as the default for a given Envelope.PayloadType +// using the RegisterType function. Once a Record type has been registered, +// an instance of that type will be created and used to unmarshal the payload of +// any Envelope with the registered PayloadType when the Envelope is opened using +// the ConsumeEnvelope function. +// +// To use an unregistered Record type instead, use ConsumeTypedEnvelope and pass in +// an instance of the Record type that you'd like the Envelope's payload to be +// unmarshaled into. +type Record interface { + + // Domain is the "signature domain" used when signing and verifying a particular + // Record type. The Domain string should be unique to your Record type, and all + // instances of the Record type must have the same Domain string. + Domain() string + + // Codec is a binary identifier for this type of record, ideally a registered multicodec + // (see https://github.com/multiformats/multicodec). + // When a Record is put into an Envelope (see record.Seal), the Codec value will be used + // as the Envelope's PayloadType. When the Envelope is later unsealed, the PayloadType + // will be used to lookup the correct Record type to unmarshal the Envelope payload into. + Codec() []byte + + // MarshalRecord converts a Record instance to a []byte, so that it can be used as an + // Envelope payload. + MarshalRecord() ([]byte, error) + + // UnmarshalRecord unmarshals a []byte payload into an instance of a particular Record type. + UnmarshalRecord([]byte) error +} + +// RegisterType associates a binary payload type identifier with a concrete +// Record type. This is used to automatically unmarshal Record payloads from Envelopes +// when using ConsumeEnvelope, and to automatically marshal Records and determine the +// correct PayloadType when calling Seal. +// +// Callers must provide an instance of the record type to be registered, which must be +// a pointer type. Registration should be done in the init function of the package +// where the Record type is defined: +// +// package hello_record +// import record "github.com/libp2p/go-libp2p-core/record" +// +// func init() { +// record.RegisterType(&HelloRecord{}) +// } +// +// type HelloRecord struct { } // etc.. +// +func RegisterType(prototype Record) { + payloadTypeRegistry[string(prototype.Codec())] = getValueType(prototype) +} + +func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (Record, error) { + rec, err := blankRecordForPayloadType(payloadType) + if err != nil { + return nil, err + } + err = rec.UnmarshalRecord(payloadBytes) + if err != nil { + return nil, err + } + return rec, nil +} + +func blankRecordForPayloadType(payloadType []byte) (Record, error) { + valueType, ok := payloadTypeRegistry[string(payloadType)] + if !ok { + return nil, ErrPayloadTypeNotRegistered + } + + val := reflect.New(valueType) + asRecord := val.Interface().(Record) + return asRecord, nil +} + +func getValueType(i interface{}) reflect.Type { + valueType := reflect.TypeOf(i) + if valueType.Kind() == reflect.Ptr { + valueType = valueType.Elem() + } + return valueType +} diff --git a/vendor/github.com/libp2p/go-openssl/.gitignore b/vendor/github.com/libp2p/go-openssl/.gitignore new file mode 100644 index 0000000000..805d350b7e --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/.gitignore @@ -0,0 +1 @@ +openssl.test diff --git a/vendor/github.com/libp2p/go-openssl/AUTHORS b/vendor/github.com/libp2p/go-openssl/AUTHORS new file mode 100644 index 0000000000..a048c1ea16 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/AUTHORS @@ -0,0 +1,24 @@ +Andrew Brampton +Anton Baklanov +Carlos Martín Nieto +Charles Strahan +Christopher Dudley +Christopher Fredericks +Colin Misare +dequis +Gabriel Russell +Giulio +Jakob Unterwurzacher +Juuso Haavisto +kujenga +Phus Lu +Russ Egan +Ryan Hileman +Scott J. Goldman +Scott Kidder +Space Monkey, Inc +Stephen Gallagher +Viacheslav Biriukov +Zack Owens +Ramesh Rayaprolu +Paras Shah diff --git a/vendor/github.com/libp2p/go-openssl/LICENSE b/vendor/github.com/libp2p/go-openssl/LICENSE new file mode 100644 index 0000000000..37ec93a14f --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/libp2p/go-openssl/README.md b/vendor/github.com/libp2p/go-openssl/README.md new file mode 100644 index 0000000000..62ac7dcd6d --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/README.md @@ -0,0 +1,40 @@ +# OpenSSL bindings for Go + +Forked from https://github.com/spacemonkeygo/openssl (unmaintained) to add: + +1. FreeBSD support. +2. Key equality checking. +3. A function to get the size of signatures produced by a key. + +--- + +Please see http://godoc.org/github.com/libp2p/go-openssl for more info + +--- + +### License + +Copyright (C) 2017. See AUTHORS. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +### Using on macOS +1. Install [homebrew](http://brew.sh/) +2. `$ brew install openssl` or `$ brew install openssl@1.1` + +### Using on Windows +1. Install [mingw-w64](http://mingw-w64.sourceforge.net/) +2. Install [pkg-config-lite](http://sourceforge.net/projects/pkgconfiglite) +3. Build (or install precompiled) openssl for mingw32-w64 +4. Set __PKG\_CONFIG\_PATH__ to the directory containing openssl.pc + (i.e. c:\mingw64\mingw64\lib\pkgconfig) diff --git a/vendor/github.com/libp2p/go-openssl/bio.go b/vendor/github.com/libp2p/go-openssl/bio.go new file mode 100644 index 0000000000..9fe32aa803 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/bio.go @@ -0,0 +1,305 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "io" + "reflect" + "sync" + "unsafe" +) + +const ( + SSLRecordSize = 16 * 1024 +) + +func nonCopyGoBytes(ptr uintptr, length int) []byte { + var slice []byte + header := (*reflect.SliceHeader)(unsafe.Pointer(&slice)) + header.Cap = length + header.Len = length + header.Data = ptr + return slice +} + +func nonCopyCString(data *C.char, size C.int) []byte { + return nonCopyGoBytes(uintptr(unsafe.Pointer(data)), int(size)) +} + +var writeBioMapping = newMapping() + +type writeBio struct { + data_mtx sync.Mutex + op_mtx sync.Mutex + buf []byte + release_buffers bool +} + +func loadWritePtr(b *C.BIO) *writeBio { + t := token(C.X_BIO_get_data(b)) + return (*writeBio)(writeBioMapping.Get(t)) +} + +func bioClearRetryFlags(b *C.BIO) { + C.X_BIO_clear_flags(b, C.BIO_FLAGS_RWS|C.BIO_FLAGS_SHOULD_RETRY) +} + +func bioSetRetryRead(b *C.BIO) { + C.X_BIO_set_flags(b, C.BIO_FLAGS_READ|C.BIO_FLAGS_SHOULD_RETRY) +} + +//export go_write_bio_write +func go_write_bio_write(b *C.BIO, data *C.char, size C.int) (rc C.int) { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: writeBioWrite panic'd: %v", err) + rc = -1 + } + }() + ptr := loadWritePtr(b) + if ptr == nil || data == nil || size < 0 { + return -1 + } + ptr.data_mtx.Lock() + defer ptr.data_mtx.Unlock() + bioClearRetryFlags(b) + ptr.buf = append(ptr.buf, nonCopyCString(data, size)...) + return size +} + +//export go_write_bio_ctrl +func go_write_bio_ctrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) ( + rc C.long) { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: writeBioCtrl panic'd: %v", err) + rc = -1 + } + }() + switch cmd { + case C.BIO_CTRL_WPENDING: + return writeBioPending(b) + case C.BIO_CTRL_DUP, C.BIO_CTRL_FLUSH: + return 1 + default: + return 0 + } +} + +func writeBioPending(b *C.BIO) C.long { + ptr := loadWritePtr(b) + if ptr == nil { + return 0 + } + ptr.data_mtx.Lock() + defer ptr.data_mtx.Unlock() + return C.long(len(ptr.buf)) +} + +func (b *writeBio) WriteTo(w io.Writer) (rv int64, err error) { + b.op_mtx.Lock() + defer b.op_mtx.Unlock() + + // write whatever data we currently have + b.data_mtx.Lock() + data := b.buf + b.data_mtx.Unlock() + + if len(data) == 0 { + return 0, nil + } + n, err := w.Write(data) + + // subtract however much data we wrote from the buffer + b.data_mtx.Lock() + b.buf = b.buf[:copy(b.buf, b.buf[n:])] + if b.release_buffers && len(b.buf) == 0 { + b.buf = nil + } + b.data_mtx.Unlock() + + return int64(n), err +} + +func (self *writeBio) Disconnect(b *C.BIO) { + if loadWritePtr(b) == self { + writeBioMapping.Del(token(C.X_BIO_get_data(b))) + C.X_BIO_set_data(b, nil) + } +} + +func (b *writeBio) MakeCBIO() *C.BIO { + rv := C.X_BIO_new_write_bio() + token := writeBioMapping.Add(unsafe.Pointer(b)) + C.X_BIO_set_data(rv, unsafe.Pointer(token)) + return rv +} + +var readBioMapping = newMapping() + +type readBio struct { + data_mtx sync.Mutex + op_mtx sync.Mutex + buf []byte + eof bool + release_buffers bool +} + +func loadReadPtr(b *C.BIO) *readBio { + return (*readBio)(readBioMapping.Get(token(C.X_BIO_get_data(b)))) +} + +//export go_read_bio_read +func go_read_bio_read(b *C.BIO, data *C.char, size C.int) (rc C.int) { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: go_read_bio_read panic'd: %v", err) + rc = -1 + } + }() + ptr := loadReadPtr(b) + if ptr == nil || size < 0 { + return -1 + } + ptr.data_mtx.Lock() + defer ptr.data_mtx.Unlock() + bioClearRetryFlags(b) + if len(ptr.buf) == 0 { + if ptr.eof { + return 0 + } + bioSetRetryRead(b) + return -1 + } + if size == 0 || data == nil { + return C.int(len(ptr.buf)) + } + n := copy(nonCopyCString(data, size), ptr.buf) + ptr.buf = ptr.buf[:copy(ptr.buf, ptr.buf[n:])] + if ptr.release_buffers && len(ptr.buf) == 0 { + ptr.buf = nil + } + return C.int(n) +} + +//export go_read_bio_ctrl +func go_read_bio_ctrl(b *C.BIO, cmd C.int, arg1 C.long, arg2 unsafe.Pointer) ( + rc C.long) { + + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: readBioCtrl panic'd: %v", err) + rc = -1 + } + }() + switch cmd { + case C.BIO_CTRL_PENDING: + return readBioPending(b) + case C.BIO_CTRL_DUP, C.BIO_CTRL_FLUSH: + return 1 + default: + return 0 + } +} + +func readBioPending(b *C.BIO) C.long { + ptr := loadReadPtr(b) + if ptr == nil { + return 0 + } + ptr.data_mtx.Lock() + defer ptr.data_mtx.Unlock() + return C.long(len(ptr.buf)) +} + +func (b *readBio) ReadFromOnce(r io.Reader) (n int, err error) { + b.op_mtx.Lock() + defer b.op_mtx.Unlock() + + // make sure we have a destination that fits at least one SSL record + b.data_mtx.Lock() + if cap(b.buf) < len(b.buf)+SSLRecordSize { + new_buf := make([]byte, len(b.buf), len(b.buf)+SSLRecordSize) + copy(new_buf, b.buf) + b.buf = new_buf + } + dst := b.buf[len(b.buf):cap(b.buf)] + dst_slice := b.buf + b.data_mtx.Unlock() + + n, err = r.Read(dst) + b.data_mtx.Lock() + defer b.data_mtx.Unlock() + if n > 0 { + if len(dst_slice) != len(b.buf) { + // someone shrunk the buffer, so we read in too far ahead and we + // need to slide backwards + copy(b.buf[len(b.buf):len(b.buf)+n], dst) + } + b.buf = b.buf[:len(b.buf)+n] + } + return n, err +} + +func (b *readBio) MakeCBIO() *C.BIO { + rv := C.X_BIO_new_read_bio() + token := readBioMapping.Add(unsafe.Pointer(b)) + C.X_BIO_set_data(rv, unsafe.Pointer(token)) + return rv +} + +func (self *readBio) Disconnect(b *C.BIO) { + if loadReadPtr(b) == self { + readBioMapping.Del(token(C.X_BIO_get_data(b))) + C.X_BIO_set_data(b, nil) + } +} + +func (b *readBio) MarkEOF() { + b.data_mtx.Lock() + defer b.data_mtx.Unlock() + b.eof = true +} + +type anyBio C.BIO + +func asAnyBio(b *C.BIO) *anyBio { return (*anyBio)(b) } + +func (b *anyBio) Read(buf []byte) (n int, err error) { + if len(buf) == 0 { + return 0, nil + } + n = int(C.X_BIO_read((*C.BIO)(b), unsafe.Pointer(&buf[0]), C.int(len(buf)))) + if n <= 0 { + return 0, io.EOF + } + return n, nil +} + +func (b *anyBio) Write(buf []byte) (written int, err error) { + if len(buf) == 0 { + return 0, nil + } + n := int(C.X_BIO_write((*C.BIO)(b), unsafe.Pointer(&buf[0]), + C.int(len(buf)))) + if n != len(buf) { + return n, errors.New("BIO write failed") + } + return n, nil +} diff --git a/vendor/github.com/libp2p/go-openssl/build.go b/vendor/github.com/libp2p/go-openssl/build.go new file mode 100644 index 0000000000..d3f19d82a0 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/build.go @@ -0,0 +1,24 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !openssl_static + +package openssl + +// #cgo linux windows freebsd openbsd solaris pkg-config: libssl libcrypto +// #cgo linux freebsd openbsd solaris CFLAGS: -Wno-deprecated-declarations +// #cgo darwin CFLAGS: -I/usr/local/opt/openssl@1.1/include -I/usr/local/opt/openssl/include -Wno-deprecated-declarations +// #cgo darwin LDFLAGS: -L/usr/local/opt/openssl@1.1/lib -L/usr/local/opt/openssl/lib -lssl -lcrypto +// #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN +import "C" diff --git a/vendor/github.com/libp2p/go-openssl/build_static.go b/vendor/github.com/libp2p/go-openssl/build_static.go new file mode 100644 index 0000000000..69fad0a4f2 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/build_static.go @@ -0,0 +1,24 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build openssl_static + +package openssl + +// #cgo linux windows freebsd openbsd solaris pkg-config: --static libssl libcrypto +// #cgo linux freebsd openbsd solaris CFLAGS: -Wno-deprecated-declarations +// #cgo darwin CFLAGS: -I/usr/local/opt/openssl@1.1/include -I/usr/local/opt/openssl/include -Wno-deprecated-declarations +// #cgo darwin LDFLAGS: -L/usr/local/opt/openssl@1.1/lib -L/usr/local/opt/openssl/lib -lssl -lcrypto +// #cgo windows CFLAGS: -DWIN32_LEAN_AND_MEAN +import "C" diff --git a/vendor/github.com/libp2p/go-openssl/cert.go b/vendor/github.com/libp2p/go-openssl/cert.go new file mode 100644 index 0000000000..e841e22cc6 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/cert.go @@ -0,0 +1,415 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "io/ioutil" + "math/big" + "runtime" + "time" + "unsafe" +) + +type EVP_MD int + +const ( + EVP_NULL EVP_MD = iota + EVP_MD5 EVP_MD = iota + EVP_MD4 EVP_MD = iota + EVP_SHA EVP_MD = iota + EVP_SHA1 EVP_MD = iota + EVP_DSS EVP_MD = iota + EVP_DSS1 EVP_MD = iota + EVP_MDC2 EVP_MD = iota + EVP_RIPEMD160 EVP_MD = iota + EVP_SHA224 EVP_MD = iota + EVP_SHA256 EVP_MD = iota + EVP_SHA384 EVP_MD = iota + EVP_SHA512 EVP_MD = iota +) + +// X509_Version represents a version on an x509 certificate. +type X509_Version int + +// Specify constants for x509 versions because the standard states that they +// are represented internally as one lower than the common version name. +const ( + X509_V1 X509_Version = 0 + X509_V3 X509_Version = 2 +) + +type Certificate struct { + x *C.X509 + Issuer *Certificate + ref interface{} + pubKey PublicKey +} + +type CertificateInfo struct { + Serial *big.Int + Issued time.Duration + Expires time.Duration + Country string + Organization string + CommonName string +} + +type Name struct { + name *C.X509_NAME +} + +// Allocate and return a new Name object. +func NewName() (*Name, error) { + n := C.X509_NAME_new() + if n == nil { + return nil, errors.New("could not create x509 name") + } + name := &Name{name: n} + runtime.SetFinalizer(name, func(n *Name) { + C.X509_NAME_free(n.name) + }) + return name, nil +} + +// AddTextEntry appends a text entry to an X509 NAME. +func (n *Name) AddTextEntry(field, value string) error { + cfield := C.CString(field) + defer C.free(unsafe.Pointer(cfield)) + cvalue := (*C.uchar)(unsafe.Pointer(C.CString(value))) + defer C.free(unsafe.Pointer(cvalue)) + ret := C.X509_NAME_add_entry_by_txt( + n.name, cfield, C.MBSTRING_ASC, cvalue, -1, -1, 0) + if ret != 1 { + return errors.New("failed to add x509 name text entry") + } + return nil +} + +// AddTextEntries allows adding multiple entries to a name in one call. +func (n *Name) AddTextEntries(entries map[string]string) error { + for f, v := range entries { + if err := n.AddTextEntry(f, v); err != nil { + return err + } + } + return nil +} + +// GetEntry returns a name entry based on NID. If no entry, then ("", false) is +// returned. +func (n *Name) GetEntry(nid NID) (entry string, ok bool) { + entrylen := C.X509_NAME_get_text_by_NID(n.name, C.int(nid), nil, 0) + if entrylen == -1 { + return "", false + } + buf := (*C.char)(C.malloc(C.size_t(entrylen + 1))) + defer C.free(unsafe.Pointer(buf)) + C.X509_NAME_get_text_by_NID(n.name, C.int(nid), buf, entrylen+1) + return C.GoStringN(buf, entrylen), true +} + +// NewCertificate generates a basic certificate based +// on the provided CertificateInfo struct +func NewCertificate(info *CertificateInfo, key PublicKey) (*Certificate, error) { + c := &Certificate{x: C.X509_new()} + runtime.SetFinalizer(c, func(c *Certificate) { + C.X509_free(c.x) + }) + + name, err := c.GetSubjectName() + if err != nil { + return nil, err + } + err = name.AddTextEntries(map[string]string{ + "C": info.Country, + "O": info.Organization, + "CN": info.CommonName, + }) + if err != nil { + return nil, err + } + // self-issue for now + if err := c.SetIssuerName(name); err != nil { + return nil, err + } + if err := c.SetSerial(info.Serial); err != nil { + return nil, err + } + if err := c.SetIssueDate(info.Issued); err != nil { + return nil, err + } + if err := c.SetExpireDate(info.Expires); err != nil { + return nil, err + } + if err := c.SetPubKey(key); err != nil { + return nil, err + } + return c, nil +} + +func (c *Certificate) GetSubjectName() (*Name, error) { + n := C.X509_get_subject_name(c.x) + if n == nil { + return nil, errors.New("failed to get subject name") + } + return &Name{name: n}, nil +} + +func (c *Certificate) GetIssuerName() (*Name, error) { + n := C.X509_get_issuer_name(c.x) + if n == nil { + return nil, errors.New("failed to get issuer name") + } + return &Name{name: n}, nil +} + +func (c *Certificate) SetSubjectName(name *Name) error { + if C.X509_set_subject_name(c.x, name.name) != 1 { + return errors.New("failed to set subject name") + } + return nil +} + +// SetIssuer updates the stored Issuer cert +// and the internal x509 Issuer Name of a certificate. +// The stored Issuer reference is used when adding extensions. +func (c *Certificate) SetIssuer(issuer *Certificate) error { + name, err := issuer.GetSubjectName() + if err != nil { + return err + } + if err = c.SetIssuerName(name); err != nil { + return err + } + c.Issuer = issuer + return nil +} + +// SetIssuerName populates the issuer name of a certificate. +// Use SetIssuer instead, if possible. +func (c *Certificate) SetIssuerName(name *Name) error { + if C.X509_set_issuer_name(c.x, name.name) != 1 { + return errors.New("failed to set subject name") + } + return nil +} + +// SetSerial sets the serial of a certificate. +func (c *Certificate) SetSerial(serial *big.Int) error { + sno := C.ASN1_INTEGER_new() + defer C.ASN1_INTEGER_free(sno) + bn := C.BN_new() + defer C.BN_free(bn) + + serialBytes := serial.Bytes() + if bn = C.BN_bin2bn((*C.uchar)(unsafe.Pointer(&serialBytes[0])), C.int(len(serialBytes)), bn); bn == nil { + return errors.New("failed to set serial") + } + if sno = C.BN_to_ASN1_INTEGER(bn, sno); sno == nil { + return errors.New("failed to set serial") + } + if C.X509_set_serialNumber(c.x, sno) != 1 { + return errors.New("failed to set serial") + } + return nil +} + +// SetIssueDate sets the certificate issue date relative to the current time. +func (c *Certificate) SetIssueDate(when time.Duration) error { + offset := C.long(when / time.Second) + result := C.X509_gmtime_adj(C.X_X509_get0_notBefore(c.x), offset) + if result == nil { + return errors.New("failed to set issue date") + } + return nil +} + +// SetExpireDate sets the certificate issue date relative to the current time. +func (c *Certificate) SetExpireDate(when time.Duration) error { + offset := C.long(when / time.Second) + result := C.X509_gmtime_adj(C.X_X509_get0_notAfter(c.x), offset) + if result == nil { + return errors.New("failed to set expire date") + } + return nil +} + +// SetPubKey assigns a new public key to a certificate. +func (c *Certificate) SetPubKey(pubKey PublicKey) error { + c.pubKey = pubKey + if C.X509_set_pubkey(c.x, pubKey.evpPKey()) != 1 { + return errors.New("failed to set public key") + } + return nil +} + +// Sign a certificate using a private key and a digest name. +// Accepted digest names are 'sha256', 'sha384', and 'sha512'. +func (c *Certificate) Sign(privKey PrivateKey, digest EVP_MD) error { + switch digest { + case EVP_SHA256: + case EVP_SHA384: + case EVP_SHA512: + default: + return errors.New("Unsupported digest" + + "You're probably looking for 'EVP_SHA256' or 'EVP_SHA512'.") + } + return c.insecureSign(privKey, digest) +} + +func (c *Certificate) insecureSign(privKey PrivateKey, digest EVP_MD) error { + var md *C.EVP_MD = getDigestFunction(digest) + if C.X509_sign(c.x, privKey.evpPKey(), md) <= 0 { + return errors.New("failed to sign certificate") + } + return nil +} + +func getDigestFunction(digest EVP_MD) (md *C.EVP_MD) { + switch digest { + // please don't use these digest functions + case EVP_NULL: + md = C.X_EVP_md_null() + case EVP_MD5: + md = C.X_EVP_md5() + case EVP_SHA: + md = C.X_EVP_sha() + case EVP_SHA1: + md = C.X_EVP_sha1() + case EVP_DSS: + md = C.X_EVP_dss() + case EVP_DSS1: + md = C.X_EVP_dss1() + case EVP_RIPEMD160: + md = C.X_EVP_ripemd160() + case EVP_SHA224: + md = C.X_EVP_sha224() + // you actually want one of these + case EVP_SHA256: + md = C.X_EVP_sha256() + case EVP_SHA384: + md = C.X_EVP_sha384() + case EVP_SHA512: + md = C.X_EVP_sha512() + } + return md +} + +// Add an extension to a certificate. +// Extension constants are NID_* as found in openssl. +func (c *Certificate) AddExtension(nid NID, value string) error { + issuer := c + if c.Issuer != nil { + issuer = c.Issuer + } + var ctx C.X509V3_CTX + C.X509V3_set_ctx(&ctx, c.x, issuer.x, nil, nil, 0) + ex := C.X509V3_EXT_conf_nid(nil, &ctx, C.int(nid), C.CString(value)) + if ex == nil { + return errors.New("failed to create x509v3 extension") + } + defer C.X509_EXTENSION_free(ex) + if C.X509_add_ext(c.x, ex, -1) <= 0 { + return errors.New("failed to add x509v3 extension") + } + return nil +} + +// Wraps AddExtension using a map of NID to text extension. +// Will return without finishing if it encounters an error. +func (c *Certificate) AddExtensions(extensions map[NID]string) error { + for nid, value := range extensions { + if err := c.AddExtension(nid, value); err != nil { + return err + } + } + return nil +} + +// LoadCertificateFromPEM loads an X509 certificate from a PEM-encoded block. +func LoadCertificateFromPEM(pem_block []byte) (*Certificate, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + cert := C.PEM_read_bio_X509(bio, nil, nil, nil) + C.BIO_free(bio) + if cert == nil { + return nil, errorFromErrorQueue() + } + x := &Certificate{x: cert} + runtime.SetFinalizer(x, func(x *Certificate) { + C.X509_free(x.x) + }) + return x, nil +} + +// MarshalPEM converts the X509 certificate to PEM-encoded format +func (c *Certificate) MarshalPEM() (pem_block []byte, err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + if int(C.PEM_write_bio_X509(bio, c.x)) != 1 { + return nil, errors.New("failed dumping certificate") + } + return ioutil.ReadAll(asAnyBio(bio)) +} + +// PublicKey returns the public key embedded in the X509 certificate. +func (c *Certificate) PublicKey() (PublicKey, error) { + pkey := C.X509_get_pubkey(c.x) + if pkey == nil { + return nil, errors.New("no public key found") + } + key := &pKey{key: pkey} + runtime.SetFinalizer(key, func(key *pKey) { + C.EVP_PKEY_free(key.key) + }) + return key, nil +} + +// GetSerialNumberHex returns the certificate's serial number in hex format +func (c *Certificate) GetSerialNumberHex() (serial string) { + asn1_i := C.X509_get_serialNumber(c.x) + bignum := C.ASN1_INTEGER_to_BN(asn1_i, nil) + hex := C.BN_bn2hex(bignum) + serial = C.GoString(hex) + C.BN_free(bignum) + C.X_OPENSSL_free(unsafe.Pointer(hex)) + return +} + +// GetVersion returns the X509 version of the certificate. +func (c *Certificate) GetVersion() X509_Version { + return X509_Version(C.X_X509_get_version(c.x)) +} + +// SetVersion sets the X509 version of the certificate. +func (c *Certificate) SetVersion(version X509_Version) error { + cvers := C.long(version) + if C.X_X509_set_version(c.x, cvers) != 1 { + return errors.New("failed to set certificate version") + } + return nil +} diff --git a/vendor/github.com/libp2p/go-openssl/ciphers.go b/vendor/github.com/libp2p/go-openssl/ciphers.go new file mode 100644 index 0000000000..509bf6410f --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/ciphers.go @@ -0,0 +1,335 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "fmt" + "runtime" + "unsafe" +) + +const ( + GCM_TAG_MAXLEN = 16 +) + +type CipherCtx interface { + Cipher() *Cipher + BlockSize() int + KeySize() int + IVSize() int +} + +type Cipher struct { + ptr *C.EVP_CIPHER +} + +func (c *Cipher) Nid() NID { + return NID(C.X_EVP_CIPHER_nid(c.ptr)) +} + +func (c *Cipher) ShortName() (string, error) { + return Nid2ShortName(c.Nid()) +} + +func (c *Cipher) BlockSize() int { + return int(C.X_EVP_CIPHER_block_size(c.ptr)) +} + +func (c *Cipher) KeySize() int { + return int(C.X_EVP_CIPHER_key_length(c.ptr)) +} + +func (c *Cipher) IVSize() int { + return int(C.X_EVP_CIPHER_iv_length(c.ptr)) +} + +func Nid2ShortName(nid NID) (string, error) { + sn := C.OBJ_nid2sn(C.int(nid)) + if sn == nil { + return "", fmt.Errorf("NID %d not found", nid) + } + return C.GoString(sn), nil +} + +func GetCipherByName(name string) (*Cipher, error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + p := C.EVP_get_cipherbyname(cname) + if p == nil { + return nil, fmt.Errorf("Cipher %v not found", name) + } + // we can consider ciphers to use static mem; don't need to free + return &Cipher{ptr: p}, nil +} + +func GetCipherByNid(nid NID) (*Cipher, error) { + sn, err := Nid2ShortName(nid) + if err != nil { + return nil, err + } + return GetCipherByName(sn) +} + +type cipherCtx struct { + ctx *C.EVP_CIPHER_CTX +} + +func newCipherCtx() (*cipherCtx, error) { + cctx := C.EVP_CIPHER_CTX_new() + if cctx == nil { + return nil, errors.New("failed to allocate cipher context") + } + ctx := &cipherCtx{cctx} + runtime.SetFinalizer(ctx, func(ctx *cipherCtx) { + C.EVP_CIPHER_CTX_free(ctx.ctx) + }) + return ctx, nil +} + +func (ctx *cipherCtx) applyKeyAndIV(key, iv []byte) error { + var kptr, iptr *C.uchar + if key != nil { + if len(key) != ctx.KeySize() { + return fmt.Errorf("bad key size (%d bytes instead of %d)", + len(key), ctx.KeySize()) + } + kptr = (*C.uchar)(&key[0]) + } + if iv != nil { + if len(iv) != ctx.IVSize() { + return fmt.Errorf("bad IV size (%d bytes instead of %d)", + len(iv), ctx.IVSize()) + } + iptr = (*C.uchar)(&iv[0]) + } + if kptr != nil || iptr != nil { + var res C.int + if C.X_EVP_CIPHER_CTX_encrypting(ctx.ctx) != 0 { + res = C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, kptr, iptr) + } else { + res = C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, kptr, iptr) + } + if 1 != res { + return errors.New("failed to apply key/IV") + } + } + return nil +} + +func (ctx *cipherCtx) Cipher() *Cipher { + return &Cipher{ptr: C.X_EVP_CIPHER_CTX_cipher(ctx.ctx)} +} + +func (ctx *cipherCtx) BlockSize() int { + return int(C.X_EVP_CIPHER_CTX_block_size(ctx.ctx)) +} + +func (ctx *cipherCtx) KeySize() int { + return int(C.X_EVP_CIPHER_CTX_key_length(ctx.ctx)) +} + +func (ctx *cipherCtx) IVSize() int { + return int(C.X_EVP_CIPHER_CTX_iv_length(ctx.ctx)) +} + +func (ctx *cipherCtx) SetPadding(pad bool) { + if pad { + C.X_EVP_CIPHER_CTX_set_padding(ctx.ctx, 1) + } else { + C.X_EVP_CIPHER_CTX_set_padding(ctx.ctx, 0) + } +} + +func (ctx *cipherCtx) setCtrl(code, arg int) error { + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), nil) + if res != 1 { + return fmt.Errorf("failed to set code %d to %d [result %d]", + code, arg, res) + } + return nil +} + +func (ctx *cipherCtx) setCtrlBytes(code, arg int, value []byte) error { + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), + unsafe.Pointer(&value[0])) + if res != 1 { + return fmt.Errorf("failed to set code %d with arg %d to %x [result %d]", + code, arg, value, res) + } + return nil +} + +func (ctx *cipherCtx) getCtrlInt(code, arg int) (int, error) { + var returnVal C.int + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), + unsafe.Pointer(&returnVal)) + if res != 1 { + return 0, fmt.Errorf("failed to get code %d with arg %d [result %d]", + code, arg, res) + } + return int(returnVal), nil +} + +func (ctx *cipherCtx) getCtrlBytes(code, arg, expectsize int) ([]byte, error) { + returnVal := make([]byte, expectsize) + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), + unsafe.Pointer(&returnVal[0])) + if res != 1 { + return nil, fmt.Errorf("failed to get code %d with arg %d [result %d]", + code, arg, res) + } + return returnVal, nil +} + +type EncryptionCipherCtx interface { + CipherCtx + + // pass in plaintext, get back ciphertext. can be called + // multiple times as needed + EncryptUpdate(input []byte) ([]byte, error) + + // call after all plaintext has been passed in; may return + // additional ciphertext if needed to finish off a block + // or extra padding information + EncryptFinal() ([]byte, error) +} + +type DecryptionCipherCtx interface { + CipherCtx + + // pass in ciphertext, get back plaintext. can be called + // multiple times as needed + DecryptUpdate(input []byte) ([]byte, error) + + // call after all ciphertext has been passed in; may return + // additional plaintext if needed to finish off a block + DecryptFinal() ([]byte, error) +} + +type encryptionCipherCtx struct { + *cipherCtx +} + +type decryptionCipherCtx struct { + *cipherCtx +} + +func newEncryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + *encryptionCipherCtx, error) { + if c == nil { + return nil, errors.New("null cipher not allowed") + } + ctx, err := newCipherCtx() + if err != nil { + return nil, err + } + var eptr *C.ENGINE + if e != nil { + eptr = e.e + } + if 1 != C.EVP_EncryptInit_ex(ctx.ctx, c.ptr, eptr, nil, nil) { + return nil, errors.New("failed to initialize cipher context") + } + err = ctx.applyKeyAndIV(key, iv) + if err != nil { + return nil, err + } + return &encryptionCipherCtx{cipherCtx: ctx}, nil +} + +func newDecryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + *decryptionCipherCtx, error) { + if c == nil { + return nil, errors.New("null cipher not allowed") + } + ctx, err := newCipherCtx() + if err != nil { + return nil, err + } + var eptr *C.ENGINE + if e != nil { + eptr = e.e + } + if 1 != C.EVP_DecryptInit_ex(ctx.ctx, c.ptr, eptr, nil, nil) { + return nil, errors.New("failed to initialize cipher context") + } + err = ctx.applyKeyAndIV(key, iv) + if err != nil { + return nil, err + } + return &decryptionCipherCtx{cipherCtx: ctx}, nil +} + +func NewEncryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + EncryptionCipherCtx, error) { + return newEncryptionCipherCtx(c, e, key, iv) +} + +func NewDecryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + DecryptionCipherCtx, error) { + return newDecryptionCipherCtx(c, e, key, iv) +} + +func (ctx *encryptionCipherCtx) EncryptUpdate(input []byte) ([]byte, error) { + if len(input) == 0 { + return nil, nil + } + outbuf := make([]byte, len(input)+ctx.BlockSize()) + outlen := C.int(len(outbuf)) + res := C.EVP_EncryptUpdate(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen, + (*C.uchar)(&input[0]), C.int(len(input))) + if res != 1 { + return nil, fmt.Errorf("failed to encrypt [result %d]", res) + } + return outbuf[:outlen], nil +} + +func (ctx *decryptionCipherCtx) DecryptUpdate(input []byte) ([]byte, error) { + if len(input) == 0 { + return nil, nil + } + outbuf := make([]byte, len(input)+ctx.BlockSize()) + outlen := C.int(len(outbuf)) + res := C.EVP_DecryptUpdate(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen, + (*C.uchar)(&input[0]), C.int(len(input))) + if res != 1 { + return nil, fmt.Errorf("failed to decrypt [result %d]", res) + } + return outbuf[:outlen], nil +} + +func (ctx *encryptionCipherCtx) EncryptFinal() ([]byte, error) { + outbuf := make([]byte, ctx.BlockSize()) + var outlen C.int + if 1 != C.EVP_EncryptFinal_ex(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen) { + return nil, errors.New("encryption failed") + } + return outbuf[:outlen], nil +} + +func (ctx *decryptionCipherCtx) DecryptFinal() ([]byte, error) { + outbuf := make([]byte, ctx.BlockSize()) + var outlen C.int + if 1 != C.EVP_DecryptFinal_ex(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen) { + // this may mean the tag failed to verify- all previous plaintext + // returned must be considered faked and invalid + return nil, errors.New("decryption failed") + } + return outbuf[:outlen], nil +} diff --git a/vendor/github.com/libp2p/go-openssl/ciphers_gcm.go b/vendor/github.com/libp2p/go-openssl/ciphers_gcm.go new file mode 100644 index 0000000000..7b08e0fd99 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/ciphers_gcm.go @@ -0,0 +1,152 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include +import "C" + +import ( + "errors" + "fmt" +) + +type AuthenticatedEncryptionCipherCtx interface { + EncryptionCipherCtx + + // data passed in to ExtraData() is part of the final output; it is + // not encrypted itself, but is part of the authenticated data. when + // decrypting or authenticating, pass back with the decryption + // context's ExtraData() + ExtraData([]byte) error + + // use after finalizing encryption to get the authenticating tag + GetTag() ([]byte, error) +} + +type AuthenticatedDecryptionCipherCtx interface { + DecryptionCipherCtx + + // pass in any extra data that was added during encryption with the + // encryption context's ExtraData() + ExtraData([]byte) error + + // use before finalizing decryption to tell the library what the + // tag is expected to be + SetTag([]byte) error +} + +type authEncryptionCipherCtx struct { + *encryptionCipherCtx +} + +type authDecryptionCipherCtx struct { + *decryptionCipherCtx +} + +func getGCMCipher(blocksize int) (*Cipher, error) { + var cipherptr *C.EVP_CIPHER + switch blocksize { + case 256: + cipherptr = C.EVP_aes_256_gcm() + case 192: + cipherptr = C.EVP_aes_192_gcm() + case 128: + cipherptr = C.EVP_aes_128_gcm() + default: + return nil, fmt.Errorf("unknown block size %d", blocksize) + } + return &Cipher{ptr: cipherptr}, nil +} + +func NewGCMEncryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( + AuthenticatedEncryptionCipherCtx, error) { + cipher, err := getGCMCipher(blocksize) + if err != nil { + return nil, err + } + ctx, err := newEncryptionCipherCtx(cipher, e, key, nil) + if err != nil { + return nil, err + } + if len(iv) > 0 { + err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) + if err != nil { + return nil, fmt.Errorf("could not set IV len to %d: %s", + len(iv), err) + } + if 1 != C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, nil, + (*C.uchar)(&iv[0])) { + return nil, errors.New("failed to apply IV") + } + } + return &authEncryptionCipherCtx{encryptionCipherCtx: ctx}, nil +} + +func NewGCMDecryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( + AuthenticatedDecryptionCipherCtx, error) { + cipher, err := getGCMCipher(blocksize) + if err != nil { + return nil, err + } + ctx, err := newDecryptionCipherCtx(cipher, e, key, nil) + if err != nil { + return nil, err + } + if len(iv) > 0 { + err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) + if err != nil { + return nil, fmt.Errorf("could not set IV len to %d: %s", + len(iv), err) + } + if 1 != C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, nil, + (*C.uchar)(&iv[0])) { + return nil, errors.New("failed to apply IV") + } + } + return &authDecryptionCipherCtx{decryptionCipherCtx: ctx}, nil +} + +func (ctx *authEncryptionCipherCtx) ExtraData(aad []byte) error { + if aad == nil { + return nil + } + var outlen C.int + if 1 != C.EVP_EncryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), + C.int(len(aad))) { + return errors.New("failed to add additional authenticated data") + } + return nil +} + +func (ctx *authDecryptionCipherCtx) ExtraData(aad []byte) error { + if aad == nil { + return nil + } + var outlen C.int + if 1 != C.EVP_DecryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), + C.int(len(aad))) { + return errors.New("failed to add additional authenticated data") + } + return nil +} + +func (ctx *authEncryptionCipherCtx) GetTag() ([]byte, error) { + return ctx.getCtrlBytes(C.EVP_CTRL_GCM_GET_TAG, GCM_TAG_MAXLEN, + GCM_TAG_MAXLEN) +} + +func (ctx *authDecryptionCipherCtx) SetTag(tag []byte) error { + return ctx.setCtrlBytes(C.EVP_CTRL_GCM_SET_TAG, len(tag), tag) +} diff --git a/vendor/github.com/libp2p/go-openssl/conn.go b/vendor/github.com/libp2p/go-openssl/conn.go new file mode 100644 index 0000000000..2758034193 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/conn.go @@ -0,0 +1,620 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "fmt" + "io" + "net" + "runtime" + "sync" + "time" + "unsafe" + + "github.com/libp2p/go-openssl/utils" +) + +var ( + zeroReturn = errors.New("zero return") + wantRead = errors.New("want read") + wantWrite = errors.New("want write") + tryAgain = errors.New("try again") +) + +type Conn struct { + *SSL + + conn net.Conn + ctx *Ctx // for gc + into_ssl *readBio + from_ssl *writeBio + is_shutdown bool + mtx sync.Mutex + want_read_future *utils.Future +} + +type VerifyResult int + +const ( + Ok VerifyResult = C.X509_V_OK + UnableToGetIssuerCert VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT + UnableToGetCrl VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_CRL + UnableToDecryptCertSignature VerifyResult = C.X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE + UnableToDecryptCrlSignature VerifyResult = C.X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE + UnableToDecodeIssuerPublicKey VerifyResult = C.X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY + CertSignatureFailure VerifyResult = C.X509_V_ERR_CERT_SIGNATURE_FAILURE + CrlSignatureFailure VerifyResult = C.X509_V_ERR_CRL_SIGNATURE_FAILURE + CertNotYetValid VerifyResult = C.X509_V_ERR_CERT_NOT_YET_VALID + CertHasExpired VerifyResult = C.X509_V_ERR_CERT_HAS_EXPIRED + CrlNotYetValid VerifyResult = C.X509_V_ERR_CRL_NOT_YET_VALID + CrlHasExpired VerifyResult = C.X509_V_ERR_CRL_HAS_EXPIRED + ErrorInCertNotBeforeField VerifyResult = C.X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD + ErrorInCertNotAfterField VerifyResult = C.X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD + ErrorInCrlLastUpdateField VerifyResult = C.X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD + ErrorInCrlNextUpdateField VerifyResult = C.X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD + OutOfMem VerifyResult = C.X509_V_ERR_OUT_OF_MEM + DepthZeroSelfSignedCert VerifyResult = C.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT + SelfSignedCertInChain VerifyResult = C.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN + UnableToGetIssuerCertLocally VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY + UnableToVerifyLeafSignature VerifyResult = C.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE + CertChainTooLong VerifyResult = C.X509_V_ERR_CERT_CHAIN_TOO_LONG + CertRevoked VerifyResult = C.X509_V_ERR_CERT_REVOKED + InvalidCa VerifyResult = C.X509_V_ERR_INVALID_CA + PathLengthExceeded VerifyResult = C.X509_V_ERR_PATH_LENGTH_EXCEEDED + InvalidPurpose VerifyResult = C.X509_V_ERR_INVALID_PURPOSE + CertUntrusted VerifyResult = C.X509_V_ERR_CERT_UNTRUSTED + CertRejected VerifyResult = C.X509_V_ERR_CERT_REJECTED + SubjectIssuerMismatch VerifyResult = C.X509_V_ERR_SUBJECT_ISSUER_MISMATCH + AkidSkidMismatch VerifyResult = C.X509_V_ERR_AKID_SKID_MISMATCH + AkidIssuerSerialMismatch VerifyResult = C.X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH + KeyusageNoCertsign VerifyResult = C.X509_V_ERR_KEYUSAGE_NO_CERTSIGN + UnableToGetCrlIssuer VerifyResult = C.X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER + UnhandledCriticalExtension VerifyResult = C.X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION + KeyusageNoCrlSign VerifyResult = C.X509_V_ERR_KEYUSAGE_NO_CRL_SIGN + UnhandledCriticalCrlExtension VerifyResult = C.X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION + InvalidNonCa VerifyResult = C.X509_V_ERR_INVALID_NON_CA + ProxyPathLengthExceeded VerifyResult = C.X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED + KeyusageNoDigitalSignature VerifyResult = C.X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE + ProxyCertificatesNotAllowed VerifyResult = C.X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED + InvalidExtension VerifyResult = C.X509_V_ERR_INVALID_EXTENSION + InvalidPolicyExtension VerifyResult = C.X509_V_ERR_INVALID_POLICY_EXTENSION + NoExplicitPolicy VerifyResult = C.X509_V_ERR_NO_EXPLICIT_POLICY + UnnestedResource VerifyResult = C.X509_V_ERR_UNNESTED_RESOURCE + ApplicationVerification VerifyResult = C.X509_V_ERR_APPLICATION_VERIFICATION +) + +func newSSL(ctx *C.SSL_CTX) (*C.SSL, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ssl := C.SSL_new(ctx) + if ssl == nil { + return nil, errorFromErrorQueue() + } + return ssl, nil +} + +func newConn(conn net.Conn, ctx *Ctx) (*Conn, error) { + ssl, err := newSSL(ctx.ctx) + if err != nil { + return nil, err + } + + into_ssl := &readBio{} + from_ssl := &writeBio{} + + if ctx.GetMode()&ReleaseBuffers > 0 { + into_ssl.release_buffers = true + from_ssl.release_buffers = true + } + + into_ssl_cbio := into_ssl.MakeCBIO() + from_ssl_cbio := from_ssl.MakeCBIO() + if into_ssl_cbio == nil || from_ssl_cbio == nil { + // these frees are null safe + C.BIO_free(into_ssl_cbio) + C.BIO_free(from_ssl_cbio) + C.SSL_free(ssl) + return nil, errors.New("failed to allocate memory BIO") + } + + // the ssl object takes ownership of these objects now + C.SSL_set_bio(ssl, into_ssl_cbio, from_ssl_cbio) + + s := &SSL{ssl: ssl} + C.SSL_set_ex_data(s.ssl, get_ssl_idx(), unsafe.Pointer(s)) + + c := &Conn{ + SSL: s, + + conn: conn, + ctx: ctx, + into_ssl: into_ssl, + from_ssl: from_ssl} + runtime.SetFinalizer(c, func(c *Conn) { + c.into_ssl.Disconnect(into_ssl_cbio) + c.from_ssl.Disconnect(from_ssl_cbio) + C.SSL_free(c.ssl) + }) + return c, nil +} + +// Client wraps an existing stream connection and puts it in the connect state +// for any subsequent handshakes. +// +// IMPORTANT NOTE: if you use this method instead of Dial to construct an SSL +// connection, you are responsible for verifying the peer's hostname. +// Otherwise, you are vulnerable to MITM attacks. +// +// Client also does not set up SNI for you like Dial does. +// +// Client connections probably won't work for you unless you set a verify +// location or add some certs to the certificate store of the client context +// you're using. This library is not nice enough to use the system certificate +// store by default for you yet. +func Client(conn net.Conn, ctx *Ctx) (*Conn, error) { + c, err := newConn(conn, ctx) + if err != nil { + return nil, err + } + C.SSL_set_connect_state(c.ssl) + return c, nil +} + +// Server wraps an existing stream connection and puts it in the accept state +// for any subsequent handshakes. +func Server(conn net.Conn, ctx *Ctx) (*Conn, error) { + c, err := newConn(conn, ctx) + if err != nil { + return nil, err + } + C.SSL_set_accept_state(c.ssl) + return c, nil +} + +func (c *Conn) GetCtx() *Ctx { return c.ctx } + +func (c *Conn) CurrentCipher() (string, error) { + p := C.X_SSL_get_cipher_name(c.ssl) + if p == nil { + return "", errors.New("Session not established") + } + + return C.GoString(p), nil +} + +func (c *Conn) fillInputBuffer() error { + for { + n, err := c.into_ssl.ReadFromOnce(c.conn) + if n == 0 && err == nil { + continue + } + if err == io.EOF { + c.into_ssl.MarkEOF() + return c.Close() + } + return err + } +} + +func (c *Conn) flushOutputBuffer() error { + _, err := c.from_ssl.WriteTo(c.conn) + return err +} + +func (c *Conn) getErrorHandler(rv C.int, errno error) func() error { + errcode := C.SSL_get_error(c.ssl, rv) + switch errcode { + case C.SSL_ERROR_ZERO_RETURN: + return func() error { + c.Close() + return io.ErrUnexpectedEOF + } + case C.SSL_ERROR_WANT_READ: + go c.flushOutputBuffer() + if c.want_read_future != nil { + want_read_future := c.want_read_future + return func() error { + _, err := want_read_future.Get() + return err + } + } + c.want_read_future = utils.NewFuture() + want_read_future := c.want_read_future + return func() (err error) { + defer func() { + c.mtx.Lock() + c.want_read_future = nil + c.mtx.Unlock() + want_read_future.Set(nil, err) + }() + err = c.fillInputBuffer() + if err != nil { + return err + } + return tryAgain + } + case C.SSL_ERROR_WANT_WRITE: + return func() error { + err := c.flushOutputBuffer() + if err != nil { + return err + } + return tryAgain + } + case C.SSL_ERROR_SYSCALL: + var err error + if C.ERR_peek_error() == 0 { + switch rv { + case 0: + err = errors.New("protocol-violating EOF") + case -1: + err = errno + default: + err = errorFromErrorQueue() + } + } else { + err = errorFromErrorQueue() + } + return func() error { return err } + default: + err := errorFromErrorQueue() + return func() error { return err } + } +} + +func (c *Conn) handleError(errcb func() error) error { + if errcb != nil { + return errcb() + } + return nil +} + +func (c *Conn) handshake() func() error { + c.mtx.Lock() + defer c.mtx.Unlock() + if c.is_shutdown { + return func() error { return io.ErrUnexpectedEOF } + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + rv, errno := C.SSL_do_handshake(c.ssl) + if rv > 0 { + return nil + } + return c.getErrorHandler(rv, errno) +} + +// Handshake performs an SSL handshake. If a handshake is not manually +// triggered, it will run before the first I/O on the encrypted stream. +func (c *Conn) Handshake() error { + err := tryAgain + for err == tryAgain { + err = c.handleError(c.handshake()) + } + go c.flushOutputBuffer() + return err +} + +// PeerCertificate returns the Certificate of the peer with which you're +// communicating. Only valid after a handshake. +func (c *Conn) PeerCertificate() (*Certificate, error) { + c.mtx.Lock() + defer c.mtx.Unlock() + if c.is_shutdown { + return nil, errors.New("connection closed") + } + x := C.SSL_get_peer_certificate(c.ssl) + if x == nil { + return nil, errors.New("no peer certificate found") + } + cert := &Certificate{x: x} + runtime.SetFinalizer(cert, func(cert *Certificate) { + C.X509_free(cert.x) + }) + return cert, nil +} + +// loadCertificateStack loads up a stack of x509 certificates and returns them, +// handling memory ownership. +func (c *Conn) loadCertificateStack(sk *C.struct_stack_st_X509) ( + rv []*Certificate) { + + sk_num := int(C.X_sk_X509_num(sk)) + rv = make([]*Certificate, 0, sk_num) + for i := 0; i < sk_num; i++ { + x := C.X_sk_X509_value(sk, C.int(i)) + // ref holds on to the underlying connection memory so we don't need to + // worry about incrementing refcounts manually or freeing the X509 + rv = append(rv, &Certificate{x: x, ref: c}) + } + return rv +} + +// PeerCertificateChain returns the certificate chain of the peer. If called on +// the client side, the stack also contains the peer's certificate; if called +// on the server side, the peer's certificate must be obtained separately using +// PeerCertificate. +func (c *Conn) PeerCertificateChain() (rv []*Certificate, err error) { + c.mtx.Lock() + defer c.mtx.Unlock() + if c.is_shutdown { + return nil, errors.New("connection closed") + } + sk := C.SSL_get_peer_cert_chain(c.ssl) + if sk == nil { + return nil, errors.New("no peer certificates found") + } + return c.loadCertificateStack(sk), nil +} + +type ConnectionState struct { + Certificate *Certificate + CertificateError error + CertificateChain []*Certificate + CertificateChainError error + SessionReused bool +} + +func (c *Conn) ConnectionState() (rv ConnectionState) { + rv.Certificate, rv.CertificateError = c.PeerCertificate() + rv.CertificateChain, rv.CertificateChainError = c.PeerCertificateChain() + rv.SessionReused = c.SessionReused() + return +} + +func (c *Conn) shutdown() func() error { + c.mtx.Lock() + defer c.mtx.Unlock() + runtime.LockOSThread() + defer runtime.UnlockOSThread() + rv, errno := C.SSL_shutdown(c.ssl) + if rv > 0 { + return nil + } + if rv == 0 { + // The OpenSSL docs say that in this case, the shutdown is not + // finished, and we should call SSL_shutdown() a second time, if a + // bidirectional shutdown is going to be performed. Further, the + // output of SSL_get_error may be misleading, as an erroneous + // SSL_ERROR_SYSCALL may be flagged even though no error occurred. + // So, TODO: revisit bidrectional shutdown, possibly trying again. + // Note: some broken clients won't engage in bidirectional shutdown + // without tickling them to close by sending a TCP_FIN packet, or + // shutting down the write-side of the connection. + return nil + } else { + return c.getErrorHandler(rv, errno) + } +} + +func (c *Conn) shutdownLoop() error { + err := tryAgain + shutdown_tries := 0 + for err == tryAgain { + shutdown_tries = shutdown_tries + 1 + err = c.handleError(c.shutdown()) + if err == nil { + return c.flushOutputBuffer() + } + if err == tryAgain && shutdown_tries >= 2 { + return errors.New("shutdown requested a third time?") + } + } + if err == io.ErrUnexpectedEOF { + err = nil + } + return err +} + +// Close shuts down the SSL connection and closes the underlying wrapped +// connection. +func (c *Conn) Close() error { + c.mtx.Lock() + if c.is_shutdown { + c.mtx.Unlock() + return nil + } + c.is_shutdown = true + c.mtx.Unlock() + var errs utils.ErrorGroup + errs.Add(c.shutdownLoop()) + errs.Add(c.conn.Close()) + return errs.Finalize() +} + +func (c *Conn) read(b []byte) (int, func() error) { + if len(b) == 0 { + return 0, nil + } + c.mtx.Lock() + defer c.mtx.Unlock() + if c.is_shutdown { + return 0, func() error { return io.EOF } + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + rv, errno := C.SSL_read(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b))) + if rv > 0 { + return int(rv), nil + } + return 0, c.getErrorHandler(rv, errno) +} + +// Read reads up to len(b) bytes into b. It returns the number of bytes read +// and an error if applicable. io.EOF is returned when the caller can expect +// to see no more data. +func (c *Conn) Read(b []byte) (n int, err error) { + if len(b) == 0 { + return 0, nil + } + err = tryAgain + for err == tryAgain { + n, errcb := c.read(b) + err = c.handleError(errcb) + if err == nil { + go c.flushOutputBuffer() + return n, nil + } + if err == io.ErrUnexpectedEOF { + err = io.EOF + } + } + return 0, err +} + +func (c *Conn) write(b []byte) (int, func() error) { + if len(b) == 0 { + return 0, nil + } + c.mtx.Lock() + defer c.mtx.Unlock() + if c.is_shutdown { + err := errors.New("connection closed") + return 0, func() error { return err } + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + rv, errno := C.SSL_write(c.ssl, unsafe.Pointer(&b[0]), C.int(len(b))) + if rv > 0 { + return int(rv), nil + } + return 0, c.getErrorHandler(rv, errno) +} + +// Write will encrypt the contents of b and write it to the underlying stream. +// Performance will be vastly improved if the size of b is a multiple of +// SSLRecordSize. +func (c *Conn) Write(b []byte) (written int, err error) { + if len(b) == 0 { + return 0, nil + } + err = tryAgain + for err == tryAgain { + n, errcb := c.write(b) + err = c.handleError(errcb) + if err == nil { + return n, c.flushOutputBuffer() + } + } + return 0, err +} + +// VerifyHostname pulls the PeerCertificate and calls VerifyHostname on the +// certificate. +func (c *Conn) VerifyHostname(host string) error { + cert, err := c.PeerCertificate() + if err != nil { + return err + } + return cert.VerifyHostname(host) +} + +// LocalAddr returns the underlying connection's local address +func (c *Conn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +// RemoteAddr returns the underlying connection's remote address +func (c *Conn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +// SetDeadline calls SetDeadline on the underlying connection. +func (c *Conn) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} + +// SetReadDeadline calls SetReadDeadline on the underlying connection. +func (c *Conn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +// SetWriteDeadline calls SetWriteDeadline on the underlying connection. +func (c *Conn) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +} + +func (c *Conn) UnderlyingConn() net.Conn { + return c.conn +} + +func (c *Conn) SetTlsExtHostName(name string) error { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if C.X_SSL_set_tlsext_host_name(c.ssl, cname) == 0 { + return errorFromErrorQueue() + } + return nil +} + +func (c *Conn) VerifyResult() VerifyResult { + return VerifyResult(C.SSL_get_verify_result(c.ssl)) +} + +func (c *Conn) SessionReused() bool { + return C.X_SSL_session_reused(c.ssl) == 1 +} + +func (c *Conn) GetSession() ([]byte, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // get1 increases the refcount of the session, so we have to free it. + session := (*C.SSL_SESSION)(C.SSL_get1_session(c.ssl)) + if session == nil { + return nil, errors.New("failed to get session") + } + defer C.SSL_SESSION_free(session) + + // get the size of the encoding + slen := C.i2d_SSL_SESSION(session, nil) + + buf := (*C.uchar)(C.malloc(C.size_t(slen))) + defer C.free(unsafe.Pointer(buf)) + + // this modifies the value of buf (seriously), so we have to pass in a temp + // var so that we can actually read the bytes from buf. + tmp := buf + slen2 := C.i2d_SSL_SESSION(session, &tmp) + if slen != slen2 { + return nil, errors.New("session had different lengths") + } + + return C.GoBytes(unsafe.Pointer(buf), slen), nil +} + +func (c *Conn) setSession(session []byte) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ptr := (*C.uchar)(&session[0]) + s := C.d2i_SSL_SESSION(nil, &ptr, C.long(len(session))) + if s == nil { + return fmt.Errorf("unable to load session: %s", errorFromErrorQueue()) + } + defer C.SSL_SESSION_free(s) + + ret := C.SSL_set_session(c.ssl, s) + if ret != 1 { + return fmt.Errorf("unable to set session: %s", errorFromErrorQueue()) + } + return nil +} diff --git a/vendor/github.com/libp2p/go-openssl/ctx.go b/vendor/github.com/libp2p/go-openssl/ctx.go new file mode 100644 index 0000000000..33befc401e --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/ctx.go @@ -0,0 +1,568 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "runtime" + "sync" + "time" + "unsafe" + + "github.com/spacemonkeygo/spacelog" +) + +var ( + ssl_ctx_idx = C.X_SSL_CTX_new_index() + + logger = spacelog.GetLogger() +) + +type Ctx struct { + ctx *C.SSL_CTX + cert *Certificate + chain []*Certificate + key PrivateKey + verify_cb VerifyCallback + sni_cb TLSExtServernameCallback + + ticket_store_mu sync.Mutex + ticket_store *TicketStore +} + +//export get_ssl_ctx_idx +func get_ssl_ctx_idx() C.int { + return ssl_ctx_idx +} + +func newCtx(method *C.SSL_METHOD) (*Ctx, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ctx := C.SSL_CTX_new(method) + if ctx == nil { + return nil, errorFromErrorQueue() + } + c := &Ctx{ctx: ctx} + C.SSL_CTX_set_ex_data(ctx, get_ssl_ctx_idx(), unsafe.Pointer(c)) + runtime.SetFinalizer(c, func(c *Ctx) { + C.SSL_CTX_free(c.ctx) + }) + return c, nil +} + +type SSLVersion int + +const ( + SSLv3 SSLVersion = 0x02 // Vulnerable to "POODLE" attack. + TLSv1 SSLVersion = 0x03 + TLSv1_1 SSLVersion = 0x04 + TLSv1_2 SSLVersion = 0x05 + + // Make sure to disable SSLv2 and SSLv3 if you use this. SSLv3 is vulnerable + // to the "POODLE" attack, and SSLv2 is what, just don't even. + AnyVersion SSLVersion = 0x06 +) + +// NewCtxWithVersion creates an SSL context that is specific to the provided +// SSL version. See http://www.openssl.org/docs/ssl/SSL_CTX_new.html for more. +func NewCtxWithVersion(version SSLVersion) (*Ctx, error) { + var method *C.SSL_METHOD + switch version { + case SSLv3: + method = C.X_SSLv3_method() + case TLSv1: + method = C.X_TLSv1_method() + case TLSv1_1: + method = C.X_TLSv1_1_method() + case TLSv1_2: + method = C.X_TLSv1_2_method() + case AnyVersion: + method = C.X_SSLv23_method() + } + if method == nil { + return nil, errors.New("unknown ssl/tls version") + } + return newCtx(method) +} + +// NewCtx creates a context that supports any TLS version 1.0 and newer. +func NewCtx() (*Ctx, error) { + c, err := NewCtxWithVersion(AnyVersion) + if err == nil { + c.SetOptions(NoSSLv2 | NoSSLv3) + } + return c, err +} + +// NewCtxFromFiles calls NewCtx, loads the provided files, and configures the +// context to use them. +func NewCtxFromFiles(cert_file string, key_file string) (*Ctx, error) { + ctx, err := NewCtx() + if err != nil { + return nil, err + } + + cert_bytes, err := ioutil.ReadFile(cert_file) + if err != nil { + return nil, err + } + + certs := SplitPEM(cert_bytes) + if len(certs) == 0 { + return nil, fmt.Errorf("No PEM certificate found in '%s'", cert_file) + } + first, certs := certs[0], certs[1:] + cert, err := LoadCertificateFromPEM(first) + if err != nil { + return nil, err + } + + err = ctx.UseCertificate(cert) + if err != nil { + return nil, err + } + + for _, pem := range certs { + cert, err := LoadCertificateFromPEM(pem) + if err != nil { + return nil, err + } + err = ctx.AddChainCertificate(cert) + if err != nil { + return nil, err + } + } + + key_bytes, err := ioutil.ReadFile(key_file) + if err != nil { + return nil, err + } + + key, err := LoadPrivateKeyFromPEM(key_bytes) + if err != nil { + return nil, err + } + + err = ctx.UsePrivateKey(key) + if err != nil { + return nil, err + } + + return ctx, nil +} + +// EllipticCurve repesents the ASN.1 OID of an elliptic curve. +// see https://www.openssl.org/docs/apps/ecparam.html for a list of implemented curves. +type EllipticCurve int + +const ( + // P-256: X9.62/SECG curve over a 256 bit prime field + Prime256v1 EllipticCurve = C.NID_X9_62_prime256v1 + // P-384: NIST/SECG curve over a 384 bit prime field + Secp384r1 EllipticCurve = C.NID_secp384r1 + // P-521: NIST/SECG curve over a 521 bit prime field + Secp521r1 EllipticCurve = C.NID_secp521r1 +) + +// SetEllipticCurve sets the elliptic curve used by the SSL context to +// enable an ECDH cipher suite to be selected during the handshake. +func (c *Ctx) SetEllipticCurve(curve EllipticCurve) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + k := C.EC_KEY_new_by_curve_name(C.int(curve)) + if k == nil { + return errors.New("Unknown curve") + } + defer C.EC_KEY_free(k) + + if int(C.X_SSL_CTX_set_tmp_ecdh(c.ctx, k)) != 1 { + return errorFromErrorQueue() + } + + return nil +} + +// UseCertificate configures the context to present the given certificate to +// peers. +func (c *Ctx) UseCertificate(cert *Certificate) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + c.cert = cert + if int(C.SSL_CTX_use_certificate(c.ctx, cert.x)) != 1 { + return errorFromErrorQueue() + } + return nil +} + +// AddChainCertificate adds a certificate to the chain presented in the +// handshake. +func (c *Ctx) AddChainCertificate(cert *Certificate) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + c.chain = append(c.chain, cert) + if int(C.X_SSL_CTX_add_extra_chain_cert(c.ctx, cert.x)) != 1 { + return errorFromErrorQueue() + } + // OpenSSL takes ownership via SSL_CTX_add_extra_chain_cert + runtime.SetFinalizer(cert, nil) + return nil +} + +// UsePrivateKey configures the context to use the given private key for SSL +// handshakes. +func (c *Ctx) UsePrivateKey(key PrivateKey) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + c.key = key + if int(C.SSL_CTX_use_PrivateKey(c.ctx, key.evpPKey())) != 1 { + return errorFromErrorQueue() + } + return nil +} + +type CertificateStore struct { + store *C.X509_STORE + // for GC + ctx *Ctx + certs []*Certificate +} + +// Allocate a new, empty CertificateStore +func NewCertificateStore() (*CertificateStore, error) { + s := C.X509_STORE_new() + if s == nil { + return nil, errors.New("failed to allocate X509_STORE") + } + store := &CertificateStore{store: s} + runtime.SetFinalizer(store, func(s *CertificateStore) { + C.X509_STORE_free(s.store) + }) + return store, nil +} + +// Parse a chained PEM file, loading all certificates into the Store. +func (s *CertificateStore) LoadCertificatesFromPEM(data []byte) error { + pems := SplitPEM(data) + for _, pem := range pems { + cert, err := LoadCertificateFromPEM(pem) + if err != nil { + return err + } + err = s.AddCertificate(cert) + if err != nil { + return err + } + } + return nil +} + +// GetCertificateStore returns the context's certificate store that will be +// used for peer validation. +func (c *Ctx) GetCertificateStore() *CertificateStore { + // we don't need to dealloc the cert store pointer here, because it points + // to a ctx internal. so we do need to keep the ctx around + return &CertificateStore{ + store: C.SSL_CTX_get_cert_store(c.ctx), + ctx: c} +} + +// AddCertificate marks the provided Certificate as a trusted certificate in +// the given CertificateStore. +func (s *CertificateStore) AddCertificate(cert *Certificate) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + s.certs = append(s.certs, cert) + if int(C.X509_STORE_add_cert(s.store, cert.x)) != 1 { + return errorFromErrorQueue() + } + return nil +} + +type CertificateStoreCtx struct { + ctx *C.X509_STORE_CTX + ssl_ctx *Ctx +} + +func (self *CertificateStoreCtx) VerifyResult() VerifyResult { + return VerifyResult(C.X509_STORE_CTX_get_error(self.ctx)) +} + +func (self *CertificateStoreCtx) Err() error { + code := C.X509_STORE_CTX_get_error(self.ctx) + if code == C.X509_V_OK { + return nil + } + return fmt.Errorf("openssl: %s", + C.GoString(C.X509_verify_cert_error_string(C.long(code)))) +} + +func (self *CertificateStoreCtx) Depth() int { + return int(C.X509_STORE_CTX_get_error_depth(self.ctx)) +} + +// the certicate returned is only valid for the lifetime of the underlying +// X509_STORE_CTX +func (self *CertificateStoreCtx) GetCurrentCert() *Certificate { + x509 := C.X509_STORE_CTX_get_current_cert(self.ctx) + if x509 == nil { + return nil + } + // add a ref + if 1 != C.X_X509_add_ref(x509) { + return nil + } + cert := &Certificate{ + x: x509, + } + runtime.SetFinalizer(cert, func(cert *Certificate) { + C.X509_free(cert.x) + }) + return cert +} + +// LoadVerifyLocations tells the context to trust all certificate authorities +// provided in either the ca_file or the ca_path. +// See http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html for +// more. +func (c *Ctx) LoadVerifyLocations(ca_file string, ca_path string) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + var c_ca_file, c_ca_path *C.char + if ca_file != "" { + c_ca_file = C.CString(ca_file) + defer C.free(unsafe.Pointer(c_ca_file)) + } + if ca_path != "" { + c_ca_path = C.CString(ca_path) + defer C.free(unsafe.Pointer(c_ca_path)) + } + if C.SSL_CTX_load_verify_locations(c.ctx, c_ca_file, c_ca_path) != 1 { + return errorFromErrorQueue() + } + return nil +} + +type Options int + +const ( + // NoCompression is only valid if you are using OpenSSL 1.0.1 or newer + NoCompression Options = C.SSL_OP_NO_COMPRESSION + NoSSLv2 Options = C.SSL_OP_NO_SSLv2 + NoSSLv3 Options = C.SSL_OP_NO_SSLv3 + NoTLSv1 Options = C.SSL_OP_NO_TLSv1 + CipherServerPreference Options = C.SSL_OP_CIPHER_SERVER_PREFERENCE + NoSessionResumptionOrRenegotiation Options = C.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + NoTicket Options = C.SSL_OP_NO_TICKET +) + +// SetOptions sets context options. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (c *Ctx) SetOptions(options Options) Options { + return Options(C.X_SSL_CTX_set_options( + c.ctx, C.long(options))) +} + +func (c *Ctx) ClearOptions(options Options) Options { + return Options(C.X_SSL_CTX_clear_options( + c.ctx, C.long(options))) +} + +// GetOptions returns context options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (c *Ctx) GetOptions() Options { + return Options(C.X_SSL_CTX_get_options(c.ctx)) +} + +type Modes int + +const ( + // ReleaseBuffers is only valid if you are using OpenSSL 1.0.1 or newer + ReleaseBuffers Modes = C.SSL_MODE_RELEASE_BUFFERS +) + +// SetMode sets context modes. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html +func (c *Ctx) SetMode(modes Modes) Modes { + return Modes(C.X_SSL_CTX_set_mode(c.ctx, C.long(modes))) +} + +// GetMode returns context modes. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html +func (c *Ctx) GetMode() Modes { + return Modes(C.X_SSL_CTX_get_mode(c.ctx)) +} + +type VerifyOptions int + +const ( + VerifyNone VerifyOptions = C.SSL_VERIFY_NONE + VerifyPeer VerifyOptions = C.SSL_VERIFY_PEER + VerifyFailIfNoPeerCert VerifyOptions = C.SSL_VERIFY_FAIL_IF_NO_PEER_CERT + VerifyClientOnce VerifyOptions = C.SSL_VERIFY_CLIENT_ONCE +) + +type VerifyCallback func(ok bool, store *CertificateStoreCtx) bool + +//export go_ssl_ctx_verify_cb_thunk +func go_ssl_ctx_verify_cb_thunk(p unsafe.Pointer, ok C.int, ctx *C.X509_STORE_CTX) C.int { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: verify callback panic'd: %v", err) + os.Exit(1) + } + }() + verify_cb := (*Ctx)(p).verify_cb + // set up defaults just in case verify_cb is nil + if verify_cb != nil { + store := &CertificateStoreCtx{ctx: ctx} + if verify_cb(ok == 1, store) { + ok = 1 + } else { + ok = 0 + } + } + return ok +} + +// SetVerify controls peer verification settings. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (c *Ctx) SetVerify(options VerifyOptions, verify_cb VerifyCallback) { + c.verify_cb = verify_cb + if verify_cb != nil { + C.SSL_CTX_set_verify(c.ctx, C.int(options), (*[0]byte)(C.X_SSL_CTX_verify_cb)) + } else { + C.SSL_CTX_set_verify(c.ctx, C.int(options), nil) + } +} + +func (c *Ctx) SetVerifyMode(options VerifyOptions) { + c.SetVerify(options, c.verify_cb) +} + +func (c *Ctx) SetVerifyCallback(verify_cb VerifyCallback) { + c.SetVerify(c.VerifyMode(), verify_cb) +} + +func (c *Ctx) GetVerifyCallback() VerifyCallback { + return c.verify_cb +} + +func (c *Ctx) VerifyMode() VerifyOptions { + return VerifyOptions(C.SSL_CTX_get_verify_mode(c.ctx)) +} + +// SetVerifyDepth controls how many certificates deep the certificate +// verification logic is willing to follow a certificate chain. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (c *Ctx) SetVerifyDepth(depth int) { + C.SSL_CTX_set_verify_depth(c.ctx, C.int(depth)) +} + +// GetVerifyDepth controls how many certificates deep the certificate +// verification logic is willing to follow a certificate chain. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (c *Ctx) GetVerifyDepth() int { + return int(C.SSL_CTX_get_verify_depth(c.ctx)) +} + +type TLSExtServernameCallback func(ssl *SSL) SSLTLSExtErr + +// SetTLSExtServernameCallback sets callback function for Server Name Indication +// (SNI) rfc6066 (http://tools.ietf.org/html/rfc6066). See +// http://stackoverflow.com/questions/22373332/serving-multiple-domains-in-one-box-with-sni +func (c *Ctx) SetTLSExtServernameCallback(sni_cb TLSExtServernameCallback) { + c.sni_cb = sni_cb + C.X_SSL_CTX_set_tlsext_servername_callback(c.ctx, (*[0]byte)(C.sni_cb)) +} + +func (c *Ctx) SetSessionId(session_id []byte) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + var ptr *C.uchar + if len(session_id) > 0 { + ptr = (*C.uchar)(unsafe.Pointer(&session_id[0])) + } + if int(C.SSL_CTX_set_session_id_context(c.ctx, ptr, + C.uint(len(session_id)))) == 0 { + return errorFromErrorQueue() + } + return nil +} + +// SetCipherList sets the list of available ciphers. The format of the list is +// described at http://www.openssl.org/docs/apps/ciphers.html, but see +// http://www.openssl.org/docs/ssl/SSL_CTX_set_cipher_list.html for more. +func (c *Ctx) SetCipherList(list string) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + clist := C.CString(list) + defer C.free(unsafe.Pointer(clist)) + if int(C.SSL_CTX_set_cipher_list(c.ctx, clist)) == 0 { + return errorFromErrorQueue() + } + return nil +} + +type SessionCacheModes int + +const ( + SessionCacheOff SessionCacheModes = C.SSL_SESS_CACHE_OFF + SessionCacheClient SessionCacheModes = C.SSL_SESS_CACHE_CLIENT + SessionCacheServer SessionCacheModes = C.SSL_SESS_CACHE_SERVER + SessionCacheBoth SessionCacheModes = C.SSL_SESS_CACHE_BOTH + NoAutoClear SessionCacheModes = C.SSL_SESS_CACHE_NO_AUTO_CLEAR + NoInternalLookup SessionCacheModes = C.SSL_SESS_CACHE_NO_INTERNAL_LOOKUP + NoInternalStore SessionCacheModes = C.SSL_SESS_CACHE_NO_INTERNAL_STORE + NoInternal SessionCacheModes = C.SSL_SESS_CACHE_NO_INTERNAL +) + +// SetSessionCacheMode enables or disables session caching. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_session_cache_mode.html +func (c *Ctx) SetSessionCacheMode(modes SessionCacheModes) SessionCacheModes { + return SessionCacheModes( + C.X_SSL_CTX_set_session_cache_mode(c.ctx, C.long(modes))) +} + +// Set session cache timeout. Returns previously set value. +// See https://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html +func (c *Ctx) SetTimeout(t time.Duration) time.Duration { + prev := C.X_SSL_CTX_set_timeout(c.ctx, C.long(t/time.Second)) + return time.Duration(prev) * time.Second +} + +// Get session cache timeout. +// See https://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html +func (c *Ctx) GetTimeout() time.Duration { + return time.Duration(C.X_SSL_CTX_get_timeout(c.ctx)) * time.Second +} + +// Set session cache size. Returns previously set value. +// https://www.openssl.org/docs/ssl/SSL_CTX_sess_set_cache_size.html +func (c *Ctx) SessSetCacheSize(t int) int { + return int(C.X_SSL_CTX_sess_set_cache_size(c.ctx, C.long(t))) +} + +// Get session cache size. +// https://www.openssl.org/docs/ssl/SSL_CTX_sess_set_cache_size.html +func (c *Ctx) SessGetCacheSize() int { + return int(C.X_SSL_CTX_sess_get_cache_size(c.ctx)) +} diff --git a/vendor/github.com/libp2p/go-openssl/dh.go b/vendor/github.com/libp2p/go-openssl/dh.go new file mode 100644 index 0000000000..75ac5ad426 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/dh.go @@ -0,0 +1,66 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" +import ( + "errors" + "unsafe" +) + +// DeriveSharedSecret derives a shared secret using a private key and a peer's +// public key. +// The specific algorithm that is used depends on the types of the +// keys, but it is most commonly a variant of Diffie-Hellman. +func DeriveSharedSecret(private PrivateKey, public PublicKey) ([]byte, error) { + // Create context for the shared secret derivation + dhCtx := C.EVP_PKEY_CTX_new(private.evpPKey(), nil) + if dhCtx == nil { + return nil, errors.New("failed creating shared secret derivation context") + } + defer C.EVP_PKEY_CTX_free(dhCtx) + + // Initialize the context + if int(C.EVP_PKEY_derive_init(dhCtx)) != 1 { + return nil, errors.New("failed initializing shared secret derivation context") + } + + // Provide the peer's public key + if int(C.EVP_PKEY_derive_set_peer(dhCtx, public.evpPKey())) != 1 { + return nil, errors.New("failed adding peer public key to context") + } + + // Determine how large of a buffer we need for the shared secret + var buffLen C.size_t + if int(C.EVP_PKEY_derive(dhCtx, nil, &buffLen)) != 1 { + return nil, errors.New("failed determining shared secret length") + } + + // Allocate a buffer + buffer := C.X_OPENSSL_malloc(buffLen) + if buffer == nil { + return nil, errors.New("failed allocating buffer for shared secret") + } + defer C.X_OPENSSL_free(buffer) + + // Derive the shared secret + if int(C.EVP_PKEY_derive(dhCtx, (*C.uchar)(buffer), &buffLen)) != 1 { + return nil, errors.New("failed deriving the shared secret") + } + + secret := C.GoBytes(unsafe.Pointer(buffer), C.int(buffLen)) + return secret, nil +} diff --git a/vendor/github.com/libp2p/go-openssl/dhparam.go b/vendor/github.com/libp2p/go-openssl/dhparam.go new file mode 100644 index 0000000000..294d0645c0 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/dhparam.go @@ -0,0 +1,64 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +type DH struct { + dh *C.struct_dh_st +} + +// LoadDHParametersFromPEM loads the Diffie-Hellman parameters from +// a PEM-encoded block. +func LoadDHParametersFromPEM(pem_block []byte) (*DH, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + params := C.PEM_read_bio_DHparams(bio, nil, nil, nil) + if params == nil { + return nil, errors.New("failed reading dh parameters") + } + dhparams := &DH{dh: params} + runtime.SetFinalizer(dhparams, func(dhparams *DH) { + C.DH_free(dhparams.dh) + }) + return dhparams, nil +} + +// SetDHParameters sets the DH group (DH parameters) used to +// negotiate an emphemeral DH key during handshaking. +func (c *Ctx) SetDHParameters(dh *DH) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if int(C.X_SSL_CTX_set_tmp_dh(c.ctx, dh.dh)) != 1 { + return errorFromErrorQueue() + } + return nil +} diff --git a/vendor/github.com/libp2p/go-openssl/digest.go b/vendor/github.com/libp2p/go-openssl/digest.go new file mode 100644 index 0000000000..6d8d2635ae --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/digest.go @@ -0,0 +1,51 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "fmt" + "unsafe" +) + +// Digest represents and openssl message digest. +type Digest struct { + ptr *C.EVP_MD +} + +// GetDigestByName returns the Digest with the name or nil and an error if the +// digest was not found. +func GetDigestByName(name string) (*Digest, error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + p := C.X_EVP_get_digestbyname(cname) + if p == nil { + return nil, fmt.Errorf("Digest %v not found", name) + } + // we can consider digests to use static mem; don't need to free + return &Digest{ptr: p}, nil +} + +// GetDigestByName returns the Digest with the NID or nil and an error if the +// digest was not found. +func GetDigestByNid(nid NID) (*Digest, error) { + sn, err := Nid2ShortName(nid) + if err != nil { + return nil, err + } + return GetDigestByName(sn) +} diff --git a/vendor/github.com/libp2p/go-openssl/engine.go b/vendor/github.com/libp2p/go-openssl/engine.go new file mode 100644 index 0000000000..78aef956fc --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/engine.go @@ -0,0 +1,50 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +/* +#include "openssl/engine.h" +*/ +import "C" + +import ( + "fmt" + "runtime" + "unsafe" +) + +type Engine struct { + e *C.ENGINE +} + +func EngineById(name string) (*Engine, error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + e := &Engine{ + e: C.ENGINE_by_id(cname), + } + if e.e == nil { + return nil, fmt.Errorf("engine %s missing", name) + } + if C.ENGINE_init(e.e) == 0 { + C.ENGINE_free(e.e) + return nil, fmt.Errorf("engine %s not initialized", name) + } + runtime.SetFinalizer(e, func(e *Engine) { + C.ENGINE_finish(e.e) + C.ENGINE_free(e.e) + }) + return e, nil +} diff --git a/vendor/github.com/libp2p/go-openssl/fips.go b/vendor/github.com/libp2p/go-openssl/fips.go new file mode 100644 index 0000000000..f65e14d3ef --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/fips.go @@ -0,0 +1,39 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +/* +#include +*/ +import "C" +import "runtime" + +// FIPSModeSet enables a FIPS 140-2 validated mode of operation. +// https://wiki.openssl.org/index.php/FIPS_mode_set() +func FIPSModeSet(mode bool) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + var r C.int + if mode { + r = C.FIPS_mode_set(1) + } else { + r = C.FIPS_mode_set(0) + } + if r != 1 { + return errorFromErrorQueue() + } + return nil +} diff --git a/vendor/github.com/libp2p/go-openssl/go.mod b/vendor/github.com/libp2p/go-openssl/go.mod new file mode 100644 index 0000000000..51068e7f57 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/go.mod @@ -0,0 +1,8 @@ +module github.com/libp2p/go-openssl + +require ( + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 + golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect +) + +go 1.12 diff --git a/vendor/github.com/libp2p/go-openssl/go.sum b/vendor/github.com/libp2p/go-openssl/go.sum new file mode 100644 index 0000000000..3b2b650f82 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/go.sum @@ -0,0 +1,4 @@ +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/libp2p/go-openssl/hmac.go b/vendor/github.com/libp2p/go-openssl/hmac.go new file mode 100644 index 0000000000..a8640cfac6 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/hmac.go @@ -0,0 +1,91 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +type HMAC struct { + ctx *C.HMAC_CTX + engine *Engine + md *C.EVP_MD +} + +func NewHMAC(key []byte, digestAlgorithm EVP_MD) (*HMAC, error) { + return NewHMACWithEngine(key, digestAlgorithm, nil) +} + +func NewHMACWithEngine(key []byte, digestAlgorithm EVP_MD, e *Engine) (*HMAC, error) { + var md *C.EVP_MD = getDigestFunction(digestAlgorithm) + h := &HMAC{engine: e, md: md} + h.ctx = C.X_HMAC_CTX_new() + if h.ctx == nil { + return nil, errors.New("unable to allocate HMAC_CTX") + } + + var c_e *C.ENGINE + if e != nil { + c_e = e.e + } + if rc := C.X_HMAC_Init_ex(h.ctx, + unsafe.Pointer(&key[0]), + C.int(len(key)), + md, + c_e); rc != 1 { + C.X_HMAC_CTX_free(h.ctx) + return nil, errors.New("failed to initialize HMAC_CTX") + } + + runtime.SetFinalizer(h, func(h *HMAC) { h.Close() }) + return h, nil +} + +func (h *HMAC) Close() { + C.X_HMAC_CTX_free(h.ctx) +} + +func (h *HMAC) Write(data []byte) (n int, err error) { + if len(data) == 0 { + return 0, nil + } + if rc := C.X_HMAC_Update(h.ctx, (*C.uchar)(unsafe.Pointer(&data[0])), + C.size_t(len(data))); rc != 1 { + return 0, errors.New("failed to update HMAC") + } + return len(data), nil +} + +func (h *HMAC) Reset() error { + if 1 != C.X_HMAC_Init_ex(h.ctx, nil, 0, nil, nil) { + return errors.New("failed to reset HMAC_CTX") + } + return nil +} + +func (h *HMAC) Final() (result []byte, err error) { + mdLength := C.X_EVP_MD_size(h.md) + result = make([]byte, mdLength) + if rc := C.X_HMAC_Final(h.ctx, (*C.uchar)(unsafe.Pointer(&result[0])), + (*C.uint)(unsafe.Pointer(&mdLength))); rc != 1 { + return nil, errors.New("failed to finalized HMAC") + } + return result, h.Reset() +} diff --git a/vendor/github.com/libp2p/go-openssl/hostname.c b/vendor/github.com/libp2p/go-openssl/hostname.c new file mode 100644 index 0000000000..0bffecad69 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/hostname.c @@ -0,0 +1,373 @@ +/* + * Go-OpenSSL notice: + * This file is required for all OpenSSL versions prior to 1.1.0. This simply + * provides the new 1.1.0 X509_check_* methods for hostname validation if they + * don't already exist. + */ + +#include + +#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT + +/* portions from x509v3.h and v3_utl.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* X509 v3 extension utilities */ + +#include +#include +#include +#include +#include + +#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1 +#define X509_CHECK_FLAG_NO_WILDCARDS 0x2 + +typedef int (*equal_fn)(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len); + +/* Compare while ASCII ignoring case. */ +static int equal_nocase(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len) + { + if (pattern_len != subject_len) + return 0; + while (pattern_len) + { + unsigned char l = *pattern; + unsigned char r = *subject; + /* The pattern must not contain NUL characters. */ + if (l == 0) + return 0; + if (l != r) + { + if ('A' <= l && l <= 'Z') + l = (l - 'A') + 'a'; + if ('A' <= r && r <= 'Z') + r = (r - 'A') + 'a'; + if (l != r) + return 0; + } + ++pattern; + ++subject; + --pattern_len; + } + return 1; + } + +/* Compare using memcmp. */ +static int equal_case(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len) +{ + /* The pattern must not contain NUL characters. */ + if (memchr(pattern, '\0', pattern_len) != NULL) + return 0; + if (pattern_len != subject_len) + return 0; + return !memcmp(pattern, subject, pattern_len); +} + +/* RFC 5280, section 7.5, requires that only the domain is compared in + a case-insensitive manner. */ +static int equal_email(const unsigned char *a, size_t a_len, + const unsigned char *b, size_t b_len) + { + size_t i = a_len; + if (a_len != b_len) + return 0; + /* We search backwards for the '@' character, so that we do + not have to deal with quoted local-parts. The domain part + is compared in a case-insensitive manner. */ + while (i > 0) + { + --i; + if (a[i] == '@' || b[i] == '@') + { + if (!equal_nocase(a + i, a_len - i, + b + i, a_len - i)) + return 0; + break; + } + } + if (i == 0) + i = a_len; + return equal_case(a, i, b, i); + } + +/* Compare the prefix and suffix with the subject, and check that the + characters in-between are valid. */ +static int wildcard_match(const unsigned char *prefix, size_t prefix_len, + const unsigned char *suffix, size_t suffix_len, + const unsigned char *subject, size_t subject_len) + { + const unsigned char *wildcard_start; + const unsigned char *wildcard_end; + const unsigned char *p; + if (subject_len < prefix_len + suffix_len) + return 0; + if (!equal_nocase(prefix, prefix_len, subject, prefix_len)) + return 0; + wildcard_start = subject + prefix_len; + wildcard_end = subject + (subject_len - suffix_len); + if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len)) + return 0; + /* The wildcard must match at least one character. */ + if (wildcard_start == wildcard_end) + return 0; + /* Check that the part matched by the wildcard contains only + permitted characters and only matches a single label. */ + for (p = wildcard_start; p != wildcard_end; ++p) + if (!(('0' <= *p && *p <= '9') || + ('A' <= *p && *p <= 'Z') || + ('a' <= *p && *p <= 'z') || + *p == '-')) + return 0; + return 1; + } + +/* Checks if the memory region consistens of [0-9A-Za-z.-]. */ +static int valid_domain_characters(const unsigned char *p, size_t len) + { + while (len) + { + if (!(('0' <= *p && *p <= '9') || + ('A' <= *p && *p <= 'Z') || + ('a' <= *p && *p <= 'z') || + *p == '-' || *p == '.')) + return 0; + ++p; + --len; + } + return 1; + } + +/* Find the '*' in a wildcard pattern. If no such character is found + or the pattern is otherwise invalid, returns NULL. */ +static const unsigned char *wildcard_find_star(const unsigned char *pattern, + size_t pattern_len) + { + const unsigned char *star = memchr(pattern, '*', pattern_len); + size_t dot_count = 0; + const unsigned char *suffix_start; + size_t suffix_length; + if (star == NULL) + return NULL; + suffix_start = star + 1; + suffix_length = (pattern + pattern_len) - (star + 1); + if (!(valid_domain_characters(pattern, star - pattern) && + valid_domain_characters(suffix_start, suffix_length))) + return NULL; + /* Check that the suffix matches at least two labels. */ + while (suffix_length) + { + if (*suffix_start == '.') + ++dot_count; + ++suffix_start; + --suffix_length; + } + if (dot_count < 2) + return NULL; + return star; + } + +/* Compare using wildcards. */ +static int equal_wildcard(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len) + { + const unsigned char *star = wildcard_find_star(pattern, pattern_len); + if (star == NULL) + return equal_nocase(pattern, pattern_len, + subject, subject_len); + return wildcard_match(pattern, star - pattern, + star + 1, (pattern + pattern_len) - star - 1, + subject, subject_len); + } + +/* Compare an ASN1_STRING to a supplied string. If they match + * return 1. If cmp_type > 0 only compare if string matches the + * type, otherwise convert it to UTF8. + */ + +static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal, + const unsigned char *b, size_t blen) + { + if (!a->data || !a->length) + return 0; + if (cmp_type > 0) + { + if (cmp_type != a->type) + return 0; + if (cmp_type == V_ASN1_IA5STRING) + return equal(a->data, a->length, b, blen); + if (a->length == (int)blen && !memcmp(a->data, b, blen)) + return 1; + else + return 0; + } + else + { + int astrlen, rv; + unsigned char *astr; + astrlen = ASN1_STRING_to_UTF8(&astr, a); + if (astrlen < 0) + return -1; + rv = equal(astr, astrlen, b, blen); + OPENSSL_free(astr); + return rv; + } + } + +static int do_x509_check(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags, int check_type) + { + STACK_OF(GENERAL_NAME) *gens = NULL; + X509_NAME *name = NULL; + int i; + int cnid; + int alt_type; + equal_fn equal; + if (check_type == GEN_EMAIL) + { + cnid = NID_pkcs9_emailAddress; + alt_type = V_ASN1_IA5STRING; + equal = equal_email; + } + else if (check_type == GEN_DNS) + { + cnid = NID_commonName; + alt_type = V_ASN1_IA5STRING; + if (flags & X509_CHECK_FLAG_NO_WILDCARDS) + equal = equal_nocase; + else + equal = equal_wildcard; + } + else + { + cnid = 0; + alt_type = V_ASN1_OCTET_STRING; + equal = equal_case; + } + + if (chklen == 0) + chklen = strlen((const char *)chk); + + gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + if (gens) + { + int rv = 0; + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + GENERAL_NAME *gen; + ASN1_STRING *cstr; + gen = sk_GENERAL_NAME_value(gens, i); + if(gen->type != check_type) + continue; + if (check_type == GEN_EMAIL) + cstr = gen->d.rfc822Name; + else if (check_type == GEN_DNS) + cstr = gen->d.dNSName; + else + cstr = gen->d.iPAddress; + if (do_check_string(cstr, alt_type, equal, chk, chklen)) + { + rv = 1; + break; + } + } + GENERAL_NAMES_free(gens); + if (rv) + return 1; + if (!(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT) || !cnid) + return 0; + } + i = -1; + name = X509_get_subject_name(x); + while((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) + { + X509_NAME_ENTRY *ne; + ASN1_STRING *str; + ne = X509_NAME_get_entry(name, i); + str = X509_NAME_ENTRY_get_data(ne); + if (do_check_string(str, -1, equal, chk, chklen)) + return 1; + } + return 0; + } + +#if OPENSSL_VERSION_NUMBER < 0x1000200fL + +int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags, char **peername) + { + return do_x509_check(x, chk, chklen, flags, GEN_DNS); + } + +int X509_check_email(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags) + { + return do_x509_check(x, chk, chklen, flags, GEN_EMAIL); + } + +int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags) + { + return do_x509_check(x, chk, chklen, flags, GEN_IPADD); + } + +#endif /* OPENSSL_VERSION_NUMBER < 0x1000200fL */ + +#endif diff --git a/vendor/github.com/libp2p/go-openssl/hostname.go b/vendor/github.com/libp2p/go-openssl/hostname.go new file mode 100644 index 0000000000..c92d959e63 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/hostname.go @@ -0,0 +1,132 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +/* +#include +#include +#include + +#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT +#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1 +#define X509_CHECK_FLAG_NO_WILDCARDS 0x2 + +extern int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags, char **peername); +extern int X509_check_email(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags); +extern int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags); +#endif +*/ +import "C" + +import ( + "errors" + "net" + "unsafe" +) + +var ( + ValidationError = errors.New("Host validation error") +) + +type CheckFlags int + +const ( + AlwaysCheckSubject CheckFlags = C.X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT + NoWildcards CheckFlags = C.X509_CHECK_FLAG_NO_WILDCARDS +) + +// CheckHost checks that the X509 certificate is signed for the provided +// host name. See http://www.openssl.org/docs/crypto/X509_check_host.html for +// more. Note that CheckHost does not check the IP field. See VerifyHostname. +// Specifically returns ValidationError if the Certificate didn't match but +// there was no internal error. +func (c *Certificate) CheckHost(host string, flags CheckFlags) error { + chost := unsafe.Pointer(C.CString(host)) + defer C.free(chost) + + rv := C.X509_check_host(c.x, (*C.uchar)(chost), C.size_t(len(host)), + C.uint(flags), nil) + if rv > 0 { + return nil + } + if rv == 0 { + return ValidationError + } + return errors.New("hostname validation had an internal failure") +} + +// CheckEmail checks that the X509 certificate is signed for the provided +// email address. See http://www.openssl.org/docs/crypto/X509_check_host.html +// for more. +// Specifically returns ValidationError if the Certificate didn't match but +// there was no internal error. +func (c *Certificate) CheckEmail(email string, flags CheckFlags) error { + cemail := unsafe.Pointer(C.CString(email)) + defer C.free(cemail) + rv := C.X509_check_email(c.x, (*C.uchar)(cemail), C.size_t(len(email)), + C.uint(flags)) + if rv > 0 { + return nil + } + if rv == 0 { + return ValidationError + } + return errors.New("email validation had an internal failure") +} + +// CheckIP checks that the X509 certificate is signed for the provided +// IP address. See http://www.openssl.org/docs/crypto/X509_check_host.html +// for more. +// Specifically returns ValidationError if the Certificate didn't match but +// there was no internal error. +func (c *Certificate) CheckIP(ip net.IP, flags CheckFlags) error { + // X509_check_ip will fail to validate the 16-byte representation of an IPv4 + // address, so convert to the 4-byte representation. + if ip4 := ip.To4(); ip4 != nil { + ip = ip4 + } + + cip := unsafe.Pointer(&ip[0]) + rv := C.X509_check_ip(c.x, (*C.uchar)(cip), C.size_t(len(ip)), + C.uint(flags)) + if rv > 0 { + return nil + } + if rv == 0 { + return ValidationError + } + return errors.New("ip validation had an internal failure") +} + +// VerifyHostname is a combination of CheckHost and CheckIP. If the provided +// hostname looks like an IP address, it will be checked as an IP address, +// otherwise it will be checked as a hostname. +// Specifically returns ValidationError if the Certificate didn't match but +// there was no internal error. +func (c *Certificate) VerifyHostname(host string) error { + var ip net.IP + if len(host) >= 3 && host[0] == '[' && host[len(host)-1] == ']' { + ip = net.ParseIP(host[1 : len(host)-1]) + } else { + ip = net.ParseIP(host) + } + if ip != nil { + return c.CheckIP(ip, 0) + } + return c.CheckHost(host, 0) +} diff --git a/vendor/github.com/libp2p/go-openssl/http.go b/vendor/github.com/libp2p/go-openssl/http.go new file mode 100644 index 0000000000..39bd5a28b5 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/http.go @@ -0,0 +1,61 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +import ( + "net/http" +) + +// ListenAndServeTLS will take an http.Handler and serve it using OpenSSL over +// the given tcp address, configured to use the provided cert and key files. +func ListenAndServeTLS(addr string, cert_file string, key_file string, + handler http.Handler) error { + return ServerListenAndServeTLS( + &http.Server{Addr: addr, Handler: handler}, cert_file, key_file) +} + +// ServerListenAndServeTLS will take an http.Server and serve it using OpenSSL +// configured to use the provided cert and key files. +func ServerListenAndServeTLS(srv *http.Server, + cert_file, key_file string) error { + addr := srv.Addr + if addr == "" { + addr = ":https" + } + + ctx, err := NewCtxFromFiles(cert_file, key_file) + if err != nil { + return err + } + + l, err := Listen("tcp", addr, ctx) + if err != nil { + return err + } + + return srv.Serve(l) +} + +// TODO: http client integration +// holy crap, getting this integrated nicely with the Go stdlib HTTP client +// stack so that it does proxying, connection pooling, and most importantly +// hostname verification is really hard. So much stuff is hardcoded to just use +// the built-in TLS lib. I think to get this to work either some crazy +// hacktackery beyond me, an almost straight up fork of the HTTP client, or +// serious stdlib internal refactoring is necessary. +// even more so, good luck getting openssl to use the operating system default +// root certificates if the user doesn't provide any. sadlol +// NOTE: if you're going to try and write your own round tripper, at least use +// openssl.Dial, or equivalent logic diff --git a/vendor/github.com/libp2p/go-openssl/init.go b/vendor/github.com/libp2p/go-openssl/init.go new file mode 100644 index 0000000000..17dc6f3875 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/init.go @@ -0,0 +1,117 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +Package openssl is a light wrapper around OpenSSL for Go. + +It strives to provide a near-drop-in replacement for the Go standard library +tls package, while allowing for: + +Performance + +OpenSSL is battle-tested and optimized C. While Go's built-in library shows +great promise, it is still young and in some places, inefficient. This simple +OpenSSL wrapper can often do at least 2x with the same cipher and protocol. + +On my lappytop, I get the following benchmarking speeds: + BenchmarkSHA1Large_openssl 1000 2611282 ns/op 401.56 MB/s + BenchmarkSHA1Large_stdlib 500 3963983 ns/op 264.53 MB/s + BenchmarkSHA1Small_openssl 1000000 3476 ns/op 0.29 MB/s + BenchmarkSHA1Small_stdlib 5000000 550 ns/op 1.82 MB/s + BenchmarkSHA256Large_openssl 200 8085314 ns/op 129.69 MB/s + BenchmarkSHA256Large_stdlib 100 18948189 ns/op 55.34 MB/s + BenchmarkSHA256Small_openssl 1000000 4262 ns/op 0.23 MB/s + BenchmarkSHA256Small_stdlib 1000000 1444 ns/op 0.69 MB/s + BenchmarkOpenSSLThroughput 100000 21634 ns/op 47.33 MB/s + BenchmarkStdlibThroughput 50000 58974 ns/op 17.36 MB/s + +Interoperability + +Many systems support OpenSSL with a variety of plugins and modules for things, +such as hardware acceleration in embedded devices. + +Greater flexibility and configuration + +OpenSSL allows for far greater configuration of corner cases and backwards +compatibility (such as support of SSLv2). You shouldn't be using SSLv2 if you +can help but, but sometimes you can't help it. + +Security + +Yeah yeah, Heartbleed. But according to the author of the standard library's +TLS implementation, Go's TLS library is vulnerable to timing attacks. And +whether or not OpenSSL received the appropriate amount of scrutiny +pre-Heartbleed, it sure is receiving it now. + +Usage + +Starting an HTTP server that uses OpenSSL is very easy. It's as simple as: + log.Fatal(openssl.ListenAndServeTLS( + ":8443", "my_server.crt", "my_server.key", myHandler)) + +Getting a net.Listener that uses OpenSSL is also easy: + ctx, err := openssl.NewCtxFromFiles("my_server.crt", "my_server.key") + if err != nil { + log.Fatal(err) + } + l, err := openssl.Listen("tcp", ":7777", ctx) + +Making a client connection is straightforward too: + ctx, err := NewCtx() + if err != nil { + log.Fatal(err) + } + err = ctx.LoadVerifyLocations("/etc/ssl/certs/ca-certificates.crt", "") + if err != nil { + log.Fatal(err) + } + conn, err := openssl.Dial("tcp", "localhost:7777", ctx, 0) + +Help wanted: To get this library to work with net/http's client, we +had to fork net/http. It would be nice if an alternate http client library +supported the generality needed to use OpenSSL instead of crypto/tls. +*/ +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "fmt" + "strings" +) + +func init() { + if rc := C.X_shim_init(); rc != 0 { + panic(fmt.Errorf("X_shim_init failed with %d", rc)) + } +} + +// errorFromErrorQueue needs to run in the same OS thread as the operation +// that caused the possible error +func errorFromErrorQueue() error { + var errs []string + for { + err := C.ERR_get_error() + if err == 0 { + break + } + errs = append(errs, fmt.Sprintf("%s:%s:%s", + C.GoString(C.ERR_lib_error_string(err)), + C.GoString(C.ERR_func_error_string(err)), + C.GoString(C.ERR_reason_error_string(err)))) + } + return errors.New(fmt.Sprintf("SSL errors: %s", strings.Join(errs, "\n"))) +} diff --git a/vendor/github.com/libp2p/go-openssl/init_posix.go b/vendor/github.com/libp2p/go-openssl/init_posix.go new file mode 100644 index 0000000000..605a24bc95 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/init_posix.go @@ -0,0 +1,68 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build linux darwin solaris freebsd openbsd +// +build !windows + +package openssl + +/* +#include +#include +#include + +pthread_mutex_t* goopenssl_locks; + +int go_init_locks() { + int rc = 0; + int nlock; + int i; + int locks_needed = CRYPTO_num_locks(); + + goopenssl_locks = (pthread_mutex_t*)malloc( + sizeof(pthread_mutex_t) * locks_needed); + if (!goopenssl_locks) { + return ENOMEM; + } + for (nlock = 0; nlock < locks_needed; ++nlock) { + rc = pthread_mutex_init(&goopenssl_locks[nlock], NULL); + if (rc != 0) { + break; + } + } + + if (rc != 0) { + for (i = nlock - 1; i >= 0; --i) { + pthread_mutex_destroy(&goopenssl_locks[i]); + } + free(goopenssl_locks); + goopenssl_locks = NULL; + } + return rc; +} + +void go_thread_locking_callback(int mode, int n, const char *file, + int line) { + if (mode & CRYPTO_LOCK) { + pthread_mutex_lock(&goopenssl_locks[n]); + } else { + pthread_mutex_unlock(&goopenssl_locks[n]); + } +} + +unsigned long go_thread_id_callback(void) { + return (unsigned long)pthread_self(); +} +*/ +import "C" diff --git a/vendor/github.com/libp2p/go-openssl/init_windows.go b/vendor/github.com/libp2p/go-openssl/init_windows.go new file mode 100644 index 0000000000..051133c393 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/init_windows.go @@ -0,0 +1,57 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build windows + +package openssl + +/* +#include +#include +#include + +CRITICAL_SECTION* goopenssl_locks; + +int go_init_locks() { + int rc = 0; + int nlock; + int i; + int locks_needed = CRYPTO_num_locks(); + + goopenssl_locks = (CRITICAL_SECTION*)malloc( + sizeof(*goopenssl_locks) * locks_needed); + if (!goopenssl_locks) { + return ENOMEM; + } + for (nlock = 0; nlock < locks_needed; ++nlock) { + InitializeCriticalSection(&goopenssl_locks[nlock]); + } + + return 0; +} + +void go_thread_locking_callback(int mode, int n, const char *file, + int line) { + if (mode & CRYPTO_LOCK) { + EnterCriticalSection(&goopenssl_locks[n]); + } else { + LeaveCriticalSection(&goopenssl_locks[n]); + } +} + +unsigned long go_thread_id_callback(void) { + return (unsigned long)GetCurrentThreadId(); +} +*/ +import "C" diff --git a/vendor/github.com/libp2p/go-openssl/key.go b/vendor/github.com/libp2p/go-openssl/key.go new file mode 100644 index 0000000000..268ff01373 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/key.go @@ -0,0 +1,518 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "io/ioutil" + "runtime" + "unsafe" +) + +var ( // some (effectively) constants for tests to refer to + ed25519_support = C.X_ED25519_SUPPORT != 0 +) + +type Method *C.EVP_MD + +var ( + SHA1_Method Method = C.X_EVP_sha1() + SHA256_Method Method = C.X_EVP_sha256() + SHA512_Method Method = C.X_EVP_sha512() +) + +// Constants for the various key types. +// Mapping of name -> NID taken from openssl/evp.h +const ( + KeyTypeNone = NID_undef + KeyTypeRSA = NID_rsaEncryption + KeyTypeRSA2 = NID_rsa + KeyTypeDSA = NID_dsa + KeyTypeDSA1 = NID_dsa_2 + KeyTypeDSA2 = NID_dsaWithSHA + KeyTypeDSA3 = NID_dsaWithSHA1 + KeyTypeDSA4 = NID_dsaWithSHA1_2 + KeyTypeDH = NID_dhKeyAgreement + KeyTypeDHX = NID_dhpublicnumber + KeyTypeEC = NID_X9_62_id_ecPublicKey + KeyTypeHMAC = NID_hmac + KeyTypeCMAC = NID_cmac + KeyTypeTLS1PRF = NID_tls1_prf + KeyTypeHKDF = NID_hkdf + KeyTypeX25519 = NID_X25519 + KeyTypeX448 = NID_X448 + KeyTypeED25519 = NID_ED25519 + KeyTypeED448 = NID_ED448 +) + +type PublicKey interface { + // Verifies the data signature using PKCS1.15 + VerifyPKCS1v15(method Method, data, sig []byte) error + + // MarshalPKIXPublicKeyPEM converts the public key to PEM-encoded PKIX + // format + MarshalPKIXPublicKeyPEM() (pem_block []byte, err error) + + // MarshalPKIXPublicKeyDER converts the public key to DER-encoded PKIX + // format + MarshalPKIXPublicKeyDER() (der_block []byte, err error) + + // KeyType returns an identifier for what kind of key is represented by this + // object. + KeyType() NID + + // BaseType returns an identifier for what kind of key is represented + // by this object. + // Keys that share same algorithm but use different legacy formats + // will have the same BaseType. + // + // For example, a key with a `KeyType() == KeyTypeRSA` and a key with a + // `KeyType() == KeyTypeRSA2` would both have `BaseType() == KeyTypeRSA`. + BaseType() NID + + // Equal compares the key with the passed in key. + Equal(key PublicKey) bool + + // Size returns the size (in bytes) of signatures created with this key. + Size() int + + evpPKey() *C.EVP_PKEY +} + +type PrivateKey interface { + PublicKey + + // Signs the data using PKCS1.15 + SignPKCS1v15(Method, []byte) ([]byte, error) + + // MarshalPKCS1PrivateKeyPEM converts the private key to PEM-encoded PKCS1 + // format + MarshalPKCS1PrivateKeyPEM() (pem_block []byte, err error) + + // MarshalPKCS1PrivateKeyDER converts the private key to DER-encoded PKCS1 + // format + MarshalPKCS1PrivateKeyDER() (der_block []byte, err error) +} + +type pKey struct { + key *C.EVP_PKEY +} + +func (key *pKey) evpPKey() *C.EVP_PKEY { return key.key } + +func (key *pKey) Equal(other PublicKey) bool { + return C.EVP_PKEY_cmp(key.key, other.evpPKey()) == 1 +} + +func (key *pKey) KeyType() NID { + return NID(C.EVP_PKEY_id(key.key)) +} + +func (key *pKey) Size() int { + return int(C.EVP_PKEY_size(key.key)) +} + +func (key *pKey) BaseType() NID { + return NID(C.EVP_PKEY_base_id(key.key)) +} + +func (key *pKey) SignPKCS1v15(method Method, data []byte) ([]byte, error) { + + ctx := C.X_EVP_MD_CTX_new() + defer C.X_EVP_MD_CTX_free(ctx) + + if key.KeyType() == KeyTypeED25519 { + // do ED specific one-shot sign + + if method != nil || len(data) == 0 { + return nil, errors.New("signpkcs1v15: 0-length data or non-null digest") + } + + if 1 != C.X_EVP_DigestSignInit(ctx, nil, nil, nil, key.key) { + return nil, errors.New("signpkcs1v15: failed to init signature") + } + + // evp signatures are 64 bytes + sig := make([]byte, 64, 64) + var sigblen C.size_t = 64 + if 1 != C.X_EVP_DigestSign(ctx, + ((*C.uchar)(unsafe.Pointer(&sig[0]))), + &sigblen, + (*C.uchar)(unsafe.Pointer(&data[0])), + C.size_t(len(data))) { + return nil, errors.New("signpkcs1v15: failed to do one-shot signature") + } + + return sig[:sigblen], nil + } else { + if 1 != C.X_EVP_SignInit(ctx, method) { + return nil, errors.New("signpkcs1v15: failed to init signature") + } + if len(data) > 0 { + if 1 != C.X_EVP_SignUpdate( + ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { + return nil, errors.New("signpkcs1v15: failed to update signature") + } + } + sig := make([]byte, C.X_EVP_PKEY_size(key.key)) + var sigblen C.uint + if 1 != C.X_EVP_SignFinal(ctx, + ((*C.uchar)(unsafe.Pointer(&sig[0]))), &sigblen, key.key) { + return nil, errors.New("signpkcs1v15: failed to finalize signature") + } + return sig[:sigblen], nil + } +} + +func (key *pKey) VerifyPKCS1v15(method Method, data, sig []byte) error { + ctx := C.X_EVP_MD_CTX_new() + defer C.X_EVP_MD_CTX_free(ctx) + + if key.KeyType() == KeyTypeED25519 { + // do ED specific one-shot sign + + if method != nil || len(data) == 0 || len(sig) == 0 { + return errors.New("verifypkcs1v15: 0-length data or sig or non-null digest") + } + + if 1 != C.X_EVP_DigestVerifyInit(ctx, nil, nil, nil, key.key) { + return errors.New("verifypkcs1v15: failed to init verify") + } + + if 1 != C.X_EVP_DigestVerify(ctx, + ((*C.uchar)(unsafe.Pointer(&sig[0]))), + C.size_t(len(sig)), + (*C.uchar)(unsafe.Pointer(&data[0])), + C.size_t(len(data))) { + return errors.New("verifypkcs1v15: failed to do one-shot verify") + } + + return nil + + } else { + if 1 != C.X_EVP_VerifyInit(ctx, method) { + return errors.New("verifypkcs1v15: failed to init verify") + } + if len(data) > 0 { + if 1 != C.X_EVP_VerifyUpdate( + ctx, unsafe.Pointer(&data[0]), C.uint(len(data))) { + return errors.New("verifypkcs1v15: failed to update verify") + } + } + if 1 != C.X_EVP_VerifyFinal(ctx, + ((*C.uchar)(unsafe.Pointer(&sig[0]))), C.uint(len(sig)), key.key) { + return errors.New("verifypkcs1v15: failed to finalize verify") + } + return nil + } +} + +func (key *pKey) MarshalPKCS1PrivateKeyPEM() (pem_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + + // PEM_write_bio_PrivateKey_traditional will use the key-specific PKCS1 + // format if one is available for that key type, otherwise it will encode + // to a PKCS8 key. + if int(C.X_PEM_write_bio_PrivateKey_traditional(bio, key.key, nil, nil, + C.int(0), nil, nil)) != 1 { + return nil, errors.New("failed dumping private key") + } + + return ioutil.ReadAll(asAnyBio(bio)) +} + +func (key *pKey) MarshalPKCS1PrivateKeyDER() (der_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + + if int(C.i2d_PrivateKey_bio(bio, key.key)) != 1 { + return nil, errors.New("failed dumping private key der") + } + + return ioutil.ReadAll(asAnyBio(bio)) +} + +func (key *pKey) MarshalPKIXPublicKeyPEM() (pem_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + + if int(C.PEM_write_bio_PUBKEY(bio, key.key)) != 1 { + return nil, errors.New("failed dumping public key pem") + } + + return ioutil.ReadAll(asAnyBio(bio)) +} + +func (key *pKey) MarshalPKIXPublicKeyDER() (der_block []byte, + err error) { + bio := C.BIO_new(C.BIO_s_mem()) + if bio == nil { + return nil, errors.New("failed to allocate memory BIO") + } + defer C.BIO_free(bio) + + if int(C.i2d_PUBKEY_bio(bio, key.key)) != 1 { + return nil, errors.New("failed dumping public key der") + } + + return ioutil.ReadAll(asAnyBio(bio)) +} + +// LoadPrivateKeyFromPEM loads a private key from a PEM-encoded block. +func LoadPrivateKeyFromPEM(pem_block []byte) (PrivateKey, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + key := C.PEM_read_bio_PrivateKey(bio, nil, nil, nil) + if key == nil { + return nil, errors.New("failed reading private key") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} + +// LoadPrivateKeyFromPEMWithPassword loads a private key from a PEM-encoded block. +func LoadPrivateKeyFromPEMWithPassword(pem_block []byte, password string) ( + PrivateKey, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + cs := C.CString(password) + defer C.free(unsafe.Pointer(cs)) + key := C.PEM_read_bio_PrivateKey(bio, nil, nil, unsafe.Pointer(cs)) + if key == nil { + return nil, errors.New("failed reading private key") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} + +// LoadPrivateKeyFromDER loads a private key from a DER-encoded block. +func LoadPrivateKeyFromDER(der_block []byte) (PrivateKey, error) { + if len(der_block) == 0 { + return nil, errors.New("empty der block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&der_block[0]), + C.int(len(der_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + key := C.d2i_PrivateKey_bio(bio, nil) + if key == nil { + return nil, errors.New("failed reading private key der") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} + +// LoadPrivateKeyFromPEMWidthPassword loads a private key from a PEM-encoded block. +// Backwards-compatible with typo +func LoadPrivateKeyFromPEMWidthPassword(pem_block []byte, password string) ( + PrivateKey, error) { + return LoadPrivateKeyFromPEMWithPassword(pem_block, password) +} + +// LoadPublicKeyFromPEM loads a public key from a PEM-encoded block. +func LoadPublicKeyFromPEM(pem_block []byte) (PublicKey, error) { + if len(pem_block) == 0 { + return nil, errors.New("empty pem block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&pem_block[0]), + C.int(len(pem_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + key := C.PEM_read_bio_PUBKEY(bio, nil, nil, nil) + if key == nil { + return nil, errors.New("failed reading public key der") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} + +// LoadPublicKeyFromDER loads a public key from a DER-encoded block. +func LoadPublicKeyFromDER(der_block []byte) (PublicKey, error) { + if len(der_block) == 0 { + return nil, errors.New("empty der block") + } + bio := C.BIO_new_mem_buf(unsafe.Pointer(&der_block[0]), + C.int(len(der_block))) + if bio == nil { + return nil, errors.New("failed creating bio") + } + defer C.BIO_free(bio) + + key := C.d2i_PUBKEY_bio(bio, nil) + if key == nil { + return nil, errors.New("failed reading public key der") + } + + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} + +// GenerateRSAKey generates a new RSA private key with an exponent of 3. +func GenerateRSAKey(bits int) (PrivateKey, error) { + return GenerateRSAKeyWithExponent(bits, 3) +} + +// GenerateRSAKeyWithExponent generates a new RSA private key. +func GenerateRSAKeyWithExponent(bits int, exponent int) (PrivateKey, error) { + rsa := C.RSA_generate_key(C.int(bits), C.ulong(exponent), nil, nil) + if rsa == nil { + return nil, errors.New("failed to generate RSA key") + } + key := C.X_EVP_PKEY_new() + if key == nil { + return nil, errors.New("failed to allocate EVP_PKEY") + } + if C.X_EVP_PKEY_assign_charp(key, C.EVP_PKEY_RSA, (*C.char)(unsafe.Pointer(rsa))) != 1 { + C.X_EVP_PKEY_free(key) + return nil, errors.New("failed to assign RSA key") + } + p := &pKey{key: key} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} + +// GenerateECKey generates a new elliptic curve private key on the speicified +// curve. +func GenerateECKey(curve EllipticCurve) (PrivateKey, error) { + + // Create context for parameter generation + paramCtx := C.EVP_PKEY_CTX_new_id(C.EVP_PKEY_EC, nil) + if paramCtx == nil { + return nil, errors.New("failed creating EC parameter generation context") + } + defer C.EVP_PKEY_CTX_free(paramCtx) + + // Intialize the parameter generation + if int(C.EVP_PKEY_paramgen_init(paramCtx)) != 1 { + return nil, errors.New("failed initializing EC parameter generation context") + } + + // Set curve in EC parameter generation context + if int(C.X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(paramCtx, C.int(curve))) != 1 { + return nil, errors.New("failed setting curve in EC parameter generation context") + } + + // Create parameter object + var params *C.EVP_PKEY + if int(C.EVP_PKEY_paramgen(paramCtx, ¶ms)) != 1 { + return nil, errors.New("failed creating EC key generation parameters") + } + defer C.EVP_PKEY_free(params) + + // Create context for the key generation + keyCtx := C.EVP_PKEY_CTX_new(params, nil) + if keyCtx == nil { + return nil, errors.New("failed creating EC key generation context") + } + defer C.EVP_PKEY_CTX_free(keyCtx) + + // Generate the key + var privKey *C.EVP_PKEY + if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 { + return nil, errors.New("failed initializing EC key generation context") + } + if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 { + return nil, errors.New("failed generating EC private key") + } + + p := &pKey{key: privKey} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} + +// GenerateED25519Key generates a Ed25519 key +func GenerateED25519Key() (PrivateKey, error) { + // Key context + keyCtx := C.EVP_PKEY_CTX_new_id(C.X_EVP_PKEY_ED25519, nil) + if keyCtx == nil { + return nil, errors.New("failed creating EC parameter generation context") + } + defer C.EVP_PKEY_CTX_free(keyCtx) + + // Generate the key + var privKey *C.EVP_PKEY + if int(C.EVP_PKEY_keygen_init(keyCtx)) != 1 { + return nil, errors.New("failed initializing ED25519 key generation context") + } + if int(C.EVP_PKEY_keygen(keyCtx, &privKey)) != 1 { + return nil, errors.New("failed generating ED25519 private key") + } + + p := &pKey{key: privKey} + runtime.SetFinalizer(p, func(p *pKey) { + C.X_EVP_PKEY_free(p.key) + }) + return p, nil +} diff --git a/vendor/github.com/libp2p/go-openssl/mapping.go b/vendor/github.com/libp2p/go-openssl/mapping.go new file mode 100644 index 0000000000..d78cc70347 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/mapping.go @@ -0,0 +1,62 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +import ( + "sync" + "unsafe" +) + +// #include +import "C" + +type mapping struct { + lock sync.Mutex + values map[token]unsafe.Pointer +} + +func newMapping() *mapping { + return &mapping{ + values: make(map[token]unsafe.Pointer), + } +} + +type token unsafe.Pointer + +func (m *mapping) Add(x unsafe.Pointer) token { + res := token(C.malloc(1)) + + m.lock.Lock() + m.values[res] = x + m.lock.Unlock() + + return res +} + +func (m *mapping) Get(x token) unsafe.Pointer { + m.lock.Lock() + res := m.values[x] + m.lock.Unlock() + + return res +} + +func (m *mapping) Del(x token) { + m.lock.Lock() + delete(m.values, x) + m.lock.Unlock() + + C.free(unsafe.Pointer(x)) +} diff --git a/vendor/github.com/libp2p/go-openssl/md4.go b/vendor/github.com/libp2p/go-openssl/md4.go new file mode 100644 index 0000000000..e5cc7d8679 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/md4.go @@ -0,0 +1,89 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +type MD4Hash struct { + ctx *C.EVP_MD_CTX + engine *Engine +} + +func NewMD4Hash() (*MD4Hash, error) { return NewMD4HashWithEngine(nil) } + +func NewMD4HashWithEngine(e *Engine) (*MD4Hash, error) { + hash := &MD4Hash{engine: e} + hash.ctx = C.X_EVP_MD_CTX_new() + if hash.ctx == nil { + return nil, errors.New("openssl: md4: unable to allocate ctx") + } + runtime.SetFinalizer(hash, func(hash *MD4Hash) { hash.Close() }) + if err := hash.Reset(); err != nil { + return nil, err + } + return hash, nil +} + +func (s *MD4Hash) Close() { + if s.ctx != nil { + C.X_EVP_MD_CTX_free(s.ctx) + s.ctx = nil + } +} + +func (s *MD4Hash) Reset() error { + if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_md4(), engineRef(s.engine)) { + return errors.New("openssl: md4: cannot init digest ctx") + } + return nil +} + +func (s *MD4Hash) Write(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), + C.size_t(len(p))) { + return 0, errors.New("openssl: md4: cannot update digest") + } + return len(p), nil +} + +func (s *MD4Hash) Sum() (result [16]byte, err error) { + if 1 != C.X_EVP_DigestFinal_ex(s.ctx, + (*C.uchar)(unsafe.Pointer(&result[0])), nil) { + return result, errors.New("openssl: md4: cannot finalize ctx") + } + return result, s.Reset() +} + +func MD4(data []byte) (result [16]byte, err error) { + hash, err := NewMD4Hash() + if err != nil { + return result, err + } + defer hash.Close() + if _, err := hash.Write(data); err != nil { + return result, err + } + return hash.Sum() +} diff --git a/vendor/github.com/libp2p/go-openssl/md5.go b/vendor/github.com/libp2p/go-openssl/md5.go new file mode 100644 index 0000000000..82f2eb2f27 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/md5.go @@ -0,0 +1,89 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +type MD5Hash struct { + ctx *C.EVP_MD_CTX + engine *Engine +} + +func NewMD5Hash() (*MD5Hash, error) { return NewMD5HashWithEngine(nil) } + +func NewMD5HashWithEngine(e *Engine) (*MD5Hash, error) { + hash := &MD5Hash{engine: e} + hash.ctx = C.X_EVP_MD_CTX_new() + if hash.ctx == nil { + return nil, errors.New("openssl: md5: unable to allocate ctx") + } + runtime.SetFinalizer(hash, func(hash *MD5Hash) { hash.Close() }) + if err := hash.Reset(); err != nil { + return nil, err + } + return hash, nil +} + +func (s *MD5Hash) Close() { + if s.ctx != nil { + C.X_EVP_MD_CTX_free(s.ctx) + s.ctx = nil + } +} + +func (s *MD5Hash) Reset() error { + if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_md5(), engineRef(s.engine)) { + return errors.New("openssl: md5: cannot init digest ctx") + } + return nil +} + +func (s *MD5Hash) Write(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), + C.size_t(len(p))) { + return 0, errors.New("openssl: md5: cannot update digest") + } + return len(p), nil +} + +func (s *MD5Hash) Sum() (result [16]byte, err error) { + if 1 != C.X_EVP_DigestFinal_ex(s.ctx, + (*C.uchar)(unsafe.Pointer(&result[0])), nil) { + return result, errors.New("openssl: md5: cannot finalize ctx") + } + return result, s.Reset() +} + +func MD5(data []byte) (result [16]byte, err error) { + hash, err := NewMD5Hash() + if err != nil { + return result, err + } + defer hash.Close() + if _, err := hash.Write(data); err != nil { + return result, err + } + return hash.Sum() +} diff --git a/vendor/github.com/libp2p/go-openssl/net.go b/vendor/github.com/libp2p/go-openssl/net.go new file mode 100644 index 0000000000..54beb8ee92 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/net.go @@ -0,0 +1,147 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +import ( + "errors" + "net" +) + +type listener struct { + net.Listener + ctx *Ctx +} + +func (l *listener) Accept() (c net.Conn, err error) { + c, err = l.Listener.Accept() + if err != nil { + return nil, err + } + ssl_c, err := Server(c, l.ctx) + if err != nil { + c.Close() + return nil, err + } + return ssl_c, nil +} + +// NewListener wraps an existing net.Listener such that all accepted +// connections are wrapped as OpenSSL server connections using the provided +// context ctx. +func NewListener(inner net.Listener, ctx *Ctx) net.Listener { + return &listener{ + Listener: inner, + ctx: ctx} +} + +// Listen is a wrapper around net.Listen that wraps incoming connections with +// an OpenSSL server connection using the provided context ctx. +func Listen(network, laddr string, ctx *Ctx) (net.Listener, error) { + if ctx == nil { + return nil, errors.New("no ssl context provided") + } + l, err := net.Listen(network, laddr) + if err != nil { + return nil, err + } + return NewListener(l, ctx), nil +} + +type DialFlags int + +const ( + InsecureSkipHostVerification DialFlags = 1 << iota + DisableSNI +) + +// Dial will connect to network/address and then wrap the corresponding +// underlying connection with an OpenSSL client connection using context ctx. +// If flags includes InsecureSkipHostVerification, the server certificate's +// hostname will not be checked to match the hostname in addr. Otherwise, flags +// should be 0. +// +// Dial probably won't work for you unless you set a verify location or add +// some certs to the certificate store of the client context you're using. +// This library is not nice enough to use the system certificate store by +// default for you yet. +func Dial(network, addr string, ctx *Ctx, flags DialFlags) (*Conn, error) { + return DialSession(network, addr, ctx, flags, nil) +} + +// DialSession will connect to network/address and then wrap the corresponding +// underlying connection with an OpenSSL client connection using context ctx. +// If flags includes InsecureSkipHostVerification, the server certificate's +// hostname will not be checked to match the hostname in addr. Otherwise, flags +// should be 0. +// +// Dial probably won't work for you unless you set a verify location or add +// some certs to the certificate store of the client context you're using. +// This library is not nice enough to use the system certificate store by +// default for you yet. +// +// If session is not nil it will be used to resume the tls state. The session +// can be retrieved from the GetSession method on the Conn. +func DialSession(network, addr string, ctx *Ctx, flags DialFlags, + session []byte) (*Conn, error) { + + host, _, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + if ctx == nil { + var err error + ctx, err = NewCtx() + if err != nil { + return nil, err + } + // TODO: use operating system default certificate chain? + } + c, err := net.Dial(network, addr) + if err != nil { + return nil, err + } + conn, err := Client(c, ctx) + if err != nil { + c.Close() + return nil, err + } + if session != nil { + err := conn.setSession(session) + if err != nil { + c.Close() + return nil, err + } + } + if flags&DisableSNI == 0 { + err = conn.SetTlsExtHostName(host) + if err != nil { + conn.Close() + return nil, err + } + } + err = conn.Handshake() + if err != nil { + conn.Close() + return nil, err + } + if flags&InsecureSkipHostVerification == 0 { + err = conn.VerifyHostname(host) + if err != nil { + conn.Close() + return nil, err + } + } + return conn, nil +} diff --git a/vendor/github.com/libp2p/go-openssl/nid.go b/vendor/github.com/libp2p/go-openssl/nid.go new file mode 100644 index 0000000000..936a52e779 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/nid.go @@ -0,0 +1,210 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +type NID int + +const ( + NID_undef NID = 0 + NID_rsadsi NID = 1 + NID_pkcs NID = 2 + NID_md2 NID = 3 + NID_md5 NID = 4 + NID_rc4 NID = 5 + NID_rsaEncryption NID = 6 + NID_md2WithRSAEncryption NID = 7 + NID_md5WithRSAEncryption NID = 8 + NID_pbeWithMD2AndDES_CBC NID = 9 + NID_pbeWithMD5AndDES_CBC NID = 10 + NID_X500 NID = 11 + NID_X509 NID = 12 + NID_commonName NID = 13 + NID_countryName NID = 14 + NID_localityName NID = 15 + NID_stateOrProvinceName NID = 16 + NID_organizationName NID = 17 + NID_organizationalUnitName NID = 18 + NID_rsa NID = 19 + NID_pkcs7 NID = 20 + NID_pkcs7_data NID = 21 + NID_pkcs7_signed NID = 22 + NID_pkcs7_enveloped NID = 23 + NID_pkcs7_signedAndEnveloped NID = 24 + NID_pkcs7_digest NID = 25 + NID_pkcs7_encrypted NID = 26 + NID_pkcs3 NID = 27 + NID_dhKeyAgreement NID = 28 + NID_des_ecb NID = 29 + NID_des_cfb64 NID = 30 + NID_des_cbc NID = 31 + NID_des_ede NID = 32 + NID_des_ede3 NID = 33 + NID_idea_cbc NID = 34 + NID_idea_cfb64 NID = 35 + NID_idea_ecb NID = 36 + NID_rc2_cbc NID = 37 + NID_rc2_ecb NID = 38 + NID_rc2_cfb64 NID = 39 + NID_rc2_ofb64 NID = 40 + NID_sha NID = 41 + NID_shaWithRSAEncryption NID = 42 + NID_des_ede_cbc NID = 43 + NID_des_ede3_cbc NID = 44 + NID_des_ofb64 NID = 45 + NID_idea_ofb64 NID = 46 + NID_pkcs9 NID = 47 + NID_pkcs9_emailAddress NID = 48 + NID_pkcs9_unstructuredName NID = 49 + NID_pkcs9_contentType NID = 50 + NID_pkcs9_messageDigest NID = 51 + NID_pkcs9_signingTime NID = 52 + NID_pkcs9_countersignature NID = 53 + NID_pkcs9_challengePassword NID = 54 + NID_pkcs9_unstructuredAddress NID = 55 + NID_pkcs9_extCertAttributes NID = 56 + NID_netscape NID = 57 + NID_netscape_cert_extension NID = 58 + NID_netscape_data_type NID = 59 + NID_des_ede_cfb64 NID = 60 + NID_des_ede3_cfb64 NID = 61 + NID_des_ede_ofb64 NID = 62 + NID_des_ede3_ofb64 NID = 63 + NID_sha1 NID = 64 + NID_sha1WithRSAEncryption NID = 65 + NID_dsaWithSHA NID = 66 + NID_dsa_2 NID = 67 + NID_pbeWithSHA1AndRC2_CBC NID = 68 + NID_id_pbkdf2 NID = 69 + NID_dsaWithSHA1_2 NID = 70 + NID_netscape_cert_type NID = 71 + NID_netscape_base_url NID = 72 + NID_netscape_revocation_url NID = 73 + NID_netscape_ca_revocation_url NID = 74 + NID_netscape_renewal_url NID = 75 + NID_netscape_ca_policy_url NID = 76 + NID_netscape_ssl_server_name NID = 77 + NID_netscape_comment NID = 78 + NID_netscape_cert_sequence NID = 79 + NID_desx_cbc NID = 80 + NID_id_ce NID = 81 + NID_subject_key_identifier NID = 82 + NID_key_usage NID = 83 + NID_private_key_usage_period NID = 84 + NID_subject_alt_name NID = 85 + NID_issuer_alt_name NID = 86 + NID_basic_constraints NID = 87 + NID_crl_number NID = 88 + NID_certificate_policies NID = 89 + NID_authority_key_identifier NID = 90 + NID_bf_cbc NID = 91 + NID_bf_ecb NID = 92 + NID_bf_cfb64 NID = 93 + NID_bf_ofb64 NID = 94 + NID_mdc2 NID = 95 + NID_mdc2WithRSA NID = 96 + NID_rc4_40 NID = 97 + NID_rc2_40_cbc NID = 98 + NID_givenName NID = 99 + NID_surname NID = 100 + NID_initials NID = 101 + NID_uniqueIdentifier NID = 102 + NID_crl_distribution_points NID = 103 + NID_md5WithRSA NID = 104 + NID_serialNumber NID = 105 + NID_title NID = 106 + NID_description NID = 107 + NID_cast5_cbc NID = 108 + NID_cast5_ecb NID = 109 + NID_cast5_cfb64 NID = 110 + NID_cast5_ofb64 NID = 111 + NID_pbeWithMD5AndCast5_CBC NID = 112 + NID_dsaWithSHA1 NID = 113 + NID_md5_sha1 NID = 114 + NID_sha1WithRSA NID = 115 + NID_dsa NID = 116 + NID_ripemd160 NID = 117 + NID_ripemd160WithRSA NID = 119 + NID_rc5_cbc NID = 120 + NID_rc5_ecb NID = 121 + NID_rc5_cfb64 NID = 122 + NID_rc5_ofb64 NID = 123 + NID_rle_compression NID = 124 + NID_zlib_compression NID = 125 + NID_ext_key_usage NID = 126 + NID_id_pkix NID = 127 + NID_id_kp NID = 128 + NID_server_auth NID = 129 + NID_client_auth NID = 130 + NID_code_sign NID = 131 + NID_email_protect NID = 132 + NID_time_stamp NID = 133 + NID_ms_code_ind NID = 134 + NID_ms_code_com NID = 135 + NID_ms_ctl_sign NID = 136 + NID_ms_sgc NID = 137 + NID_ms_efs NID = 138 + NID_ns_sgc NID = 139 + NID_delta_crl NID = 140 + NID_crl_reason NID = 141 + NID_invalidity_date NID = 142 + NID_sxnet NID = 143 + NID_pbe_WithSHA1And128BitRC4 NID = 144 + NID_pbe_WithSHA1And40BitRC4 NID = 145 + NID_pbe_WithSHA1And3_Key_TripleDES_CBC NID = 146 + NID_pbe_WithSHA1And2_Key_TripleDES_CBC NID = 147 + NID_pbe_WithSHA1And128BitRC2_CBC NID = 148 + NID_pbe_WithSHA1And40BitRC2_CBC NID = 149 + NID_keyBag NID = 150 + NID_pkcs8ShroudedKeyBag NID = 151 + NID_certBag NID = 152 + NID_crlBag NID = 153 + NID_secretBag NID = 154 + NID_safeContentsBag NID = 155 + NID_friendlyName NID = 156 + NID_localKeyID NID = 157 + NID_x509Certificate NID = 158 + NID_sdsiCertificate NID = 159 + NID_x509Crl NID = 160 + NID_pbes2 NID = 161 + NID_pbmac1 NID = 162 + NID_hmacWithSHA1 NID = 163 + NID_id_qt_cps NID = 164 + NID_id_qt_unotice NID = 165 + NID_rc2_64_cbc NID = 166 + NID_SMIMECapabilities NID = 167 + NID_pbeWithMD2AndRC2_CBC NID = 168 + NID_pbeWithMD5AndRC2_CBC NID = 169 + NID_pbeWithSHA1AndDES_CBC NID = 170 + NID_ms_ext_req NID = 171 + NID_ext_req NID = 172 + NID_name NID = 173 + NID_dnQualifier NID = 174 + NID_id_pe NID = 175 + NID_id_ad NID = 176 + NID_info_access NID = 177 + NID_ad_OCSP NID = 178 + NID_ad_ca_issuers NID = 179 + NID_OCSP_sign NID = 180 + NID_X9_62_id_ecPublicKey NID = 408 + NID_hmac NID = 855 + NID_cmac NID = 894 + NID_dhpublicnumber NID = 920 + NID_tls1_prf NID = 1021 + NID_hkdf NID = 1036 + NID_X25519 NID = 1034 + NID_X448 NID = 1035 + NID_ED25519 NID = 1087 + NID_ED448 NID = 1088 +) diff --git a/vendor/github.com/libp2p/go-openssl/object.go b/vendor/github.com/libp2p/go-openssl/object.go new file mode 100644 index 0000000000..86ab1e4c00 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/object.go @@ -0,0 +1,24 @@ +// Copyright (C) 2020. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +// CreateObjectIdentifier creates ObjectIdentifier and returns NID for the created +// ObjectIdentifier +func CreateObjectIdentifier(oid string, shortName string, longName string) int { + return int(C.OBJ_create(C.CString(oid), C.CString(shortName), C.CString(longName))) +} diff --git a/vendor/github.com/libp2p/go-openssl/pem.go b/vendor/github.com/libp2p/go-openssl/pem.go new file mode 100644 index 0000000000..c8b0c1cf19 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/pem.go @@ -0,0 +1,32 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +import ( + "regexp" +) + +var pemSplit *regexp.Regexp = regexp.MustCompile(`(?sm)` + + `(^-----[\s-]*?BEGIN.*?-----$` + + `.*?` + + `^-----[\s-]*?END.*?-----$)`) + +func SplitPEM(data []byte) [][]byte { + var results [][]byte + for _, block := range pemSplit.FindAll(data, -1) { + results = append(results, block) + } + return results +} diff --git a/vendor/github.com/libp2p/go-openssl/sha1.go b/vendor/github.com/libp2p/go-openssl/sha1.go new file mode 100644 index 0000000000..c227bee846 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/sha1.go @@ -0,0 +1,96 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +type SHA1Hash struct { + ctx *C.EVP_MD_CTX + engine *Engine +} + +func NewSHA1Hash() (*SHA1Hash, error) { return NewSHA1HashWithEngine(nil) } + +func NewSHA1HashWithEngine(e *Engine) (*SHA1Hash, error) { + hash := &SHA1Hash{engine: e} + hash.ctx = C.X_EVP_MD_CTX_new() + if hash.ctx == nil { + return nil, errors.New("openssl: sha1: unable to allocate ctx") + } + runtime.SetFinalizer(hash, func(hash *SHA1Hash) { hash.Close() }) + if err := hash.Reset(); err != nil { + return nil, err + } + return hash, nil +} + +func (s *SHA1Hash) Close() { + if s.ctx != nil { + C.X_EVP_MD_CTX_free(s.ctx) + s.ctx = nil + } +} + +func engineRef(e *Engine) *C.ENGINE { + if e == nil { + return nil + } + return e.e +} + +func (s *SHA1Hash) Reset() error { + if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_sha1(), engineRef(s.engine)) { + return errors.New("openssl: sha1: cannot init digest ctx") + } + return nil +} + +func (s *SHA1Hash) Write(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), + C.size_t(len(p))) { + return 0, errors.New("openssl: sha1: cannot update digest") + } + return len(p), nil +} + +func (s *SHA1Hash) Sum() (result [20]byte, err error) { + if 1 != C.X_EVP_DigestFinal_ex(s.ctx, + (*C.uchar)(unsafe.Pointer(&result[0])), nil) { + return result, errors.New("openssl: sha1: cannot finalize ctx") + } + return result, s.Reset() +} + +func SHA1(data []byte) (result [20]byte, err error) { + hash, err := NewSHA1Hash() + if err != nil { + return result, err + } + defer hash.Close() + if _, err := hash.Write(data); err != nil { + return result, err + } + return hash.Sum() +} diff --git a/vendor/github.com/libp2p/go-openssl/sha256.go b/vendor/github.com/libp2p/go-openssl/sha256.go new file mode 100644 index 0000000000..d25c7a959d --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/sha256.go @@ -0,0 +1,89 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "errors" + "runtime" + "unsafe" +) + +type SHA256Hash struct { + ctx *C.EVP_MD_CTX + engine *Engine +} + +func NewSHA256Hash() (*SHA256Hash, error) { return NewSHA256HashWithEngine(nil) } + +func NewSHA256HashWithEngine(e *Engine) (*SHA256Hash, error) { + hash := &SHA256Hash{engine: e} + hash.ctx = C.X_EVP_MD_CTX_new() + if hash.ctx == nil { + return nil, errors.New("openssl: sha256: unable to allocate ctx") + } + runtime.SetFinalizer(hash, func(hash *SHA256Hash) { hash.Close() }) + if err := hash.Reset(); err != nil { + return nil, err + } + return hash, nil +} + +func (s *SHA256Hash) Close() { + if s.ctx != nil { + C.X_EVP_MD_CTX_free(s.ctx) + s.ctx = nil + } +} + +func (s *SHA256Hash) Reset() error { + if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_sha256(), engineRef(s.engine)) { + return errors.New("openssl: sha256: cannot init digest ctx") + } + return nil +} + +func (s *SHA256Hash) Write(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]), + C.size_t(len(p))) { + return 0, errors.New("openssl: sha256: cannot update digest") + } + return len(p), nil +} + +func (s *SHA256Hash) Sum() (result [32]byte, err error) { + if 1 != C.X_EVP_DigestFinal_ex(s.ctx, + (*C.uchar)(unsafe.Pointer(&result[0])), nil) { + return result, errors.New("openssl: sha256: cannot finalize ctx") + } + return result, s.Reset() +} + +func SHA256(data []byte) (result [32]byte, err error) { + hash, err := NewSHA256Hash() + if err != nil { + return result, err + } + defer hash.Close() + if _, err := hash.Write(data); err != nil { + return result, err + } + return hash.Sum() +} diff --git a/vendor/github.com/libp2p/go-openssl/shim.c b/vendor/github.com/libp2p/go-openssl/shim.c new file mode 100644 index 0000000000..6e680841cb --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/shim.c @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2014 Space Monkey, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "_cgo_export.h" + +/* + * Functions defined in other .c files + */ +extern int go_init_locks(); +extern void go_thread_locking_callback(int, int, const char*, int); +extern unsigned long go_thread_id_callback(); +static int go_write_bio_puts(BIO *b, const char *str) { + return go_write_bio_write(b, (char*)str, (int)strlen(str)); +} + +/* + ************************************************ + * v1.1.1 and later implementation + ************************************************ + */ +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL + +const int X_ED25519_SUPPORT = 1; +int X_EVP_PKEY_ED25519 = EVP_PKEY_ED25519; + +int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ + return EVP_DigestSignInit(ctx, pctx, type, e, pkey); +} + +int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, + size_t *siglen, const unsigned char *tbs, size_t tbslen) { + return EVP_DigestSign(ctx, sigret, siglen, tbs, tbslen); +} + + +int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ + return EVP_DigestVerifyInit(ctx, pctx, type, e, pkey); +} + +int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, + size_t siglen, const unsigned char *tbs, size_t tbslen){ + return EVP_DigestVerify(ctx, sigret, siglen, tbs, tbslen); +} + +#else + +const int X_ED25519_SUPPORT = 0; +int X_EVP_PKEY_ED25519 = EVP_PKEY_NONE; + +int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ + return 0; +} + +int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, + size_t *siglen, const unsigned char *tbs, size_t tbslen) { + return 0; +} + + +int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey){ + return 0; +} + +int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, + size_t siglen, const unsigned char *tbs, size_t tbslen){ + return 0; +} + +#endif + +/* + ************************************************ + * v1.1.X and later implementation + ************************************************ + */ +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL + +void X_BIO_set_data(BIO* bio, void* data) { + BIO_set_data(bio, data); +} + +void* X_BIO_get_data(BIO* bio) { + return BIO_get_data(bio); +} + +EVP_MD_CTX* X_EVP_MD_CTX_new() { + return EVP_MD_CTX_new(); +} + +void X_EVP_MD_CTX_free(EVP_MD_CTX* ctx) { + EVP_MD_CTX_free(ctx); +} + +static int x_bio_create(BIO *b) { + BIO_set_shutdown(b, 1); + BIO_set_init(b, 1); + BIO_set_data(b, NULL); + BIO_clear_flags(b, ~0); + return 1; +} + +static int x_bio_free(BIO *b) { + return 1; +} + +static BIO_METHOD *writeBioMethod; +static BIO_METHOD *readBioMethod; + +BIO_METHOD* BIO_s_readBio() { return readBioMethod; } +BIO_METHOD* BIO_s_writeBio() { return writeBioMethod; } + +int x_bio_init_methods() { + writeBioMethod = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "Go Write BIO"); + if (!writeBioMethod) { + return 1; + } + if (1 != BIO_meth_set_write(writeBioMethod, + (int (*)(BIO *, const char *, int))go_write_bio_write)) { + return 2; + } + if (1 != BIO_meth_set_puts(writeBioMethod, go_write_bio_puts)) { + return 3; + } + if (1 != BIO_meth_set_ctrl(writeBioMethod, go_write_bio_ctrl)) { + return 4; + } + if (1 != BIO_meth_set_create(writeBioMethod, x_bio_create)) { + return 5; + } + if (1 != BIO_meth_set_destroy(writeBioMethod, x_bio_free)) { + return 6; + } + + readBioMethod = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "Go Read BIO"); + if (!readBioMethod) { + return 7; + } + if (1 != BIO_meth_set_read(readBioMethod, go_read_bio_read)) { + return 8; + } + if (1 != BIO_meth_set_ctrl(readBioMethod, go_read_bio_ctrl)) { + return 9; + } + if (1 != BIO_meth_set_create(readBioMethod, x_bio_create)) { + return 10; + } + if (1 != BIO_meth_set_destroy(readBioMethod, x_bio_free)) { + return 11; + } + + return 0; +} + +const EVP_MD *X_EVP_dss() { + return NULL; +} + +const EVP_MD *X_EVP_dss1() { + return NULL; +} + +const EVP_MD *X_EVP_sha() { + return NULL; +} + +int X_EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx) { + return EVP_CIPHER_CTX_encrypting(ctx); +} + +int X_X509_add_ref(X509* x509) { + return X509_up_ref(x509); +} + +const ASN1_TIME *X_X509_get0_notBefore(const X509 *x) { + return X509_get0_notBefore(x); +} + +const ASN1_TIME *X_X509_get0_notAfter(const X509 *x) { + return X509_get0_notAfter(x); +} + +HMAC_CTX *X_HMAC_CTX_new(void) { + return HMAC_CTX_new(); +} + +void X_HMAC_CTX_free(HMAC_CTX *ctx) { + HMAC_CTX_free(ctx); +} + +int X_PEM_write_bio_PrivateKey_traditional(BIO *bio, EVP_PKEY *key, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { + return PEM_write_bio_PrivateKey_traditional(bio, key, enc, kstr, klen, cb, u); +} + +#endif + +/* + ************************************************ + * v1.0.X implementation + ************************************************ + */ +#if OPENSSL_VERSION_NUMBER < 0x1010000fL + +static int x_bio_create(BIO *b) { + b->shutdown = 1; + b->init = 1; + b->num = -1; + b->ptr = NULL; + b->flags = 0; + return 1; +} + +static int x_bio_free(BIO *b) { + return 1; +} + +static BIO_METHOD writeBioMethod = { + BIO_TYPE_SOURCE_SINK, + "Go Write BIO", + (int (*)(BIO *, const char *, int))go_write_bio_write, + NULL, + go_write_bio_puts, + NULL, + go_write_bio_ctrl, + x_bio_create, + x_bio_free, + NULL}; + +static BIO_METHOD* BIO_s_writeBio() { return &writeBioMethod; } + +static BIO_METHOD readBioMethod = { + BIO_TYPE_SOURCE_SINK, + "Go Read BIO", + NULL, + go_read_bio_read, + NULL, + NULL, + go_read_bio_ctrl, + x_bio_create, + x_bio_free, + NULL}; + +static BIO_METHOD* BIO_s_readBio() { return &readBioMethod; } + +int x_bio_init_methods() { + /* statically initialized above */ + return 0; +} + +void X_BIO_set_data(BIO* bio, void* data) { + bio->ptr = data; +} + +void* X_BIO_get_data(BIO* bio) { + return bio->ptr; +} + +EVP_MD_CTX* X_EVP_MD_CTX_new() { + return EVP_MD_CTX_create(); +} + +void X_EVP_MD_CTX_free(EVP_MD_CTX* ctx) { + EVP_MD_CTX_destroy(ctx); +} + +int X_X509_add_ref(X509* x509) { + CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); + return 1; +} + +const ASN1_TIME *X_X509_get0_notBefore(const X509 *x) { + return x->cert_info->validity->notBefore; +} + +const ASN1_TIME *X_X509_get0_notAfter(const X509 *x) { + return x->cert_info->validity->notAfter; +} + +const EVP_MD *X_EVP_dss() { + return EVP_dss(); +} + +const EVP_MD *X_EVP_dss1() { + return EVP_dss1(); +} + +const EVP_MD *X_EVP_sha() { + return EVP_sha(); +} + +int X_EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx) { + return ctx->encrypt; +} + +HMAC_CTX *X_HMAC_CTX_new(void) { + /* v1.1.0 uses a OPENSSL_zalloc to allocate the memory which does not exist + * in previous versions. malloc+memset to get the same behavior */ + HMAC_CTX *ctx = (HMAC_CTX *)OPENSSL_malloc(sizeof(HMAC_CTX)); + if (ctx) { + memset(ctx, 0, sizeof(HMAC_CTX)); + HMAC_CTX_init(ctx); + } + return ctx; +} + +void X_HMAC_CTX_free(HMAC_CTX *ctx) { + if (ctx) { + HMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +int X_PEM_write_bio_PrivateKey_traditional(BIO *bio, EVP_PKEY *key, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) { + /* PEM_write_bio_PrivateKey always tries to use the PKCS8 format if it + * is available, instead of using the "traditional" format as stated in the + * OpenSSL man page. + * i2d_PrivateKey should give us the correct DER encoding, so we'll just + * use PEM_ASN1_write_bio directly to write the DER encoding with the correct + * type header. */ + + int ppkey_id, pkey_base_id, ppkey_flags; + const char *pinfo, *ppem_str; + char pem_type_str[80]; + + // Lookup the ASN1 method information to get the pem type + if (EVP_PKEY_asn1_get0_info(&ppkey_id, &pkey_base_id, &ppkey_flags, &pinfo, &ppem_str, key->ameth) != 1) { + return 0; + } + // Set up the PEM type string + if (BIO_snprintf(pem_type_str, 80, "%s PRIVATE KEY", ppem_str) <= 0) { + // Failed to write out the pem type string, something is really wrong. + return 0; + } + // Write out everything to the BIO + return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, + pem_type_str, bio, key, enc, kstr, klen, cb, u); +} + +#endif + +/* + ************************************************ + * common implementation + ************************************************ + */ + +int X_shim_init() { + int rc = 0; + + OPENSSL_config(NULL); + ENGINE_load_builtin_engines(); + SSL_load_error_strings(); + SSL_library_init(); + OpenSSL_add_all_algorithms(); + // + // Set up OPENSSL thread safety callbacks. + rc = go_init_locks(); + if (rc != 0) { + return rc; + } + CRYPTO_set_locking_callback(go_thread_locking_callback); + CRYPTO_set_id_callback(go_thread_id_callback); + + rc = x_bio_init_methods(); + if (rc != 0) { + return rc; + } + + return 0; +} + +void * X_OPENSSL_malloc(size_t size) { + return OPENSSL_malloc(size); +} + +void X_OPENSSL_free(void *ref) { + OPENSSL_free(ref); +} + +long X_SSL_set_options(SSL* ssl, long options) { + return SSL_set_options(ssl, options); +} + +long X_SSL_get_options(SSL* ssl) { + return SSL_get_options(ssl); +} + +long X_SSL_clear_options(SSL* ssl, long options) { + return SSL_clear_options(ssl, options); +} + +long X_SSL_set_tlsext_host_name(SSL *ssl, const char *name) { + return SSL_set_tlsext_host_name(ssl, name); +} +const char * X_SSL_get_cipher_name(const SSL *ssl) { + return SSL_get_cipher_name(ssl); +} +int X_SSL_session_reused(SSL *ssl) { + return SSL_session_reused(ssl); +} + +int X_SSL_new_index() { + return SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); +} + +int X_SSL_verify_cb(int ok, X509_STORE_CTX* store) { + SSL* ssl = (SSL *)X509_STORE_CTX_get_ex_data(store, + SSL_get_ex_data_X509_STORE_CTX_idx()); + void* p = SSL_get_ex_data(ssl, get_ssl_idx()); + // get the pointer to the go Ctx object and pass it back into the thunk + return go_ssl_verify_cb_thunk(p, ok, store); +} + +const SSL_METHOD *X_SSLv23_method() { + return SSLv23_method(); +} + +const SSL_METHOD *X_SSLv3_method() { +#ifndef OPENSSL_NO_SSL3_METHOD + return SSLv3_method(); +#else + return NULL; +#endif +} + +const SSL_METHOD *X_TLSv1_method() { + return TLSv1_method(); +} + +const SSL_METHOD *X_TLSv1_1_method() { +#if defined(TLS1_1_VERSION) && !defined(OPENSSL_SYSNAME_MACOSX) + return TLSv1_1_method(); +#else + return NULL; +#endif +} + +const SSL_METHOD *X_TLSv1_2_method() { +#if defined(TLS1_2_VERSION) && !defined(OPENSSL_SYSNAME_MACOSX) + return TLSv1_2_method(); +#else + return NULL; +#endif +} + +int X_SSL_CTX_new_index() { + return SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); +} + +long X_SSL_CTX_set_options(SSL_CTX* ctx, long options) { + return SSL_CTX_set_options(ctx, options); +} + +long X_SSL_CTX_clear_options(SSL_CTX* ctx, long options) { + return SSL_CTX_clear_options(ctx, options); +} + +long X_SSL_CTX_get_options(SSL_CTX* ctx) { + return SSL_CTX_get_options(ctx); +} + +long X_SSL_CTX_set_mode(SSL_CTX* ctx, long modes) { + return SSL_CTX_set_mode(ctx, modes); +} + +long X_SSL_CTX_get_mode(SSL_CTX* ctx) { + return SSL_CTX_get_mode(ctx); +} + +long X_SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long modes) { + return SSL_CTX_set_session_cache_mode(ctx, modes); +} + +long X_SSL_CTX_sess_set_cache_size(SSL_CTX* ctx, long t) { + return SSL_CTX_sess_set_cache_size(ctx, t); +} + +long X_SSL_CTX_sess_get_cache_size(SSL_CTX* ctx) { + return SSL_CTX_sess_get_cache_size(ctx); +} + +long X_SSL_CTX_set_timeout(SSL_CTX* ctx, long t) { + return SSL_CTX_set_timeout(ctx, t); +} + +long X_SSL_CTX_get_timeout(SSL_CTX* ctx) { + return SSL_CTX_get_timeout(ctx); +} + +long X_SSL_CTX_add_extra_chain_cert(SSL_CTX* ctx, X509 *cert) { + return SSL_CTX_add_extra_chain_cert(ctx, cert); +} + +long X_SSL_CTX_set_tmp_ecdh(SSL_CTX* ctx, EC_KEY *key) { + return SSL_CTX_set_tmp_ecdh(ctx, key); +} + +long X_SSL_CTX_set_tlsext_servername_callback( + SSL_CTX* ctx, int (*cb)(SSL *con, int *ad, void *args)) { + return SSL_CTX_set_tlsext_servername_callback(ctx, cb); +} + +int X_SSL_CTX_verify_cb(int ok, X509_STORE_CTX* store) { + SSL* ssl = (SSL *)X509_STORE_CTX_get_ex_data(store, + SSL_get_ex_data_X509_STORE_CTX_idx()); + SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(ssl); + void* p = SSL_CTX_get_ex_data(ssl_ctx, get_ssl_ctx_idx()); + // get the pointer to the go Ctx object and pass it back into the thunk + return go_ssl_ctx_verify_cb_thunk(p, ok, store); +} + +long X_SSL_CTX_set_tmp_dh(SSL_CTX* ctx, DH *dh) { + return SSL_CTX_set_tmp_dh(ctx, dh); +} + +long X_PEM_read_DHparams(SSL_CTX* ctx, DH *dh) { + return SSL_CTX_set_tmp_dh(ctx, dh); +} + +int X_SSL_CTX_set_tlsext_ticket_key_cb(SSL_CTX *sslctx, + int (*cb)(SSL *s, unsigned char key_name[16], + unsigned char iv[EVP_MAX_IV_LENGTH], + EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc)) { + return SSL_CTX_set_tlsext_ticket_key_cb(sslctx, cb); +} + +int X_SSL_CTX_ticket_key_cb(SSL *s, unsigned char key_name[16], + unsigned char iv[EVP_MAX_IV_LENGTH], + EVP_CIPHER_CTX *cctx, HMAC_CTX *hctx, int enc) { + + SSL_CTX* ssl_ctx = SSL_get_SSL_CTX(s); + void* p = SSL_CTX_get_ex_data(ssl_ctx, get_ssl_ctx_idx()); + // get the pointer to the go Ctx object and pass it back into the thunk + return go_ticket_key_cb_thunk(p, s, key_name, iv, cctx, hctx, enc); +} + +int X_BIO_get_flags(BIO *b) { + return BIO_get_flags(b); +} + +void X_BIO_set_flags(BIO *b, int flags) { + return BIO_set_flags(b, flags); +} + +void X_BIO_clear_flags(BIO *b, int flags) { + BIO_clear_flags(b, flags); +} + +int X_BIO_read(BIO *b, void *buf, int len) { + return BIO_read(b, buf, len); +} + +int X_BIO_write(BIO *b, const void *buf, int len) { + return BIO_write(b, buf, len); +} + +BIO *X_BIO_new_write_bio() { + return BIO_new(BIO_s_writeBio()); +} + +BIO *X_BIO_new_read_bio() { + return BIO_new(BIO_s_readBio()); +} + +const EVP_MD *X_EVP_get_digestbyname(const char *name) { + return EVP_get_digestbyname(name); +} + +const EVP_MD *X_EVP_md_null() { + return EVP_md_null(); +} + +const EVP_MD *X_EVP_md5() { + return EVP_md5(); +} + +const EVP_MD *X_EVP_md4() { + return EVP_md4(); +} + +const EVP_MD *X_EVP_ripemd160() { + return EVP_ripemd160(); +} + +const EVP_MD *X_EVP_sha224() { + return EVP_sha224(); +} + +const EVP_MD *X_EVP_sha1() { + return EVP_sha1(); +} + +const EVP_MD *X_EVP_sha256() { + return EVP_sha256(); +} + +const EVP_MD *X_EVP_sha384() { + return EVP_sha384(); +} + +const EVP_MD *X_EVP_sha512() { + return EVP_sha512(); +} + +int X_EVP_MD_size(const EVP_MD *md) { + return EVP_MD_size(md); +} + +int X_EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) { + return EVP_DigestInit_ex(ctx, type, impl); +} + +int X_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt) { + return EVP_DigestUpdate(ctx, d, cnt); +} + +int X_EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s) { + return EVP_DigestFinal_ex(ctx, md, s); +} + +int X_EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + return EVP_SignInit(ctx, type); +} + +int X_EVP_SignUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt) { + return EVP_SignUpdate(ctx, d, cnt); +} + +EVP_PKEY *X_EVP_PKEY_new(void) { + return EVP_PKEY_new(); +} + +void X_EVP_PKEY_free(EVP_PKEY *pkey) { + EVP_PKEY_free(pkey); +} + +int X_EVP_PKEY_size(EVP_PKEY *pkey) { + return EVP_PKEY_size(pkey); +} + +struct rsa_st *X_EVP_PKEY_get1_RSA(EVP_PKEY *pkey) { + return EVP_PKEY_get1_RSA(pkey); +} + +int X_EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key) { + return EVP_PKEY_set1_RSA(pkey, key); +} + +int X_EVP_PKEY_assign_charp(EVP_PKEY *pkey, int type, char *key) { + return EVP_PKEY_assign(pkey, type, key); +} + +int X_EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s, EVP_PKEY *pkey) { + return EVP_SignFinal(ctx, md, s, pkey); +} + +int X_EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + return EVP_VerifyInit(ctx, type); +} + +int X_EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, + unsigned int cnt) { + return EVP_VerifyUpdate(ctx, d, cnt); +} + +int X_EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf, unsigned int siglen, EVP_PKEY *pkey) { + return EVP_VerifyFinal(ctx, sigbuf, siglen, pkey); +} + +int X_EVP_CIPHER_block_size(EVP_CIPHER *c) { + return EVP_CIPHER_block_size(c); +} + +int X_EVP_CIPHER_key_length(EVP_CIPHER *c) { + return EVP_CIPHER_key_length(c); +} + +int X_EVP_CIPHER_iv_length(EVP_CIPHER *c) { + return EVP_CIPHER_iv_length(c); +} + +int X_EVP_CIPHER_nid(EVP_CIPHER *c) { + return EVP_CIPHER_nid(c); +} + +int X_EVP_CIPHER_CTX_block_size(EVP_CIPHER_CTX *ctx) { + return EVP_CIPHER_CTX_block_size(ctx); +} + +int X_EVP_CIPHER_CTX_key_length(EVP_CIPHER_CTX *ctx) { + return EVP_CIPHER_CTX_key_length(ctx); +} + +int X_EVP_CIPHER_CTX_iv_length(EVP_CIPHER_CTX *ctx) { + return EVP_CIPHER_CTX_iv_length(ctx); +} + +void X_EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int padding) { + //openssl always returns 1 for set_padding + //hence return value is not checked + EVP_CIPHER_CTX_set_padding(ctx, padding); +} + +const EVP_CIPHER *X_EVP_CIPHER_CTX_cipher(EVP_CIPHER_CTX *ctx) { + return EVP_CIPHER_CTX_cipher(ctx); +} + +int X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid) { + return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid); +} + +size_t X_HMAC_size(const HMAC_CTX *e) { + return HMAC_size(e); +} + +int X_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, ENGINE *impl) { + return HMAC_Init_ex(ctx, key, len, md, impl); +} + +int X_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len) { + return HMAC_Update(ctx, data, len); +} + +int X_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len) { + return HMAC_Final(ctx, md, len); +} + +int X_sk_X509_num(STACK_OF(X509) *sk) { + return sk_X509_num(sk); +} + +X509 *X_sk_X509_value(STACK_OF(X509)* sk, int i) { + return sk_X509_value(sk, i); +} + +long X_X509_get_version(const X509 *x) { + return X509_get_version(x); +} + +int X_X509_set_version(X509 *x, long version) { + return X509_set_version(x, version); +} diff --git a/vendor/github.com/libp2p/go-openssl/shim.h b/vendor/github.com/libp2p/go-openssl/shim.h new file mode 100644 index 0000000000..75ee0b19f0 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/shim.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2014 Space Monkey, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef SSL_MODE_RELEASE_BUFFERS +#define SSL_MODE_RELEASE_BUFFERS 0 +#endif + +#ifndef SSL_OP_NO_COMPRESSION +#define SSL_OP_NO_COMPRESSION 0 +#endif + +/* shim methods */ +extern int X_shim_init(); + +/* Library methods */ +extern void X_OPENSSL_free(void *ref); +extern void *X_OPENSSL_malloc(size_t size); + +/* SSL methods */ +extern long X_SSL_set_options(SSL* ssl, long options); +extern long X_SSL_get_options(SSL* ssl); +extern long X_SSL_clear_options(SSL* ssl, long options); +extern long X_SSL_set_tlsext_host_name(SSL *ssl, const char *name); +extern const char * X_SSL_get_cipher_name(const SSL *ssl); +extern int X_SSL_session_reused(SSL *ssl); +extern int X_SSL_new_index(); + +extern const SSL_METHOD *X_SSLv23_method(); +extern const SSL_METHOD *X_SSLv3_method(); +extern const SSL_METHOD *X_TLSv1_method(); +extern const SSL_METHOD *X_TLSv1_1_method(); +extern const SSL_METHOD *X_TLSv1_2_method(); + +#if defined SSL_CTRL_SET_TLSEXT_HOSTNAME +extern int sni_cb(SSL *ssl_conn, int *ad, void *arg); +#endif +extern int X_SSL_verify_cb(int ok, X509_STORE_CTX* store); + +/* SSL_CTX methods */ +extern int X_SSL_CTX_new_index(); +extern long X_SSL_CTX_set_options(SSL_CTX* ctx, long options); +extern long X_SSL_CTX_clear_options(SSL_CTX* ctx, long options); +extern long X_SSL_CTX_get_options(SSL_CTX* ctx); +extern long X_SSL_CTX_set_mode(SSL_CTX* ctx, long modes); +extern long X_SSL_CTX_get_mode(SSL_CTX* ctx); +extern long X_SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long modes); +extern long X_SSL_CTX_sess_set_cache_size(SSL_CTX* ctx, long t); +extern long X_SSL_CTX_sess_get_cache_size(SSL_CTX* ctx); +extern long X_SSL_CTX_set_timeout(SSL_CTX* ctx, long t); +extern long X_SSL_CTX_get_timeout(SSL_CTX* ctx); +extern long X_SSL_CTX_add_extra_chain_cert(SSL_CTX* ctx, X509 *cert); +extern long X_SSL_CTX_set_tmp_ecdh(SSL_CTX* ctx, EC_KEY *key); +extern long X_SSL_CTX_set_tlsext_servername_callback(SSL_CTX* ctx, int (*cb)(SSL *con, int *ad, void *args)); +extern int X_SSL_CTX_verify_cb(int ok, X509_STORE_CTX* store); +extern long X_SSL_CTX_set_tmp_dh(SSL_CTX* ctx, DH *dh); +extern long X_PEM_read_DHparams(SSL_CTX* ctx, DH *dh); +extern int X_SSL_CTX_set_tlsext_ticket_key_cb(SSL_CTX *sslctx, + int (*cb)(SSL *s, unsigned char key_name[16], + unsigned char iv[EVP_MAX_IV_LENGTH], + EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc)); +extern int X_SSL_CTX_ticket_key_cb(SSL *s, unsigned char key_name[16], + unsigned char iv[EVP_MAX_IV_LENGTH], + EVP_CIPHER_CTX *cctx, HMAC_CTX *hctx, int enc); + +/* BIO methods */ +extern int X_BIO_get_flags(BIO *b); +extern void X_BIO_set_flags(BIO *bio, int flags); +extern void X_BIO_clear_flags(BIO *bio, int flags); +extern void X_BIO_set_data(BIO *bio, void* data); +extern void *X_BIO_get_data(BIO *bio); +extern int X_BIO_read(BIO *b, void *buf, int len); +extern int X_BIO_write(BIO *b, const void *buf, int len); +extern BIO *X_BIO_new_write_bio(); +extern BIO *X_BIO_new_read_bio(); + +/* EVP methods */ +extern const int X_ED25519_SUPPORT; +extern int X_EVP_PKEY_ED25519; +extern const EVP_MD *X_EVP_get_digestbyname(const char *name); +extern EVP_MD_CTX *X_EVP_MD_CTX_new(); +extern void X_EVP_MD_CTX_free(EVP_MD_CTX *ctx); +extern const EVP_MD *X_EVP_md_null(); +extern const EVP_MD *X_EVP_md5(); +extern const EVP_MD *X_EVP_md4(); +extern const EVP_MD *X_EVP_sha(); +extern const EVP_MD *X_EVP_sha1(); +extern const EVP_MD *X_EVP_dss(); +extern const EVP_MD *X_EVP_dss1(); +extern const EVP_MD *X_EVP_ripemd160(); +extern const EVP_MD *X_EVP_sha224(); +extern const EVP_MD *X_EVP_sha256(); +extern const EVP_MD *X_EVP_sha384(); +extern const EVP_MD *X_EVP_sha512(); +extern int X_EVP_MD_size(const EVP_MD *md); +extern int X_EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl); +extern int X_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt); +extern int X_EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s); +extern int X_EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type); +extern int X_EVP_SignUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt); +extern int X_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey); +extern int X_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs, size_t tbslen); +extern EVP_PKEY *X_EVP_PKEY_new(void); +extern void X_EVP_PKEY_free(EVP_PKEY *pkey); +extern int X_EVP_PKEY_size(EVP_PKEY *pkey); +extern struct rsa_st *X_EVP_PKEY_get1_RSA(EVP_PKEY *pkey); +extern int X_EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key); +extern int X_EVP_PKEY_assign_charp(EVP_PKEY *pkey, int type, char *key); +extern int X_EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s, EVP_PKEY *pkey); +extern int X_EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type); +extern int X_EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt); +extern int X_EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf, unsigned int siglen, EVP_PKEY *pkey); +extern int X_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey); +extern int X_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen); +extern int X_EVP_CIPHER_block_size(EVP_CIPHER *c); +extern int X_EVP_CIPHER_key_length(EVP_CIPHER *c); +extern int X_EVP_CIPHER_iv_length(EVP_CIPHER *c); +extern int X_EVP_CIPHER_nid(EVP_CIPHER *c); +extern int X_EVP_CIPHER_CTX_block_size(EVP_CIPHER_CTX *ctx); +extern int X_EVP_CIPHER_CTX_key_length(EVP_CIPHER_CTX *ctx); +extern int X_EVP_CIPHER_CTX_iv_length(EVP_CIPHER_CTX *ctx); +extern void X_EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int padding); +extern const EVP_CIPHER *X_EVP_CIPHER_CTX_cipher(EVP_CIPHER_CTX *ctx); +extern int X_EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx); +extern int X_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX *ctx, int nid); + +/* HMAC methods */ +extern size_t X_HMAC_size(const HMAC_CTX *e); +extern HMAC_CTX *X_HMAC_CTX_new(void); +extern void X_HMAC_CTX_free(HMAC_CTX *ctx); +extern int X_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, ENGINE *impl); +extern int X_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len); +extern int X_HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); + +/* X509 methods */ +extern int X_X509_add_ref(X509* x509); +extern const ASN1_TIME *X_X509_get0_notBefore(const X509 *x); +extern const ASN1_TIME *X_X509_get0_notAfter(const X509 *x); +extern int X_sk_X509_num(STACK_OF(X509) *sk); +extern X509 *X_sk_X509_value(STACK_OF(X509)* sk, int i); +extern long X_X509_get_version(const X509 *x); +extern int X_X509_set_version(X509 *x, long version); + +/* PEM methods */ +extern int X_PEM_write_bio_PrivateKey_traditional(BIO *bio, EVP_PKEY *key, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +/* Object methods */ +extern int OBJ_create(const char *oid,const char *sn,const char *ln); \ No newline at end of file diff --git a/vendor/github.com/libp2p/go-openssl/sni.c b/vendor/github.com/libp2p/go-openssl/sni.c new file mode 100644 index 0000000000..f9e8d16b0e --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/sni.c @@ -0,0 +1,23 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "_cgo_export.h" +#include + +int sni_cb(SSL *con, int *ad, void *arg) { + SSL_CTX* ssl_ctx = ssl_ctx = SSL_get_SSL_CTX(con); + void* p = SSL_CTX_get_ex_data(ssl_ctx, get_ssl_ctx_idx()); + return sni_cb_thunk(p, con, ad, arg); +} diff --git a/vendor/github.com/libp2p/go-openssl/ssl.go b/vendor/github.com/libp2p/go-openssl/ssl.go new file mode 100644 index 0000000000..117c30c0f9 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/ssl.go @@ -0,0 +1,170 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "os" + "unsafe" +) + +type SSLTLSExtErr int + +const ( + SSLTLSExtErrOK SSLTLSExtErr = C.SSL_TLSEXT_ERR_OK + SSLTLSExtErrAlertWarning SSLTLSExtErr = C.SSL_TLSEXT_ERR_ALERT_WARNING + SSLTLSEXTErrAlertFatal SSLTLSExtErr = C.SSL_TLSEXT_ERR_ALERT_FATAL + SSLTLSEXTErrNoAck SSLTLSExtErr = C.SSL_TLSEXT_ERR_NOACK +) + +var ( + ssl_idx = C.X_SSL_new_index() +) + +//export get_ssl_idx +func get_ssl_idx() C.int { + return ssl_idx +} + +type SSL struct { + ssl *C.SSL + verify_cb VerifyCallback +} + +//export go_ssl_verify_cb_thunk +func go_ssl_verify_cb_thunk(p unsafe.Pointer, ok C.int, ctx *C.X509_STORE_CTX) C.int { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: verify callback panic'd: %v", err) + os.Exit(1) + } + }() + verify_cb := (*SSL)(p).verify_cb + // set up defaults just in case verify_cb is nil + if verify_cb != nil { + store := &CertificateStoreCtx{ctx: ctx} + if verify_cb(ok == 1, store) { + ok = 1 + } else { + ok = 0 + } + } + return ok +} + +// Wrapper around SSL_get_servername. Returns server name according to rfc6066 +// http://tools.ietf.org/html/rfc6066. +func (s *SSL) GetServername() string { + return C.GoString(C.SSL_get_servername(s.ssl, C.TLSEXT_NAMETYPE_host_name)) +} + +// GetOptions returns SSL options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (s *SSL) GetOptions() Options { + return Options(C.X_SSL_get_options(s.ssl)) +} + +// SetOptions sets SSL options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (s *SSL) SetOptions(options Options) Options { + return Options(C.X_SSL_set_options(s.ssl, C.long(options))) +} + +// ClearOptions clear SSL options. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html +func (s *SSL) ClearOptions(options Options) Options { + return Options(C.X_SSL_clear_options(s.ssl, C.long(options))) +} + +// SetVerify controls peer verification settings. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerify(options VerifyOptions, verify_cb VerifyCallback) { + s.verify_cb = verify_cb + if verify_cb != nil { + C.SSL_set_verify(s.ssl, C.int(options), (*[0]byte)(C.X_SSL_verify_cb)) + } else { + C.SSL_set_verify(s.ssl, C.int(options), nil) + } +} + +// SetVerifyMode controls peer verification setting. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerifyMode(options VerifyOptions) { + s.SetVerify(options, s.verify_cb) +} + +// SetVerifyCallback controls peer verification setting. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerifyCallback(verify_cb VerifyCallback) { + s.SetVerify(s.VerifyMode(), verify_cb) +} + +// GetVerifyCallback returns callback function. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) GetVerifyCallback() VerifyCallback { + return s.verify_cb +} + +// VerifyMode returns peer verification setting. See +// http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) VerifyMode() VerifyOptions { + return VerifyOptions(C.SSL_get_verify_mode(s.ssl)) +} + +// SetVerifyDepth controls how many certificates deep the certificate +// verification logic is willing to follow a certificate chain. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) SetVerifyDepth(depth int) { + C.SSL_set_verify_depth(s.ssl, C.int(depth)) +} + +// GetVerifyDepth controls how many certificates deep the certificate +// verification logic is willing to follow a certificate chain. See +// https://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html +func (s *SSL) GetVerifyDepth() int { + return int(C.SSL_get_verify_depth(s.ssl)) +} + +// SetSSLCtx changes context to new one. Useful for Server Name Indication (SNI) +// rfc6066 http://tools.ietf.org/html/rfc6066. See +// http://stackoverflow.com/questions/22373332/serving-multiple-domains-in-one-box-with-sni +func (s *SSL) SetSSLCtx(ctx *Ctx) { + /* + * SSL_set_SSL_CTX() only changes certs as of 1.0.0d + * adjust other things we care about + */ + C.SSL_set_SSL_CTX(s.ssl, ctx.ctx) +} + +//export sni_cb_thunk +func sni_cb_thunk(p unsafe.Pointer, con *C.SSL, ad unsafe.Pointer, arg unsafe.Pointer) C.int { + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: verify callback sni panic'd: %v", err) + os.Exit(1) + } + }() + + sni_cb := (*Ctx)(p).sni_cb + + s := &SSL{ssl: con} + // This attaches a pointer to our SSL struct into the SNI callback. + C.SSL_set_ex_data(s.ssl, get_ssl_idx(), unsafe.Pointer(s)) + + // Note: this is ctx.sni_cb, not C.sni_cb + return C.int(sni_cb(s)) +} diff --git a/vendor/github.com/libp2p/go-openssl/tickets.go b/vendor/github.com/libp2p/go-openssl/tickets.go new file mode 100644 index 0000000000..a064d38592 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/tickets.go @@ -0,0 +1,222 @@ +// Copyright (C) 2017. See AUTHORS. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openssl + +// #include "shim.h" +import "C" + +import ( + "os" + "unsafe" +) + +const ( + KeyNameSize = 16 +) + +// TicketCipherCtx describes the cipher that will be used by the ticket store +// for encrypting the tickets. Engine may be nil if no engine is desired. +type TicketCipherCtx struct { + Cipher *Cipher + Engine *Engine +} + +// TicketDigestCtx describes the digest that will be used by the ticket store +// to authenticate the data. Engine may be nil if no engine is desired. +type TicketDigestCtx struct { + Digest *Digest + Engine *Engine +} + +// TicketName is an identifier for the key material for a ticket. +type TicketName [KeyNameSize]byte + +// TicketKey is the key material for a ticket. If this is lost, forward secrecy +// is lost as it allows decrypting TLS sessions retroactively. +type TicketKey struct { + Name TicketName + CipherKey []byte + HMACKey []byte + IV []byte +} + +// TicketKeyManager is a manager for TicketKeys. It allows one to control the +// lifetime of tickets, causing renewals and expirations for keys that are +// created. Calls to the manager are serialized. +type TicketKeyManager interface { + // New should create a brand new TicketKey with a new name. + New() *TicketKey + + // Current should return a key that is still valid. + Current() *TicketKey + + // Lookup should return a key with the given name, or nil if no name + // exists. + Lookup(name TicketName) *TicketKey + + // Expired should return if the key with the given name is expired and + // should not be used any more. + Expired(name TicketName) bool + + // ShouldRenew should return if the key is still ok to use for the current + // session, but we should send a new key for the client. + ShouldRenew(name TicketName) bool +} + +// TicketStore descibes the encryption and authentication methods the tickets +// will use along with a key manager for generating and keeping track of the +// secrets. +type TicketStore struct { + CipherCtx TicketCipherCtx + DigestCtx TicketDigestCtx + Keys TicketKeyManager +} + +func (t *TicketStore) cipherEngine() *C.ENGINE { + if t.CipherCtx.Engine == nil { + return nil + } + return t.CipherCtx.Engine.e +} + +func (t *TicketStore) digestEngine() *C.ENGINE { + if t.DigestCtx.Engine == nil { + return nil + } + return t.DigestCtx.Engine.e +} + +const ( + // instruct to do a handshake + ticket_resp_requireHandshake = 0 + // crypto context is set up correctly + ticket_resp_sessionOk = 1 + // crypto context is ok, but the ticket should be reissued + ticket_resp_renewSession = 2 + // we had a problem that shouldn't fall back to doing a handshake + ticket_resp_error = -1 + + // asked to create session crypto context + ticket_req_newSession = 1 + // asked to load crypto context for a previous session + ticket_req_lookupSession = 0 +) + +//export go_ticket_key_cb_thunk +func go_ticket_key_cb_thunk(p unsafe.Pointer, s *C.SSL, key_name *C.uchar, + iv *C.uchar, cctx *C.EVP_CIPHER_CTX, hctx *C.HMAC_CTX, enc C.int) C.int { + + // no panic's allowed. it's super hard to guarantee any state at this point + // so just abort everything. + defer func() { + if err := recover(); err != nil { + logger.Critf("openssl: ticket key callback panic'd: %v", err) + os.Exit(1) + } + }() + + ctx := (*Ctx)(p) + store := ctx.ticket_store + if store == nil { + // TODO(jeff): should this be an error condition? it doesn't make sense + // to be called if we don't have a store I believe, but that's probably + // not worth aborting the handshake which is what I believe returning + // an error would do. + return ticket_resp_requireHandshake + } + + ctx.ticket_store_mu.Lock() + defer ctx.ticket_store_mu.Unlock() + + switch enc { + case ticket_req_newSession: + key := store.Keys.Current() + if key == nil { + key = store.Keys.New() + if key == nil { + return ticket_resp_requireHandshake + } + } + + C.memcpy( + unsafe.Pointer(key_name), + unsafe.Pointer(&key.Name[0]), + KeyNameSize) + C.EVP_EncryptInit_ex( + cctx, + store.CipherCtx.Cipher.ptr, + store.cipherEngine(), + (*C.uchar)(&key.CipherKey[0]), + (*C.uchar)(&key.IV[0])) + C.HMAC_Init_ex( + hctx, + unsafe.Pointer(&key.HMACKey[0]), + C.int(len(key.HMACKey)), + store.DigestCtx.Digest.ptr, + store.digestEngine()) + + return ticket_resp_sessionOk + + case ticket_req_lookupSession: + var name TicketName + C.memcpy( + unsafe.Pointer(&name[0]), + unsafe.Pointer(key_name), + KeyNameSize) + + key := store.Keys.Lookup(name) + if key == nil { + return ticket_resp_requireHandshake + } + if store.Keys.Expired(name) { + return ticket_resp_requireHandshake + } + + C.EVP_DecryptInit_ex( + cctx, + store.CipherCtx.Cipher.ptr, + store.cipherEngine(), + (*C.uchar)(&key.CipherKey[0]), + (*C.uchar)(&key.IV[0])) + C.HMAC_Init_ex( + hctx, + unsafe.Pointer(&key.HMACKey[0]), + C.int(len(key.HMACKey)), + store.DigestCtx.Digest.ptr, + store.digestEngine()) + + if store.Keys.ShouldRenew(name) { + return ticket_resp_renewSession + } + + return ticket_resp_sessionOk + + default: + return ticket_resp_error + } +} + +// SetTicketStore sets the ticket store for the context so that clients can do +// ticket based session resumption. If the store is nil, the +func (c *Ctx) SetTicketStore(store *TicketStore) { + c.ticket_store = store + + if store == nil { + C.X_SSL_CTX_set_tlsext_ticket_key_cb(c.ctx, nil) + } else { + C.X_SSL_CTX_set_tlsext_ticket_key_cb(c.ctx, + (*[0]byte)(C.X_SSL_CTX_ticket_key_cb)) + } +} diff --git a/vendor/github.com/libp2p/go-openssl/utils/errors.go b/vendor/github.com/libp2p/go-openssl/utils/errors.go new file mode 100644 index 0000000000..bab314c95d --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/utils/errors.go @@ -0,0 +1,50 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "errors" + "strings" +) + +// ErrorGroup collates errors +type ErrorGroup struct { + Errors []error +} + +// Add adds an error to an existing error group +func (e *ErrorGroup) Add(err error) { + if err != nil { + e.Errors = append(e.Errors, err) + } +} + +// Finalize returns an error corresponding to the ErrorGroup state. If there's +// no errors in the group, finalize returns nil. If there's only one error, +// Finalize returns that error. Otherwise, Finalize will make a new error +// consisting of the messages from the constituent errors. +func (e *ErrorGroup) Finalize() error { + if len(e.Errors) == 0 { + return nil + } + if len(e.Errors) == 1 { + return e.Errors[0] + } + msgs := make([]string, 0, len(e.Errors)) + for _, err := range e.Errors { + msgs = append(msgs, err.Error()) + } + return errors.New(strings.Join(msgs, "\n")) +} diff --git a/vendor/github.com/libp2p/go-openssl/utils/future.go b/vendor/github.com/libp2p/go-openssl/utils/future.go new file mode 100644 index 0000000000..fa1bbbfb86 --- /dev/null +++ b/vendor/github.com/libp2p/go-openssl/utils/future.go @@ -0,0 +1,79 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "sync" +) + +// Future is a type that is essentially the inverse of a channel. With a +// channel, you have multiple senders and one receiver. With a future, you can +// have multiple receivers and one sender. Additionally, a future protects +// against double-sends. Since this is usually used for returning function +// results, we also capture and return error values as well. Use NewFuture +// to initialize. +type Future struct { + mutex *sync.Mutex + cond *sync.Cond + received bool + val interface{} + err error +} + +// NewFuture returns an initialized and ready Future. +func NewFuture() *Future { + mutex := &sync.Mutex{} + return &Future{ + mutex: mutex, + cond: sync.NewCond(mutex), + received: false, + val: nil, + err: nil, + } +} + +// Get blocks until the Future has a value set. +func (self *Future) Get() (interface{}, error) { + self.mutex.Lock() + defer self.mutex.Unlock() + for { + if self.received { + return self.val, self.err + } + self.cond.Wait() + } +} + +// Fired returns whether or not a value has been set. If Fired is true, Get +// won't block. +func (self *Future) Fired() bool { + self.mutex.Lock() + defer self.mutex.Unlock() + return self.received +} + +// Set provides the value to present and future Get calls. If Set has already +// been called, this is a no-op. +func (self *Future) Set(val interface{}, err error) { + self.mutex.Lock() + defer self.mutex.Unlock() + if self.received { + return + } + self.received = true + self.val = val + self.err = err + self.cond.Broadcast() +} diff --git a/vendor/github.com/multiformats/go-base32/LICENSE b/vendor/github.com/multiformats/go-base32/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/github.com/multiformats/go-base32/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/multiformats/go-base32/base32.go b/vendor/github.com/multiformats/go-base32/base32.go new file mode 100644 index 0000000000..768a235099 --- /dev/null +++ b/vendor/github.com/multiformats/go-base32/base32.go @@ -0,0 +1,505 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package base32 implements base32 encoding as specified by RFC 4648. +package base32 + +import ( + "io" + "strconv" +) + +/* + * Encodings + */ + +// An Encoding is a radix 32 encoding/decoding scheme, defined by a +// 32-character alphabet. The most common is the "base32" encoding +// introduced for SASL GSSAPI and standardized in RFC 4648. +// The alternate "base32hex" encoding is used in DNSSEC. +type Encoding struct { + encode string + decodeMap [256]byte + padChar rune +} + +// Alphabet returns the Base32 alphabet used +func (enc *Encoding) Alphabet() string { + return enc.encode +} + +const ( + StdPadding rune = '=' + NoPadding rune = -1 +) + +const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" +const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV" + +// NewEncoding returns a new Encoding defined by the given alphabet, +// which must be a 32-byte string. +func NewEncoding(encoder string) *Encoding { + e := new(Encoding) + e.padChar = StdPadding + e.encode = encoder + for i := 0; i < len(e.decodeMap); i++ { + e.decodeMap[i] = 0xFF + } + for i := 0; i < len(encoder); i++ { + e.decodeMap[encoder[i]] = byte(i) + } + return e +} + +// NewEncoding returns a new case insensitive Encoding defined by the +// given alphabet, which must be a 32-byte string. +func NewEncodingCI(encoder string) *Encoding { + e := new(Encoding) + e.padChar = StdPadding + e.encode = encoder + for i := 0; i < len(e.decodeMap); i++ { + e.decodeMap[i] = 0xFF + } + for i := 0; i < len(encoder); i++ { + e.decodeMap[asciiToLower(encoder[i])] = byte(i) + e.decodeMap[asciiToUpper(encoder[i])] = byte(i) + } + return e +} + +func asciiToLower(c byte) byte { + if c >= 'A' && c <= 'Z' { + return c + 32 + } + return c +} + +func asciiToUpper(c byte) byte { + if c >= 'a' && c <= 'z' { + return c - 32 + } + return c +} + +// WithPadding creates a new encoding identical to enc except +// with a specified padding character, or NoPadding to disable padding. +func (enc Encoding) WithPadding(padding rune) *Encoding { + enc.padChar = padding + return &enc +} + +// StdEncoding is the standard base32 encoding, as defined in +// RFC 4648. +var StdEncoding = NewEncodingCI(encodeStd) + +// HexEncoding is the ``Extended Hex Alphabet'' defined in RFC 4648. +// It is typically used in DNS. +var HexEncoding = NewEncodingCI(encodeHex) + +var RawStdEncoding = NewEncodingCI(encodeStd).WithPadding(NoPadding) +var RawHexEncoding = NewEncodingCI(encodeHex).WithPadding(NoPadding) + +/* + * Encoder + */ + +// Encode encodes src using the encoding enc, writing +// EncodedLen(len(src)) bytes to dst. +// +// The encoding pads the output to a multiple of 8 bytes, +// so Encode is not appropriate for use on individual blocks +// of a large data stream. Use NewEncoder() instead. +func (enc *Encoding) Encode(dst, src []byte) { + if len(src) == 0 { + return + } + + for len(src) > 0 { + var carry byte + + // Unpack 8x 5-bit source blocks into a 5 byte + // destination quantum + switch len(src) { + default: + dst[7] = enc.encode[src[4]&0x1F] + carry = src[4] >> 5 + fallthrough + case 4: + dst[6] = enc.encode[carry|(src[3]<<3)&0x1F] + dst[5] = enc.encode[(src[3]>>2)&0x1F] + carry = src[3] >> 7 + fallthrough + case 3: + dst[4] = enc.encode[carry|(src[2]<<1)&0x1F] + carry = (src[2] >> 4) & 0x1F + fallthrough + case 2: + dst[3] = enc.encode[carry|(src[1]<<4)&0x1F] + dst[2] = enc.encode[(src[1]>>1)&0x1F] + carry = (src[1] >> 6) & 0x1F + fallthrough + case 1: + dst[1] = enc.encode[carry|(src[0]<<2)&0x1F] + dst[0] = enc.encode[src[0]>>3] + } + + // Pad the final quantum + if len(src) < 5 { + if enc.padChar != NoPadding { + dst[7] = byte(enc.padChar) + if len(src) < 4 { + dst[6] = byte(enc.padChar) + dst[5] = byte(enc.padChar) + if len(src) < 3 { + dst[4] = byte(enc.padChar) + if len(src) < 2 { + dst[3] = byte(enc.padChar) + dst[2] = byte(enc.padChar) + } + } + } + } + break + } + src = src[5:] + dst = dst[8:] + } +} + +// EncodeToString returns the base32 encoding of src. +func (enc *Encoding) EncodeToString(src []byte) string { + buf := make([]byte, enc.EncodedLen(len(src))) + enc.Encode(buf, src) + return string(buf) +} + +type encoder struct { + err error + enc *Encoding + w io.Writer + buf [5]byte // buffered data waiting to be encoded + nbuf int // number of bytes in buf + out [1024]byte // output buffer +} + +func (e *encoder) Write(p []byte) (n int, err error) { + if e.err != nil { + return 0, e.err + } + + // Leading fringe. + if e.nbuf > 0 { + var i int + for i = 0; i < len(p) && e.nbuf < 5; i++ { + e.buf[e.nbuf] = p[i] + e.nbuf++ + } + n += i + p = p[i:] + if e.nbuf < 5 { + return + } + e.enc.Encode(e.out[0:], e.buf[0:]) + if _, e.err = e.w.Write(e.out[0:8]); e.err != nil { + return n, e.err + } + e.nbuf = 0 + } + + // Large interior chunks. + for len(p) >= 5 { + nn := len(e.out) / 8 * 5 + if nn > len(p) { + nn = len(p) + nn -= nn % 5 + } + e.enc.Encode(e.out[0:], p[0:nn]) + if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil { + return n, e.err + } + n += nn + p = p[nn:] + } + + // Trailing fringe. + for i := 0; i < len(p); i++ { + e.buf[i] = p[i] + } + e.nbuf = len(p) + n += len(p) + return +} + +// Close flushes any pending output from the encoder. +// It is an error to call Write after calling Close. +func (e *encoder) Close() error { + // If there's anything left in the buffer, flush it out + if e.err == nil && e.nbuf > 0 { + e.enc.Encode(e.out[0:], e.buf[0:e.nbuf]) + e.nbuf = 0 + _, e.err = e.w.Write(e.out[0:8]) + } + return e.err +} + +// NewEncoder returns a new base32 stream encoder. Data written to +// the returned writer will be encoded using enc and then written to w. +// Base32 encodings operate in 5-byte blocks; when finished +// writing, the caller must Close the returned encoder to flush any +// partially written blocks. +func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser { + return &encoder{enc: enc, w: w} +} + +// EncodedLen returns the length in bytes of the base32 encoding +// of an input buffer of length n. +func (enc *Encoding) EncodedLen(n int) int { + if enc.padChar == NoPadding { + return (n*8 + 4) / 5 // minimum # chars at 5 bits per char + } + return (n + 4) / 5 * 8 +} + +/* + * Decoder + */ + +type CorruptInputError int64 + +func (e CorruptInputError) Error() string { + return "illegal base32 data at input byte " + strconv.FormatInt(int64(e), 10) +} + +// decode is like Decode but returns an additional 'end' value, which +// indicates if end-of-message padding was encountered and thus any +// additional data is an error. This method assumes that src has been +// stripped of all supported whitespace ('\r' and '\n'). +func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { + olen := len(src) + for len(src) > 0 && !end { + // Decode quantum using the base32 alphabet + var dbuf [8]byte + dlen := 8 + + for j := 0; j < 8; { + if len(src) == 0 { + if enc.padChar != NoPadding { + return n, false, CorruptInputError(olen - len(src) - j) + } + dlen = j + break + } + in := src[0] + src = src[1:] + if in == byte(enc.padChar) && j >= 2 && len(src) < 8 { + if enc.padChar == NoPadding { + return n, false, CorruptInputError(olen) + } + + // We've reached the end and there's padding + if len(src)+j < 8-1 { + // not enough padding + return n, false, CorruptInputError(olen) + } + for k := 0; k < 8-1-j; k++ { + if len(src) > k && src[k] != byte(enc.padChar) { + // incorrect padding + return n, false, CorruptInputError(olen - len(src) + k - 1) + } + } + dlen, end = j, true + // 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not + // valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing + // the five valid padding lengths, and Section 9 "Illustrations and + // Examples" for an illustration for how the 1st, 3rd and 6th base32 + // src bytes do not yield enough information to decode a dst byte. + if dlen == 1 || dlen == 3 || dlen == 6 { + return n, false, CorruptInputError(olen - len(src) - 1) + } + break + } + dbuf[j] = enc.decodeMap[in] + if dbuf[j] == 0xFF { + return n, false, CorruptInputError(olen - len(src) - 1) + } + j++ + } + + // Pack 8x 5-bit source blocks into 5 byte destination + // quantum + switch dlen { + case 8: + dst[4] = dbuf[6]<<5 | dbuf[7] + fallthrough + case 7: + dst[3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3 + fallthrough + case 5: + dst[2] = dbuf[3]<<4 | dbuf[4]>>1 + fallthrough + case 4: + dst[1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4 + fallthrough + case 2: + dst[0] = dbuf[0]<<3 | dbuf[1]>>2 + } + + if len(dst) > 5 { + dst = dst[5:] + } + + switch dlen { + case 2: + n += 1 + case 4: + n += 2 + case 5: + n += 3 + case 7: + n += 4 + case 8: + n += 5 + } + } + return n, end, nil +} + +// Decode decodes src using the encoding enc. It writes at most +// DecodedLen(len(src)) bytes to dst and returns the number of bytes +// written. If src contains invalid base32 data, it will return the +// number of bytes successfully written and CorruptInputError. +// New line characters (\r and \n) are ignored. +func (enc *Encoding) Decode(dst, s []byte) (n int, err error) { + // FIXME: if dst is the same as s use decodeInPlace + stripped := make([]byte, 0, len(s)) + for _, c := range s { + if c != '\r' && c != '\n' { + stripped = append(stripped, c) + } + } + n, _, err = enc.decode(dst, stripped) + return +} + +func (enc *Encoding) decodeInPlace(strb []byte) (n int, err error) { + off := 0 + for _, b := range strb { + if b == '\n' || b == '\r' { + continue + } + strb[off] = b + off++ + } + n, _, err = enc.decode(strb, strb[:off]) + return +} + +// DecodeString returns the bytes represented by the base32 string s. +func (enc *Encoding) DecodeString(s string) ([]byte, error) { + strb := []byte(s) + n, err := enc.decodeInPlace(strb) + if err != nil { + return nil, err + } + return strb[:n], nil +} + +type decoder struct { + err error + enc *Encoding + r io.Reader + end bool // saw end of message + buf [1024]byte // leftover input + nbuf int + out []byte // leftover decoded output + outbuf [1024 / 8 * 5]byte +} + +func (d *decoder) Read(p []byte) (n int, err error) { + if d.err != nil { + return 0, d.err + } + + // Use leftover decoded output from last read. + if len(d.out) > 0 { + n = copy(p, d.out) + d.out = d.out[n:] + return n, nil + } + + // Read a chunk. + nn := len(p) / 5 * 8 + if nn < 8 { + nn = 8 + } + if nn > len(d.buf) { + nn = len(d.buf) + } + nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 8-d.nbuf) + d.nbuf += nn + if d.nbuf < 8 { + return 0, d.err + } + + // Decode chunk into p, or d.out and then p if p is too small. + nr := d.nbuf / 8 * 8 + nw := d.nbuf / 8 * 5 + if nw > len(p) { + nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr]) + d.out = d.outbuf[0:nw] + n = copy(p, d.out) + d.out = d.out[n:] + } else { + n, d.end, d.err = d.enc.decode(p, d.buf[0:nr]) + } + d.nbuf -= nr + for i := 0; i < d.nbuf; i++ { + d.buf[i] = d.buf[i+nr] + } + + if d.err == nil { + d.err = err + } + return n, d.err +} + +type newlineFilteringReader struct { + wrapped io.Reader +} + +func (r *newlineFilteringReader) Read(p []byte) (int, error) { + n, err := r.wrapped.Read(p) + for n > 0 { + offset := 0 + for i, b := range p[0:n] { + if b != '\r' && b != '\n' { + if i != offset { + p[offset] = b + } + offset++ + } + } + if offset > 0 { + return offset, err + } + // Previous buffer entirely whitespace, read again + n, err = r.wrapped.Read(p) + } + return n, err +} + +// NewDecoder constructs a new base32 stream decoder. +func NewDecoder(enc *Encoding, r io.Reader) io.Reader { + return &decoder{enc: enc, r: &newlineFilteringReader{r}} +} + +// DecodedLen returns the maximum length in bytes of the decoded data +// corresponding to n bytes of base32-encoded data. +func (enc *Encoding) DecodedLen(n int) int { + if enc.padChar == NoPadding { + return (n*5 + 7) / 8 + } + + return n / 8 * 5 +} diff --git a/vendor/github.com/multiformats/go-base32/go.mod b/vendor/github.com/multiformats/go-base32/go.mod new file mode 100644 index 0000000000..fcc446feaf --- /dev/null +++ b/vendor/github.com/multiformats/go-base32/go.mod @@ -0,0 +1 @@ +module github.com/multiformats/go-base32 diff --git a/vendor/github.com/multiformats/go-base32/package.json b/vendor/github.com/multiformats/go-base32/package.json new file mode 100644 index 0000000000..04a9970d73 --- /dev/null +++ b/vendor/github.com/multiformats/go-base32/package.json @@ -0,0 +1,15 @@ +{ + "author": "Golang", + "bugs": { + "url": "https://github.com/multiformats/go-base32" + }, + "gx": { + "dvcsimport": "github.com/multiformats/go-base32" + }, + "gxVersion": "0.7.0", + "language": "go", + "license": "BSD-3", + "name": "base32", + "version": "0.0.3" +} + diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/.gitignore b/vendor/github.com/multiformats/go-multiaddr-dns/.gitignore new file mode 100644 index 0000000000..4621ab7383 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/.gitignore @@ -0,0 +1 @@ +/madns/madns diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/.travis.yml b/vendor/github.com/multiformats/go-multiaddr-dns/.travis.yml new file mode 100644 index 0000000000..336deb460c --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/.travis.yml @@ -0,0 +1,30 @@ +os: + - linux + +language: go + +go: + - 1.12.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/pkg/mod + - /home/travis/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/LICENSE b/vendor/github.com/multiformats/go-multiaddr-dns/LICENSE new file mode 100644 index 0000000000..c7386b3c94 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/README.md b/vendor/github.com/multiformats/go-multiaddr-dns/README.md new file mode 100644 index 0000000000..3958c3cf20 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/README.md @@ -0,0 +1,57 @@ +# go-multiaddr-dns + +> Resolve /dns4, /dns6, and /dnsaddr multiaddrs. + +```sh +> madns /dnsaddr/ipfs.io/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx +/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx +/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx +/ip6/fc3d:9a4e:3c96:2fd2:1afa:18fe:8dd2:b602/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx +/dns4/jupiter.i.ipfs.io/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx +/dns6/jupiter.i.ipfs.io/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx +``` + + +In more detail: + +```sh +> madns /dns6/example.net +/ip6/2001:db8::a3 +/ip6/2001:db8::a4 +... + +> madns /dns4/example.net/tcp/443/wss +/ip4/192.0.2.1/tcp/443/wss +/ip4/192.0.2.2/tcp/443/wss + +# No-op if it's not a dns-ish address. + +> madns /ip4/127.0.0.1/tcp/8080 +/ip4/127.0.0.1/tcp/8080 + +# /dnsaddr resolves by looking up TXT records. + +> dig +short TXT _dnsaddr.example.net +"dnsaddr=/ip6/2001:db8::a3/tcp/443/wss/ipfs/Qmfoo" +"dnsaddr=/ip6/2001:db8::a4/tcp/443/wss/ipfs/Qmbar" +"dnsaddr=/ip4/192.0.2.1/tcp/443/wss/ipfs/Qmfoo" +"dnsaddr=/ip4/192.0.2.2/tcp/443/wss/ipfs/Qmbar" +... + +# /dnsaddr returns addrs which encapsulate whatever /dnsaddr encapsulates too. + +> madns example.net/ipfs/Qmfoo +info: changing query to /dnsaddr/example.net/ipfs/Qmfoo +/ip6/2001:db8::a3/tcp/443/wss/ipfs/Qmfoo +/ip4/192.0.2.1/tcp/443/wss/ipfs/Qmfoo + +# TODO -p filters by protocol stacks. + +> madns -p /ip6/tcp/wss /dnsaddr/example.net +/ip6/2001:db8::a3/tcp/443/wss/ipfs/Qmfoo +/ip6/2001:db8::a4/tcp/443/wss/ipfs/Qmbar + +# TODO -c filters by CIDR +> madns -c /ip4/104.236.76.0/ipcidr/24 /dnsaddr/example.net +/ip4/192.0.2.2/tcp/443/wss/ipfs/Qmbar +``` diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/dns.go b/vendor/github.com/multiformats/go-multiaddr-dns/dns.go new file mode 100644 index 0000000000..4a5a93460c --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/dns.go @@ -0,0 +1,29 @@ +package madns + +import ( + ma "github.com/multiformats/go-multiaddr" +) + +// Extracted from source of truth for multicodec codes: https://github.com/multiformats/multicodec +const ( + // Deprecated: use ma.P_DNS + P_DNS = ma.P_DNS + // Deprecated: use ma.P_DNS4 + P_DNS4 = ma.P_DNS4 + // Deprecated: use ma.P_DNS6 + P_DNS6 = ma.P_DNS6 + // Deprecated: use ma.P_DNSADDR + P_DNSADDR = ma.P_DNSADDR +) + +// Deprecated: use ma.ProtocolWithCode(P_DNS) +var DnsProtocol = ma.ProtocolWithCode(P_DNS) + +// Deprecated: use ma.ProtocolWithCode(P_DNS4) +var Dns4Protocol = ma.ProtocolWithCode(P_DNS4) + +// Deprecated: use ma.ProtocolWithCode(P_DNS6) +var Dns6Protocol = ma.ProtocolWithCode(P_DNS6) + +// Deprecated: use ma.ProtocolWithCode(P_DNSADDR) +var DnsaddrProtocol = ma.ProtocolWithCode(P_DNSADDR) diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/go.mod b/vendor/github.com/multiformats/go-multiaddr-dns/go.mod new file mode 100644 index 0000000000..0824647482 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/go.mod @@ -0,0 +1,5 @@ +module github.com/multiformats/go-multiaddr-dns + +require github.com/multiformats/go-multiaddr v0.1.1 + +go 1.12 diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/go.sum b/vendor/github.com/multiformats/go-multiaddr-dns/go.sum new file mode 100644 index 0000000000..0061b94a7d --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/go.sum @@ -0,0 +1,20 @@ +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-multiaddr v0.1.1 h1:rVAztJYMhCQ7vEFr8FvxW3mS+HF2eY/oPbOMeS0ZDnE= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/multiformats/go-multiaddr-dns/resolve.go b/vendor/github.com/multiformats/go-multiaddr-dns/resolve.go new file mode 100644 index 0000000000..64d8f707db --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr-dns/resolve.go @@ -0,0 +1,269 @@ +package madns + +import ( + "context" + "net" + "strings" + + ma "github.com/multiformats/go-multiaddr" +) + +var ResolvableProtocols = []ma.Protocol{DnsaddrProtocol, Dns4Protocol, Dns6Protocol, DnsProtocol} +var DefaultResolver = &Resolver{Backend: net.DefaultResolver} + +const dnsaddrTXTPrefix = "dnsaddr=" + +type backend interface { + LookupIPAddr(context.Context, string) ([]net.IPAddr, error) + LookupTXT(context.Context, string) ([]string, error) +} + +type Resolver struct { + Backend backend +} + +type MockBackend struct { + IP map[string][]net.IPAddr + TXT map[string][]string +} + +func (r *MockBackend) LookupIPAddr(ctx context.Context, name string) ([]net.IPAddr, error) { + results, ok := r.IP[name] + if ok { + return results, nil + } else { + return []net.IPAddr{}, nil + } +} + +func (r *MockBackend) LookupTXT(ctx context.Context, name string) ([]string, error) { + results, ok := r.TXT[name] + if ok { + return results, nil + } else { + return []string{}, nil + } +} + +func Matches(maddr ma.Multiaddr) (matches bool) { + ma.ForEach(maddr, func(c ma.Component) bool { + switch c.Protocol().Code { + case DnsProtocol.Code, Dns4Protocol.Code, Dns6Protocol.Code, DnsaddrProtocol.Code: + matches = true + } + return !matches + }) + return matches +} + +func Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) { + return DefaultResolver.Resolve(ctx, maddr) +} + +func (r *Resolver) Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) { + var results []ma.Multiaddr + for i := 0; maddr != nil; i++ { + var keep ma.Multiaddr + + // Find the next dns component. + keep, maddr = ma.SplitFunc(maddr, func(c ma.Component) bool { + switch c.Protocol().Code { + case DnsProtocol.Code, Dns4Protocol.Code, Dns6Protocol.Code, DnsaddrProtocol.Code: + return true + default: + return false + } + }) + + // Keep everything before the dns component. + if keep != nil { + if len(results) == 0 { + results = []ma.Multiaddr{keep} + } else { + for i, r := range results { + results[i] = r.Encapsulate(keep) + } + } + } + + // If the rest is empty, we've hit the end (there _was_ no dns component). + if maddr == nil { + break + } + + // split off the dns component. + var resolve *ma.Component + resolve, maddr = ma.SplitFirst(maddr) + + proto := resolve.Protocol() + value := resolve.Value() + + // resolve the dns component + var resolved []ma.Multiaddr + switch proto.Code { + case Dns4Protocol.Code, Dns6Protocol.Code, DnsProtocol.Code: + // The dns, dns4, and dns6 resolver simply resolves each + // dns* component into an ipv4/ipv6 address. + + v4only := proto.Code == Dns4Protocol.Code + v6only := proto.Code == Dns6Protocol.Code + + // XXX: Unfortunately, go does a pretty terrible job of + // differentiating between IPv6 and IPv4. A v4-in-v6 + // AAAA record will _look_ like an A record to us and + // there's nothing we can do about that. + records, err := r.Backend.LookupIPAddr(ctx, value) + if err != nil { + return nil, err + } + + // Convert each DNS record into a multiaddr. If the + // protocol is dns4, throw away any IPv6 addresses. If + // the protocol is dns6, throw away any IPv4 addresses. + + for _, r := range records { + var ( + rmaddr ma.Multiaddr + err error + ) + ip4 := r.IP.To4() + if ip4 == nil { + if v4only { + continue + } + rmaddr, err = ma.NewMultiaddr("/ip6/" + r.IP.String()) + } else { + if v6only { + continue + } + rmaddr, err = ma.NewMultiaddr("/ip4/" + ip4.String()) + } + if err != nil { + return nil, err + } + resolved = append(resolved, rmaddr) + } + case DnsaddrProtocol.Code: + // The dnsaddr resolver is a bit more complicated. We: + // + // 1. Lookup the dnsaddr txt record on _dnsaddr.DOMAIN.TLD + // 2. Take everything _after_ the `/dnsaddr/DOMAIN.TLD` + // part of the multiaddr. + // 3. Find the dnsaddr records (if any) with suffixes + // matching the result of step 2. + + // First, lookup the TXT record + records, err := r.Backend.LookupTXT(ctx, "_dnsaddr."+value) + if err != nil { + return nil, err + } + + // Then, calculate the length of the suffix we're + // looking for. + length := 0 + if maddr != nil { + length = addrLen(maddr) + } + + for _, r := range records { + // Ignore non dnsaddr TXT records. + if !strings.HasPrefix(r, dnsaddrTXTPrefix) { + continue + } + + // Extract and decode the multiaddr. + rmaddr, err := ma.NewMultiaddr(r[len(dnsaddrTXTPrefix):]) + if err != nil { + // discard multiaddrs we don't understand. + // XXX: Is this right? It's the best we + // can do for now, really. + continue + } + + // If we have a suffix to match on. + if maddr != nil { + // Make sure the new address is at least + // as long as the suffix we're looking + // for. + rmlen := addrLen(rmaddr) + if rmlen < length { + // not long enough. + continue + } + + // Matches everything after the /dnsaddr/... with the end of the + // dnsaddr record: + // + // v----------rmlen-----------------v + // /ip4/1.2.3.4/tcp/1234/p2p/QmFoobar + // /p2p/QmFoobar + // ^--(rmlen - length)--^---length--^ + if !maddr.Equal(offset(rmaddr, rmlen-length)) { + continue + } + } + + resolved = append(resolved, rmaddr) + } + + // consumes the rest of the multiaddr as part of the "match" process. + maddr = nil + default: + panic("unreachable") + } + + if len(resolved) == 0 { + return nil, nil + } else if len(results) == 0 { + results = resolved + } else { + // We take the cross product here as we don't have any + // better way to represent "ORs" in multiaddrs. For + // example, `/dns/foo.com/p2p-circuit/dns/bar.com` could + // resolve to: + // + // * /ip4/1.1.1.1/p2p-circuit/ip4/2.1.1.1 + // * /ip4/1.1.1.1/p2p-circuit/ip4/2.1.1.2 + // * /ip4/1.1.1.2/p2p-circuit/ip4/2.1.1.1 + // * /ip4/1.1.1.2/p2p-circuit/ip4/2.1.1.2 + results = cross(results, resolved) + } + } + + return results, nil +} + +// counts the number of components in the multiaddr +func addrLen(maddr ma.Multiaddr) int { + length := 0 + ma.ForEach(maddr, func(_ ma.Component) bool { + length++ + return true + }) + return length +} + +// trims `offset` components from the beginning of the multiaddr. +func offset(maddr ma.Multiaddr, offset int) ma.Multiaddr { + _, after := ma.SplitFunc(maddr, func(c ma.Component) bool { + if offset == 0 { + return true + } + offset-- + return false + }) + return after +} + +// takes the cross product of two sets of multiaddrs +// +// assumes `a` is non-empty. +func cross(a, b []ma.Multiaddr) []ma.Multiaddr { + res := make([]ma.Multiaddr, 0, len(a)*len(b)) + for _, x := range a { + for _, y := range b { + res = append(res, x.Encapsulate(y)) + } + } + return res +} diff --git a/vendor/github.com/multiformats/go-multiaddr/.gitignore b/vendor/github.com/multiformats/go-multiaddr/.gitignore new file mode 100644 index 0000000000..699d271b02 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/.gitignore @@ -0,0 +1,3 @@ +.vscode/ +multiaddr/multiaddr +tmp/ diff --git a/vendor/github.com/multiformats/go-multiaddr/.travis.yml b/vendor/github.com/multiformats/go-multiaddr/.travis.yml new file mode 100644 index 0000000000..95e4daaa06 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/.travis.yml @@ -0,0 +1,31 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + - GO111MODULE=on + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + - make conformance + +cache: + directories: + - $GOPATH/pkg/mod + - /home/travis/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/multiformats/go-multiaddr/LICENSE b/vendor/github.com/multiformats/go-multiaddr/LICENSE new file mode 100644 index 0000000000..c7386b3c94 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/multiformats/go-multiaddr/Makefile b/vendor/github.com/multiformats/go-multiaddr/Makefile new file mode 100644 index 0000000000..fa5197afaf --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/Makefile @@ -0,0 +1,12 @@ +conformance: tmp/multiaddr + go build -o tmp/multiaddr/test/go-multiaddr ./multiaddr + cd tmp/multiaddr/test && MULTIADDR_BIN="./go-multiaddr" go test -v + +tmp/multiaddr: + mkdir -p tmp/ + git clone https://github.com/multiformats/multiaddr tmp/multiaddr/ + +clean: + rm -rf tmp/ + +.PHONY: conformance clean diff --git a/vendor/github.com/multiformats/go-multiaddr/README.md b/vendor/github.com/multiformats/go-multiaddr/README.md new file mode 100644 index 0000000000..df2766aa18 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/README.md @@ -0,0 +1,117 @@ +# go-multiaddr + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) +[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/multiformats/go-multiaddr?status.svg)](https://godoc.org/github.com/multiformats/go-multiaddr) +[![Travis CI](https://img.shields.io/travis/multiformats/go-multiaddr.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multiaddr) +[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multiaddr.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multiaddr?branch=master) + +> [multiaddr](https://github.com/multiformats/multiaddr) implementation in go + +Multiaddr is a standard way to represent addresses that: + +- Support any standard network protocols. +- Self-describe (include protocols). +- Have a binary packed format. +- Have a nice string representation. +- Encapsulate well. + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) + - [Example](#example) + - [Simple](#simple) + - [Protocols](#protocols) + - [En/decapsulate](#endecapsulate) + - [Tunneling](#tunneling) +- [Maintainers](#maintainers) +- [Contribute](#contribute) +- [License](#license) + +## Install + +```sh +go get github.com/multiformats/go-multiaddr +``` + +## Usage + +### Example + +#### Simple + +```go +import ma "github.com/multiformats/go-multiaddr" + +// construct from a string (err signals parse failure) +m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234") + +// construct from bytes (err signals parse failure) +m2, err := ma.NewMultiaddrBytes(m1.Bytes()) + +// true +strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234") +strings.Equal(m1.String(), m2.String()) +bytes.Equal(m1.Bytes(), m2.Bytes()) +m1.Equal(m2) +m2.Equal(m1) +``` + +#### Protocols + +```go +// get the multiaddr protocol description objects +m1.Protocols() +// []Protocol{ +// Protocol{ Code: 4, Name: 'ip4', Size: 32}, +// Protocol{ Code: 17, Name: 'udp', Size: 16}, +// } +``` + +#### En/decapsulate + +```go +import ma "github.com/multiformats/go-multiaddr" + +m, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234") +// + +sctpMA, err := ma.NewMultiaddr("/sctp/5678") + +m.Encapsulate(sctpMA) +// + +udpMA, err := ma.NewMultiaddr("/udp/1234") + +m.Decapsulate(udpMA) // up to + inc last occurrence of subaddr +// +``` + +#### Tunneling + +Multiaddr allows expressing tunnels very nicely. + +```js +printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80") +proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443") +printerOverProxy := proxy.Encapsulate(printer) +// /ip4/10.20.30.40/tcp/443/ip4/192.168.0.13/tcp/80 + +proxyAgain := printerOverProxy.Decapsulate(printer) +// /ip4/10.20.30.40/tcp/443 +``` + +## Contribute + +Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multiaddr/issues). + +Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +[MIT](LICENSE) © 2014 Juan Batiz-Benet diff --git a/vendor/github.com/multiformats/go-multiaddr/codec.go b/vendor/github.com/multiformats/go-multiaddr/codec.go new file mode 100644 index 0000000000..e6b74479cc --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/codec.go @@ -0,0 +1,204 @@ +package multiaddr + +import ( + "bytes" + "fmt" + "strings" + + "github.com/multiformats/go-varint" +) + +func stringToBytes(s string) ([]byte, error) { + // consume trailing slashes + s = strings.TrimRight(s, "/") + + var b bytes.Buffer + sp := strings.Split(s, "/") + + if sp[0] != "" { + return nil, fmt.Errorf("failed to parse multiaddr %q: must begin with /", s) + } + + // consume first empty elem + sp = sp[1:] + + if len(sp) == 0 { + return nil, fmt.Errorf("failed to parse multiaddr %q: empty multiaddr", s) + } + + for len(sp) > 0 { + name := sp[0] + p := ProtocolWithName(name) + if p.Code == 0 { + return nil, fmt.Errorf("failed to parse multiaddr %q: unknown protocol %s", s, sp[0]) + } + _, _ = b.Write(p.VCode) + sp = sp[1:] + + if p.Size == 0 { // no length. + continue + } + + if len(sp) < 1 { + return nil, fmt.Errorf("failed to parse multiaddr %q: unexpected end of multiaddr", s) + } + + if p.Path { + // it's a path protocol (terminal). + // consume the rest of the address as the next component. + sp = []string{"/" + strings.Join(sp, "/")} + } + + a, err := p.Transcoder.StringToBytes(sp[0]) + if err != nil { + return nil, fmt.Errorf("failed to parse multiaddr %q: invalid value %q for protocol %s: %s", s, sp[0], p.Name, err) + } + if p.Size < 0 { // varint size. + _, _ = b.Write(varint.ToUvarint(uint64(len(a)))) + } + b.Write(a) + sp = sp[1:] + } + + return b.Bytes(), nil +} + +func validateBytes(b []byte) (err error) { + if len(b) == 0 { + return fmt.Errorf("empty multiaddr") + } + for len(b) > 0 { + code, n, err := ReadVarintCode(b) + if err != nil { + return err + } + + b = b[n:] + p := ProtocolWithCode(code) + if p.Code == 0 { + return fmt.Errorf("no protocol with code %d", code) + } + + if p.Size == 0 { + continue + } + + n, size, err := sizeForAddr(p, b) + if err != nil { + return err + } + + b = b[n:] + + if len(b) < size || size < 0 { + return fmt.Errorf("invalid value for size %d", len(b)) + } + + err = p.Transcoder.ValidateBytes(b[:size]) + if err != nil { + return err + } + + b = b[size:] + } + + return nil +} + +func readComponent(b []byte) (int, Component, error) { + var offset int + code, n, err := ReadVarintCode(b) + if err != nil { + return 0, Component{}, err + } + offset += n + + p := ProtocolWithCode(code) + if p.Code == 0 { + return 0, Component{}, fmt.Errorf("no protocol with code %d", code) + } + + if p.Size == 0 { + return offset, Component{ + bytes: b[:offset], + offset: offset, + protocol: p, + }, nil + } + + n, size, err := sizeForAddr(p, b[offset:]) + if err != nil { + return 0, Component{}, err + } + + offset += n + + if len(b[offset:]) < size || size < 0 { + return 0, Component{}, fmt.Errorf("invalid value for size %d", len(b[offset:])) + } + + return offset + size, Component{ + bytes: b[:offset+size], + protocol: p, + offset: offset, + }, nil +} + +func bytesToString(b []byte) (ret string, err error) { + if len(b) == 0 { + return "", fmt.Errorf("empty multiaddr") + } + var buf strings.Builder + + for len(b) > 0 { + n, c, err := readComponent(b) + if err != nil { + return "", err + } + b = b[n:] + c.writeTo(&buf) + } + + return buf.String(), nil +} + +func sizeForAddr(p Protocol, b []byte) (skip, size int, err error) { + switch { + case p.Size > 0: + return 0, (p.Size / 8), nil + case p.Size == 0: + return 0, 0, nil + default: + size, n, err := ReadVarintCode(b) + if err != nil { + return 0, 0, err + } + return n, size, nil + } +} + +func bytesSplit(b []byte) ([][]byte, error) { + var ret [][]byte + for len(b) > 0 { + code, n, err := ReadVarintCode(b) + if err != nil { + return nil, err + } + + p := ProtocolWithCode(code) + if p.Code == 0 { + return nil, fmt.Errorf("no protocol with code %d", b[0]) + } + + n2, size, err := sizeForAddr(p, b[n:]) + if err != nil { + return nil, err + } + + length := n + n2 + size + ret = append(ret, b[:length]) + b = b[length:] + } + + return ret, nil +} diff --git a/vendor/github.com/multiformats/go-multiaddr/codecov.yml b/vendor/github.com/multiformats/go-multiaddr/codecov.yml new file mode 100644 index 0000000000..ca8100ab11 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "multiaddr" diff --git a/vendor/github.com/multiformats/go-multiaddr/component.go b/vendor/github.com/multiformats/go-multiaddr/component.go new file mode 100644 index 0000000000..490b8ac90e --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/component.go @@ -0,0 +1,183 @@ +package multiaddr + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "strings" + + "github.com/multiformats/go-varint" +) + +// Component is a single multiaddr Component. +type Component struct { + bytes []byte + protocol Protocol + offset int +} + +func (c *Component) Bytes() []byte { + return c.bytes +} + +func (c *Component) MarshalBinary() ([]byte, error) { + return c.Bytes(), nil +} + +func (c *Component) UnmarshalBinary(data []byte) error { + _, comp, err := readComponent(data) + if err != nil { + return err + } + *c = comp + return nil +} + +func (c *Component) MarshalText() ([]byte, error) { + return []byte(c.String()), nil +} + +func (c *Component) UnmarshalText(data []byte) error { + bytes, err := stringToBytes(string(data)) + if err != nil { + return err + } + _, comp, err := readComponent(bytes) + if err != nil { + return err + } + *c = comp + return nil +} + +func (c *Component) MarshalJSON() ([]byte, error) { + txt, err := c.MarshalText() + if err != nil { + return nil, err + } + + return json.Marshal(string(txt)) +} + +func (m *Component) UnmarshalJSON(data []byte) error { + var v string + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + return m.UnmarshalText([]byte(v)) +} + +func (c *Component) Equal(o Multiaddr) bool { + return bytes.Equal(c.bytes, o.Bytes()) +} + +func (c *Component) Protocols() []Protocol { + return []Protocol{c.protocol} +} + +func (c *Component) Decapsulate(o Multiaddr) Multiaddr { + if c.Equal(o) { + return nil + } + return c +} + +func (c *Component) Encapsulate(o Multiaddr) Multiaddr { + m := &multiaddr{bytes: c.bytes} + return m.Encapsulate(o) +} + +func (c *Component) ValueForProtocol(code int) (string, error) { + if c.protocol.Code != code { + return "", ErrProtocolNotFound + } + return c.Value(), nil +} + +func (c *Component) Protocol() Protocol { + return c.protocol +} + +func (c *Component) RawValue() []byte { + return c.bytes[c.offset:] +} + +func (c *Component) Value() string { + if c.protocol.Transcoder == nil { + return "" + } + value, err := c.protocol.Transcoder.BytesToString(c.bytes[c.offset:]) + if err != nil { + // This Component must have been checked. + panic(err) + } + return value +} + +func (c *Component) String() string { + var b strings.Builder + c.writeTo(&b) + return b.String() +} + +// writeTo is an efficient, private function for string-formatting a multiaddr. +// Trust me, we tend to allocate a lot when doing this. +func (c *Component) writeTo(b *strings.Builder) { + b.WriteByte('/') + b.WriteString(c.protocol.Name) + value := c.Value() + if len(value) == 0 { + return + } + if !(c.protocol.Path && value[0] == '/') { + b.WriteByte('/') + } + b.WriteString(value) +} + +// NewComponent constructs a new multiaddr component +func NewComponent(protocol, value string) (*Component, error) { + p := ProtocolWithName(protocol) + if p.Code == 0 { + return nil, fmt.Errorf("unsupported protocol: %s", protocol) + } + if p.Transcoder != nil { + bts, err := p.Transcoder.StringToBytes(value) + if err != nil { + return nil, err + } + return newComponent(p, bts), nil + } else if value != "" { + return nil, fmt.Errorf("protocol %s doesn't take a value", p.Name) + } + return newComponent(p, nil), nil + // TODO: handle path /? +} + +func newComponent(protocol Protocol, bvalue []byte) *Component { + size := len(bvalue) + size += len(protocol.VCode) + if protocol.Size < 0 { + size += varint.UvarintSize(uint64(len(bvalue))) + } + maddr := make([]byte, size) + var offset int + offset += copy(maddr[offset:], protocol.VCode) + if protocol.Size < 0 { + offset += binary.PutUvarint(maddr[offset:], uint64(len(bvalue))) + } + copy(maddr[offset:], bvalue) + + // For debugging + if len(maddr) != offset+len(bvalue) { + panic("incorrect length") + } + + return &Component{ + bytes: maddr, + protocol: protocol, + offset: offset, + } +} diff --git a/vendor/github.com/multiformats/go-multiaddr/doc.go b/vendor/github.com/multiformats/go-multiaddr/doc.go new file mode 100644 index 0000000000..d8c37b2651 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/doc.go @@ -0,0 +1,36 @@ +/* +Package multiaddr provides an implementation of the Multiaddr network +address format. Multiaddr emphasizes explicitness, self-description, and +portability. It allows applications to treat addresses as opaque tokens, +and to avoid making assumptions about the address representation (e.g. length). +Learn more at https://github.com/multiformats/multiaddr + +Basic Use: + + import ( + "bytes" + "strings" + ma "github.com/multiformats/go-multiaddr" + ) + + // construct from a string (err signals parse failure) + m1, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234") + + // construct from bytes (err signals parse failure) + m2, err := ma.NewMultiaddrBytes(m1.Bytes()) + + // true + strings.Equal(m1.String(), "/ip4/127.0.0.1/udp/1234") + strings.Equal(m1.String(), m2.String()) + bytes.Equal(m1.Bytes(), m2.Bytes()) + m1.Equal(m2) + m2.Equal(m1) + + // tunneling (en/decap) + printer, _ := ma.NewMultiaddr("/ip4/192.168.0.13/tcp/80") + proxy, _ := ma.NewMultiaddr("/ip4/10.20.30.40/tcp/443") + printerOverProxy := proxy.Encapsulate(printer) + proxyAgain := printerOverProxy.Decapsulate(printer) + +*/ +package multiaddr diff --git a/vendor/github.com/multiformats/go-multiaddr/filter.go b/vendor/github.com/multiformats/go-multiaddr/filter.go new file mode 100644 index 0000000000..6751202a86 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/filter.go @@ -0,0 +1,179 @@ +package multiaddr + +import ( + "net" + "sync" +) + +// Action is an enum modelling all possible filter actions. +type Action int32 + +const ( + ActionNone Action = iota // zero value. + ActionAccept + ActionDeny +) + +type filterEntry struct { + f net.IPNet + action Action +} + +// Filters is a structure representing a collection of accept/deny +// net.IPNet filters, together with the DefaultAction flag, which +// represents the default filter policy. +// +// Note that the last policy added to the Filters is authoritative. +type Filters struct { + DefaultAction Action + + mu sync.RWMutex + filters []*filterEntry +} + +// NewFilters constructs and returns a new set of net.IPNet filters. +// By default, the new filter accepts all addresses. +func NewFilters() *Filters { + return &Filters{ + DefaultAction: ActionAccept, + filters: make([]*filterEntry, 0), + } +} + +func (fs *Filters) find(ipnet net.IPNet) (int, *filterEntry) { + s := ipnet.String() + for idx, ft := range fs.filters { + if ft.f.String() == s { + return idx, ft + } + } + return -1, nil +} + +// AddDialFilter adds a deny rule to this Filters set. Hosts +// matching the given net.IPNet filter will be denied, unless +// another rule is added which states that they should be accepted. +// +// No effort is made to prevent duplication of filters, or to simplify +// the filters list. +// +// Deprecated: Use AddFilter(). +func (fs *Filters) AddDialFilter(f *net.IPNet) { + fs.AddFilter(*f, ActionDeny) +} + +// AddFilter adds a rule to the Filters set, enforcing the desired action for +// the provided IPNet mask. +func (fs *Filters) AddFilter(ipnet net.IPNet, action Action) { + fs.mu.Lock() + defer fs.mu.Unlock() + + if _, f := fs.find(ipnet); f != nil { + f.action = action + } else { + fs.filters = append(fs.filters, &filterEntry{ipnet, action}) + } +} + +// RemoveLiteral removes the first filter associated with the supplied IPNet, +// returning whether something was removed or not. It makes no distinction +// between whether the rule is an accept or a deny. +// +// Deprecated: use RemoveLiteral() instead. +func (fs *Filters) Remove(ipnet *net.IPNet) (removed bool) { + return fs.RemoveLiteral(*ipnet) +} + +// RemoveLiteral removes the first filter associated with the supplied IPNet, +// returning whether something was removed or not. It makes no distinction +// between whether the rule is an accept or a deny. +func (fs *Filters) RemoveLiteral(ipnet net.IPNet) (removed bool) { + fs.mu.Lock() + defer fs.mu.Unlock() + + if idx, _ := fs.find(ipnet); idx != -1 { + fs.filters = append(fs.filters[:idx], fs.filters[idx+1:]...) + return true + } + return false +} + +// AddrBlocked parses a ma.Multiaddr and, if a valid netip is found, it applies the +// Filter set rules, returning true if the given address should be denied, and false if +// the given address is accepted. +// +// If a parsing error occurs, or no filter matches, the Filters' +// default is returned. +// +// TODO: currently, the last filter to match wins always, but it shouldn't be that way. +// Instead, the highest-specific last filter should win; that way more specific filters +// override more general ones. +func (fs *Filters) AddrBlocked(a Multiaddr) (deny bool) { + var ( + netip net.IP + found bool + ) + + ForEach(a, func(c Component) bool { + switch c.Protocol().Code { + case P_IP6ZONE: + return true + case P_IP6, P_IP4: + found = true + netip = net.IP(c.RawValue()) + return false + default: + return false + } + }) + + if !found { + return fs.DefaultAction == ActionDeny + } + + fs.mu.RLock() + defer fs.mu.RUnlock() + + action := fs.DefaultAction + for _, ft := range fs.filters { + if ft.f.Contains(netip) { + action = ft.action + } + } + + return action == ActionDeny +} + +// Filters returns the list of DENY net.IPNet masks. For backwards compatibility. +// +// A copy of the filters is made prior to returning, so the inner state is not exposed. +// +// Deprecated: Use FiltersForAction(). +func (fs *Filters) Filters() (result []*net.IPNet) { + ffa := fs.FiltersForAction(ActionDeny) + for _, res := range ffa { + res := res // allocate a new copy + result = append(result, &res) + } + return result +} + +func (fs *Filters) ActionForFilter(ipnet net.IPNet) (action Action, ok bool) { + if _, f := fs.find(ipnet); f != nil { + return f.action, true + } + return ActionNone, false +} + +// FiltersForAction returns the filters associated with the indicated action. +func (fs *Filters) FiltersForAction(action Action) (result []net.IPNet) { + fs.mu.RLock() + defer fs.mu.RUnlock() + + for _, ff := range fs.filters { + if ff.action == action { + result = append(result, ff.f) + } + } + return result +} diff --git a/vendor/github.com/multiformats/go-multiaddr/go.mod b/vendor/github.com/multiformats/go-multiaddr/go.mod new file mode 100644 index 0000000000..a340eda28f --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/go.mod @@ -0,0 +1,8 @@ +module github.com/multiformats/go-multiaddr + +go 1.13 + +require ( + github.com/multiformats/go-multihash v0.0.13 + github.com/multiformats/go-varint v0.0.5 +) diff --git a/vendor/github.com/multiformats/go-multiaddr/go.sum b/vendor/github.com/multiformats/go-multiaddr/go.sum new file mode 100644 index 0000000000..b36340cd48 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/go.sum @@ -0,0 +1,20 @@ +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/multiformats/go-multiaddr/interface.go b/vendor/github.com/multiformats/go-multiaddr/interface.go new file mode 100644 index 0000000000..82cc764010 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/interface.go @@ -0,0 +1,62 @@ +package multiaddr + +import ( + "encoding" + "encoding/json" +) + +/* +Multiaddr is a cross-protocol, cross-platform format for representing +internet addresses. It emphasizes explicitness and self-description. +Learn more here: https://github.com/multiformats/multiaddr + +Multiaddrs have both a binary and string representation. + + import ma "github.com/multiformats/go-multiaddr" + + addr, err := ma.NewMultiaddr("/ip4/1.2.3.4/tcp/80") + // err non-nil when parsing failed. + +*/ +type Multiaddr interface { + json.Marshaler + json.Unmarshaler + encoding.TextMarshaler + encoding.TextUnmarshaler + encoding.BinaryMarshaler + encoding.BinaryUnmarshaler + + // Equal returns whether two Multiaddrs are exactly equal + Equal(Multiaddr) bool + + // Bytes returns the []byte representation of this Multiaddr + // + // This function may expose immutable, internal state. Do not modify. + Bytes() []byte + + // String returns the string representation of this Multiaddr + // (may panic if internal state is corrupted) + String() string + + // Protocols returns the list of Protocols this Multiaddr includes + // will panic if protocol code incorrect (and bytes accessed incorrectly) + Protocols() []Protocol + + // Encapsulate wraps this Multiaddr around another. For example: + // + // /ip4/1.2.3.4 encapsulate /tcp/80 = /ip4/1.2.3.4/tcp/80 + // + Encapsulate(Multiaddr) Multiaddr + + // Decapsultate removes a Multiaddr wrapping. For example: + // + // /ip4/1.2.3.4/tcp/80 decapsulate /ip4/1.2.3.4 = /tcp/80 + // + Decapsulate(Multiaddr) Multiaddr + + // ValueForProtocol returns the value (if any) following the specified protocol + // + // Note: protocols can appear multiple times in a single multiaddr. + // Consider using `ForEach` to walk over the addr manually. + ValueForProtocol(code int) (string, error) +} diff --git a/vendor/github.com/multiformats/go-multiaddr/multiaddr.go b/vendor/github.com/multiformats/go-multiaddr/multiaddr.go new file mode 100644 index 0000000000..58fe8cecbc --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/multiaddr.go @@ -0,0 +1,186 @@ +package multiaddr + +import ( + "bytes" + "encoding/json" + "fmt" + "log" + "strings" +) + +// multiaddr is the data structure representing a Multiaddr +type multiaddr struct { + bytes []byte +} + +// NewMultiaddr parses and validates an input string, returning a *Multiaddr +func NewMultiaddr(s string) (a Multiaddr, err error) { + defer func() { + if e := recover(); e != nil { + log.Printf("Panic in NewMultiaddr on input %q: %s", s, e) + err = fmt.Errorf("%v", e) + } + }() + b, err := stringToBytes(s) + if err != nil { + return nil, err + } + return &multiaddr{bytes: b}, nil +} + +// NewMultiaddrBytes initializes a Multiaddr from a byte representation. +// It validates it as an input string. +func NewMultiaddrBytes(b []byte) (a Multiaddr, err error) { + defer func() { + if e := recover(); e != nil { + log.Printf("Panic in NewMultiaddrBytes on input %q: %s", b, e) + err = fmt.Errorf("%v", e) + } + }() + + if err := validateBytes(b); err != nil { + return nil, err + } + + return &multiaddr{bytes: b}, nil +} + +// Equal tests whether two multiaddrs are equal +func (m *multiaddr) Equal(m2 Multiaddr) bool { + return bytes.Equal(m.bytes, m2.Bytes()) +} + +// Bytes returns the []byte representation of this Multiaddr +// +// Do not modify the returned buffer, it may be shared. +func (m *multiaddr) Bytes() []byte { + return m.bytes +} + +// String returns the string representation of a Multiaddr +func (m *multiaddr) String() string { + s, err := bytesToString(m.bytes) + if err != nil { + panic(fmt.Errorf("multiaddr failed to convert back to string. corrupted? %s", err)) + } + return s +} + +func (m *multiaddr) MarshalBinary() ([]byte, error) { + return m.Bytes(), nil +} + +func (m *multiaddr) UnmarshalBinary(data []byte) error { + new, err := NewMultiaddrBytes(data) + if err != nil { + return err + } + *m = *(new.(*multiaddr)) + return nil +} + +func (m *multiaddr) MarshalText() ([]byte, error) { + return []byte(m.String()), nil +} + +func (m *multiaddr) UnmarshalText(data []byte) error { + new, err := NewMultiaddr(string(data)) + if err != nil { + return err + } + *m = *(new.(*multiaddr)) + return nil +} + +func (m *multiaddr) MarshalJSON() ([]byte, error) { + return json.Marshal(m.String()) +} + +func (m *multiaddr) UnmarshalJSON(data []byte) error { + var v string + if err := json.Unmarshal(data, &v); err != nil { + return err + } + new, err := NewMultiaddr(v) + *m = *(new.(*multiaddr)) + return err +} + +// Protocols returns the list of protocols this Multiaddr has. +// will panic in case we access bytes incorrectly. +func (m *multiaddr) Protocols() []Protocol { + ps := make([]Protocol, 0, 8) + b := m.bytes + for len(b) > 0 { + code, n, err := ReadVarintCode(b) + if err != nil { + panic(err) + } + + p := ProtocolWithCode(code) + if p.Code == 0 { + // this is a panic (and not returning err) because this should've been + // caught on constructing the Multiaddr + panic(fmt.Errorf("no protocol with code %d", b[0])) + } + ps = append(ps, p) + b = b[n:] + + n, size, err := sizeForAddr(p, b) + if err != nil { + panic(err) + } + + b = b[n+size:] + } + return ps +} + +// Encapsulate wraps a given Multiaddr, returning the resulting joined Multiaddr +func (m *multiaddr) Encapsulate(o Multiaddr) Multiaddr { + mb := m.bytes + ob := o.Bytes() + + b := make([]byte, len(mb)+len(ob)) + copy(b, mb) + copy(b[len(mb):], ob) + return &multiaddr{bytes: b} +} + +// Decapsulate unwraps Multiaddr up until the given Multiaddr is found. +func (m *multiaddr) Decapsulate(o Multiaddr) Multiaddr { + s1 := m.String() + s2 := o.String() + i := strings.LastIndex(s1, s2) + if i < 0 { + // if multiaddr not contained, returns a copy. + cpy := make([]byte, len(m.bytes)) + copy(cpy, m.bytes) + return &multiaddr{bytes: cpy} + } + + if i == 0 { + return nil + } + + ma, err := NewMultiaddr(s1[:i]) + if err != nil { + panic("Multiaddr.Decapsulate incorrect byte boundaries.") + } + return ma +} + +var ErrProtocolNotFound = fmt.Errorf("protocol not found in multiaddr") + +func (m *multiaddr) ValueForProtocol(code int) (value string, err error) { + err = ErrProtocolNotFound + ForEach(m, func(c Component) bool { + if c.Protocol().Code == code { + value = c.Value() + err = nil + return false + } + return true + }) + return +} diff --git a/vendor/github.com/multiformats/go-multiaddr/package.json b/vendor/github.com/multiformats/go-multiaddr/package.json new file mode 100644 index 0000000000..c493b27e54 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/package.json @@ -0,0 +1,23 @@ +{ + "author": "multiformats", + "bugs": { + "url": "https://github.com/multiformats/go-multiaddr/issues" + }, + "gx": { + "dvcsimport": "github.com/multiformats/go-multiaddr" + }, + "gxDependencies": [ + { + "hash": "QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW", + "name": "go-multihash", + "version": "1.0.9" + } + ], + "gxVersion": "0.9.0", + "language": "go", + "license": "MIT", + "name": "go-multiaddr", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "1.4.1" +} + diff --git a/vendor/github.com/multiformats/go-multiaddr/protocol.go b/vendor/github.com/multiformats/go-multiaddr/protocol.go new file mode 100644 index 0000000000..4be1b4e224 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/protocol.go @@ -0,0 +1,119 @@ +package multiaddr + +import ( + "fmt" + "strings" +) + +// These are special sizes +const ( + LengthPrefixedVarSize = -1 +) + +// Protocol is a Multiaddr protocol description structure. +type Protocol struct { + // Name is the string representation of the protocol code. E.g., ip4, + // ip6, tcp, udp, etc. + Name string + + // Code is the protocol's multicodec (a normal, non-varint number). + Code int + + // VCode is a precomputed varint encoded version of Code. + VCode []byte + + // Size is the size of the argument to this protocol. + // + // * Size == 0 means this protocol takes no argument. + // * Size > 0 means this protocol takes a constant sized argument. + // * Size < 0 means this protocol takes a variable length, varint + // prefixed argument. + Size int // a size of -1 indicates a length-prefixed variable size + + // Path indicates a path protocol (e.g., unix). When parsing multiaddr + // strings, path protocols consume the remainder of the address instead + // of stopping at the next forward slash. + // + // Size must be LengthPrefixedVarSize. + Path bool + + // Transcoder converts between the byte representation and the string + // representation of this protocol's argument (if any). + // + // This should only be non-nil if Size != 0 + Transcoder Transcoder +} + +var protocolsByName = map[string]Protocol{} +var protocolsByCode = map[int]Protocol{} + +// Protocols is the list of multiaddr protocols supported by this module. +var Protocols = []Protocol{} + +// SwapToP2pMultiaddrs is a function to make the transition from /ipfs/... +// multiaddrs to /p2p/... multiaddrs easier +// The first stage of the rollout is to ship this package to all users so +// that all users of multiaddr can parse both /ipfs/ and /p2p/ multiaddrs +// as the same code (P_P2P). During this stage of the rollout, all addresses +// with P_P2P will continue printing as /ipfs/, so that older clients without +// the new parsing code won't break. +// Once the network has adopted the new parsing code broadly enough, users of +// multiaddr can add a call to this method to an init function in their codebase. +// This will cause any P_P2P multiaddr to print out as /p2p/ instead of /ipfs/. +// Note that the binary serialization of this multiaddr does not change at any +// point. This means that this code is not a breaking network change at any point +// +// DEPRECATED: this is now the default +func SwapToP2pMultiaddrs() { +} + +func AddProtocol(p Protocol) error { + if _, ok := protocolsByName[p.Name]; ok { + return fmt.Errorf("protocol by the name %q already exists", p.Name) + } + + if _, ok := protocolsByCode[p.Code]; ok { + return fmt.Errorf("protocol code %d already taken by %q", p.Code, p.Code) + } + + if p.Size != 0 && p.Transcoder == nil { + return fmt.Errorf("protocols with arguments must define transcoders") + } + if p.Path && p.Size >= 0 { + return fmt.Errorf("path protocols must have variable-length sizes") + } + + Protocols = append(Protocols, p) + protocolsByName[p.Name] = p + protocolsByCode[p.Code] = p + return nil +} + +// ProtocolWithName returns the Protocol description with given string name. +func ProtocolWithName(s string) Protocol { + return protocolsByName[s] +} + +// ProtocolWithCode returns the Protocol description with given protocol code. +func ProtocolWithCode(c int) Protocol { + return protocolsByCode[c] +} + +// ProtocolsWithString returns a slice of protocols matching given string. +func ProtocolsWithString(s string) ([]Protocol, error) { + s = strings.Trim(s, "/") + sp := strings.Split(s, "/") + if len(sp) == 0 { + return nil, nil + } + + t := make([]Protocol, len(sp)) + for i, name := range sp { + p := ProtocolWithName(name) + if p.Code == 0 { + return nil, fmt.Errorf("no protocol with name: %s", name) + } + t[i] = p + } + return t, nil +} diff --git a/vendor/github.com/multiformats/go-multiaddr/protocols.go b/vendor/github.com/multiformats/go-multiaddr/protocols.go new file mode 100644 index 0000000000..d6df859504 --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/protocols.go @@ -0,0 +1,249 @@ +package multiaddr + +// You **MUST** register your multicodecs with +// https://github.com/multiformats/multicodec before adding them here. +const ( + P_IP4 = 0x0004 + P_TCP = 0x0006 + P_DNS = 0x0035 // 4 or 6 + P_DNS4 = 0x0036 + P_DNS6 = 0x0037 + P_DNSADDR = 0x0038 + P_UDP = 0x0111 + P_DCCP = 0x0021 + P_IP6 = 0x0029 + P_IP6ZONE = 0x002A + P_QUIC = 0x01CC + P_SCTP = 0x0084 + P_CIRCUIT = 0x0122 + P_UDT = 0x012D + P_UTP = 0x012E + P_UNIX = 0x0190 + P_P2P = 0x01A5 + P_IPFS = 0x01A5 // alias for backwards compatability + P_HTTP = 0x01E0 + P_HTTPS = 0x01BB + P_ONION = 0x01BC // also for backwards compatibility + P_ONION3 = 0x01BD + P_GARLIC64 = 0x01BE + P_GARLIC32 = 0x01BF + P_P2P_WEBRTC_DIRECT = 0x0114 + P_WS = 0x01DD + P_WSS = 0x01DE +) + +var ( + protoIP4 = Protocol{ + Name: "ip4", + Code: P_IP4, + VCode: CodeToVarint(P_IP4), + Size: 32, + Path: false, + Transcoder: TranscoderIP4, + } + protoTCP = Protocol{ + Name: "tcp", + Code: P_TCP, + VCode: CodeToVarint(P_TCP), + Size: 16, + Path: false, + Transcoder: TranscoderPort, + } + protoDNS = Protocol{ + Code: P_DNS, + Size: LengthPrefixedVarSize, + Name: "dns", + VCode: CodeToVarint(P_DNS), + Transcoder: TranscoderDns, + } + protoDNS4 = Protocol{ + Code: P_DNS4, + Size: LengthPrefixedVarSize, + Name: "dns4", + VCode: CodeToVarint(P_DNS4), + Transcoder: TranscoderDns, + } + protoDNS6 = Protocol{ + Code: P_DNS6, + Size: LengthPrefixedVarSize, + Name: "dns6", + VCode: CodeToVarint(P_DNS6), + Transcoder: TranscoderDns, + } + protoDNSADDR = Protocol{ + Code: P_DNSADDR, + Size: LengthPrefixedVarSize, + Name: "dnsaddr", + VCode: CodeToVarint(P_DNSADDR), + Transcoder: TranscoderDns, + } + protoUDP = Protocol{ + Name: "udp", + Code: P_UDP, + VCode: CodeToVarint(P_UDP), + Size: 16, + Path: false, + Transcoder: TranscoderPort, + } + protoDCCP = Protocol{ + Name: "dccp", + Code: P_DCCP, + VCode: CodeToVarint(P_DCCP), + Size: 16, + Path: false, + Transcoder: TranscoderPort, + } + protoIP6 = Protocol{ + Name: "ip6", + Code: P_IP6, + VCode: CodeToVarint(P_IP6), + Size: 128, + Transcoder: TranscoderIP6, + } + // these require varint + protoIP6ZONE = Protocol{ + Name: "ip6zone", + Code: P_IP6ZONE, + VCode: CodeToVarint(P_IP6ZONE), + Size: LengthPrefixedVarSize, + Path: false, + Transcoder: TranscoderIP6Zone, + } + protoSCTP = Protocol{ + Name: "sctp", + Code: P_SCTP, + VCode: CodeToVarint(P_SCTP), + Size: 16, + Transcoder: TranscoderPort, + } + + protoCIRCUIT = Protocol{ + Code: P_CIRCUIT, + Size: 0, + Name: "p2p-circuit", + VCode: CodeToVarint(P_CIRCUIT), + } + + protoONION2 = Protocol{ + Name: "onion", + Code: P_ONION, + VCode: CodeToVarint(P_ONION), + Size: 96, + Transcoder: TranscoderOnion, + } + protoONION3 = Protocol{ + Name: "onion3", + Code: P_ONION3, + VCode: CodeToVarint(P_ONION3), + Size: 296, + Transcoder: TranscoderOnion3, + } + protoGARLIC64 = Protocol{ + Name: "garlic64", + Code: P_GARLIC64, + VCode: CodeToVarint(P_GARLIC64), + Size: LengthPrefixedVarSize, + Transcoder: TranscoderGarlic64, + } + protoGARLIC32 = Protocol{ + Name: "garlic32", + Code: P_GARLIC32, + VCode: CodeToVarint(P_GARLIC32), + Size: LengthPrefixedVarSize, + Transcoder: TranscoderGarlic32, + } + protoUTP = Protocol{ + Name: "utp", + Code: P_UTP, + VCode: CodeToVarint(P_UTP), + } + protoUDT = Protocol{ + Name: "udt", + Code: P_UDT, + VCode: CodeToVarint(P_UDT), + } + protoQUIC = Protocol{ + Name: "quic", + Code: P_QUIC, + VCode: CodeToVarint(P_QUIC), + } + protoHTTP = Protocol{ + Name: "http", + Code: P_HTTP, + VCode: CodeToVarint(P_HTTP), + } + protoHTTPS = Protocol{ + Name: "https", + Code: P_HTTPS, + VCode: CodeToVarint(P_HTTPS), + } + protoP2P = Protocol{ + Name: "p2p", + Code: P_P2P, + VCode: CodeToVarint(P_P2P), + Size: LengthPrefixedVarSize, + Transcoder: TranscoderP2P, + } + protoUNIX = Protocol{ + Name: "unix", + Code: P_UNIX, + VCode: CodeToVarint(P_UNIX), + Size: LengthPrefixedVarSize, + Path: true, + Transcoder: TranscoderUnix, + } + protoP2P_WEBRTC_DIRECT = Protocol{ + Name: "p2p-webrtc-direct", + Code: P_P2P_WEBRTC_DIRECT, + VCode: CodeToVarint(P_P2P_WEBRTC_DIRECT), + } + protoWS = Protocol{ + Name: "ws", + Code: P_WS, + VCode: CodeToVarint(P_WS), + } + protoWSS = Protocol{ + Name: "wss", + Code: P_WSS, + VCode: CodeToVarint(P_WSS), + } +) + +func init() { + for _, p := range []Protocol{ + protoIP4, + protoTCP, + protoDNS, + protoDNS4, + protoDNS6, + protoDNSADDR, + protoUDP, + protoDCCP, + protoIP6, + protoIP6ZONE, + protoSCTP, + protoCIRCUIT, + protoONION2, + protoONION3, + protoGARLIC64, + protoGARLIC32, + protoUTP, + protoUDT, + protoQUIC, + protoHTTP, + protoHTTPS, + protoP2P, + protoUNIX, + protoP2P_WEBRTC_DIRECT, + protoWS, + protoWSS, + } { + if err := AddProtocol(p); err != nil { + panic(err) + } + } + + // explicitly set both of these + protocolsByName["p2p"] = protoP2P + protocolsByName["ipfs"] = protoP2P +} diff --git a/vendor/github.com/multiformats/go-multiaddr/transcoders.go b/vendor/github.com/multiformats/go-multiaddr/transcoders.go new file mode 100644 index 0000000000..89da69542e --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/transcoders.go @@ -0,0 +1,342 @@ +package multiaddr + +import ( + "bytes" + "encoding/base32" + "encoding/base64" + "encoding/binary" + "fmt" + "net" + "strconv" + "strings" + + mh "github.com/multiformats/go-multihash" +) + +type Transcoder interface { + // Validates and encodes to bytes a multiaddr that's in the string representation. + StringToBytes(string) ([]byte, error) + // Validates and decodes to a string a multiaddr that's in the bytes representation. + BytesToString([]byte) (string, error) + // Validates bytes when parsing a multiaddr that's already in the bytes representation. + ValidateBytes([]byte) error +} + +func NewTranscoderFromFunctions( + s2b func(string) ([]byte, error), + b2s func([]byte) (string, error), + val func([]byte) error, +) Transcoder { + return twrp{s2b, b2s, val} +} + +type twrp struct { + strtobyte func(string) ([]byte, error) + bytetostr func([]byte) (string, error) + validbyte func([]byte) error +} + +func (t twrp) StringToBytes(s string) ([]byte, error) { + return t.strtobyte(s) +} +func (t twrp) BytesToString(b []byte) (string, error) { + return t.bytetostr(b) +} + +func (t twrp) ValidateBytes(b []byte) error { + if t.validbyte == nil { + return nil + } + return t.validbyte(b) +} + +var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ip4BtS, nil) +var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ip6BtS, nil) +var TranscoderIP6Zone = NewTranscoderFromFunctions(ip6zoneStB, ip6zoneBtS, ip6zoneVal) + +func ip4StB(s string) ([]byte, error) { + i := net.ParseIP(s).To4() + if i == nil { + return nil, fmt.Errorf("failed to parse ip4 addr: %s", s) + } + return i, nil +} + +func ip6zoneStB(s string) ([]byte, error) { + if len(s) == 0 { + return nil, fmt.Errorf("empty ip6zone") + } + if strings.Contains(s, "/") { + return nil, fmt.Errorf("IPv6 zone ID contains '/': %s", s) + } + return []byte(s), nil +} + +func ip6zoneBtS(b []byte) (string, error) { + if len(b) == 0 { + return "", fmt.Errorf("invalid length (should be > 0)") + } + return string(b), nil +} + +func ip6zoneVal(b []byte) error { + if len(b) == 0 { + return fmt.Errorf("invalid length (should be > 0)") + } + // Not supported as this would break multiaddrs. + if bytes.IndexByte(b, '/') >= 0 { + return fmt.Errorf("IPv6 zone ID contains '/': %s", string(b)) + } + return nil +} + +func ip6StB(s string) ([]byte, error) { + i := net.ParseIP(s).To16() + if i == nil { + return nil, fmt.Errorf("failed to parse ip6 addr: %s", s) + } + return i, nil +} + +func ip6BtS(b []byte) (string, error) { + ip := net.IP(b) + if ip4 := ip.To4(); ip4 != nil { + // Go fails to prepend the `::ffff:` part. + return "::ffff:" + ip4.String(), nil + } + return ip.String(), nil +} + +func ip4BtS(b []byte) (string, error) { + return net.IP(b).String(), nil +} + +var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS, nil) + +func portStB(s string) ([]byte, error) { + i, err := strconv.Atoi(s) + if err != nil { + return nil, fmt.Errorf("failed to parse port addr: %s", err) + } + if i >= 65536 { + return nil, fmt.Errorf("failed to parse port addr: %s", "greater than 65536") + } + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, uint16(i)) + return b, nil +} + +func portBtS(b []byte) (string, error) { + i := binary.BigEndian.Uint16(b) + return strconv.Itoa(int(i)), nil +} + +var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS, nil) + +func onionStB(s string) ([]byte, error) { + addr := strings.Split(s, ":") + if len(addr) != 2 { + return nil, fmt.Errorf("failed to parse onion addr: %s does not contain a port number.", s) + } + + // onion address without the ".onion" substring + if len(addr[0]) != 16 { + return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onion address.", s) + } + onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0])) + if err != nil { + return nil, fmt.Errorf("failed to decode base32 onion addr: %s %s", s, err) + } + + // onion port number + i, err := strconv.Atoi(addr[1]) + if err != nil { + return nil, fmt.Errorf("failed to parse onion addr: %s", err) + } + if i >= 65536 { + return nil, fmt.Errorf("failed to parse onion addr: %s", "port greater than 65536") + } + if i < 1 { + return nil, fmt.Errorf("failed to parse onion addr: %s", "port less than 1") + } + + onionPortBytes := make([]byte, 2) + binary.BigEndian.PutUint16(onionPortBytes, uint16(i)) + bytes := []byte{} + bytes = append(bytes, onionHostBytes...) + bytes = append(bytes, onionPortBytes...) + return bytes, nil +} + +func onionBtS(b []byte) (string, error) { + addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:10])) + port := binary.BigEndian.Uint16(b[10:12]) + return addr + ":" + strconv.Itoa(int(port)), nil +} + +var TranscoderOnion3 = NewTranscoderFromFunctions(onion3StB, onion3BtS, nil) + +func onion3StB(s string) ([]byte, error) { + addr := strings.Split(s, ":") + if len(addr) != 2 { + return nil, fmt.Errorf("failed to parse onion addr: %s does not contain a port number.", s) + } + + // onion address without the ".onion" substring + if len(addr[0]) != 56 { + return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onionv3 address. len == %d", s, len(addr[0])) + } + onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0])) + if err != nil { + return nil, fmt.Errorf("failed to decode base32 onion addr: %s %s", s, err) + } + + // onion port number + i, err := strconv.Atoi(addr[1]) + if err != nil { + return nil, fmt.Errorf("failed to parse onion addr: %s", err) + } + if i >= 65536 { + return nil, fmt.Errorf("failed to parse onion addr: %s", "port greater than 65536") + } + if i < 1 { + return nil, fmt.Errorf("failed to parse onion addr: %s", "port less than 1") + } + + onionPortBytes := make([]byte, 2) + binary.BigEndian.PutUint16(onionPortBytes, uint16(i)) + bytes := []byte{} + bytes = append(bytes, onionHostBytes[0:35]...) + bytes = append(bytes, onionPortBytes...) + return bytes, nil +} + +func onion3BtS(b []byte) (string, error) { + addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:35])) + port := binary.BigEndian.Uint16(b[35:37]) + str := addr + ":" + strconv.Itoa(int(port)) + return str, nil +} + +var TranscoderGarlic64 = NewTranscoderFromFunctions(garlic64StB, garlic64BtS, garlic64Validate) + +// i2p uses an alternate character set for base64 addresses. This returns an appropriate encoder. +var garlicBase64Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~") + +func garlic64StB(s string) ([]byte, error) { + // i2p base64 address will be between 516 and 616 characters long, depending on + // certificate type + if len(s) < 516 || len(s) > 616 { + return nil, fmt.Errorf("failed to parse garlic addr: %s not an i2p base64 address. len: %d\n", s, len(s)) + } + garlicHostBytes, err := garlicBase64Encoding.DecodeString(s) + if err != nil { + return nil, fmt.Errorf("failed to decode base64 i2p addr: %s %s", s, err) + } + + return garlicHostBytes, nil +} + +func garlic64BtS(b []byte) (string, error) { + if err := garlic64Validate(b); err != nil { + return "", err + } + addr := garlicBase64Encoding.EncodeToString(b) + return addr, nil +} + +func garlic64Validate(b []byte) error { + // A garlic64 address will always be greater than 386 bytes long when encoded. + if len(b) < 386 { + return fmt.Errorf("failed to validate garlic addr: %s not an i2p base64 address. len: %d\n", b, len(b)) + } + return nil +} + +var TranscoderGarlic32 = NewTranscoderFromFunctions(garlic32StB, garlic32BtS, garlic32Validate) + +var garlicBase32Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567") + +func garlic32StB(s string) ([]byte, error) { + // an i2p base32 address with a length of greater than 55 characters is + // using an Encrypted Leaseset v2. all other base32 addresses will always be + // exactly 52 characters + if len(s) < 55 && len(s) != 52 { + return nil, fmt.Errorf("failed to parse garlic addr: %s not a i2p base32 address. len: %d", s, len(s)) + } + for len(s)%8 != 0 { + s += "=" + } + garlicHostBytes, err := garlicBase32Encoding.DecodeString(s) + if err != nil { + return nil, fmt.Errorf("failed to decode base32 garlic addr: %s, err: %v len: %v", s, err, len(s)) + } + return garlicHostBytes, nil +} + +func garlic32BtS(b []byte) (string, error) { + if err := garlic32Validate(b); err != nil { + return "", err + } + return strings.TrimRight(garlicBase32Encoding.EncodeToString(b), "="), nil +} + +func garlic32Validate(b []byte) error { + // an i2p base64 for an Encrypted Leaseset v2 will be at least 35 bytes + // long other than that, they will be exactly 32 bytes + if len(b) < 35 && len(b) != 32 { + return fmt.Errorf("failed to validate garlic addr: %s not an i2p base32 address. len: %d\n", b, len(b)) + } + return nil +} + +var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS, p2pVal) + +func p2pStB(s string) ([]byte, error) { + // the address is a varint prefixed multihash string representation + m, err := mh.FromB58String(s) + if err != nil { + return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err) + } + return m, nil +} + +func p2pVal(b []byte) error { + _, err := mh.Cast(b) + return err +} + +func p2pBtS(b []byte) (string, error) { + m, err := mh.Cast(b) + if err != nil { + return "", err + } + return m.B58String(), nil +} + +var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS, nil) + +func unixStB(s string) ([]byte, error) { + return []byte(s), nil +} + +func unixBtS(b []byte) (string, error) { + return string(b), nil +} + +var TranscoderDns = NewTranscoderFromFunctions(dnsStB, dnsBtS, dnsVal) + +func dnsVal(b []byte) error { + if bytes.IndexByte(b, '/') >= 0 { + return fmt.Errorf("domain name %q contains a slash", string(b)) + } + return nil +} + +func dnsStB(s string) ([]byte, error) { + return []byte(s), nil +} + +func dnsBtS(b []byte) (string, error) { + return string(b), nil +} diff --git a/vendor/github.com/multiformats/go-multiaddr/util.go b/vendor/github.com/multiformats/go-multiaddr/util.go new file mode 100644 index 0000000000..cf4469affa --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/util.go @@ -0,0 +1,180 @@ +package multiaddr + +import "fmt" + +// Split returns the sub-address portions of a multiaddr. +func Split(m Multiaddr) []Multiaddr { + if _, ok := m.(*Component); ok { + return []Multiaddr{m} + } + var addrs []Multiaddr + ForEach(m, func(c Component) bool { + addrs = append(addrs, &c) + return true + }) + return addrs +} + +// Join returns a combination of addresses. +func Join(ms ...Multiaddr) Multiaddr { + switch len(ms) { + case 0: + // empty multiaddr, unfortunately, we have callers that rely on + // this contract. + return &multiaddr{} + case 1: + return ms[0] + } + + length := 0 + bs := make([][]byte, len(ms)) + for i, m := range ms { + bs[i] = m.Bytes() + length += len(bs[i]) + } + + bidx := 0 + b := make([]byte, length) + for _, mb := range bs { + bidx += copy(b[bidx:], mb) + } + return &multiaddr{bytes: b} +} + +// Cast re-casts a byte slice as a multiaddr. will panic if it fails to parse. +func Cast(b []byte) Multiaddr { + m, err := NewMultiaddrBytes(b) + if err != nil { + panic(fmt.Errorf("multiaddr failed to parse: %s", err)) + } + return m +} + +// StringCast like Cast, but parses a string. Will also panic if it fails to parse. +func StringCast(s string) Multiaddr { + m, err := NewMultiaddr(s) + if err != nil { + panic(fmt.Errorf("multiaddr failed to parse: %s", err)) + } + return m +} + +// SplitFirst returns the first component and the rest of the multiaddr. +func SplitFirst(m Multiaddr) (*Component, Multiaddr) { + // Shortcut if we already have a component + if c, ok := m.(*Component); ok { + return c, nil + } + + b := m.Bytes() + if len(b) == 0 { + return nil, nil + } + n, c, err := readComponent(b) + if err != nil { + panic(err) + } + if len(b) == n { + return &c, nil + } + return &c, &multiaddr{b[n:]} +} + +// SplitLast returns the rest of the multiaddr and the last component. +func SplitLast(m Multiaddr) (Multiaddr, *Component) { + // Shortcut if we already have a component + if c, ok := m.(*Component); ok { + return nil, c + } + + b := m.Bytes() + if len(b) == 0 { + return nil, nil + } + + var ( + c Component + err error + offset int + ) + for { + var n int + n, c, err = readComponent(b[offset:]) + if err != nil { + panic(err) + } + if len(b) == n+offset { + // Reached end + if offset == 0 { + // Only one component + return nil, &c + } + return &multiaddr{b[:offset]}, &c + } + offset += n + } +} + +// SplitFunc splits the multiaddr when the callback first returns true. The +// component on which the callback first returns will be included in the +// *second* multiaddr. +func SplitFunc(m Multiaddr, cb func(Component) bool) (Multiaddr, Multiaddr) { + // Shortcut if we already have a component + if c, ok := m.(*Component); ok { + if cb(*c) { + return nil, m + } + return m, nil + } + b := m.Bytes() + if len(b) == 0 { + return nil, nil + } + var ( + c Component + err error + offset int + ) + for offset < len(b) { + var n int + n, c, err = readComponent(b[offset:]) + if err != nil { + panic(err) + } + if cb(c) { + break + } + offset += n + } + switch offset { + case 0: + return nil, m + case len(b): + return m, nil + default: + return &multiaddr{b[:offset]}, &multiaddr{b[offset:]} + } +} + +// ForEach walks over the multiaddr, component by component. +// +// This function iterates over components *by value* to avoid allocating. +func ForEach(m Multiaddr, cb func(c Component) bool) { + // Shortcut if we already have a component + if c, ok := m.(*Component); ok { + cb(*c) + return + } + + b := m.Bytes() + for len(b) > 0 { + n, c, err := readComponent(b) + if err != nil { + panic(err) + } + if !cb(c) { + return + } + b = b[n:] + } +} diff --git a/vendor/github.com/multiformats/go-multiaddr/varint.go b/vendor/github.com/multiformats/go-multiaddr/varint.go new file mode 100644 index 0000000000..d1ea7fc4fc --- /dev/null +++ b/vendor/github.com/multiformats/go-multiaddr/varint.go @@ -0,0 +1,27 @@ +package multiaddr + +import ( + "math" + + "github.com/multiformats/go-varint" +) + +// CodeToVarint converts an integer to a varint-encoded []byte +func CodeToVarint(num int) []byte { + if num < 0 || num > math.MaxInt32 { + panic("invalid code") + } + return varint.ToUvarint(uint64(num)) +} + +func ReadVarintCode(b []byte) (int, int, error) { + code, n, err := varint.FromUvarint(b) + if err != nil { + return 0, 0, err + } + if code > math.MaxInt32 { + // we only allow 32bit codes. + return 0, 0, varint.ErrOverflow + } + return int(code), n, err +} diff --git a/vendor/github.com/multiformats/go-multibase/.codecov.yml b/vendor/github.com/multiformats/go-multibase/.codecov.yml new file mode 100644 index 0000000000..db2472009c --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/.codecov.yml @@ -0,0 +1 @@ +comment: off diff --git a/vendor/github.com/multiformats/go-multibase/.gitignore b/vendor/github.com/multiformats/go-multibase/.gitignore new file mode 100644 index 0000000000..175b291646 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/.gitignore @@ -0,0 +1,3 @@ +*.swp + +multibase-conv/multibase-conv diff --git a/vendor/github.com/multiformats/go-multibase/.gitmodules b/vendor/github.com/multiformats/go-multibase/.gitmodules new file mode 100644 index 0000000000..74c037fa66 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/.gitmodules @@ -0,0 +1,3 @@ +[submodule "spec"] + path = spec + url = https://github.com/multiformats/multibase.git diff --git a/vendor/github.com/multiformats/go-multibase/.gxignore b/vendor/github.com/multiformats/go-multibase/.gxignore new file mode 100644 index 0000000000..c1d28ba5bb --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/.gxignore @@ -0,0 +1,2 @@ +/spec/ +*_test.go diff --git a/vendor/github.com/multiformats/go-multibase/.travis.yml b/vendor/github.com/multiformats/go-multibase/.travis.yml new file mode 100644 index 0000000000..18f4287d76 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/.travis.yml @@ -0,0 +1,32 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gx + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/src/gx + - $GOPATH/pkg/mod + - /home/travis/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/multiformats/go-multibase/LICENSE b/vendor/github.com/multiformats/go-multibase/LICENSE new file mode 100644 index 0000000000..f64ffb042d --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Protocol Labs Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/multiformats/go-multibase/Makefile b/vendor/github.com/multiformats/go-multibase/Makefile new file mode 100644 index 0000000000..411b4a8880 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/Makefile @@ -0,0 +1,13 @@ +test: deps + go test -race -v ./... + +export IPFS_API ?= v04x.ipfs.io + +gx: + go get -u github.com/whyrusleeping/gx + go get -u github.com/whyrusleeping/gx-go + +deps: gx + gx --verbose install --global + gx-go rewrite + go get -t ./... diff --git a/vendor/github.com/multiformats/go-multibase/README.md b/vendor/github.com/multiformats/go-multibase/README.md new file mode 100644 index 0000000000..3c745445a8 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/README.md @@ -0,0 +1,49 @@ +# go-multibase + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) +[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![Travis CI](https://img.shields.io/travis/multiformats/go-multibase.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multibase) +[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multibase.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multibase?branch=master) + +> Implementation of [multibase](https://github.com/multiformats/multibase) -self identifying base encodings- in Go. + + +## Install + +`go-multibase` is a standard Go module which can be installed with: + +```sh +go get github.com/multiformats/go-multibase +``` + +Note that `go-multibase` is packaged with Gx, so it is recommended to use Gx to install and use it (see Usage section). + +## Usage + +This module is packaged with [Gx](https://github.com/whyrusleeping/gx). In order to use it in your own project it is recommended that you: + +```sh +go get -u github.com/whyrusleeping/gx +go get -u github.com/whyrusleeping/gx-go +cd +gx init +gx import github.com/multiformats/go-multibase +gx install --global +gx-go --rewrite +``` + +Please check [Gx](https://github.com/whyrusleeping/gx) and [Gx-go](https://github.com/whyrusleeping/gx-go) documentation for more information. + +## Contribute + +Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multibase/issues). + +Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +[MIT](LICENSE) © 2016 Protocol Labs Inc. diff --git a/vendor/github.com/multiformats/go-multibase/base16.go b/vendor/github.com/multiformats/go-multibase/base16.go new file mode 100644 index 0000000000..6b8794191a --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/base16.go @@ -0,0 +1,21 @@ +package multibase + +func hexEncodeToStringUpper(src []byte) string { + dst := make([]byte, len(src)*2) + hexEncodeUpper(dst, src) + return string(dst) +} + +var hexTableUppers = [16]byte{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', +} + +func hexEncodeUpper(dst, src []byte) int { + for i, v := range src { + dst[i*2] = hexTableUppers[v>>4] + dst[i*2+1] = hexTableUppers[v&0x0f] + } + + return len(src) * 2 +} diff --git a/vendor/github.com/multiformats/go-multibase/base2.go b/vendor/github.com/multiformats/go-multibase/base2.go new file mode 100644 index 0000000000..6e3f0cfff2 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/base2.go @@ -0,0 +1,52 @@ +package multibase + +import ( + "fmt" + "strconv" + "strings" +) + +// binaryEncodeToString takes an array of bytes and returns +// multibase binary representation +func binaryEncodeToString(src []byte) string { + dst := make([]byte, len(src)*8) + encodeBinary(dst, src) + return string(dst) +} + +// encodeBinary takes the src and dst bytes and converts each +// byte to their binary rep using power reduction method +func encodeBinary(dst []byte, src []byte) { + for i, b := range src { + for j := 0; j < 8; j++ { + if b&(1<>3) + + for i, dstIndex := 0, 0; i < len(s); i = i + 8 { + value, err := strconv.ParseInt(s[i:i+8], 2, 0) + if err != nil { + return nil, fmt.Errorf("error while conversion: %s", err) + } + + data[dstIndex] = byte(value) + dstIndex++ + } + + return data, nil +} diff --git a/vendor/github.com/multiformats/go-multibase/base32.go b/vendor/github.com/multiformats/go-multibase/base32.go new file mode 100644 index 0000000000..a6fe8eb064 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/base32.go @@ -0,0 +1,17 @@ +package multibase + +import ( + b32 "github.com/multiformats/go-base32" +) + +var base32StdLowerPad = b32.NewEncodingCI("abcdefghijklmnopqrstuvwxyz234567") +var base32StdLowerNoPad = base32StdLowerPad.WithPadding(b32.NoPadding) + +var base32StdUpperPad = b32.NewEncodingCI("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567") +var base32StdUpperNoPad = base32StdUpperPad.WithPadding(b32.NoPadding) + +var base32HexLowerPad = b32.NewEncodingCI("0123456789abcdefghijklmnopqrstuv") +var base32HexLowerNoPad = base32HexLowerPad.WithPadding(b32.NoPadding) + +var base32HexUpperPad = b32.NewEncodingCI("0123456789ABCDEFGHIJKLMNOPQRSTUV") +var base32HexUpperNoPad = base32HexUpperPad.WithPadding(b32.NoPadding) diff --git a/vendor/github.com/multiformats/go-multibase/encoder.go b/vendor/github.com/multiformats/go-multibase/encoder.go new file mode 100644 index 0000000000..42e753f5ca --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/encoder.go @@ -0,0 +1,63 @@ +package multibase + +import ( + "fmt" +) + +// Encoder is a multibase encoding that is verified to be supported and +// supports an Encode method that does not return an error +type Encoder struct { + enc Encoding +} + +// NewEncoder create a new Encoder from an Encoding +func NewEncoder(base Encoding) (Encoder, error) { + _, ok := EncodingToStr[base] + if !ok { + return Encoder{-1}, fmt.Errorf("Unsupported multibase encoding: %d", base) + } + return Encoder{base}, nil +} + +// MustNewEncoder is like NewEncoder but will panic if the encoding is +// invalid. +func MustNewEncoder(base Encoding) Encoder { + _, ok := EncodingToStr[base] + if !ok { + panic("Unsupported multibase encoding") + } + return Encoder{base} +} + +// EncoderByName creates an encoder from a string, the string can +// either be the multibase name or single character multibase prefix +func EncoderByName(str string) (Encoder, error) { + var base Encoding + ok := true + if len(str) == 0 { + return Encoder{-1}, fmt.Errorf("Empty multibase encoding") + } else if len(str) == 1 { + base = Encoding(str[0]) + _, ok = EncodingToStr[base] + } else { + base, ok = Encodings[str] + } + if !ok { + return Encoder{-1}, fmt.Errorf("Unsupported multibase encoding: %s", str) + } + return Encoder{base}, nil +} + +func (p Encoder) Encoding() Encoding { + return p.enc +} + +// Encode encodes the multibase using the given Encoder. +func (p Encoder) Encode(data []byte) string { + str, err := Encode(p.enc, data) + if err != nil { + // should not happen + panic(err) + } + return str +} diff --git a/vendor/github.com/multiformats/go-multibase/go.mod b/vendor/github.com/multiformats/go-multibase/go.mod new file mode 100644 index 0000000000..28d6eb12ca --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/go.mod @@ -0,0 +1,6 @@ +module github.com/multiformats/go-multibase + +require ( + github.com/mr-tron/base58 v1.1.0 + github.com/multiformats/go-base32 v0.0.3 +) diff --git a/vendor/github.com/multiformats/go-multibase/go.sum b/vendor/github.com/multiformats/go-multibase/go.sum new file mode 100644 index 0000000000..510e3dcdc2 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/go.sum @@ -0,0 +1,4 @@ +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= diff --git a/vendor/github.com/multiformats/go-multibase/multibase.go b/vendor/github.com/multiformats/go-multibase/multibase.go new file mode 100644 index 0000000000..a60403d549 --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/multibase.go @@ -0,0 +1,186 @@ +package multibase + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + + b58 "github.com/mr-tron/base58/base58" + b32 "github.com/multiformats/go-base32" +) + +// Encoding identifies the type of base-encoding that a multibase is carrying. +type Encoding int + +// These are the encodings specified in the standard, not are all +// supported yet +const ( + Identity = 0x00 + Base2 = '0' + Base8 = '7' + Base10 = '9' + Base16 = 'f' + Base16Upper = 'F' + Base32 = 'b' + Base32Upper = 'B' + Base32pad = 'c' + Base32padUpper = 'C' + Base32hex = 'v' + Base32hexUpper = 'V' + Base32hexPad = 't' + Base32hexPadUpper = 'T' + Base58Flickr = 'Z' + Base58BTC = 'z' + Base64 = 'm' + Base64url = 'u' + Base64pad = 'M' + Base64urlPad = 'U' +) + +// Encodings is a map of the supported encoding, unsupported encoding +// specified in standard are left out +var Encodings = map[string]Encoding{ + "identity": 0x00, + "base2": '0', + "base16": 'f', + "base16upper": 'F', + "base32": 'b', + "base32upper": 'B', + "base32pad": 'c', + "base32padupper": 'C', + "base32hex": 'v', + "base32hexupper": 'V', + "base32hexpad": 't', + "base32hexpadupper": 'T', + "base58flickr": 'Z', + "base58btc": 'z', + "base64": 'm', + "base64url": 'u', + "base64pad": 'M', + "base64urlpad": 'U', +} + +var EncodingToStr = map[Encoding]string{ + 0x00: "identity", + '0': "base2", + 'f': "base16", + 'F': "base16upper", + 'b': "base32", + 'B': "base32upper", + 'c': "base32pad", + 'C': "base32padupper", + 'v': "base32hex", + 'V': "base32hexupper", + 't': "base32hexpad", + 'T': "base32hexpadupper", + 'Z': "base58flickr", + 'z': "base58btc", + 'm': "base64", + 'u': "base64url", + 'M': "base64pad", + 'U': "base64urlpad", +} + +// ErrUnsupportedEncoding is returned when the selected encoding is not known or +// implemented. +var ErrUnsupportedEncoding = fmt.Errorf("selected encoding not supported") + +// Encode encodes a given byte slice with the selected encoding and returns a +// multibase string (). It will return +// an error if the selected base is not known. +func Encode(base Encoding, data []byte) (string, error) { + switch base { + case Identity: + // 0x00 inside a string is OK in golang and causes no problems with the length calculation. + return string(Identity) + string(data), nil + case Base2: + return string(Base2) + binaryEncodeToString(data), nil + case Base16: + return string(Base16) + hex.EncodeToString(data), nil + case Base16Upper: + return string(Base16Upper) + hexEncodeToStringUpper(data), nil + case Base32: + return string(Base32) + base32StdLowerNoPad.EncodeToString(data), nil + case Base32Upper: + return string(Base32Upper) + base32StdUpperNoPad.EncodeToString(data), nil + case Base32hex: + return string(Base32hex) + base32HexLowerNoPad.EncodeToString(data), nil + case Base32hexUpper: + return string(Base32hexUpper) + base32HexUpperNoPad.EncodeToString(data), nil + case Base32pad: + return string(Base32pad) + base32StdLowerPad.EncodeToString(data), nil + case Base32padUpper: + return string(Base32padUpper) + base32StdUpperPad.EncodeToString(data), nil + case Base32hexPad: + return string(Base32hexPad) + base32HexLowerPad.EncodeToString(data), nil + case Base32hexPadUpper: + return string(Base32hexPadUpper) + base32HexUpperPad.EncodeToString(data), nil + case Base58BTC: + return string(Base58BTC) + b58.EncodeAlphabet(data, b58.BTCAlphabet), nil + case Base58Flickr: + return string(Base58Flickr) + b58.EncodeAlphabet(data, b58.FlickrAlphabet), nil + case Base64pad: + return string(Base64pad) + base64.StdEncoding.EncodeToString(data), nil + case Base64urlPad: + return string(Base64urlPad) + base64.URLEncoding.EncodeToString(data), nil + case Base64url: + return string(Base64url) + base64.RawURLEncoding.EncodeToString(data), nil + case Base64: + return string(Base64) + base64.RawStdEncoding.EncodeToString(data), nil + default: + return "", ErrUnsupportedEncoding + } +} + +// Decode takes a multibase string and decodes into a bytes buffer. +// It will return an error if the selected base is not known. +func Decode(data string) (Encoding, []byte, error) { + if len(data) == 0 { + return 0, nil, fmt.Errorf("cannot decode multibase for zero length string") + } + + enc := Encoding(data[0]) + + switch enc { + case Identity: + return Identity, []byte(data[1:]), nil + case Base2: + bytes, err := decodeBinaryString(data[1:]) + return enc, bytes, err + case Base16, Base16Upper: + bytes, err := hex.DecodeString(data[1:]) + return enc, bytes, err + case Base32, Base32Upper: + bytes, err := b32.RawStdEncoding.DecodeString(data[1:]) + return enc, bytes, err + case Base32hex, Base32hexUpper: + bytes, err := b32.RawHexEncoding.DecodeString(data[1:]) + return enc, bytes, err + case Base32pad, Base32padUpper: + bytes, err := b32.StdEncoding.DecodeString(data[1:]) + return enc, bytes, err + case Base32hexPad, Base32hexPadUpper: + bytes, err := b32.HexEncoding.DecodeString(data[1:]) + return enc, bytes, err + case Base58BTC: + bytes, err := b58.DecodeAlphabet(data[1:], b58.BTCAlphabet) + return Base58BTC, bytes, err + case Base58Flickr: + bytes, err := b58.DecodeAlphabet(data[1:], b58.FlickrAlphabet) + return Base58Flickr, bytes, err + case Base64pad: + bytes, err := base64.StdEncoding.DecodeString(data[1:]) + return Base64pad, bytes, err + case Base64urlPad: + bytes, err := base64.URLEncoding.DecodeString(data[1:]) + return Base64urlPad, bytes, err + case Base64: + bytes, err := base64.RawStdEncoding.DecodeString(data[1:]) + return Base64, bytes, err + case Base64url: + bytes, err := base64.RawURLEncoding.DecodeString(data[1:]) + return Base64url, bytes, err + default: + return -1, nil, ErrUnsupportedEncoding + } +} diff --git a/vendor/github.com/multiformats/go-multibase/package.json b/vendor/github.com/multiformats/go-multibase/package.json new file mode 100644 index 0000000000..75f742e6de --- /dev/null +++ b/vendor/github.com/multiformats/go-multibase/package.json @@ -0,0 +1,30 @@ +{ + "author": "whyrusleeping", + "bugs": { + "url": "https://github.com/multiformats/go-multibase" + }, + "gx": { + "dvcsimport": "github.com/multiformats/go-multibase" + }, + "gxDependencies": [ + { + "author": "mr-tron", + "hash": "QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY", + "name": "go-base58-fast", + "version": "0.1.1" + }, + { + "author": "Golang", + "hash": "QmPbbYin7KBd1Y1BfUe15vHzwJiioyi3wtKQTtXWWf8SC5", + "name": "base32", + "version": "0.0.3" + } + ], + "gxVersion": "0.8.0", + "language": "go", + "license": "", + "name": "go-multibase", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "0.3.0" +} + diff --git a/vendor/github.com/multiformats/go-multihash/.gitignore b/vendor/github.com/multiformats/go-multihash/.gitignore new file mode 100644 index 0000000000..1d74e21965 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/.gitignore @@ -0,0 +1 @@ +.vscode/ diff --git a/vendor/github.com/multiformats/go-multihash/.gitmodules b/vendor/github.com/multiformats/go-multihash/.gitmodules new file mode 100644 index 0000000000..d92ce4f1bc --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/.gitmodules @@ -0,0 +1,6 @@ +[submodule "spec/multicodec"] + path = spec/multicodec + url = https://github.com/multiformats/multicodec.git +[submodule "spec/multihash"] + path = spec/multihash + url = https://github.com/multiformats/multihash.git diff --git a/vendor/github.com/multiformats/go-multihash/.travis.yml b/vendor/github.com/multiformats/go-multihash/.travis.yml new file mode 100644 index 0000000000..09f9a4cc36 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/.travis.yml @@ -0,0 +1,30 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + + +cache: + directories: + - $GOPATH/pkg/mod + - /home/travis/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/multiformats/go-multihash/LICENSE b/vendor/github.com/multiformats/go-multihash/LICENSE new file mode 100644 index 0000000000..c7386b3c94 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/multiformats/go-multihash/Makefile b/vendor/github.com/multiformats/go-multihash/Makefile new file mode 100644 index 0000000000..20619413c9 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/Makefile @@ -0,0 +1,11 @@ +gx: + go get github.com/whyrusleeping/gx + go get github.com/whyrusleeping/gx-go + +deps: gx + gx --verbose install --global + gx-go rewrite + +publish: + gx-go rewrite --undo + diff --git a/vendor/github.com/multiformats/go-multihash/README.md b/vendor/github.com/multiformats/go-multihash/README.md new file mode 100644 index 0000000000..dd7f2386ad --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/README.md @@ -0,0 +1,90 @@ +# go-multihash + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) +[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/multiformats/go-multihash?status.svg)](https://godoc.org/github.com/multiformats/go-multihash) +[![Travis CI](https://img.shields.io/travis/multiformats/go-multihash.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-multihash) +[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-multihash.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-multihash?branch=master) + +> [multihash](https://github.com/multiformats/multihash) implementation in Go + +## Table of Contents + +- [Install](#install) +- [Usage](#usage) +- [Maintainers](#maintainers) +- [Contribute](#contribute) +- [License](#license) + +## Install + +`go-multihash` is a standard Go module which can be installed with: + +```sh +go get github.com/multiformats/go-multihash +``` + +## Usage + + +### Example + +This example takes a standard hex-encoded data and uses `EncodeName` to calculate the SHA1 multihash value for the buffer. + +The resulting hex-encoded data corresponds to: ``, which could be re-parsed +with `Multihash.FromHexString()`. + + +```go +package main + +import ( + "encoding/hex" + "fmt" + + "github.com/multiformats/go-multihash" +) + +func main() { + // ignores errors for simplicity. + // don't do that at home. + // Decode a SHA1 hash to a binary buffer + buf, _ := hex.DecodeString("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") + + // Create a new multihash with it. + mHashBuf, _ := multihash.EncodeName(buf, "sha1") + // Print the multihash as hex string + fmt.Printf("hex: %s\n", hex.EncodeToString(mHashBuf)) + + // Parse the binary multihash to a DecodedMultihash + mHash, _ := multihash.Decode(mHashBuf) + // Convert the sha1 value to hex string + sha1hex := hex.EncodeToString(mHash.Digest) + // Print all the information in the multihash + fmt.Printf("obj: %v 0x%x %d %s\n", mHash.Name, mHash.Code, mHash.Length, sha1hex) +} +``` + +To run, copy to [example/foo.go](example/foo.go) and: + +``` +> cd example/ +> go build +> ./example +hex: 11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 +obj: sha1 0x11 20 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 +``` + +## Contribute + +Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multihash/issues). + +Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +[MIT](LICENSE) © 2014 Juan Batiz-Benet diff --git a/vendor/github.com/multiformats/go-multihash/codecov.yml b/vendor/github.com/multiformats/go-multihash/codecov.yml new file mode 100644 index 0000000000..5f88a9ea27 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/codecov.yml @@ -0,0 +1,3 @@ +coverage: + range: "50...100" +comment: off diff --git a/vendor/github.com/multiformats/go-multihash/go.mod b/vendor/github.com/multiformats/go-multihash/go.mod new file mode 100644 index 0000000000..9a825bbc7e --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/go.mod @@ -0,0 +1,12 @@ +module github.com/multiformats/go-multihash + +require ( + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 + github.com/mr-tron/base58 v1.1.3 + github.com/multiformats/go-varint v0.0.5 + github.com/spaolacci/murmur3 v1.1.0 + golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 +) + +go 1.13 diff --git a/vendor/github.com/multiformats/go-multihash/go.sum b/vendor/github.com/multiformats/go-multihash/go.sum new file mode 100644 index 0000000000..6425497697 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/go.sum @@ -0,0 +1,22 @@ +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-varint v0.0.3 h1:1OZFaq4XbSNQE6ujqgr6/EIZlgHE7DmojAFsLqAJ26M= +github.com/multiformats/go-varint v0.0.3/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.4 h1:CplQWhUouUgTZ53vNFE8VoWr2VjaKXci+xyrKyyFuSw= +github.com/multiformats/go-varint v0.0.4/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/multiformats/go-multihash/io.go b/vendor/github.com/multiformats/go-multihash/io.go new file mode 100644 index 0000000000..3a31baa418 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/io.go @@ -0,0 +1,98 @@ +package multihash + +import ( + "errors" + "io" + "math" + + "github.com/multiformats/go-varint" +) + +// Reader is an io.Reader wrapper that exposes a function +// to read a whole multihash, parse it, and return it. +type Reader interface { + io.Reader + + ReadMultihash() (Multihash, error) +} + +// Writer is an io.Writer wrapper that exposes a function +// to write a whole multihash. +type Writer interface { + io.Writer + + WriteMultihash(Multihash) error +} + +// NewReader wraps an io.Reader with a multihash.Reader +func NewReader(r io.Reader) Reader { + return &mhReader{r} +} + +// NewWriter wraps an io.Writer with a multihash.Writer +func NewWriter(w io.Writer) Writer { + return &mhWriter{w} +} + +type mhReader struct { + r io.Reader +} + +func (r *mhReader) Read(buf []byte) (n int, err error) { + return r.r.Read(buf) +} + +func (r *mhReader) ReadByte() (byte, error) { + if br, ok := r.r.(io.ByteReader); ok { + return br.ReadByte() + } + var b [1]byte + n, err := r.r.Read(b[:]) + if n == 1 { + return b[0], nil + } + if err == nil { + if n != 0 { + panic("reader returned an invalid length") + } + err = io.ErrNoProgress + } + return 0, err +} + +func (r *mhReader) ReadMultihash() (Multihash, error) { + code, err := varint.ReadUvarint(r) + if err != nil { + return nil, err + } + + length, err := varint.ReadUvarint(r) + if err != nil { + return nil, err + } + if length > math.MaxInt32 { + return nil, errors.New("digest too long, supporting only <= 2^31-1") + } + + buf := make([]byte, varint.UvarintSize(code)+varint.UvarintSize(length)+int(length)) + n := varint.PutUvarint(buf, code) + n += varint.PutUvarint(buf[n:], length) + if _, err := io.ReadFull(r.r, buf[n:]); err != nil { + return nil, err + } + + return Cast(buf) +} + +type mhWriter struct { + w io.Writer +} + +func (w *mhWriter) Write(buf []byte) (n int, err error) { + return w.w.Write(buf) +} + +func (w *mhWriter) WriteMultihash(m Multihash) error { + _, err := w.w.Write([]byte(m)) + return err +} diff --git a/vendor/github.com/multiformats/go-multihash/multihash.go b/vendor/github.com/multiformats/go-multihash/multihash.go new file mode 100644 index 0000000000..cd44006dd6 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/multihash.go @@ -0,0 +1,331 @@ +// Package multihash is the Go implementation of +// https://github.com/multiformats/multihash, or self-describing +// hashes. +package multihash + +import ( + "encoding/hex" + "errors" + "fmt" + "math" + + b58 "github.com/mr-tron/base58/base58" + "github.com/multiformats/go-varint" +) + +// errors +var ( + ErrUnknownCode = errors.New("unknown multihash code") + ErrTooShort = errors.New("multihash too short. must be >= 2 bytes") + ErrTooLong = errors.New("multihash too long. must be < 129 bytes") + ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes") + ErrInvalidMultihash = errors.New("input isn't valid multihash") + + ErrVarintBufferShort = errors.New("uvarint: buffer too small") + ErrVarintTooLong = errors.New("uvarint: varint too big (max 64bit)") +) + +// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length +type ErrInconsistentLen struct { + dm *DecodedMultihash +} + +func (e ErrInconsistentLen) Error() string { + return fmt.Sprintf("multihash length inconsistent: expected %d, got %d", e.dm.Length, len(e.dm.Digest)) +} + +// constants +const ( + IDENTITY = 0x00 + // Deprecated: use IDENTITY + ID = IDENTITY + SHA1 = 0x11 + SHA2_256 = 0x12 + SHA2_512 = 0x13 + SHA3_224 = 0x17 + SHA3_256 = 0x16 + SHA3_384 = 0x15 + SHA3_512 = 0x14 + SHA3 = SHA3_512 + KECCAK_224 = 0x1A + KECCAK_256 = 0x1B + KECCAK_384 = 0x1C + KECCAK_512 = 0x1D + + SHAKE_128 = 0x18 + SHAKE_256 = 0x19 + + BLAKE2B_MIN = 0xb201 + BLAKE2B_MAX = 0xb240 + BLAKE2S_MIN = 0xb241 + BLAKE2S_MAX = 0xb260 + + MD5 = 0xd5 + + DBL_SHA2_256 = 0x56 + + MURMUR3_128 = 0x22 + // Deprecated: use MURMUR3_128 + MURMUR3 = MURMUR3_128 + + X11 = 0x1100 +) + +func init() { + // Add blake2b (64 codes) + for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ { + n := c - BLAKE2B_MIN + 1 + name := fmt.Sprintf("blake2b-%d", n*8) + Names[name] = c + Codes[c] = name + DefaultLengths[c] = int(n) + } + + // Add blake2s (32 codes) + for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ { + n := c - BLAKE2S_MIN + 1 + name := fmt.Sprintf("blake2s-%d", n*8) + Names[name] = c + Codes[c] = name + DefaultLengths[c] = int(n) + } +} + +// Names maps the name of a hash to the code +var Names = map[string]uint64{ + "identity": IDENTITY, + "sha1": SHA1, + "sha2-256": SHA2_256, + "sha2-512": SHA2_512, + "sha3": SHA3_512, + "sha3-224": SHA3_224, + "sha3-256": SHA3_256, + "sha3-384": SHA3_384, + "sha3-512": SHA3_512, + "dbl-sha2-256": DBL_SHA2_256, + "murmur3-128": MURMUR3_128, + "keccak-224": KECCAK_224, + "keccak-256": KECCAK_256, + "keccak-384": KECCAK_384, + "keccak-512": KECCAK_512, + "shake-128": SHAKE_128, + "shake-256": SHAKE_256, + "x11": X11, + "md5": MD5, +} + +// Codes maps a hash code to it's name +var Codes = map[uint64]string{ + IDENTITY: "identity", + SHA1: "sha1", + SHA2_256: "sha2-256", + SHA2_512: "sha2-512", + SHA3_224: "sha3-224", + SHA3_256: "sha3-256", + SHA3_384: "sha3-384", + SHA3_512: "sha3-512", + DBL_SHA2_256: "dbl-sha2-256", + MURMUR3_128: "murmur3-128", + KECCAK_224: "keccak-224", + KECCAK_256: "keccak-256", + KECCAK_384: "keccak-384", + KECCAK_512: "keccak-512", + SHAKE_128: "shake-128", + SHAKE_256: "shake-256", + X11: "x11", + MD5: "md5", +} + +// DefaultLengths maps a hash code to it's default length +var DefaultLengths = map[uint64]int{ + IDENTITY: -1, + SHA1: 20, + SHA2_256: 32, + SHA2_512: 64, + SHA3_224: 28, + SHA3_256: 32, + SHA3_384: 48, + SHA3_512: 64, + DBL_SHA2_256: 32, + KECCAK_224: 28, + KECCAK_256: 32, + MURMUR3_128: 4, + KECCAK_384: 48, + KECCAK_512: 64, + SHAKE_128: 32, + SHAKE_256: 64, + X11: 64, + MD5: 16, +} + +func uvarint(buf []byte) (uint64, []byte, error) { + n, c, err := varint.FromUvarint(buf) + if err != nil { + return n, buf, err + } + + if c == 0 { + return n, buf, ErrVarintBufferShort + } else if c < 0 { + return n, buf[-c:], ErrVarintTooLong + } else { + return n, buf[c:], nil + } +} + +// DecodedMultihash represents a parsed multihash and allows +// easy access to the different parts of a multihash. +type DecodedMultihash struct { + Code uint64 + Name string + Length int // Length is just int as it is type of len() opearator + Digest []byte // Digest holds the raw multihash bytes +} + +// Multihash is byte slice with the following form: +// . +// See the spec for more information. +type Multihash []byte + +// HexString returns the hex-encoded representation of a multihash. +func (m *Multihash) HexString() string { + return hex.EncodeToString([]byte(*m)) +} + +// String is an alias to HexString(). +func (m *Multihash) String() string { + return m.HexString() +} + +// FromHexString parses a hex-encoded multihash. +func FromHexString(s string) (Multihash, error) { + b, err := hex.DecodeString(s) + if err != nil { + return Multihash{}, err + } + + return Cast(b) +} + +// B58String returns the B58-encoded representation of a multihash. +func (m Multihash) B58String() string { + return b58.Encode([]byte(m)) +} + +// FromB58String parses a B58-encoded multihash. +func FromB58String(s string) (m Multihash, err error) { + b, err := b58.Decode(s) + if err != nil { + return Multihash{}, ErrInvalidMultihash + } + + return Cast(b) +} + +// Cast casts a buffer onto a multihash, and returns an error +// if it does not work. +func Cast(buf []byte) (Multihash, error) { + dm, err := Decode(buf) + if err != nil { + return Multihash{}, err + } + + if !ValidCode(dm.Code) { + return Multihash{}, ErrUnknownCode + } + + return Multihash(buf), nil +} + +// Decode parses multihash bytes into a DecodedMultihash. +func Decode(buf []byte) (*DecodedMultihash, error) { + rlen, code, hdig, err := readMultihashFromBuf(buf) + if err != nil { + return nil, err + } + + dm := &DecodedMultihash{ + Code: code, + Name: Codes[code], + Length: len(hdig), + Digest: hdig, + } + + if len(buf) != rlen { + return nil, ErrInconsistentLen{dm} + } + + return dm, nil +} + +// Encode a hash digest along with the specified function code. +// Note: the length is derived from the length of the digest itself. +func Encode(buf []byte, code uint64) ([]byte, error) { + if !ValidCode(code) { + return nil, ErrUnknownCode + } + + newBuf := make([]byte, varint.UvarintSize(code)+varint.UvarintSize(uint64(len(buf)))+len(buf)) + n := varint.PutUvarint(newBuf, code) + n += varint.PutUvarint(newBuf[n:], uint64(len(buf))) + + copy(newBuf[n:], buf) + return newBuf, nil +} + +// EncodeName is like Encode() but providing a string name +// instead of a numeric code. See Names for allowed values. +func EncodeName(buf []byte, name string) ([]byte, error) { + return Encode(buf, Names[name]) +} + +// ValidCode checks whether a multihash code is valid. +func ValidCode(code uint64) bool { + _, ok := Codes[code] + return ok +} + +// readMultihashFromBuf reads a multihash from the given buffer, returning the +// individual pieces of the multihash. +// Note: the returned digest is a slice over the passed in data and should be +// copied if the buffer will be reused +func readMultihashFromBuf(buf []byte) (int, uint64, []byte, error) { + bufl := len(buf) + if bufl < 2 { + return 0, 0, nil, ErrTooShort + } + + var err error + var code, length uint64 + + code, buf, err = uvarint(buf) + if err != nil { + return 0, 0, nil, err + } + + length, buf, err = uvarint(buf) + if err != nil { + return 0, 0, nil, err + } + + if length > math.MaxInt32 { + return 0, 0, nil, errors.New("digest too long, supporting only <= 2^31-1") + } + if int(length) > len(buf) { + return 0, 0, nil, errors.New("length greater than remaining number of bytes in buffer") + } + + rlen := (bufl - len(buf)) + int(length) + return rlen, code, buf[:length], nil +} + +// MHFromBytes reads a multihash from the given byte buffer, returning the +// number of bytes read as well as the multihash +func MHFromBytes(buf []byte) (int, Multihash, error) { + nr, _, _, err := readMultihashFromBuf(buf) + if err != nil { + return 0, nil, err + } + + return nr, Multihash(buf[:nr]), nil +} diff --git a/vendor/github.com/multiformats/go-multihash/set.go b/vendor/github.com/multiformats/go-multihash/set.go new file mode 100644 index 0000000000..f56a27570a --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/set.go @@ -0,0 +1,66 @@ +package multihash + +// Set is a set of Multihashes, holding one copy per Multihash. +type Set struct { + set map[string]struct{} +} + +// NewSet creates a new set correctly initialized. +func NewSet() *Set { + return &Set{ + set: make(map[string]struct{}), + } +} + +// Add adds a new multihash to the set. +func (s *Set) Add(m Multihash) { + s.set[string(m)] = struct{}{} +} + +// Len returns the number of elements in the set. +func (s *Set) Len() int { + return len(s.set) +} + +// Has returns true if the element is in the set. +func (s *Set) Has(m Multihash) bool { + _, ok := s.set[string(m)] + return ok +} + +// Visit adds a multihash only if it is not in the set already. Returns true +// if the multihash was added (was not in the set before). +func (s *Set) Visit(m Multihash) bool { + _, ok := s.set[string(m)] + if !ok { + s.set[string(m)] = struct{}{} + return true + } + return false +} + +// ForEach runs f(m) with each multihash in the set. If returns immediately if +// f(m) returns an error. +func (s *Set) ForEach(f func(m Multihash) error) error { + for elem := range s.set { + mh := Multihash(elem) + if err := f(mh); err != nil { + return err + } + } + return nil +} + +// Remove removes an element from the set. +func (s *Set) Remove(m Multihash) { + delete(s.set, string(m)) +} + +// All returns a slice with all the elements in the set. +func (s *Set) All() []Multihash { + out := make([]Multihash, 0, len(s.set)) + for m := range s.set { + out = append(out, Multihash(m)) + } + return out +} diff --git a/vendor/github.com/multiformats/go-multihash/sum.go b/vendor/github.com/multiformats/go-multihash/sum.go new file mode 100644 index 0000000000..26b3bc6cf1 --- /dev/null +++ b/vendor/github.com/multiformats/go-multihash/sum.go @@ -0,0 +1,236 @@ +package multihash + +import ( + "crypto/md5" + "crypto/sha1" + "crypto/sha512" + "errors" + "fmt" + + blake2b "github.com/minio/blake2b-simd" + sha256 "github.com/minio/sha256-simd" + murmur3 "github.com/spaolacci/murmur3" + blake2s "golang.org/x/crypto/blake2s" + sha3 "golang.org/x/crypto/sha3" +) + +// ErrSumNotSupported is returned when the Sum function code is not implemented +var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.") + +var ErrLenTooLarge = errors.New("requested length was too large for digest") + +// HashFunc is a hash function that hashes data into digest. +// +// The length is the size the digest will be truncated to. While the hash +// function isn't responsible for truncating the digest, it may want to error if +// the length is invalid for the hash function (e.g., truncation would make the +// hash useless). +type HashFunc func(data []byte, length int) (digest []byte, err error) + +// funcTable maps multicodec values to hash functions. +var funcTable = make(map[uint64]HashFunc) + +// Sum obtains the cryptographic sum of a given buffer. The length parameter +// indicates the length of the resulting digest and passing a negative value +// use default length values for the selected hash function. +func Sum(data []byte, code uint64, length int) (Multihash, error) { + if !ValidCode(code) { + return nil, fmt.Errorf("invalid multihash code %d", code) + } + + if length < 0 { + var ok bool + length, ok = DefaultLengths[code] + if !ok { + return nil, fmt.Errorf("no default length for code %d", code) + } + } + + hashFunc, ok := funcTable[code] + if !ok { + return nil, ErrSumNotSupported + } + + d, err := hashFunc(data, length) + if err != nil { + return nil, err + } + if len(d) < length { + return nil, ErrLenTooLarge + } + + if length >= 0 { + d = d[:length] + } + return Encode(d, code) +} + +func sumBlake2s(data []byte, size int) ([]byte, error) { + if size != 32 { + return nil, fmt.Errorf("unsupported length for blake2s: %d", size) + } + d := blake2s.Sum256(data) + return d[:], nil +} +func sumBlake2b(data []byte, size int) ([]byte, error) { + hasher, err := blake2b.New(&blake2b.Config{Size: uint8(size)}) + if err != nil { + return nil, err + } + + if _, err := hasher.Write(data); err != nil { + return nil, err + } + + return hasher.Sum(nil)[:], nil +} + +func sumID(data []byte, length int) ([]byte, error) { + if length >= 0 && length != len(data) { + return nil, fmt.Errorf("the length of the identity hash (%d) must be equal to the length of the data (%d)", + length, len(data)) + + } + return data, nil +} + +func sumSHA1(data []byte, length int) ([]byte, error) { + a := sha1.Sum(data) + return a[0:20], nil +} + +func sumSHA256(data []byte, length int) ([]byte, error) { + a := sha256.Sum256(data) + return a[0:32], nil +} + +func sumMD5(data []byte, length int) ([]byte, error) { + a := md5.Sum(data) + return a[0:md5.Size], nil +} + +func sumDoubleSHA256(data []byte, length int) ([]byte, error) { + val, _ := sumSHA256(data, len(data)) + return sumSHA256(val, len(val)) +} + +func sumSHA512(data []byte, length int) ([]byte, error) { + a := sha512.Sum512(data) + return a[0:64], nil +} +func sumKeccak256(data []byte, length int) ([]byte, error) { + h := sha3.NewLegacyKeccak256() + h.Write(data) + return h.Sum(nil), nil +} + +func sumKeccak512(data []byte, length int) ([]byte, error) { + h := sha3.NewLegacyKeccak512() + h.Write(data) + return h.Sum(nil), nil +} + +func sumSHA3_512(data []byte, length int) ([]byte, error) { + a := sha3.Sum512(data) + return a[:], nil +} + +func sumMURMUR3(data []byte, length int) ([]byte, error) { + number := murmur3.Sum32(data) + bytes := make([]byte, 4) + for i := range bytes { + bytes[i] = byte(number & 0xff) + number >>= 8 + } + return bytes, nil +} + +func sumSHAKE128(data []byte, length int) ([]byte, error) { + bytes := make([]byte, 32) + sha3.ShakeSum128(bytes, data) + return bytes, nil +} + +func sumSHAKE256(data []byte, length int) ([]byte, error) { + bytes := make([]byte, 64) + sha3.ShakeSum256(bytes, data) + return bytes, nil +} + +func sumSHA3_384(data []byte, length int) ([]byte, error) { + a := sha3.Sum384(data) + return a[:], nil +} + +func sumSHA3_256(data []byte, length int) ([]byte, error) { + a := sha3.Sum256(data) + return a[:], nil +} + +func sumSHA3_224(data []byte, length int) ([]byte, error) { + a := sha3.Sum224(data) + return a[:], nil +} + +func registerStdlibHashFuncs() { + RegisterHashFunc(IDENTITY, sumID) + RegisterHashFunc(SHA1, sumSHA1) + RegisterHashFunc(SHA2_512, sumSHA512) + RegisterHashFunc(MD5, sumMD5) +} + +func registerNonStdlibHashFuncs() { + RegisterHashFunc(SHA2_256, sumSHA256) + RegisterHashFunc(DBL_SHA2_256, sumDoubleSHA256) + + RegisterHashFunc(KECCAK_256, sumKeccak256) + RegisterHashFunc(KECCAK_512, sumKeccak512) + + RegisterHashFunc(SHA3_224, sumSHA3_224) + RegisterHashFunc(SHA3_256, sumSHA3_256) + RegisterHashFunc(SHA3_384, sumSHA3_384) + RegisterHashFunc(SHA3_512, sumSHA3_512) + + RegisterHashFunc(MURMUR3_128, sumMURMUR3) + + RegisterHashFunc(SHAKE_128, sumSHAKE128) + RegisterHashFunc(SHAKE_256, sumSHAKE256) + + // Blake family of hash functions + // BLAKE2S + for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ { + size := int(c - BLAKE2S_MIN + 1) + RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) { + return sumBlake2s(buf, size) + }) + } + // BLAKE2B + for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ { + size := int(c - BLAKE2B_MIN + 1) + RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) { + return sumBlake2b(buf, size) + }) + } +} + +func init() { + registerStdlibHashFuncs() + registerNonStdlibHashFuncs() +} + +// RegisterHashFunc adds an entry to the package-level code -> hash func map. +// The hash function must return at least the requested number of bytes. If it +// returns more, the hash will be truncated. +func RegisterHashFunc(code uint64, hashFunc HashFunc) error { + if !ValidCode(code) { + return fmt.Errorf("code %v not valid", code) + } + + _, ok := funcTable[code] + if ok { + return fmt.Errorf("hash func for code %v already registered", code) + } + + funcTable[code] = hashFunc + return nil +} diff --git a/vendor/github.com/multiformats/go-varint/.travis.yml b/vendor/github.com/multiformats/go-varint/.travis.yml new file mode 100644 index 0000000000..248d09b672 --- /dev/null +++ b/vendor/github.com/multiformats/go-varint/.travis.yml @@ -0,0 +1,30 @@ +os: + - linux + +language: go + +go: + - 1.11.x + +env: + global: + - GOTFLAGS="-race" + - GO111MODULE=on + matrix: + - BUILD_DEPTYPE=gomod + + +# disable travis install +install: + - true + +script: + - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh) + +cache: + directories: + - $GOPATH/pkg/mod + - /home/travis/.cache/go-build + +notifications: + email: false diff --git a/vendor/github.com/multiformats/go-varint/LICENSE b/vendor/github.com/multiformats/go-varint/LICENSE new file mode 100644 index 0000000000..14121ca71d --- /dev/null +++ b/vendor/github.com/multiformats/go-varint/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Protocol Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/multiformats/go-varint/README.md b/vendor/github.com/multiformats/go-varint/README.md new file mode 100644 index 0000000000..57f0a4a024 --- /dev/null +++ b/vendor/github.com/multiformats/go-varint/README.md @@ -0,0 +1,35 @@ +# go-varint + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai) +[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) +[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) +[![GoDoc](https://godoc.org/github.com/multiformats/go-varint?status.svg)](https://godoc.org/github.com/multiformats/go-varint) +[![Travis CI](https://img.shields.io/travis/multiformats/go-varint.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-varint) +[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-varint.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-varint?branch=master) + +> Varint helpers that enforce minimal encoding. + +## Table of Contents + +- [Install](#install) +- [Contribute](#contribute) +- [License](#license) + +## Install + +```sh +go get github.com/multiformats/go-varint +``` + +## Contribute + +Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multiaddr/issues). + +Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). + +Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification. + +## License + +[MIT](LICENSE) © 2019 Protocol Labs diff --git a/vendor/github.com/multiformats/go-varint/codecov.yml b/vendor/github.com/multiformats/go-varint/codecov.yml new file mode 100644 index 0000000000..ca8100ab11 --- /dev/null +++ b/vendor/github.com/multiformats/go-varint/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "multiaddr" diff --git a/vendor/github.com/multiformats/go-varint/go.mod b/vendor/github.com/multiformats/go-varint/go.mod new file mode 100644 index 0000000000..f32e76408e --- /dev/null +++ b/vendor/github.com/multiformats/go-varint/go.mod @@ -0,0 +1,3 @@ +module github.com/multiformats/go-varint + +go 1.12 diff --git a/vendor/github.com/multiformats/go-varint/varint.go b/vendor/github.com/multiformats/go-varint/varint.go new file mode 100644 index 0000000000..2648b0c8a3 --- /dev/null +++ b/vendor/github.com/multiformats/go-varint/varint.go @@ -0,0 +1,94 @@ +package varint + +import ( + "encoding/binary" + "errors" + "io" + "math/bits" +) + +var ( + ErrOverflow = errors.New("varints larger than uint64 not yet supported") + ErrUnderflow = errors.New("varints malformed, could not reach the end") + ErrNotMinimal = errors.New("varint not minimally encoded") +) + +// UvarintSize returns the size (in bytes) of `num` encoded as a unsigned varint. +func UvarintSize(num uint64) int { + bits := bits.Len64(num) + q, r := bits/7, bits%7 + size := q + if r > 0 || size == 0 { + size++ + } + return size +} + +// ToUvarint converts an unsigned integer to a varint-encoded []byte +func ToUvarint(num uint64) []byte { + buf := make([]byte, UvarintSize(num)) + n := binary.PutUvarint(buf, uint64(num)) + return buf[:n] +} + +// FromUvarint reads an unsigned varint from the beginning of buf, returns the +// varint, and the number of bytes read. +func FromUvarint(buf []byte) (uint64, int, error) { + // Modified from the go standard library. Copyright the Go Authors and + // released under the BSD License. + var x uint64 + var s uint + for i, b := range buf { + if b < 0x80 { + if i > 9 || i == 9 && b > 1 { + return 0, 0, ErrOverflow + } else if b == 0 && s > 0 { + return 0, 0, ErrNotMinimal + } + return x | uint64(b)< 9 || i == 9 && b > 1 { + return 0, ErrOverflow + } else if b == 0 && s > 0 { + // we should never _finish_ on a 0 byte if we + // have more than one byte. + return 0, ErrNotMinimal + } + return x | uint64(b)< A tool to run go benchmarks with a common parseable format + +## Install + +`go get github.com/whyrusleeping/bencher` + +## Usage + +Bencher accepts all standard `go test` flags. + +To just run the benchmarks in your package: + +`bencher` + +To run all tests in all packages below you: + +`bencher ./...` + + +### License + +MIT + diff --git a/vendor/github.com/whyrusleeping/bencher/go.mod b/vendor/github.com/whyrusleeping/bencher/go.mod new file mode 100644 index 0000000000..0cb25b78a4 --- /dev/null +++ b/vendor/github.com/whyrusleeping/bencher/go.mod @@ -0,0 +1,9 @@ +module github.com/whyrusleeping/bencher + +go 1.12 + +require ( + github.com/shirou/gopsutil v2.18.12+incompatible + github.com/stretchr/testify v1.4.0 // indirect + golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 // indirect +) diff --git a/vendor/github.com/whyrusleeping/bencher/go.sum b/vendor/github.com/whyrusleeping/bencher/go.sum new file mode 100644 index 0000000000..84d1f8105d --- /dev/null +++ b/vendor/github.com/whyrusleeping/bencher/go.sum @@ -0,0 +1,14 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= +github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/whyrusleeping/bencher/main.go b/vendor/github.com/whyrusleeping/bencher/main.go new file mode 100644 index 0000000000..db9e43ded4 --- /dev/null +++ b/vendor/github.com/whyrusleeping/bencher/main.go @@ -0,0 +1,237 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "time" + + "github.com/shirou/gopsutil/cpu" + "github.com/shirou/gopsutil/mem" +) + +type BenchResults struct { + Commit CommitInfo `json:"commit"` + Tags []string `json:"tags"` + Submitter string `json:"submitter"` + Repo string `json:"repo"` + Branch string `json:"branch"` + RunDate int64 `json:"runDate"` + System SysInfo `json:"system"` + Benchmarks []Benchmark `json:"benchmarks"` +} + +type CommitInfo struct { + Hash string `json:"hash"` + Date int64 `json:"date"` +} + +type SysInfo struct { + CPU string `json:"cpu"` + OS string `json:"os"` + Memory string `json:"mem"` +} + +type Benchmark struct { + Name string `json:"name"` + Module string `json:"module"` + Metrics []Metric `json:"metrics"` +} + +type Metric struct { + Name string `json:"name"` + Output bool `json:"output"` + Value float64 `json:"value"` + Type string `json:"type"` +} + +func fatal(err error) { + fmt.Println(err) + os.Exit(1) +} + +func getBasicInfo() (*BenchResults, error) { + out := new(BenchResults) + + ci, err := getCommitInfo() + if err != nil { + return nil, err + } + + out.Commit = *ci + + out.Submitter = os.Getenv("USER") + + branch, err := getBranch() + if err != nil { + return nil, err + } + out.Branch = branch + + sysinfo, err := getSystemInfo() + if err != nil { + return nil, err + } + out.System = *sysinfo + + dir, err := os.Getwd() + if err != nil { + return nil, err + } + + out.Repo = filepath.Base(dir) + + out.RunDate = time.Now().Unix() + + return out, nil +} + +func getCommitInfo() (*CommitInfo, error) { + out, err := exec.Command("git", "show", "-s", "--no-color").Output() + if err != nil { + return nil, err + } + + lines := strings.Split(string(out), "\n") + commitHash := strings.Fields(lines[0])[1] + + var dateStr string + for _, l := range lines { + if strings.HasPrefix(l, "Date:") { + dateStr = strings.TrimSpace(l[5:]) + break + } + } + + t, err := time.Parse("Mon Jan 2 15:04:05 2006 -0700", dateStr) + if err != nil { + return nil, err + } + + return &CommitInfo{ + Hash: commitHash, + Date: t.Unix(), + }, nil +} + +func getBranch() (string, error) { + out, err := exec.Command("git", "branch", "--no-color").Output() + if err != nil { + return "", err + } + + for _, l := range strings.Split(string(out), "\n") { + if strings.HasPrefix(l, "*") { + return strings.Trim(l, "* \t"), nil + } + } + + return "", fmt.Errorf("failed to determine git branch") +} + +func getSystemInfo() (*SysInfo, error) { + infostat, err := cpu.Info() + if err != nil { + return nil, err + } + + vmem, err := mem.VirtualMemory() + if err != nil { + return nil, err + } + + return &SysInfo{ + CPU: infostat[0].ModelName, + OS: runtime.GOOS, + Memory: fmt.Sprint(vmem.Total), + }, nil +} + +func main() { + args := os.Args[1:] + if len(args) == 0 { + args = []string{".", "-bench=."} + } + + var hasfilter bool + for _, arg := range args { + if strings.HasPrefix(arg, "-bench=") { + hasfilter = true + break + } + } + + if !hasfilter { + args = append(args, "-bench=.") + } + + args = append([]string{"test"}, args...) + + benchrun, err := getBasicInfo() + if err != nil { + fatal(err) + } + + cmd := exec.Command("go", args...) + cmd.Stderr = os.Stderr + + out, err := cmd.Output() + if err != nil { + fatal(err) + } + + lines := strings.Split(string(out), "\n") + var curpkg string + for _, l := range lines { + fields := strings.Fields(l) + if len(fields) == 0 { + continue + } + switch fields[0] { + case "?", "PASS", "ok", "FAIL": + continue + case "pkg:": + curpkg = fields[1] + default: + if !strings.HasPrefix(fields[0], "Benchmark") { + continue + } + + b := Benchmark{ + Name: fields[0], + Module: curpkg, + } + + for i := 2; i < len(fields); i += 2 { + val, err := strconv.ParseFloat(fields[i], 64) + if err != nil { + fmt.Printf("parsing line failed: %q\n", l) + fatal(err) + } + + metricName := fields[i+1] + units := strings.Split(metricName, "/")[0] + + b.Metrics = append(b.Metrics, Metric{ + Name: metricName, + Value: val, + Output: true, + Type: units, + }) + } + benchrun.Benchmarks = append(benchrun.Benchmarks, b) + } + } + + jsonout, err := json.MarshalIndent(benchrun, "", " ") + if err != nil { + fatal(err) + } + + fmt.Println(string(jsonout)) +} diff --git a/vendor/github.com/whyrusleeping/cbor-gen/Makefile b/vendor/github.com/whyrusleeping/cbor-gen/Makefile new file mode 100644 index 0000000000..cbb8d39026 --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/Makefile @@ -0,0 +1,8 @@ +gentest: + rm -rf ./testing/cbor_gen.go ./testing/cbor_map_gen.go + go run ./testgen/main.go +.PHONY: gentest + +test: gentest + go test ./... +.PHONY: test diff --git a/vendor/github.com/whyrusleeping/cbor-gen/README.md b/vendor/github.com/whyrusleeping/cbor-gen/README.md new file mode 100644 index 0000000000..93603a98dd --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/README.md @@ -0,0 +1,6 @@ +# cbor-gen + +Some basic utilities to generate fast path cbor codecs for your types. + +## License +MIT diff --git a/vendor/github.com/whyrusleeping/cbor-gen/cbor_cid.go b/vendor/github.com/whyrusleeping/cbor-gen/cbor_cid.go new file mode 100644 index 0000000000..ab4654a80e --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/cbor_cid.go @@ -0,0 +1,22 @@ +package typegen + +import ( + "io" + + cid "github.com/ipfs/go-cid" +) + +type CborCid cid.Cid + +func (c *CborCid) MarshalCBOR(w io.Writer) error { + return WriteCid(w, cid.Cid(*c)) +} + +func (c *CborCid) UnmarshalCBOR(r io.Reader) error { + oc, err := ReadCid(r) + if err != nil { + return err + } + *c = CborCid(oc) + return nil +} diff --git a/vendor/github.com/whyrusleeping/cbor-gen/gen.go b/vendor/github.com/whyrusleeping/cbor-gen/gen.go new file mode 100644 index 0000000000..743f58ed59 --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/gen.go @@ -0,0 +1,1258 @@ +package typegen + +import ( + "fmt" + "io" + "reflect" + "strings" + "text/template" +) + +const MaxLength = 8192 + +const ByteArrayMaxLen = 2 << 20 + +func doTemplate(w io.Writer, info interface{}, templ string) error { + t := template.Must(template.New(""). + Funcs(template.FuncMap{ + "MajorType": func(wname string, tname string, val string) string { + return fmt.Sprintf(`if err := cbg.WriteMajorTypeHeaderBuf(scratch, %s, %s, uint64(%s)); err != nil { + return err +}`, wname, tname, val) + }, + "ReadHeader": func(rdr string) string { + return fmt.Sprintf(`cbg.CborReadHeaderBuf(%s, scratch)`, rdr) + }, + }).Parse(templ)) + + return t.Execute(w, info) +} + +func PrintHeaderAndUtilityMethods(w io.Writer, pkg string) error { + data := struct { + Package string + }{pkg} + return doTemplate(w, data, `// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package {{ .Package }} + +import ( + "fmt" + "io" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + + +var _ = xerrors.Errorf + +`) +} + +type Field struct { + Name string + Pointer bool + Type reflect.Type + Pkg string + + IterLabel string +} + +func typeName(pkg string, t reflect.Type) string { + switch t.Kind() { + case reflect.Array: + return fmt.Sprintf("[%d]%s", t.Len(), typeName(pkg, t.Elem())) + case reflect.Slice: + return "[]" + typeName(pkg, t.Elem()) + case reflect.Ptr: + return "*" + typeName(pkg, t.Elem()) + case reflect.Map: + return "map[" + typeName(pkg, t.Key()) + "]" + typeName(pkg, t.Elem()) + default: + return strings.TrimPrefix(t.String(), pkg+".") + } +} + +func (f Field) TypeName() string { + if f.Type.PkgPath() == "github.com/whyrusleeping/cbor-gen" { + return "cbg" + strings.TrimPrefix(typeName(f.Pkg, f.Type), "typegen") + } + return typeName(f.Pkg, f.Type) +} + +func (f Field) ElemName() string { + return typeName(f.Pkg, f.Type.Elem()) +} + +func (f Field) IsArray() bool { + return f.Type.Kind() == reflect.Array +} + +func (f Field) Len() int { + return f.Type.Len() +} + +type GenTypeInfo struct { + Name string + Fields []Field +} + +func (gti *GenTypeInfo) NeedsScratch() bool { + for _, f := range gti.Fields { + switch f.Type.Kind() { + case reflect.String, + reflect.Uint64, + reflect.Int64, + reflect.Uint8, + reflect.Array, + reflect.Slice, + reflect.Map: + return true + + case reflect.Struct: + fname := f.Type.PkgPath() + "." + f.Type.Name() + switch fname { + case "math/big.Int": + return true + case "github.com/ipfs/go-cid.Cid": + return true + } + // nope + case reflect.Bool: + // nope + } + } + return false +} + +func nameIsExported(name string) bool { + return strings.ToUpper(name[0:1]) == name[0:1] +} + +func ParseTypeInfo(pkg string, i interface{}) (*GenTypeInfo, error) { + t := reflect.TypeOf(i) + + out := GenTypeInfo{ + Name: t.Name(), + } + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if !nameIsExported(f.Name) { + continue + } + + ft := f.Type + var pointer bool + if ft.Kind() == reflect.Ptr { + ft = ft.Elem() + pointer = true + } + + out.Fields = append(out.Fields, Field{ + Name: f.Name, + Pointer: pointer, + Type: ft, + Pkg: pkg, + }) + } + + return &out, nil +} + +func (gti GenTypeInfo) TupleHeader() []byte { + return CborEncodeMajorType(MajArray, uint64(len(gti.Fields))) +} + +func (gti GenTypeInfo) TupleHeaderAsByteString() string { + h := gti.TupleHeader() + s := "[]byte{" + for _, b := range h { + s += fmt.Sprintf("%d,", b) + } + s += "}" + return s +} + +func (gti GenTypeInfo) MapHeader() []byte { + return CborEncodeMajorType(MajMap, uint64(len(gti.Fields))) +} + +func (gti GenTypeInfo) MapHeaderAsByteString() string { + h := gti.MapHeader() + s := "[]byte{" + for _, b := range h { + s += fmt.Sprintf("%d,", b) + } + s += "}" + return s +} + +func emitCborMarshalStringField(w io.Writer, f Field) error { + if f.Pointer { + return fmt.Errorf("pointers to strings not supported") + } + + return doTemplate(w, f, ` + if len({{ .Name }}) > cbg.MaxLength { + return xerrors.Errorf("Value in field {{ .Name | js }} was too long") + } + + {{ MajorType "w" "cbg.MajTextString" (print "len(" .Name ")") }} + if _, err := io.WriteString(w, {{ .Name }}); err != nil { + return err + } +`) +} +func emitCborMarshalStructField(w io.Writer, f Field) error { + fname := f.Type.PkgPath() + "." + f.Type.Name() + switch fname { + case "math/big.Int": + return doTemplate(w, f, ` + { + if err := cbg.CborWriteHeader(w, cbg.MajTag, 2); err != nil { + return err + } + var b []byte + if {{ .Name }} != nil { + b = {{ .Name }}.Bytes() + } + + if err := cbg.CborWriteHeader(w, cbg.MajByteString, uint64(len(b))); err != nil { + return err + } + if _, err := w.Write(b); err != nil { + return err + } + } +`) + + case "github.com/ipfs/go-cid.Cid": + return doTemplate(w, f, ` +{{ if .Pointer }} + if {{ .Name }} == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCidBuf(scratch, w, *{{ .Name }}); err != nil { + return xerrors.Errorf("failed to write cid field {{ .Name }}: %w", err) + } + } +{{ else }} + if err := cbg.WriteCidBuf(scratch, w, {{ .Name }}); err != nil { + return xerrors.Errorf("failed to write cid field {{ .Name }}: %w", err) + } +{{ end }} +`) + default: + return doTemplate(w, f, ` + if err := {{ .Name }}.MarshalCBOR(w); err != nil { + return err + } +`) + } + +} + +func emitCborMarshalUint64Field(w io.Writer, f Field) error { + return doTemplate(w, f, ` +{{ if .Pointer }} + if {{ .Name }} == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + {{ MajorType "w" "cbg.MajUnsignedInt" (print "*" .Name) }} + } +{{ else }} + {{ MajorType "w" "cbg.MajUnsignedInt" .Name }} +{{ end }} +`) +} + +func emitCborMarshalUint8Field(w io.Writer, f Field) error { + if f.Pointer { + return fmt.Errorf("pointers to integers not supported") + } + return doTemplate(w, f, ` +{{ MajorType "w" "cbg.MajUnsignedInt" .Name }} +`) +} + +func emitCborMarshalInt64Field(w io.Writer, f Field) error { + if f.Pointer { + return fmt.Errorf("pointers to integers not supported") + } + + // if negative + // val = -1 - cbor + // cbor = -val -1 + + return doTemplate(w, f, ` + if {{ .Name }} >= 0 { + {{ MajorType "w" "cbg.MajUnsignedInt" .Name }} + } else { + {{ MajorType "w" "cbg.MajNegativeInt" (print "-" .Name "-1") }} + } +`) +} + +func emitCborMarshalBoolField(w io.Writer, f Field) error { + return doTemplate(w, f, ` + if err := cbg.WriteBool(w, {{ .Name }}); err != nil { + return err + } +`) +} + +func emitCborMarshalMapField(w io.Writer, f Field) error { + err := doTemplate(w, f, ` +{ + if len({{ .Name }}) > 4096 { + return xerrors.Errorf("cannot marshal {{ .Name }} map too large") + } + + {{ MajorType "w" "cbg.MajMap" (print "len(" .Name ")") }} + + keys := make([]string, 0, len({{ .Name }})) + for k := range {{ .Name }} { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := {{ .Name }}[k] + +`) + if err != nil { + return err + } + + // Map key + switch f.Type.Key().Kind() { + case reflect.String: + if err := emitCborMarshalStringField(w, Field{Name: "k"}); err != nil { + return err + } + default: + return fmt.Errorf("non-string map keys are not yet supported") + } + + // Map value + switch f.Type.Elem().Kind() { + case reflect.Ptr: + if f.Type.Elem().Elem().Kind() != reflect.Struct { + return fmt.Errorf("unsupported map elem ptr type: %s", f.Type.Elem()) + } + + fallthrough + case reflect.Struct: + if err := emitCborMarshalStructField(w, Field{Name: "v", Type: f.Type.Elem(), Pkg: f.Pkg}); err != nil { + return err + } + default: + return fmt.Errorf("currently unsupported map elem type: %s", f.Type.Elem()) + } + + return doTemplate(w, f, ` + } + } +`) +} + +func emitCborMarshalSliceField(w io.Writer, f Field) error { + if f.Pointer { + return fmt.Errorf("pointers to slices not supported") + } + e := f.Type.Elem() + + if e.Kind() == reflect.Uint8 { + return doTemplate(w, f, ` + if len({{ .Name }}) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field {{ .Name }} was too long") + } + + {{ MajorType "w" "cbg.MajByteString" (print "len(" .Name ")" ) }} + + if _, err := w.Write({{ .Name }}); err != nil { + return err + } +`) + } + + if e.Kind() == reflect.Ptr { + e = e.Elem() + } + + err := doTemplate(w, f, ` + if len({{ .Name }}) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field {{ .Name }} was too long") + } + + {{ MajorType "w" "cbg.MajArray" ( print "len(" .Name ")" ) }} + for _, v := range {{ .Name }} {`) + if err != nil { + return err + } + + switch e.Kind() { + default: + return fmt.Errorf("do not yet support slices of %s yet", e.Kind()) + case reflect.Struct: + fname := e.PkgPath() + "." + e.Name() + switch fname { + case "github.com/ipfs/go-cid.Cid": + err := doTemplate(w, f, ` + if err := cbg.WriteCidBuf(scratch, w, v); err != nil { + return xerrors.Errorf("failed writing cid field {{ .Name }}: %w", err) + } +`) + if err != nil { + return err + } + + default: + err := doTemplate(w, f, ` + if err := v.MarshalCBOR(w); err != nil { + return err + } +`) + if err != nil { + return err + } + } + case reflect.Uint64: + err := doTemplate(w, f, ` + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } +`) + if err != nil { + return err + } + case reflect.Uint8: + err := doTemplate(w, f, ` + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } +`) + if err != nil { + return err + } + case reflect.Int64: + subf := Field{Name: "v", Type: e, Pkg: f.Pkg} + if err := emitCborMarshalInt64Field(w, subf); err != nil { + return err + } + + case reflect.Slice: + subf := Field{Name: "v", Type: e, Pkg: f.Pkg} + if err := emitCborMarshalSliceField(w, subf); err != nil { + return err + } + } + + // array end + fmt.Fprintf(w, "\t}\n") + return nil +} + +func emitCborMarshalStructTuple(w io.Writer, gti *GenTypeInfo) error { + // 9 byte buffer to accomodate for the maximum header length (cbor varints are maximum 9 bytes_ + err := doTemplate(w, gti, `var lengthBuf{{ .Name }} = {{ .TupleHeaderAsByteString }} +func (t *{{ .Name }}) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBuf{{ .Name }}); err != nil { + return err + } +{{ if .NeedsScratch }} + scratch := make([]byte, 9) +{{ end }} +`) + if err != nil { + return err + } + + for _, f := range gti.Fields { + fmt.Fprintf(w, "\n\t// t.%s (%s) (%s)", f.Name, f.Type, f.Type.Kind()) + f.Name = "t." + f.Name + + switch f.Type.Kind() { + case reflect.String: + if err := emitCborMarshalStringField(w, f); err != nil { + return err + } + case reflect.Struct: + if err := emitCborMarshalStructField(w, f); err != nil { + return err + } + case reflect.Uint64: + if err := emitCborMarshalUint64Field(w, f); err != nil { + return err + } + case reflect.Uint8: + if err := emitCborMarshalUint8Field(w, f); err != nil { + return err + } + case reflect.Int64: + if err := emitCborMarshalInt64Field(w, f); err != nil { + return err + } + case reflect.Array: + fallthrough + case reflect.Slice: + if err := emitCborMarshalSliceField(w, f); err != nil { + return err + } + case reflect.Bool: + if err := emitCborMarshalBoolField(w, f); err != nil { + return err + } + case reflect.Map: + if err := emitCborMarshalMapField(w, f); err != nil { + return err + } + default: + return fmt.Errorf("field %q of %q has unsupported kind %q", f.Name, gti.Name, f.Type.Kind()) + } + } + + fmt.Fprintf(w, "\treturn nil\n}\n\n") + return nil +} + +func emitCborUnmarshalStringField(w io.Writer, f Field) error { + if f.Pointer { + return fmt.Errorf("pointers to strings not supported") + } + if f.Type == nil { + f.Type = reflect.TypeOf("") + } + return doTemplate(w, f, ` + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + {{ .Name }} = {{ .TypeName }}(sval) + } +`) +} + +func emitCborUnmarshalStructField(w io.Writer, f Field) error { + fname := f.Type.PkgPath() + "." + f.Type.Name() + + switch fname { + case "math/big.Int": + return doTemplate(w, f, ` + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } + + if maj != cbg.MajTag || extra != 2 { + return fmt.Errorf("big ints should be cbor bignums") + } + + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } + + if maj != cbg.MajByteString { + return fmt.Errorf("big ints should be tagged cbor byte strings") + } + + if extra > 256 { + return fmt.Errorf("{{ .Name }}: cbor bignum was too large") + } + + if extra > 0 { + buf := make([]byte, extra) + if _, err := io.ReadFull(br, buf); err != nil { + return err + } + {{ .Name }} = big.NewInt(0).SetBytes(buf) + } else { + {{ .Name }} = big.NewInt(0) + } +`) + case "github.com/ipfs/go-cid.Cid": + return doTemplate(w, f, ` + { +{{ if .Pointer }} + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { +{{ end }} + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field {{ .Name }}: %w", err) + } +{{ if .Pointer }} + {{ .Name }} = &c + } +{{ else }} + {{ .Name }} = c +{{ end }} + } +`) + case "github.com/whyrusleeping/cbor-gen.Deferred": + return doTemplate(w, f, ` + { +{{ if .Pointer }} + {{ .Name }} = new(cbg.Deferred) +{{ end }} + if err := {{ .Name }}.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("failed to read deferred field: %w", err) + } + } +`) + + default: + return doTemplate(w, f, ` + { +{{ if .Pointer }} + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + {{ .Name }} = new({{ .TypeName }}) + if err := {{ .Name }}.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling {{ .Name }} pointer: %w", err) + } + } +{{ else }} + if err := {{ .Name }}.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling {{ .Name }}: %w", err) + } +{{ end }} + } +`) + } +} + +func emitCborUnmarshalInt64Field(w io.Writer, f Field) error { + return doTemplate(w, f, `{ + maj, extra, err := {{ ReadHeader "br" }} + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + {{ .Name }} = {{ .TypeName }}(extraI) +} +`) +} + +func emitCborUnmarshalUint64Field(w io.Writer, f Field) error { + return doTemplate(w, f, ` + { +{{ if .Pointer }} + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + typed := {{ .TypeName }}(extra) + {{ .Name }} = &typed + } +{{ else }} + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + {{ .Name }} = {{ .TypeName }}(extra) +{{ end }} + } +`) +} + +func emitCborUnmarshalUint8Field(w io.Writer, f Field) error { + return doTemplate(w, f, ` + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint8 field") + } + if extra > math.MaxUint8 { + return fmt.Errorf("integer in input was too large for uint8 field") + } + {{ .Name }} = {{ .TypeName }}(extra) +`) +} + +func emitCborUnmarshalBoolField(w io.Writer, f Field) error { + return doTemplate(w, f, ` + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + {{ .Name }} = false + case 21: + {{ .Name }} = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } +`) +} + +func emitCborUnmarshalMapField(w io.Writer, f Field) error { + err := doTemplate(w, f, ` + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("expected a map (major type 5)") + } + if extra > 4096 { + return fmt.Errorf("{{ .Name }}: map too large") + } + + {{ .Name }} = make({{ .TypeName }}, extra) + + + for i, l := 0, int(extra); i < l; i++ { +`) + if err != nil { + return err + } + + switch f.Type.Key().Kind() { + case reflect.String: + if err := doTemplate(w, f, ` + var k string +`); err != nil { + return err + } + if err := emitCborUnmarshalStringField(w, Field{Name: "k"}); err != nil { + return err + } + default: + return fmt.Errorf("maps with non-string keys are not yet supported") + } + + var pointer bool + t := f.Type.Elem() + switch t.Kind() { + case reflect.Ptr: + if t.Elem().Kind() != reflect.Struct { + return fmt.Errorf("unsupported map elem ptr type: %s", t) + } + + pointer = true + fallthrough + case reflect.Struct: + subf := Field{Name: "v", Pointer: pointer, Type: t, Pkg: f.Pkg} + if err := doTemplate(w, subf, ` + var v {{ .TypeName }} +`); err != nil { + return err + } + + if pointer { + subf.Type = subf.Type.Elem() + } + if err := emitCborUnmarshalStructField(w, subf); err != nil { + return err + } + if err := doTemplate(w, f, ` + {{ .Name }}[k] = v +`); err != nil { + return err + } + default: + return fmt.Errorf("currently only support maps of structs") + } + + return doTemplate(w, f, ` + } +`) +} + +func emitCborUnmarshalSliceField(w io.Writer, f Field) error { + if f.IterLabel == "" { + f.IterLabel = "i" + } + + e := f.Type.Elem() + var pointer bool + if e.Kind() == reflect.Ptr { + pointer = true + e = e.Elem() + } + + err := doTemplate(w, f, ` + maj, extra, err = {{ ReadHeader "br" }} + if err != nil { + return err + } +`) + if err != nil { + return err + } + + if e.Kind() == reflect.Uint8 { + return doTemplate(w, f, ` + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("{{ .Name }}: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + {{ .Name }} = make([]byte, extra) + if _, err := io.ReadFull(br, {{ .Name }}); err != nil { + return err + } +`) + } + + if err := doTemplate(w, f, ` + if extra > cbg.MaxLength { + return fmt.Errorf("{{ .Name }}: array too large (%d)", extra) + } +`); err != nil { + return err + } + + err = doTemplate(w, f, ` + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + {{if .IsArray}} + if extra != {{ .Len }} { + return fmt.Errorf("expected array to have {{ .Len }} elements") + } + + {{ .Name }} = {{ .TypeName }}{} + {{else}} + if extra > 0 { + {{ .Name }} = make({{ .TypeName }}, extra) + } + {{end}} + for {{ .IterLabel }} := 0; {{ .IterLabel }} < int(extra); {{ .IterLabel }}++ { +`) + if err != nil { + return err + } + + switch e.Kind() { + case reflect.Struct: + fname := e.PkgPath() + "." + e.Name() + switch fname { + case "github.com/ipfs/go-cid.Cid": + err := doTemplate(w, f, ` + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("reading cid field {{ .Name }} failed: %w", err) + } + {{ .Name }}[{{ .IterLabel }}] = c +`) + if err != nil { + return err + } + default: + subf := Field{ + Type: e, + Pkg: f.Pkg, + Pointer: pointer, + Name: f.Name + "[" + f.IterLabel + "]", + } + + err := doTemplate(w, subf, ` + var v {{ .TypeName }} + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + {{ .Name }} = {{ if .Pointer }}&{{ end }}v +`) + if err != nil { + return err + } + } + case reflect.Uint64: + err := doTemplate(w, f, ` + maj, val, err := {{ ReadHeader "br" }} + if err != nil { + return xerrors.Errorf("failed to read uint64 for {{ .Name }} slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array {{ .Name }} was not a uint, instead got %d", maj) + } + + {{ .Name }}[{{ .IterLabel}}] = {{ .ElemName }}(val) +`) + if err != nil { + return err + } + case reflect.Int64: + subf := Field{ + Type: e, + Pkg: f.Pkg, + Name: f.Name + "[" + f.IterLabel + "]", + } + err := emitCborUnmarshalInt64Field(w, subf) + if err != nil { + return err + } + case reflect.Array: + fallthrough + case reflect.Slice: + nextIter := string([]byte{f.IterLabel[0] + 1}) + subf := Field{ + Name: fmt.Sprintf("%s[%s]", f.Name, f.IterLabel), + Type: e, + IterLabel: nextIter, + Pkg: f.Pkg, + } + fmt.Fprintf(w, "\t\t{\n\t\t\tvar maj byte\n\t\tvar extra uint64\n\t\tvar err error\n") + if err := emitCborUnmarshalSliceField(w, subf); err != nil { + return err + } + fmt.Fprintf(w, "\t\t}\n") + + default: + return fmt.Errorf("do not yet support slices of %s yet", e.Elem()) + } + fmt.Fprintf(w, "\t}\n\n") + + return nil +} + +func emitCborUnmarshalStructTuple(w io.Writer, gti *GenTypeInfo) error { + err := doTemplate(w, gti, ` +func (t *{{ .Name}}) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := {{ ReadHeader "br" }} + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != {{ len .Fields }} { + return fmt.Errorf("cbor input had wrong number of fields") + } + +`) + if err != nil { + return err + } + + for _, f := range gti.Fields { + fmt.Fprintf(w, "\t// t.%s (%s) (%s)\n", f.Name, f.Type, f.Type.Kind()) + f.Name = "t." + f.Name + + switch f.Type.Kind() { + case reflect.String: + if err := emitCborUnmarshalStringField(w, f); err != nil { + return err + } + case reflect.Struct: + if err := emitCborUnmarshalStructField(w, f); err != nil { + return err + } + case reflect.Uint64: + if err := emitCborUnmarshalUint64Field(w, f); err != nil { + return err + } + case reflect.Uint8: + if err := emitCborUnmarshalUint8Field(w, f); err != nil { + return err + } + case reflect.Int64: + if err := emitCborUnmarshalInt64Field(w, f); err != nil { + return err + } + case reflect.Array: + fallthrough + case reflect.Slice: + if err := emitCborUnmarshalSliceField(w, f); err != nil { + return err + } + case reflect.Bool: + if err := emitCborUnmarshalBoolField(w, f); err != nil { + return err + } + case reflect.Map: + if err := emitCborUnmarshalMapField(w, f); err != nil { + return err + } + default: + return fmt.Errorf("field %q of %q has unsupported kind %q", f.Name, gti.Name, f.Type.Kind()) + } + } + + fmt.Fprintf(w, "\treturn nil\n}\n\n") + + return nil +} + +// Generates 'tuple representation' cbor encoders for the given type +func GenTupleEncodersForType(inpkg string, i interface{}, w io.Writer) error { + gti, err := ParseTypeInfo(inpkg, i) + if err != nil { + return err + } + + if err := emitCborMarshalStructTuple(w, gti); err != nil { + return err + } + + if err := emitCborUnmarshalStructTuple(w, gti); err != nil { + return err + } + + return nil +} + +func emitCborMarshalStructMap(w io.Writer, gti *GenTypeInfo) error { + err := doTemplate(w, gti, `func (t *{{ .Name }}) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write({{ .MapHeaderAsByteString }}); err != nil { + return err + } +{{ if .NeedsScratch }} + scratch := make([]byte, 9) +{{ end }} +`) + if err != nil { + return err + } + + for _, f := range gti.Fields { + fmt.Fprintf(w, "\n\t// t.%s (%s) (%s)", f.Name, f.Type, f.Type.Kind()) + + if err := emitCborMarshalStringField(w, Field{ + Name: `"` + f.Name + `"`, + }); err != nil { + return err + } + + f.Name = "t." + f.Name + + switch f.Type.Kind() { + case reflect.String: + if err := emitCborMarshalStringField(w, f); err != nil { + return err + } + case reflect.Struct: + if err := emitCborMarshalStructField(w, f); err != nil { + return err + } + case reflect.Uint64: + if err := emitCborMarshalUint64Field(w, f); err != nil { + return err + } + case reflect.Int64: + if err := emitCborMarshalInt64Field(w, f); err != nil { + return err + } + case reflect.Uint8: + if err := emitCborMarshalUint8Field(w, f); err != nil { + return err + } + case reflect.Array: + fallthrough + case reflect.Slice: + if err := emitCborMarshalSliceField(w, f); err != nil { + return err + } + case reflect.Bool: + if err := emitCborMarshalBoolField(w, f); err != nil { + return err + } + case reflect.Map: + if err := emitCborMarshalMapField(w, f); err != nil { + return err + } + default: + return fmt.Errorf("field %q of %q has unsupported kind %q", f.Name, gti.Name, f.Type.Kind()) + } + } + + fmt.Fprintf(w, "\treturn nil\n}\n\n") + return nil +} + +func emitCborUnmarshalStructMap(w io.Writer, gti *GenTypeInfo) error { + err := doTemplate(w, gti, ` +func (t *{{ .Name}}) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := {{ ReadHeader "br" }} + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("{{ .Name }}: map struct too large (%d)", extra) + } + + var name string + n := extra + + for i := uint64(0); i < n; i++ { +`) + if err != nil { + return err + } + + if err := emitCborUnmarshalStringField(w, Field{Name: "name"}); err != nil { + return err + } + + err = doTemplate(w, gti, ` + switch name { +`) + if err != nil { + return err + } + + for _, f := range gti.Fields { + fmt.Fprintf(w, "// t.%s (%s) (%s)", f.Name, f.Type, f.Type.Kind()) + + err := doTemplate(w, f, ` + case "{{ .Name }}": +`) + if err != nil { + return err + } + + f.Name = "t." + f.Name + + switch f.Type.Kind() { + case reflect.String: + if err := emitCborUnmarshalStringField(w, f); err != nil { + return err + } + case reflect.Struct: + if err := emitCborUnmarshalStructField(w, f); err != nil { + return err + } + case reflect.Uint64: + if err := emitCborUnmarshalUint64Field(w, f); err != nil { + return err + } + case reflect.Int64: + if err := emitCborUnmarshalInt64Field(w, f); err != nil { + return err + } + case reflect.Uint8: + if err := emitCborUnmarshalUint8Field(w, f); err != nil { + return err + } + case reflect.Array: + fallthrough + case reflect.Slice: + if err := emitCborUnmarshalSliceField(w, f); err != nil { + return err + } + case reflect.Bool: + if err := emitCborUnmarshalBoolField(w, f); err != nil { + return err + } + case reflect.Map: + if err := emitCborUnmarshalMapField(w, f); err != nil { + return err + } + default: + return fmt.Errorf("field %q of %q has unsupported kind %q", f.Name, gti.Name, f.Type.Kind()) + } + } + + return doTemplate(w, gti, ` + default: + return fmt.Errorf("unknown struct field %d: '%s'", i, name) + } + } + + return nil +} +`) +} + +// Generates 'tuple representation' cbor encoders for the given type +func GenMapEncodersForType(inpkg string, i interface{}, w io.Writer) error { + gti, err := ParseTypeInfo(inpkg, i) + if err != nil { + return err + } + + if err := emitCborMarshalStructMap(w, gti); err != nil { + return err + } + + if err := emitCborUnmarshalStructMap(w, gti); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/whyrusleeping/cbor-gen/go.mod b/vendor/github.com/whyrusleeping/cbor-gen/go.mod new file mode 100644 index 0000000000..54bf117a1d --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/go.mod @@ -0,0 +1,11 @@ +module github.com/whyrusleeping/cbor-gen + +go 1.12 + +require ( + github.com/google/go-cmp v0.4.0 + github.com/gxed/hashland/keccakpg v0.0.1 // indirect + github.com/gxed/hashland/murmur3 v0.0.1 // indirect + github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +) diff --git a/vendor/github.com/whyrusleeping/cbor-gen/go.sum b/vendor/github.com/whyrusleeping/cbor-gen/go.sum new file mode 100644 index 0000000000..917becbf04 --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/go.sum @@ -0,0 +1,48 @@ +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.6-0.20200501225435-c1c89c20c166 h1:yUKAFk6gkzNsYQyUidUqCnXWcOBft8YhYXtolTpPUoI= +github.com/ipfs/go-cid v0.0.6-0.20200501225435-c1c89c20c166/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 h1:QN88Q0kT2QiDaLxpR/SDsqOBtNIEF/F3n96gSDUimkA= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/whyrusleeping/cbor-gen/utils.go b/vendor/github.com/whyrusleeping/cbor-gen/utils.go new file mode 100644 index 0000000000..5b55666b0b --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/utils.go @@ -0,0 +1,690 @@ +package typegen + +import ( + "bufio" + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "math" + + cid "github.com/ipfs/go-cid" +) + +func ScanForLinks(br io.Reader) ([]cid.Cid, error) { + var out []cid.Cid + if err := scanForLinksRec(br, func(c cid.Cid) { + out = append(out, c) + }); err != nil { + return nil, err + } + + return out, nil +} + +func scanForLinksRec(br io.Reader, cb func(cid.Cid)) error { + maj, extra, err := CborReadHeader(br) + if err != nil { + return err + } + + switch maj { + case MajUnsignedInt, MajNegativeInt, MajOther: + case MajByteString, MajTextString: + _, err := io.CopyN(ioutil.Discard, br, int64(extra)) + if err != nil { + return err + } + case MajTag: + if extra == 42 { + buf, err := ReadByteArray(br, 1000) + if err != nil { + return err + } + c, err := cid.Cast(buf[1:]) + if err != nil { + return err + } + cb(c) + } else { + if err := scanForLinksRec(br, cb); err != nil { + return err + } + } + case MajArray: + for i := 0; i < int(extra); i++ { + if err := scanForLinksRec(br, cb); err != nil { + return err + } + } + case MajMap: + for i := 0; i < int(extra*2); i++ { + if err := scanForLinksRec(br, cb); err != nil { + return err + } + } + default: + return fmt.Errorf("unhandled cbor type: %d", maj) + } + return nil +} + +const ( + MajUnsignedInt = 0 + MajNegativeInt = 1 + MajByteString = 2 + MajTextString = 3 + MajArray = 4 + MajMap = 5 + MajTag = 6 + MajOther = 7 +) + +type CBORUnmarshaler interface { + UnmarshalCBOR(io.Reader) error +} + +type CBORMarshaler interface { + MarshalCBOR(io.Writer) error +} + +type Deferred struct { + Raw []byte +} + +func (d *Deferred) MarshalCBOR(w io.Writer) error { + if d == nil { + _, err := w.Write(CborNull) + return err + } + if d.Raw == nil { + return errors.New("cannot marshal Deferred with nil value for Raw (will not unmarshal)") + } + _, err := w.Write(d.Raw) + return err +} + +func (d *Deferred) UnmarshalCBOR(br io.Reader) error { + // TODO: theres a more efficient way to implement this method, but for now + // this is fine + maj, extra, err := CborReadHeader(br) + if err != nil { + return err + } + header := CborEncodeMajorType(maj, extra) + + switch maj { + case MajUnsignedInt, MajNegativeInt, MajOther: + d.Raw = header + return nil + case MajByteString, MajTextString: + buf := make([]byte, int(extra)+len(header)) + copy(buf, header) + if _, err := io.ReadFull(br, buf[len(header):]); err != nil { + return err + } + + d.Raw = buf + + return nil + case MajTag: + sub := new(Deferred) + if err := sub.UnmarshalCBOR(br); err != nil { + return err + } + + d.Raw = append(header, sub.Raw...) + return nil + case MajArray: + d.Raw = header + for i := 0; i < int(extra); i++ { + sub := new(Deferred) + if err := sub.UnmarshalCBOR(br); err != nil { + return err + } + + d.Raw = append(d.Raw, sub.Raw...) + } + return nil + case MajMap: + d.Raw = header + sub := new(Deferred) + for i := 0; i < int(extra*2); i++ { + sub.Raw = sub.Raw[:0] + if err := sub.UnmarshalCBOR(br); err != nil { + return err + } + d.Raw = append(d.Raw, sub.Raw...) + } + return nil + default: + return fmt.Errorf("unhandled deferred cbor type: %d", maj) + } +} + +// this is a bit gnarly i should just switch to taking in a byte array at the top level +type BytePeeker interface { + io.Reader + PeekByte() (byte, error) +} + +type peeker struct { + io.Reader +} + +func (p *peeker) PeekByte() (byte, error) { + switch r := p.Reader.(type) { + case *bytes.Reader: + b, err := r.ReadByte() + if err != nil { + return 0, err + } + return b, r.UnreadByte() + case *bytes.Buffer: + b, err := r.ReadByte() + if err != nil { + return 0, err + } + return b, r.UnreadByte() + case *bufio.Reader: + o, err := r.Peek(1) + if err != nil { + return 0, err + } + + return o[0], nil + default: + panic("invariant violated") + } +} + +func GetPeeker(r io.Reader) BytePeeker { + switch r := r.(type) { + case *bytes.Reader: + return &peeker{r} + case *bytes.Buffer: + return &peeker{r} + case *bufio.Reader: + return &peeker{r} + case *peeker: + return r + default: + return &peeker{bufio.NewReaderSize(r, 16)} + } +} + +func readByte(r io.Reader) (byte, error) { + if br, ok := r.(io.ByteReader); ok { + return br.ReadByte() + } + var buf [1]byte + _, err := io.ReadFull(r, buf[:1]) + return buf[0], err +} + +func CborReadHeader(br io.Reader) (byte, uint64, error) { + first, err := readByte(br) + if err != nil { + return 0, 0, err + } + + maj := (first & 0xe0) >> 5 + low := first & 0x1f + + switch { + case low < 24: + return maj, uint64(low), nil + case low == 24: + next, err := readByte(br) + if err != nil { + return 0, 0, err + } + if next < 24 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 24 with value < 24)") + } + return maj, uint64(next), nil + case low == 25: + scratch := make([]byte, 2) + if _, err := io.ReadAtLeast(br, scratch[:2], 2); err != nil { + return 0, 0, err + } + val := uint64(binary.BigEndian.Uint16(scratch[:2])) + if val <= math.MaxUint8 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 25 with value <= MaxUint8)") + } + return maj, val, nil + case low == 26: + scratch := make([]byte, 4) + if _, err := io.ReadAtLeast(br, scratch[:4], 4); err != nil { + return 0, 0, err + } + val := uint64(binary.BigEndian.Uint32(scratch[:4])) + if val <= math.MaxUint16 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 26 with value <= MaxUint16)") + } + return maj, val, nil + case low == 27: + scratch := make([]byte, 8) + if _, err := io.ReadAtLeast(br, scratch, 8); err != nil { + return 0, 0, err + } + val := binary.BigEndian.Uint64(scratch) + if val <= math.MaxUint32 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 27 with value <= MaxUint32)") + } + return maj, val, nil + default: + return 0, 0, fmt.Errorf("invalid header: (%x)", first) + } +} + +func readByteBuf(r io.Reader, scratch []byte) (byte, error) { + n, err := r.Read(scratch[:1]) + if err != nil { + return 0, err + } + if n != 1 { + return 0, fmt.Errorf("failed to read a byte") + } + return scratch[0], err +} + +// same as the above, just tries to allocate less by using a passed in scratch buffer +func CborReadHeaderBuf(br io.Reader, scratch []byte) (byte, uint64, error) { + first, err := readByteBuf(br, scratch) + if err != nil { + return 0, 0, err + } + + maj := (first & 0xe0) >> 5 + low := first & 0x1f + + switch { + case low < 24: + return maj, uint64(low), nil + case low == 24: + next, err := readByteBuf(br, scratch) + if err != nil { + return 0, 0, err + } + if next < 24 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 24 with value < 24)") + } + return maj, uint64(next), nil + case low == 25: + if _, err := io.ReadAtLeast(br, scratch[:2], 2); err != nil { + return 0, 0, err + } + val := uint64(binary.BigEndian.Uint16(scratch[:2])) + if val <= math.MaxUint8 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 25 with value <= MaxUint8)") + } + return maj, val, nil + case low == 26: + if _, err := io.ReadAtLeast(br, scratch[:4], 4); err != nil { + return 0, 0, err + } + val := uint64(binary.BigEndian.Uint32(scratch[:4])) + if val <= math.MaxUint16 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 26 with value <= MaxUint16)") + } + return maj, val, nil + case low == 27: + if _, err := io.ReadAtLeast(br, scratch[:8], 8); err != nil { + return 0, 0, err + } + val := binary.BigEndian.Uint64(scratch[:8]) + if val <= math.MaxUint32 { + return 0, 0, fmt.Errorf("cbor input was not canonical (lval 27 with value <= MaxUint32)") + } + return maj, val, nil + default: + return 0, 0, fmt.Errorf("invalid header: (%x)", first) + } +} + +func CborWriteHeader(w io.Writer, t byte, l uint64) error { + return WriteMajorTypeHeader(w, t, l) +} + +// TODO: No matter what I do, this function *still* allocates. Its super frustrating. +// See issue: https://github.com/golang/go/issues/33160 +func WriteMajorTypeHeader(w io.Writer, t byte, l uint64) error { + switch { + case l < 24: + _, err := w.Write([]byte{(t << 5) | byte(l)}) + return err + case l < (1 << 8): + _, err := w.Write([]byte{(t << 5) | 24, byte(l)}) + return err + case l < (1 << 16): + var b [3]byte + b[0] = (t << 5) | 25 + binary.BigEndian.PutUint16(b[1:3], uint16(l)) + _, err := w.Write(b[:]) + return err + case l < (1 << 32): + var b [5]byte + b[0] = (t << 5) | 26 + binary.BigEndian.PutUint32(b[1:5], uint32(l)) + _, err := w.Write(b[:]) + return err + default: + var b [9]byte + b[0] = (t << 5) | 27 + binary.BigEndian.PutUint64(b[1:], uint64(l)) + _, err := w.Write(b[:]) + return err + } +} + +// Same as the above, but uses a passed in buffer to avoid allocations +func WriteMajorTypeHeaderBuf(buf []byte, w io.Writer, t byte, l uint64) error { + switch { + case l < 24: + buf[0] = (t << 5) | byte(l) + _, err := w.Write(buf[:1]) + return err + case l < (1 << 8): + buf[0] = (t << 5) | 24 + buf[1] = byte(l) + _, err := w.Write(buf[:2]) + return err + case l < (1 << 16): + buf[0] = (t << 5) | 25 + binary.BigEndian.PutUint16(buf[1:3], uint16(l)) + _, err := w.Write(buf[:3]) + return err + case l < (1 << 32): + buf[0] = (t << 5) | 26 + binary.BigEndian.PutUint32(buf[1:5], uint32(l)) + _, err := w.Write(buf[:5]) + return err + default: + buf[0] = (t << 5) | 27 + binary.BigEndian.PutUint64(buf[1:9], uint64(l)) + _, err := w.Write(buf[:9]) + return err + } +} + +func CborEncodeMajorType(t byte, l uint64) []byte { + switch { + case l < 24: + var b [1]byte + b[0] = (t << 5) | byte(l) + return b[:1] + case l < (1 << 8): + var b [2]byte + b[0] = (t << 5) | 24 + b[1] = byte(l) + return b[:2] + case l < (1 << 16): + var b [3]byte + b[0] = (t << 5) | 25 + binary.BigEndian.PutUint16(b[1:3], uint16(l)) + return b[:3] + case l < (1 << 32): + var b [5]byte + b[0] = (t << 5) | 26 + binary.BigEndian.PutUint32(b[1:5], uint32(l)) + return b[:5] + default: + var b [9]byte + b[0] = (t << 5) | 27 + binary.BigEndian.PutUint64(b[1:], uint64(l)) + return b[:] + } +} + +func ReadTaggedByteArray(br io.Reader, exptag uint64, maxlen uint64) ([]byte, error) { + maj, extra, err := CborReadHeader(br) + if err != nil { + return nil, err + } + + if maj != MajTag { + return nil, fmt.Errorf("expected cbor type 'tag' in input") + } + + if extra != exptag { + return nil, fmt.Errorf("expected tag %d", exptag) + } + + return ReadByteArray(br, maxlen) +} + +func ReadByteArray(br io.Reader, maxlen uint64) ([]byte, error) { + maj, extra, err := CborReadHeader(br) + if err != nil { + return nil, err + } + + if maj != MajByteString { + return nil, fmt.Errorf("expected cbor type 'byte string' in input") + } + + if extra > 256*1024 { + return nil, fmt.Errorf("string in cbor input too long") + } + + buf := make([]byte, extra) + if _, err := io.ReadAtLeast(br, buf, int(extra)); err != nil { + return nil, err + } + + return buf, nil +} + +var ( + CborBoolFalse = []byte{0xf4} + CborBoolTrue = []byte{0xf5} + CborNull = []byte{0xf6} +) + +func EncodeBool(b bool) []byte { + if b { + return CborBoolTrue + } + return CborBoolFalse +} + +func WriteBool(w io.Writer, b bool) error { + _, err := w.Write(EncodeBool(b)) + return err +} + +func ReadString(r io.Reader) (string, error) { + maj, l, err := CborReadHeader(r) + if err != nil { + return "", err + } + + if maj != MajTextString { + return "", fmt.Errorf("got tag %d while reading string value (l = %d)", maj, l) + } + + if l > MaxLength { + return "", fmt.Errorf("string in input was too long") + } + + buf := make([]byte, l) + _, err = io.ReadAtLeast(r, buf, int(l)) + if err != nil { + return "", err + } + + return string(buf), nil +} + +func ReadStringBuf(r io.Reader, scratch []byte) (string, error) { + maj, l, err := CborReadHeaderBuf(r, scratch) + if err != nil { + return "", err + } + + if maj != MajTextString { + return "", fmt.Errorf("got tag %d while reading string value (l = %d)", maj, l) + } + + if l > MaxLength { + return "", fmt.Errorf("string in input was too long") + } + + buf := make([]byte, l) + _, err = io.ReadAtLeast(r, buf, int(l)) + if err != nil { + return "", err + } + + return string(buf), nil +} + +func ReadCid(br io.Reader) (cid.Cid, error) { + buf, err := ReadTaggedByteArray(br, 42, 512) + if err != nil { + return cid.Undef, err + } + + return bufToCid(buf) +} + +func bufToCid(buf []byte) (cid.Cid, error) { + + if len(buf) == 0 { + return cid.Undef, fmt.Errorf("undefined cid") + } + + if len(buf) < 2 { + return cid.Undef, fmt.Errorf("cbor serialized CIDs must have at least two bytes") + } + + if buf[0] != 0 { + return cid.Undef, fmt.Errorf("cbor serialized CIDs must have binary multibase") + } + + return cid.Cast(buf[1:]) +} + +var byteArrZero = []byte{0} + +func WriteCid(w io.Writer, c cid.Cid) error { + if err := WriteMajorTypeHeader(w, MajTag, 42); err != nil { + return err + } + if c == cid.Undef { + return fmt.Errorf("undefined cid") + //return CborWriteHeader(w, MajByteString, 0) + } + + if err := WriteMajorTypeHeader(w, MajByteString, uint64(c.ByteLen()+1)); err != nil { + return err + } + + // that binary multibase prefix... + if _, err := w.Write(byteArrZero); err != nil { + return err + } + + if _, err := c.WriteBytes(w); err != nil { + return err + } + + return nil +} + +func WriteCidBuf(buf []byte, w io.Writer, c cid.Cid) error { + if err := WriteMajorTypeHeaderBuf(buf, w, MajTag, 42); err != nil { + return err + } + if c == cid.Undef { + return fmt.Errorf("undefined cid") + //return CborWriteHeader(w, MajByteString, 0) + } + + if err := WriteMajorTypeHeaderBuf(buf, w, MajByteString, uint64(c.ByteLen()+1)); err != nil { + return err + } + + // that binary multibase prefix... + if _, err := w.Write(byteArrZero); err != nil { + return err + } + + if _, err := c.WriteBytes(w); err != nil { + return err + } + + return nil +} + +type CborBool bool + +func (cb *CborBool) MarshalCBOR(w io.Writer) error { + return WriteBool(w, bool(*cb)) +} + +func (cb *CborBool) UnmarshalCBOR(r io.Reader) error { + t, val, err := CborReadHeader(r) + if err != nil { + return err + } + + if t != MajOther { + return fmt.Errorf("booleans should be major type 7") + } + + switch val { + case 20: + *cb = false + case 21: + *cb = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", val) + } + return nil +} + +type CborInt int64 + +func (ci *CborInt) MarshalCBOR(w io.Writer) error { + v := int64(*ci) + if v >= 0 { + if err := WriteMajorTypeHeader(w, MajUnsignedInt, uint64(v)); err != nil { + return err + } + } else { + if err := WriteMajorTypeHeader(w, MajNegativeInt, uint64(-v)-1); err != nil { + return err + } + } + return nil +} + +func (ci *CborInt) UnmarshalCBOR(r io.Reader) error { + maj, extra, err := CborReadHeader(r) + if err != nil { + return err + } + var extraI int64 + switch maj { + case MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + *ci = CborInt(extraI) + return nil +} diff --git a/vendor/github.com/whyrusleeping/cbor-gen/writefile.go b/vendor/github.com/whyrusleeping/cbor-gen/writefile.go new file mode 100644 index 0000000000..18de6e617a --- /dev/null +++ b/vendor/github.com/whyrusleeping/cbor-gen/writefile.go @@ -0,0 +1,84 @@ +package typegen + +import ( + "bytes" + "go/format" + "os" + "os/exec" + + "golang.org/x/xerrors" +) + +func WriteTupleEncodersToFile(fname, pkg string, types ...interface{}) error { + buf := new(bytes.Buffer) + + if err := PrintHeaderAndUtilityMethods(buf, pkg); err != nil { + return xerrors.Errorf("failed to write header: %w", err) + } + + for _, t := range types { + if err := GenTupleEncodersForType(pkg, t, buf); err != nil { + return xerrors.Errorf("failed to generate encoders: %w", err) + } + } + + data, err := format.Source(buf.Bytes()) + if err != nil { + return err + } + + fi, err := os.Create(fname) + if err != nil { + return xerrors.Errorf("failed to open file: %w", err) + } + + _, err = fi.Write(data) + if err != nil { + _ = fi.Close() + return err + } + _ = fi.Close() + + if err := exec.Command("goimports", "-w", fname).Run(); err != nil { + return err + } + + return nil +} + +func WriteMapEncodersToFile(fname, pkg string, types ...interface{}) error { + buf := new(bytes.Buffer) + + if err := PrintHeaderAndUtilityMethods(buf, pkg); err != nil { + return xerrors.Errorf("failed to write header: %w", err) + } + + for _, t := range types { + if err := GenMapEncodersForType(pkg, t, buf); err != nil { + return xerrors.Errorf("failed to generate encoders: %w", err) + } + } + + data, err := format.Source(buf.Bytes()) + if err != nil { + return err + } + + fi, err := os.Create(fname) + if err != nil { + return xerrors.Errorf("failed to open file: %w", err) + } + + _, err = fi.Write(data) + if err != nil { + _ = fi.Close() + return err + } + _ = fi.Close() + + if err := exec.Command("goimports", "-w", fname).Run(); err != nil { + return err + } + + return nil +} diff --git a/vendor/go.uber.org/atomic/.codecov.yml b/vendor/go.uber.org/atomic/.codecov.yml new file mode 100644 index 0000000000..6d4d1be7b5 --- /dev/null +++ b/vendor/go.uber.org/atomic/.codecov.yml @@ -0,0 +1,15 @@ +coverage: + range: 80..100 + round: down + precision: 2 + + status: + project: # measuring the overall project coverage + default: # context, you can create multiple ones with custom titles + enabled: yes # must be yes|true to enable this status + target: 100 # specify the target coverage for each commit status + # option: "auto" (must increase from parent commit or pull request base) + # option: "X%" a static target percentage to hit + if_not_found: success # if parent is not found report status as success, error, or failure + if_ci_failed: error # if ci fails report status as success, error, or failure + diff --git a/vendor/go.uber.org/atomic/.gitignore b/vendor/go.uber.org/atomic/.gitignore new file mode 100644 index 0000000000..c3fa253893 --- /dev/null +++ b/vendor/go.uber.org/atomic/.gitignore @@ -0,0 +1,12 @@ +/bin +.DS_Store +/vendor +cover.html +cover.out +lint.log + +# Binaries +*.test + +# Profiling output +*.prof diff --git a/vendor/go.uber.org/atomic/.travis.yml b/vendor/go.uber.org/atomic/.travis.yml new file mode 100644 index 0000000000..4e73268b60 --- /dev/null +++ b/vendor/go.uber.org/atomic/.travis.yml @@ -0,0 +1,27 @@ +sudo: false +language: go +go_import_path: go.uber.org/atomic + +env: + global: + - GO111MODULE=on + +matrix: + include: + - go: 1.12.x + - go: 1.13.x + env: LINT=1 + +cache: + directories: + - vendor + +before_install: + - go version + +script: + - test -z "$LINT" || make lint + - make cover + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/go.uber.org/atomic/CHANGELOG.md b/vendor/go.uber.org/atomic/CHANGELOG.md new file mode 100644 index 0000000000..aef8b6ebc4 --- /dev/null +++ b/vendor/go.uber.org/atomic/CHANGELOG.md @@ -0,0 +1,64 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.6.0] - 2020-02-24 +### Changed +- Drop library dependency on `golang.org/x/{lint, tools}`. + +## [1.5.1] - 2019-11-19 +- Fix bug where `Bool.CAS` and `Bool.Toggle` do work correctly together + causing `CAS` to fail even though the old value matches. + +## [1.5.0] - 2019-10-29 +### Changed +- With Go modules, only the `go.uber.org/atomic` import path is supported now. + If you need to use the old import path, please add a `replace` directive to + your `go.mod`. + +## [1.4.0] - 2019-05-01 +### Added + - Add `atomic.Error` type for atomic operations on `error` values. + +## [1.3.2] - 2018-05-02 +### Added +- Add `atomic.Duration` type for atomic operations on `time.Duration` values. + +## [1.3.1] - 2017-11-14 +### Fixed +- Revert optimization for `atomic.String.Store("")` which caused data races. + +## [1.3.0] - 2017-11-13 +### Added +- Add `atomic.Bool.CAS` for compare-and-swap semantics on bools. + +### Changed +- Optimize `atomic.String.Store("")` by avoiding an allocation. + +## [1.2.0] - 2017-04-12 +### Added +- Shadow `atomic.Value` from `sync/atomic`. + +## [1.1.0] - 2017-03-10 +### Added +- Add atomic `Float64` type. + +### Changed +- Support new `go.uber.org/atomic` import path. + +## [1.0.0] - 2016-07-18 + +- Initial release. + +[1.6.0]: https://github.com/uber-go/atomic/compare/v1.5.1...v1.6.0 +[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1 +[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0 +[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0 +[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2 +[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1 +[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0 +[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0 +[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0 +[1.0.0]: https://github.com/uber-go/atomic/releases/tag/v1.0.0 diff --git a/vendor/go.uber.org/atomic/LICENSE.txt b/vendor/go.uber.org/atomic/LICENSE.txt new file mode 100644 index 0000000000..8765c9fbc6 --- /dev/null +++ b/vendor/go.uber.org/atomic/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2016 Uber Technologies, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/go.uber.org/atomic/Makefile b/vendor/go.uber.org/atomic/Makefile new file mode 100644 index 0000000000..39af0fb63f --- /dev/null +++ b/vendor/go.uber.org/atomic/Makefile @@ -0,0 +1,35 @@ +# Directory to place `go install`ed binaries into. +export GOBIN ?= $(shell pwd)/bin + +GOLINT = $(GOBIN)/golint + +GO_FILES ?= *.go + +.PHONY: build +build: + go build ./... + +.PHONY: test +test: + go test -race ./... + +.PHONY: gofmt +gofmt: + $(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX)) + gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true + @[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" && cat $(FMT_LOG) && false) + +$(GOLINT): + go install golang.org/x/lint/golint + +.PHONY: golint +golint: $(GOLINT) + $(GOLINT) ./... + +.PHONY: lint +lint: gofmt golint + +.PHONY: cover +cover: + go test -coverprofile=cover.out -coverpkg ./... -v ./... + go tool cover -html=cover.out -o cover.html diff --git a/vendor/go.uber.org/atomic/README.md b/vendor/go.uber.org/atomic/README.md new file mode 100644 index 0000000000..ade0c20f16 --- /dev/null +++ b/vendor/go.uber.org/atomic/README.md @@ -0,0 +1,63 @@ +# atomic [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][reportcard-img]][reportcard] + +Simple wrappers for primitive types to enforce atomic access. + +## Installation + +```shell +$ go get -u go.uber.org/atomic@v1 +``` + +### Legacy Import Path + +As of v1.5.0, the import path `go.uber.org/atomic` is the only supported way +of using this package. If you are using Go modules, this package will fail to +compile with the legacy import path path `github.com/uber-go/atomic`. + +We recommend migrating your code to the new import path but if you're unable +to do so, or if your dependencies are still using the old import path, you +will have to add a `replace` directive to your `go.mod` file downgrading the +legacy import path to an older version. + +``` +replace github.com/uber-go/atomic => github.com/uber-go/atomic v1.4.0 +``` + +You can do so automatically by running the following command. + +```shell +$ go mod edit -replace github.com/uber-go/atomic=github.com/uber-go/atomic@v1.4.0 +``` + +## Usage + +The standard library's `sync/atomic` is powerful, but it's easy to forget which +variables must be accessed atomically. `go.uber.org/atomic` preserves all the +functionality of the standard library, but wraps the primitive types to +provide a safer, more convenient API. + +```go +var atom atomic.Uint32 +atom.Store(42) +atom.Sub(2) +atom.CAS(40, 11) +``` + +See the [documentation][doc] for a complete API specification. + +## Development Status + +Stable. + +--- + +Released under the [MIT License](LICENSE.txt). + +[doc-img]: https://godoc.org/github.com/uber-go/atomic?status.svg +[doc]: https://godoc.org/go.uber.org/atomic +[ci-img]: https://travis-ci.com/uber-go/atomic.svg?branch=master +[ci]: https://travis-ci.com/uber-go/atomic +[cov-img]: https://codecov.io/gh/uber-go/atomic/branch/master/graph/badge.svg +[cov]: https://codecov.io/gh/uber-go/atomic +[reportcard-img]: https://goreportcard.com/badge/go.uber.org/atomic +[reportcard]: https://goreportcard.com/report/go.uber.org/atomic diff --git a/vendor/go.uber.org/atomic/atomic.go b/vendor/go.uber.org/atomic/atomic.go new file mode 100644 index 0000000000..ad5fa0980a --- /dev/null +++ b/vendor/go.uber.org/atomic/atomic.go @@ -0,0 +1,356 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package atomic provides simple wrappers around numerics to enforce atomic +// access. +package atomic + +import ( + "math" + "sync/atomic" + "time" +) + +// Int32 is an atomic wrapper around an int32. +type Int32 struct{ v int32 } + +// NewInt32 creates an Int32. +func NewInt32(i int32) *Int32 { + return &Int32{i} +} + +// Load atomically loads the wrapped value. +func (i *Int32) Load() int32 { + return atomic.LoadInt32(&i.v) +} + +// Add atomically adds to the wrapped int32 and returns the new value. +func (i *Int32) Add(n int32) int32 { + return atomic.AddInt32(&i.v, n) +} + +// Sub atomically subtracts from the wrapped int32 and returns the new value. +func (i *Int32) Sub(n int32) int32 { + return atomic.AddInt32(&i.v, -n) +} + +// Inc atomically increments the wrapped int32 and returns the new value. +func (i *Int32) Inc() int32 { + return i.Add(1) +} + +// Dec atomically decrements the wrapped int32 and returns the new value. +func (i *Int32) Dec() int32 { + return i.Sub(1) +} + +// CAS is an atomic compare-and-swap. +func (i *Int32) CAS(old, new int32) bool { + return atomic.CompareAndSwapInt32(&i.v, old, new) +} + +// Store atomically stores the passed value. +func (i *Int32) Store(n int32) { + atomic.StoreInt32(&i.v, n) +} + +// Swap atomically swaps the wrapped int32 and returns the old value. +func (i *Int32) Swap(n int32) int32 { + return atomic.SwapInt32(&i.v, n) +} + +// Int64 is an atomic wrapper around an int64. +type Int64 struct{ v int64 } + +// NewInt64 creates an Int64. +func NewInt64(i int64) *Int64 { + return &Int64{i} +} + +// Load atomically loads the wrapped value. +func (i *Int64) Load() int64 { + return atomic.LoadInt64(&i.v) +} + +// Add atomically adds to the wrapped int64 and returns the new value. +func (i *Int64) Add(n int64) int64 { + return atomic.AddInt64(&i.v, n) +} + +// Sub atomically subtracts from the wrapped int64 and returns the new value. +func (i *Int64) Sub(n int64) int64 { + return atomic.AddInt64(&i.v, -n) +} + +// Inc atomically increments the wrapped int64 and returns the new value. +func (i *Int64) Inc() int64 { + return i.Add(1) +} + +// Dec atomically decrements the wrapped int64 and returns the new value. +func (i *Int64) Dec() int64 { + return i.Sub(1) +} + +// CAS is an atomic compare-and-swap. +func (i *Int64) CAS(old, new int64) bool { + return atomic.CompareAndSwapInt64(&i.v, old, new) +} + +// Store atomically stores the passed value. +func (i *Int64) Store(n int64) { + atomic.StoreInt64(&i.v, n) +} + +// Swap atomically swaps the wrapped int64 and returns the old value. +func (i *Int64) Swap(n int64) int64 { + return atomic.SwapInt64(&i.v, n) +} + +// Uint32 is an atomic wrapper around an uint32. +type Uint32 struct{ v uint32 } + +// NewUint32 creates a Uint32. +func NewUint32(i uint32) *Uint32 { + return &Uint32{i} +} + +// Load atomically loads the wrapped value. +func (i *Uint32) Load() uint32 { + return atomic.LoadUint32(&i.v) +} + +// Add atomically adds to the wrapped uint32 and returns the new value. +func (i *Uint32) Add(n uint32) uint32 { + return atomic.AddUint32(&i.v, n) +} + +// Sub atomically subtracts from the wrapped uint32 and returns the new value. +func (i *Uint32) Sub(n uint32) uint32 { + return atomic.AddUint32(&i.v, ^(n - 1)) +} + +// Inc atomically increments the wrapped uint32 and returns the new value. +func (i *Uint32) Inc() uint32 { + return i.Add(1) +} + +// Dec atomically decrements the wrapped int32 and returns the new value. +func (i *Uint32) Dec() uint32 { + return i.Sub(1) +} + +// CAS is an atomic compare-and-swap. +func (i *Uint32) CAS(old, new uint32) bool { + return atomic.CompareAndSwapUint32(&i.v, old, new) +} + +// Store atomically stores the passed value. +func (i *Uint32) Store(n uint32) { + atomic.StoreUint32(&i.v, n) +} + +// Swap atomically swaps the wrapped uint32 and returns the old value. +func (i *Uint32) Swap(n uint32) uint32 { + return atomic.SwapUint32(&i.v, n) +} + +// Uint64 is an atomic wrapper around a uint64. +type Uint64 struct{ v uint64 } + +// NewUint64 creates a Uint64. +func NewUint64(i uint64) *Uint64 { + return &Uint64{i} +} + +// Load atomically loads the wrapped value. +func (i *Uint64) Load() uint64 { + return atomic.LoadUint64(&i.v) +} + +// Add atomically adds to the wrapped uint64 and returns the new value. +func (i *Uint64) Add(n uint64) uint64 { + return atomic.AddUint64(&i.v, n) +} + +// Sub atomically subtracts from the wrapped uint64 and returns the new value. +func (i *Uint64) Sub(n uint64) uint64 { + return atomic.AddUint64(&i.v, ^(n - 1)) +} + +// Inc atomically increments the wrapped uint64 and returns the new value. +func (i *Uint64) Inc() uint64 { + return i.Add(1) +} + +// Dec atomically decrements the wrapped uint64 and returns the new value. +func (i *Uint64) Dec() uint64 { + return i.Sub(1) +} + +// CAS is an atomic compare-and-swap. +func (i *Uint64) CAS(old, new uint64) bool { + return atomic.CompareAndSwapUint64(&i.v, old, new) +} + +// Store atomically stores the passed value. +func (i *Uint64) Store(n uint64) { + atomic.StoreUint64(&i.v, n) +} + +// Swap atomically swaps the wrapped uint64 and returns the old value. +func (i *Uint64) Swap(n uint64) uint64 { + return atomic.SwapUint64(&i.v, n) +} + +// Bool is an atomic Boolean. +type Bool struct{ v uint32 } + +// NewBool creates a Bool. +func NewBool(initial bool) *Bool { + return &Bool{boolToInt(initial)} +} + +// Load atomically loads the Boolean. +func (b *Bool) Load() bool { + return truthy(atomic.LoadUint32(&b.v)) +} + +// CAS is an atomic compare-and-swap. +func (b *Bool) CAS(old, new bool) bool { + return atomic.CompareAndSwapUint32(&b.v, boolToInt(old), boolToInt(new)) +} + +// Store atomically stores the passed value. +func (b *Bool) Store(new bool) { + atomic.StoreUint32(&b.v, boolToInt(new)) +} + +// Swap sets the given value and returns the previous value. +func (b *Bool) Swap(new bool) bool { + return truthy(atomic.SwapUint32(&b.v, boolToInt(new))) +} + +// Toggle atomically negates the Boolean and returns the previous value. +func (b *Bool) Toggle() bool { + for { + old := b.Load() + if b.CAS(old, !old) { + return old + } + } +} + +func truthy(n uint32) bool { + return n == 1 +} + +func boolToInt(b bool) uint32 { + if b { + return 1 + } + return 0 +} + +// Float64 is an atomic wrapper around float64. +type Float64 struct { + v uint64 +} + +// NewFloat64 creates a Float64. +func NewFloat64(f float64) *Float64 { + return &Float64{math.Float64bits(f)} +} + +// Load atomically loads the wrapped value. +func (f *Float64) Load() float64 { + return math.Float64frombits(atomic.LoadUint64(&f.v)) +} + +// Store atomically stores the passed value. +func (f *Float64) Store(s float64) { + atomic.StoreUint64(&f.v, math.Float64bits(s)) +} + +// Add atomically adds to the wrapped float64 and returns the new value. +func (f *Float64) Add(s float64) float64 { + for { + old := f.Load() + new := old + s + if f.CAS(old, new) { + return new + } + } +} + +// Sub atomically subtracts from the wrapped float64 and returns the new value. +func (f *Float64) Sub(s float64) float64 { + return f.Add(-s) +} + +// CAS is an atomic compare-and-swap. +func (f *Float64) CAS(old, new float64) bool { + return atomic.CompareAndSwapUint64(&f.v, math.Float64bits(old), math.Float64bits(new)) +} + +// Duration is an atomic wrapper around time.Duration +// https://godoc.org/time#Duration +type Duration struct { + v Int64 +} + +// NewDuration creates a Duration. +func NewDuration(d time.Duration) *Duration { + return &Duration{v: *NewInt64(int64(d))} +} + +// Load atomically loads the wrapped value. +func (d *Duration) Load() time.Duration { + return time.Duration(d.v.Load()) +} + +// Store atomically stores the passed value. +func (d *Duration) Store(n time.Duration) { + d.v.Store(int64(n)) +} + +// Add atomically adds to the wrapped time.Duration and returns the new value. +func (d *Duration) Add(n time.Duration) time.Duration { + return time.Duration(d.v.Add(int64(n))) +} + +// Sub atomically subtracts from the wrapped time.Duration and returns the new value. +func (d *Duration) Sub(n time.Duration) time.Duration { + return time.Duration(d.v.Sub(int64(n))) +} + +// Swap atomically swaps the wrapped time.Duration and returns the old value. +func (d *Duration) Swap(n time.Duration) time.Duration { + return time.Duration(d.v.Swap(int64(n))) +} + +// CAS is an atomic compare-and-swap. +func (d *Duration) CAS(old, new time.Duration) bool { + return d.v.CAS(int64(old), int64(new)) +} + +// Value shadows the type of the same name from sync/atomic +// https://godoc.org/sync/atomic#Value +type Value struct{ atomic.Value } diff --git a/vendor/go.uber.org/atomic/error.go b/vendor/go.uber.org/atomic/error.go new file mode 100644 index 0000000000..0489d19bad --- /dev/null +++ b/vendor/go.uber.org/atomic/error.go @@ -0,0 +1,55 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package atomic + +// Error is an atomic type-safe wrapper around Value for errors +type Error struct{ v Value } + +// errorHolder is non-nil holder for error object. +// atomic.Value panics on saving nil object, so err object needs to be +// wrapped with valid object first. +type errorHolder struct{ err error } + +// NewError creates new atomic error object +func NewError(err error) *Error { + e := &Error{} + if err != nil { + e.Store(err) + } + return e +} + +// Load atomically loads the wrapped error +func (e *Error) Load() error { + v := e.v.Load() + if v == nil { + return nil + } + + eh := v.(errorHolder) + return eh.err +} + +// Store atomically stores error. +// NOTE: a holder object is allocated on each Store call. +func (e *Error) Store(err error) { + e.v.Store(errorHolder{err: err}) +} diff --git a/vendor/go.uber.org/atomic/go.mod b/vendor/go.uber.org/atomic/go.mod new file mode 100644 index 0000000000..a935daebb9 --- /dev/null +++ b/vendor/go.uber.org/atomic/go.mod @@ -0,0 +1,10 @@ +module go.uber.org/atomic + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/stretchr/testify v1.3.0 + golang.org/x/lint v0.0.0-20190930215403-16217165b5de + golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c // indirect +) + +go 1.13 diff --git a/vendor/go.uber.org/atomic/go.sum b/vendor/go.uber.org/atomic/go.sum new file mode 100644 index 0000000000..51b2b62afb --- /dev/null +++ b/vendor/go.uber.org/atomic/go.sum @@ -0,0 +1,22 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/go.uber.org/atomic/string.go b/vendor/go.uber.org/atomic/string.go new file mode 100644 index 0000000000..ede8136fac --- /dev/null +++ b/vendor/go.uber.org/atomic/string.go @@ -0,0 +1,49 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package atomic + +// String is an atomic type-safe wrapper around Value for strings. +type String struct{ v Value } + +// NewString creates a String. +func NewString(str string) *String { + s := &String{} + if str != "" { + s.Store(str) + } + return s +} + +// Load atomically loads the wrapped string. +func (s *String) Load() string { + v := s.v.Load() + if v == nil { + return "" + } + return v.(string) +} + +// Store atomically stores the passed string. +// Note: Converting the string to an interface{} to store in the Value +// requires an allocation. +func (s *String) Store(str string) { + s.v.Store(str) +} diff --git a/vendor/go.uber.org/multierr/.codecov.yml b/vendor/go.uber.org/multierr/.codecov.yml new file mode 100644 index 0000000000..6d4d1be7b5 --- /dev/null +++ b/vendor/go.uber.org/multierr/.codecov.yml @@ -0,0 +1,15 @@ +coverage: + range: 80..100 + round: down + precision: 2 + + status: + project: # measuring the overall project coverage + default: # context, you can create multiple ones with custom titles + enabled: yes # must be yes|true to enable this status + target: 100 # specify the target coverage for each commit status + # option: "auto" (must increase from parent commit or pull request base) + # option: "X%" a static target percentage to hit + if_not_found: success # if parent is not found report status as success, error, or failure + if_ci_failed: error # if ci fails report status as success, error, or failure + diff --git a/vendor/go.uber.org/multierr/.gitignore b/vendor/go.uber.org/multierr/.gitignore new file mode 100644 index 0000000000..b9a05e3da0 --- /dev/null +++ b/vendor/go.uber.org/multierr/.gitignore @@ -0,0 +1,4 @@ +/vendor +cover.html +cover.out +/bin diff --git a/vendor/go.uber.org/multierr/.travis.yml b/vendor/go.uber.org/multierr/.travis.yml new file mode 100644 index 0000000000..786c917a39 --- /dev/null +++ b/vendor/go.uber.org/multierr/.travis.yml @@ -0,0 +1,29 @@ +sudo: false +language: go +go_import_path: go.uber.org/multierr + +env: + global: + - GO15VENDOREXPERIMENT=1 + - GO111MODULE=on + +go: + - 1.11.x + - 1.12.x + - 1.13.x + +cache: + directories: + - vendor + +before_install: +- go version + +script: +- | + set -e + make lint + make cover + +after_success: +- bash <(curl -s https://codecov.io/bash) diff --git a/vendor/go.uber.org/multierr/CHANGELOG.md b/vendor/go.uber.org/multierr/CHANGELOG.md new file mode 100644 index 0000000000..3110c5af0b --- /dev/null +++ b/vendor/go.uber.org/multierr/CHANGELOG.md @@ -0,0 +1,54 @@ +Releases +======== + +v1.5.0 (2020-02-24) +=================== + +- Drop library dependency on development-time tooling. + + +v1.4.0 (2019-11-04) +=================== + +- Add `AppendInto` function to more ergonomically build errors inside a + loop. + + +v1.3.0 (2019-10-29) +=================== + +- Switch to Go modules. + + +v1.2.0 (2019-09-26) +=================== + +- Support extracting and matching against wrapped errors with `errors.As` + and `errors.Is`. + + +v1.1.0 (2017-06-30) +=================== + +- Added an `Errors(error) []error` function to extract the underlying list of + errors for a multierr error. + + +v1.0.0 (2017-05-31) +=================== + +No changes since v0.2.0. This release is committing to making no breaking +changes to the current API in the 1.X series. + + +v0.2.0 (2017-04-11) +=================== + +- Repeatedly appending to the same error is now faster due to fewer + allocations. + + +v0.1.0 (2017-31-03) +=================== + +- Initial release diff --git a/vendor/go.uber.org/multierr/LICENSE.txt b/vendor/go.uber.org/multierr/LICENSE.txt new file mode 100644 index 0000000000..858e02475f --- /dev/null +++ b/vendor/go.uber.org/multierr/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2017 Uber Technologies, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/go.uber.org/multierr/Makefile b/vendor/go.uber.org/multierr/Makefile new file mode 100644 index 0000000000..416018237e --- /dev/null +++ b/vendor/go.uber.org/multierr/Makefile @@ -0,0 +1,42 @@ +# Directory to put `go install`ed binaries in. +export GOBIN ?= $(shell pwd)/bin + +GO_FILES := $(shell \ + find . '(' -path '*/.*' -o -path './vendor' ')' -prune \ + -o -name '*.go' -print | cut -b3-) + +.PHONY: build +build: + go build ./... + +.PHONY: test +test: + go test -race ./... + +.PHONY: gofmt +gofmt: + $(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX)) + @gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true + @[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false) + +.PHONY: golint +golint: + @go install golang.org/x/lint/golint + @$(GOBIN)/golint ./... + +.PHONY: staticcheck +staticcheck: + @go install honnef.co/go/tools/cmd/staticcheck + @$(GOBIN)/staticcheck ./... + +.PHONY: lint +lint: gofmt golint staticcheck + +.PHONY: cover +cover: + go test -coverprofile=cover.out -coverpkg=./... -v ./... + go tool cover -html=cover.out -o cover.html + +update-license: + @go install go.uber.org/tools/update-license + @$(GOBIN)/update-license $(GO_FILES) diff --git a/vendor/go.uber.org/multierr/README.md b/vendor/go.uber.org/multierr/README.md new file mode 100644 index 0000000000..751bd65e58 --- /dev/null +++ b/vendor/go.uber.org/multierr/README.md @@ -0,0 +1,23 @@ +# multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] + +`multierr` allows combining one or more Go `error`s together. + +## Installation + + go get -u go.uber.org/multierr + +## Status + +Stable: No breaking changes will be made before 2.0. + +------------------------------------------------------------------------------- + +Released under the [MIT License]. + +[MIT License]: LICENSE.txt +[doc-img]: https://godoc.org/go.uber.org/multierr?status.svg +[doc]: https://godoc.org/go.uber.org/multierr +[ci-img]: https://travis-ci.com/uber-go/multierr.svg?branch=master +[cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg +[ci]: https://travis-ci.com/uber-go/multierr +[cov]: https://codecov.io/gh/uber-go/multierr diff --git a/vendor/go.uber.org/multierr/error.go b/vendor/go.uber.org/multierr/error.go new file mode 100644 index 0000000000..04eb9618c1 --- /dev/null +++ b/vendor/go.uber.org/multierr/error.go @@ -0,0 +1,449 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package multierr allows combining one or more errors together. +// +// Overview +// +// Errors can be combined with the use of the Combine function. +// +// multierr.Combine( +// reader.Close(), +// writer.Close(), +// conn.Close(), +// ) +// +// If only two errors are being combined, the Append function may be used +// instead. +// +// err = multierr.Append(reader.Close(), writer.Close()) +// +// This makes it possible to record resource cleanup failures from deferred +// blocks with the help of named return values. +// +// func sendRequest(req Request) (err error) { +// conn, err := openConnection() +// if err != nil { +// return err +// } +// defer func() { +// err = multierr.Append(err, conn.Close()) +// }() +// // ... +// } +// +// The underlying list of errors for a returned error object may be retrieved +// with the Errors function. +// +// errors := multierr.Errors(err) +// if len(errors) > 0 { +// fmt.Println("The following errors occurred:") +// } +// +// Advanced Usage +// +// Errors returned by Combine and Append MAY implement the following +// interface. +// +// type errorGroup interface { +// // Returns a slice containing the underlying list of errors. +// // +// // This slice MUST NOT be modified by the caller. +// Errors() []error +// } +// +// Note that if you need access to list of errors behind a multierr error, you +// should prefer using the Errors function. That said, if you need cheap +// read-only access to the underlying errors slice, you can attempt to cast +// the error to this interface. You MUST handle the failure case gracefully +// because errors returned by Combine and Append are not guaranteed to +// implement this interface. +// +// var errors []error +// group, ok := err.(errorGroup) +// if ok { +// errors = group.Errors() +// } else { +// errors = []error{err} +// } +package multierr // import "go.uber.org/multierr" + +import ( + "bytes" + "fmt" + "io" + "strings" + "sync" + + "go.uber.org/atomic" +) + +var ( + // Separator for single-line error messages. + _singlelineSeparator = []byte("; ") + + // Prefix for multi-line messages + _multilinePrefix = []byte("the following errors occurred:") + + // Prefix for the first and following lines of an item in a list of + // multi-line error messages. + // + // For example, if a single item is: + // + // foo + // bar + // + // It will become, + // + // - foo + // bar + _multilineSeparator = []byte("\n - ") + _multilineIndent = []byte(" ") +) + +// _bufferPool is a pool of bytes.Buffers. +var _bufferPool = sync.Pool{ + New: func() interface{} { + return &bytes.Buffer{} + }, +} + +type errorGroup interface { + Errors() []error +} + +// Errors returns a slice containing zero or more errors that the supplied +// error is composed of. If the error is nil, a nil slice is returned. +// +// err := multierr.Append(r.Close(), w.Close()) +// errors := multierr.Errors(err) +// +// If the error is not composed of other errors, the returned slice contains +// just the error that was passed in. +// +// Callers of this function are free to modify the returned slice. +func Errors(err error) []error { + if err == nil { + return nil + } + + // Note that we're casting to multiError, not errorGroup. Our contract is + // that returned errors MAY implement errorGroup. Errors, however, only + // has special behavior for multierr-specific error objects. + // + // This behavior can be expanded in the future but I think it's prudent to + // start with as little as possible in terms of contract and possibility + // of misuse. + eg, ok := err.(*multiError) + if !ok { + return []error{err} + } + + errors := eg.Errors() + result := make([]error, len(errors)) + copy(result, errors) + return result +} + +// multiError is an error that holds one or more errors. +// +// An instance of this is guaranteed to be non-empty and flattened. That is, +// none of the errors inside multiError are other multiErrors. +// +// multiError formats to a semi-colon delimited list of error messages with +// %v and with a more readable multi-line format with %+v. +type multiError struct { + copyNeeded atomic.Bool + errors []error +} + +var _ errorGroup = (*multiError)(nil) + +// Errors returns the list of underlying errors. +// +// This slice MUST NOT be modified. +func (merr *multiError) Errors() []error { + if merr == nil { + return nil + } + return merr.errors +} + +func (merr *multiError) Error() string { + if merr == nil { + return "" + } + + buff := _bufferPool.Get().(*bytes.Buffer) + buff.Reset() + + merr.writeSingleline(buff) + + result := buff.String() + _bufferPool.Put(buff) + return result +} + +func (merr *multiError) Format(f fmt.State, c rune) { + if c == 'v' && f.Flag('+') { + merr.writeMultiline(f) + } else { + merr.writeSingleline(f) + } +} + +func (merr *multiError) writeSingleline(w io.Writer) { + first := true + for _, item := range merr.errors { + if first { + first = false + } else { + w.Write(_singlelineSeparator) + } + io.WriteString(w, item.Error()) + } +} + +func (merr *multiError) writeMultiline(w io.Writer) { + w.Write(_multilinePrefix) + for _, item := range merr.errors { + w.Write(_multilineSeparator) + writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item)) + } +} + +// Writes s to the writer with the given prefix added before each line after +// the first. +func writePrefixLine(w io.Writer, prefix []byte, s string) { + first := true + for len(s) > 0 { + if first { + first = false + } else { + w.Write(prefix) + } + + idx := strings.IndexByte(s, '\n') + if idx < 0 { + idx = len(s) - 1 + } + + io.WriteString(w, s[:idx+1]) + s = s[idx+1:] + } +} + +type inspectResult struct { + // Number of top-level non-nil errors + Count int + + // Total number of errors including multiErrors + Capacity int + + // Index of the first non-nil error in the list. Value is meaningless if + // Count is zero. + FirstErrorIdx int + + // Whether the list contains at least one multiError + ContainsMultiError bool +} + +// Inspects the given slice of errors so that we can efficiently allocate +// space for it. +func inspect(errors []error) (res inspectResult) { + first := true + for i, err := range errors { + if err == nil { + continue + } + + res.Count++ + if first { + first = false + res.FirstErrorIdx = i + } + + if merr, ok := err.(*multiError); ok { + res.Capacity += len(merr.errors) + res.ContainsMultiError = true + } else { + res.Capacity++ + } + } + return +} + +// fromSlice converts the given list of errors into a single error. +func fromSlice(errors []error) error { + res := inspect(errors) + switch res.Count { + case 0: + return nil + case 1: + // only one non-nil entry + return errors[res.FirstErrorIdx] + case len(errors): + if !res.ContainsMultiError { + // already flat + return &multiError{errors: errors} + } + } + + nonNilErrs := make([]error, 0, res.Capacity) + for _, err := range errors[res.FirstErrorIdx:] { + if err == nil { + continue + } + + if nested, ok := err.(*multiError); ok { + nonNilErrs = append(nonNilErrs, nested.errors...) + } else { + nonNilErrs = append(nonNilErrs, err) + } + } + + return &multiError{errors: nonNilErrs} +} + +// Combine combines the passed errors into a single error. +// +// If zero arguments were passed or if all items are nil, a nil error is +// returned. +// +// Combine(nil, nil) // == nil +// +// If only a single error was passed, it is returned as-is. +// +// Combine(err) // == err +// +// Combine skips over nil arguments so this function may be used to combine +// together errors from operations that fail independently of each other. +// +// multierr.Combine( +// reader.Close(), +// writer.Close(), +// pipe.Close(), +// ) +// +// If any of the passed errors is a multierr error, it will be flattened along +// with the other errors. +// +// multierr.Combine(multierr.Combine(err1, err2), err3) +// // is the same as +// multierr.Combine(err1, err2, err3) +// +// The returned error formats into a readable multi-line error message if +// formatted with %+v. +// +// fmt.Sprintf("%+v", multierr.Combine(err1, err2)) +func Combine(errors ...error) error { + return fromSlice(errors) +} + +// Append appends the given errors together. Either value may be nil. +// +// This function is a specialization of Combine for the common case where +// there are only two errors. +// +// err = multierr.Append(reader.Close(), writer.Close()) +// +// The following pattern may also be used to record failure of deferred +// operations without losing information about the original error. +// +// func doSomething(..) (err error) { +// f := acquireResource() +// defer func() { +// err = multierr.Append(err, f.Close()) +// }() +func Append(left error, right error) error { + switch { + case left == nil: + return right + case right == nil: + return left + } + + if _, ok := right.(*multiError); !ok { + if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) { + // Common case where the error on the left is constantly being + // appended to. + errs := append(l.errors, right) + return &multiError{errors: errs} + } else if !ok { + // Both errors are single errors. + return &multiError{errors: []error{left, right}} + } + } + + // Either right or both, left and right, are multiErrors. Rely on usual + // expensive logic. + errors := [2]error{left, right} + return fromSlice(errors[0:]) +} + +// AppendInto appends an error into the destination of an error pointer and +// returns whether the error being appended was non-nil. +// +// var err error +// multierr.AppendInto(&err, r.Close()) +// multierr.AppendInto(&err, w.Close()) +// +// The above is equivalent to, +// +// err := multierr.Append(r.Close(), w.Close()) +// +// As AppendInto reports whether the provided error was non-nil, it may be +// used to build a multierr error in a loop more ergonomically. For example: +// +// var err error +// for line := range lines { +// var item Item +// if multierr.AppendInto(&err, parse(line, &item)) { +// continue +// } +// items = append(items, item) +// } +// +// Compare this with a verison that relies solely on Append: +// +// var err error +// for line := range lines { +// var item Item +// if parseErr := parse(line, &item); parseErr != nil { +// err = multierr.Append(err, parseErr) +// continue +// } +// items = append(items, item) +// } +func AppendInto(into *error, err error) (errored bool) { + if into == nil { + // We panic if 'into' is nil. This is not documented above + // because suggesting that the pointer must be non-nil may + // confuse users into thinking that the error that it points + // to must be non-nil. + panic("misuse of multierr.AppendInto: into pointer must not be nil") + } + + if err == nil { + return false + } + *into = Append(*into, err) + return true +} diff --git a/vendor/go.uber.org/multierr/glide.yaml b/vendor/go.uber.org/multierr/glide.yaml new file mode 100644 index 0000000000..6ef084ec24 --- /dev/null +++ b/vendor/go.uber.org/multierr/glide.yaml @@ -0,0 +1,8 @@ +package: go.uber.org/multierr +import: +- package: go.uber.org/atomic + version: ^1 +testImport: +- package: github.com/stretchr/testify + subpackages: + - assert diff --git a/vendor/go.uber.org/multierr/go.mod b/vendor/go.uber.org/multierr/go.mod new file mode 100644 index 0000000000..58d5f90bbd --- /dev/null +++ b/vendor/go.uber.org/multierr/go.mod @@ -0,0 +1,12 @@ +module go.uber.org/multierr + +go 1.12 + +require ( + github.com/stretchr/testify v1.3.0 + go.uber.org/atomic v1.6.0 + go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee + golang.org/x/lint v0.0.0-20190930215403-16217165b5de + golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 // indirect + honnef.co/go/tools v0.0.1-2019.2.3 +) diff --git a/vendor/go.uber.org/multierr/go.sum b/vendor/go.uber.org/multierr/go.sum new file mode 100644 index 0000000000..557fbba28f --- /dev/null +++ b/vendor/go.uber.org/multierr/go.sum @@ -0,0 +1,45 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/go.uber.org/multierr/go113.go b/vendor/go.uber.org/multierr/go113.go new file mode 100644 index 0000000000..264b0eac0d --- /dev/null +++ b/vendor/go.uber.org/multierr/go113.go @@ -0,0 +1,52 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// +build go1.13 + +package multierr + +import "errors" + +// As attempts to find the first error in the error list that matches the type +// of the value that target points to. +// +// This function allows errors.As to traverse the values stored on the +// multierr error. +func (merr *multiError) As(target interface{}) bool { + for _, err := range merr.Errors() { + if errors.As(err, target) { + return true + } + } + return false +} + +// Is attempts to match the provided error against errors in the error list. +// +// This function allows errors.Is to traverse the values stored on the +// multierr error. +func (merr *multiError) Is(target error) bool { + for _, err := range merr.Errors() { + if errors.Is(err, target) { + return true + } + } + return false +} diff --git a/vendor/go.uber.org/zap/.codecov.yml b/vendor/go.uber.org/zap/.codecov.yml new file mode 100644 index 0000000000..8e5ca7d3e2 --- /dev/null +++ b/vendor/go.uber.org/zap/.codecov.yml @@ -0,0 +1,17 @@ +coverage: + range: 80..100 + round: down + precision: 2 + + status: + project: # measuring the overall project coverage + default: # context, you can create multiple ones with custom titles + enabled: yes # must be yes|true to enable this status + target: 95% # specify the target coverage for each commit status + # option: "auto" (must increase from parent commit or pull request base) + # option: "X%" a static target percentage to hit + if_not_found: success # if parent is not found report status as success, error, or failure + if_ci_failed: error # if ci fails report status as success, error, or failure +ignore: + - internal/readme/readme.go + diff --git a/vendor/go.uber.org/zap/.gitignore b/vendor/go.uber.org/zap/.gitignore new file mode 100644 index 0000000000..da9d9d00b4 --- /dev/null +++ b/vendor/go.uber.org/zap/.gitignore @@ -0,0 +1,32 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test +vendor + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +*.pprof +*.out +*.log + +/bin +cover.out +cover.html diff --git a/vendor/go.uber.org/zap/.readme.tmpl b/vendor/go.uber.org/zap/.readme.tmpl new file mode 100644 index 0000000000..3154a1e64c --- /dev/null +++ b/vendor/go.uber.org/zap/.readme.tmpl @@ -0,0 +1,109 @@ +# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] + +Blazing fast, structured, leveled logging in Go. + +## Installation + +`go get -u go.uber.org/zap` + +Note that zap only supports the two most recent minor versions of Go. + +## Quick Start + +In contexts where performance is nice, but not critical, use the +`SugaredLogger`. It's 4-10x faster than other structured logging +packages and includes both structured and `printf`-style APIs. + +```go +logger, _ := zap.NewProduction() +defer logger.Sync() // flushes buffer, if any +sugar := logger.Sugar() +sugar.Infow("failed to fetch URL", + // Structured context as loosely typed key-value pairs. + "url", url, + "attempt", 3, + "backoff", time.Second, +) +sugar.Infof("Failed to fetch URL: %s", url) +``` + +When performance and type safety are critical, use the `Logger`. It's even +faster than the `SugaredLogger` and allocates far less, but it only supports +structured logging. + +```go +logger, _ := zap.NewProduction() +defer logger.Sync() +logger.Info("failed to fetch URL", + // Structured context as strongly typed Field values. + zap.String("url", url), + zap.Int("attempt", 3), + zap.Duration("backoff", time.Second), +) +``` + +See the [documentation][doc] and [FAQ](FAQ.md) for more details. + +## Performance + +For applications that log in the hot path, reflection-based serialization and +string formatting are prohibitively expensive — they're CPU-intensive +and make many small allocations. Put differently, using `encoding/json` and +`fmt.Fprintf` to log tons of `interface{}`s makes your application slow. + +Zap takes a different approach. It includes a reflection-free, zero-allocation +JSON encoder, and the base `Logger` strives to avoid serialization overhead +and allocations wherever possible. By building the high-level `SugaredLogger` +on that foundation, zap lets users *choose* when they need to count every +allocation and when they'd prefer a more familiar, loosely typed API. + +As measured by its own [benchmarking suite][], not only is zap more performant +than comparable structured logging packages — it's also faster than the +standard library. Like all benchmarks, take these with a grain of salt.[1](#footnote-versions) + +Log a message and 10 fields: + +{{.BenchmarkAddingFields}} + +Log a message with a logger that already has 10 fields of context: + +{{.BenchmarkAccumulatedContext}} + +Log a static string, without any context or `printf`-style templating: + +{{.BenchmarkWithoutFields}} + +## Development Status: Stable + +All APIs are finalized, and no breaking changes will be made in the 1.x series +of releases. Users of semver-aware dependency management systems should pin +zap to `^1`. + +## Contributing + +We encourage and support an active, healthy community of contributors — +including you! Details are in the [contribution guide](CONTRIBUTING.md) and +the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on +issues and pull requests, but you can also report any negative conduct to +oss-conduct@uber.com. That email list is a private, safe space; even the zap +maintainers don't have access, so don't hesitate to hold us to a high +standard. + +
+ +Released under the [MIT License](LICENSE.txt). + +1 In particular, keep in mind that we may be +benchmarking against slightly older versions of other packages. Versions are +pinned in zap's [glide.lock][] file. [↩](#anchor-versions) + +[doc-img]: https://godoc.org/go.uber.org/zap?status.svg +[doc]: https://godoc.org/go.uber.org/zap +[ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master +[ci]: https://travis-ci.com/uber-go/zap +[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg +[cov]: https://codecov.io/gh/uber-go/zap +[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks +[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock + diff --git a/vendor/go.uber.org/zap/.travis.yml b/vendor/go.uber.org/zap/.travis.yml new file mode 100644 index 0000000000..cfdc69f413 --- /dev/null +++ b/vendor/go.uber.org/zap/.travis.yml @@ -0,0 +1,23 @@ +language: go +sudo: false + +go_import_path: go.uber.org/zap +env: + global: + - TEST_TIMEOUT_SCALE=10 + - GO111MODULE=on + +matrix: + include: + - go: 1.13.x + - go: 1.14.x + env: LINT=1 + +script: + - test -z "$LINT" || make lint + - make test + - make bench + +after_success: + - make cover + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/go.uber.org/zap/CHANGELOG.md b/vendor/go.uber.org/zap/CHANGELOG.md new file mode 100644 index 0000000000..aeff90e4ea --- /dev/null +++ b/vendor/go.uber.org/zap/CHANGELOG.md @@ -0,0 +1,401 @@ +# Changelog + +## 1.15.0 (23 Apr 2020) + +Bugfixes: +* [#804][]: Fix handling of `Time` values out of `UnixNano` range. +* [#812][]: Fix `IncreaseLevel` being reset after a call to `With`. + +Enhancements: +* [#806][]: Add `WithCaller` option to supersede the `AddCaller` option. This + allows disabling annotation of log entries with caller information if + previously enabled with `AddCaller`. +* [#813][]: Deprecate `NewSampler` constructor in favor of + `NewSamplerWithOptions` which supports a `SamplerHook` option. This option + adds support for monitoring sampling decisions through a hook. + +Thanks to @danielbprice for their contributions to this release. + +## 1.14.1 (14 Mar 2020) + +Bugfixes: +* [#791][]: Fix panic on attempting to build a logger with an invalid Config. +* [#795][]: Vendoring Zap with `go mod vendor` no longer includes Zap's + development-time dependencies. +* [#799][]: Fix issue introduced in 1.14.0 that caused invalid JSON output to + be generated for arrays of `time.Time` objects when using string-based time + formats. + +Thanks to @YashishDua for their contributions to this release. + +## 1.14.0 (20 Feb 2020) + +Enhancements: +* [#771][]: Optimize calls for disabled log levels. +* [#773][]: Add millisecond duration encoder. +* [#775][]: Add option to increase the level of a logger. +* [#786][]: Optimize time formatters using `Time.AppendFormat` where possible. + +Thanks to @caibirdme for their contributions to this release. + +## 1.13.0 (13 Nov 2019) + +Enhancements: +* [#758][]: Add `Intp`, `Stringp`, and other similar `*p` field constructors + to log pointers to primitives with support for `nil` values. + +Thanks to @jbizzle for their contributions to this release. + +## 1.12.0 (29 Oct 2019) + +Enhancements: +* [#751][]: Migrate to Go modules. + +## 1.11.0 (21 Oct 2019) + +Enhancements: +* [#725][]: Add `zapcore.OmitKey` to omit keys in an `EncoderConfig`. +* [#736][]: Add `RFC3339` and `RFC3339Nano` time encoders. + +Thanks to @juicemia, @uhthomas for their contributions to this release. + +## 1.10.0 (29 Apr 2019) + +Bugfixes: +* [#657][]: Fix `MapObjectEncoder.AppendByteString` not adding value as a + string. +* [#706][]: Fix incorrect call depth to determine caller in Go 1.12. + +Enhancements: +* [#610][]: Add `zaptest.WrapOptions` to wrap `zap.Option` for creating test + loggers. +* [#675][]: Don't panic when encoding a String field. +* [#704][]: Disable HTML escaping for JSON objects encoded using the + reflect-based encoder. + +Thanks to @iaroslav-ciupin, @lelenanam, @joa, @NWilson for their contributions +to this release. + +## v1.9.1 (06 Aug 2018) + +Bugfixes: + +* [#614][]: MapObjectEncoder should not ignore empty slices. + +## v1.9.0 (19 Jul 2018) + +Enhancements: +* [#602][]: Reduce number of allocations when logging with reflection. +* [#572][], [#606][]: Expose a registry for third-party logging sinks. + +Thanks to @nfarah86, @AlekSi, @JeanMertz, @philippgille, @etsangsplk, and +@dimroc for their contributions to this release. + +## v1.8.0 (13 Apr 2018) + +Enhancements: +* [#508][]: Make log level configurable when redirecting the standard + library's logger. +* [#518][]: Add a logger that writes to a `*testing.TB`. +* [#577][]: Add a top-level alias for `zapcore.Field` to clean up GoDoc. + +Bugfixes: +* [#574][]: Add a missing import comment to `go.uber.org/zap/buffer`. + +Thanks to @DiSiqueira and @djui for their contributions to this release. + +## v1.7.1 (25 Sep 2017) + +Bugfixes: +* [#504][]: Store strings when using AddByteString with the map encoder. + +## v1.7.0 (21 Sep 2017) + +Enhancements: + +* [#487][]: Add `NewStdLogAt`, which extends `NewStdLog` by allowing the user + to specify the level of the logged messages. + +## v1.6.0 (30 Aug 2017) + +Enhancements: + +* [#491][]: Omit zap stack frames from stacktraces. +* [#490][]: Add a `ContextMap` method to observer logs for simpler + field validation in tests. + +## v1.5.0 (22 Jul 2017) + +Enhancements: + +* [#460][] and [#470][]: Support errors produced by `go.uber.org/multierr`. +* [#465][]: Support user-supplied encoders for logger names. + +Bugfixes: + +* [#477][]: Fix a bug that incorrectly truncated deep stacktraces. + +Thanks to @richard-tunein and @pavius for their contributions to this release. + +## v1.4.1 (08 Jun 2017) + +This release fixes two bugs. + +Bugfixes: + +* [#435][]: Support a variety of case conventions when unmarshaling levels. +* [#444][]: Fix a panic in the observer. + +## v1.4.0 (12 May 2017) + +This release adds a few small features and is fully backward-compatible. + +Enhancements: + +* [#424][]: Add a `LineEnding` field to `EncoderConfig`, allowing users to + override the Unix-style default. +* [#425][]: Preserve time zones when logging times. +* [#431][]: Make `zap.AtomicLevel` implement `fmt.Stringer`, which makes a + variety of operations a bit simpler. + +## v1.3.0 (25 Apr 2017) + +This release adds an enhancement to zap's testing helpers as well as the +ability to marshal an AtomicLevel. It is fully backward-compatible. + +Enhancements: + +* [#415][]: Add a substring-filtering helper to zap's observer. This is + particularly useful when testing the `SugaredLogger`. +* [#416][]: Make `AtomicLevel` implement `encoding.TextMarshaler`. + +## v1.2.0 (13 Apr 2017) + +This release adds a gRPC compatibility wrapper. It is fully backward-compatible. + +Enhancements: + +* [#402][]: Add a `zapgrpc` package that wraps zap's Logger and implements + `grpclog.Logger`. + +## v1.1.0 (31 Mar 2017) + +This release fixes two bugs and adds some enhancements to zap's testing helpers. +It is fully backward-compatible. + +Bugfixes: + +* [#385][]: Fix caller path trimming on Windows. +* [#396][]: Fix a panic when attempting to use non-existent directories with + zap's configuration struct. + +Enhancements: + +* [#386][]: Add filtering helpers to zaptest's observing logger. + +Thanks to @moitias for contributing to this release. + +## v1.0.0 (14 Mar 2017) + +This is zap's first stable release. All exported APIs are now final, and no +further breaking changes will be made in the 1.x release series. Anyone using a +semver-aware dependency manager should now pin to `^1`. + +Breaking changes: + +* [#366][]: Add byte-oriented APIs to encoders to log UTF-8 encoded text without + casting from `[]byte` to `string`. +* [#364][]: To support buffering outputs, add `Sync` methods to `zapcore.Core`, + `zap.Logger`, and `zap.SugaredLogger`. +* [#371][]: Rename the `testutils` package to `zaptest`, which is less likely to + clash with other testing helpers. + +Bugfixes: + +* [#362][]: Make the ISO8601 time formatters fixed-width, which is friendlier + for tab-separated console output. +* [#369][]: Remove the automatic locks in `zapcore.NewCore`, which allows zap to + work with concurrency-safe `WriteSyncer` implementations. +* [#347][]: Stop reporting errors when trying to `fsync` standard out on Linux + systems. +* [#373][]: Report the correct caller from zap's standard library + interoperability wrappers. + +Enhancements: + +* [#348][]: Add a registry allowing third-party encodings to work with zap's + built-in `Config`. +* [#327][]: Make the representation of logger callers configurable (like times, + levels, and durations). +* [#376][]: Allow third-party encoders to use their own buffer pools, which + removes the last performance advantage that zap's encoders have over plugins. +* [#346][]: Add `CombineWriteSyncers`, a convenience function to tee multiple + `WriteSyncer`s and lock the result. +* [#365][]: Make zap's stacktraces compatible with mid-stack inlining (coming in + Go 1.9). +* [#372][]: Export zap's observing logger as `zaptest/observer`. This makes it + easier for particularly punctilious users to unit test their application's + logging. + +Thanks to @suyash, @htrendev, @flisky, @Ulexus, and @skipor for their +contributions to this release. + +## v1.0.0-rc.3 (7 Mar 2017) + +This is the third release candidate for zap's stable release. There are no +breaking changes. + +Bugfixes: + +* [#339][]: Byte slices passed to `zap.Any` are now correctly treated as binary blobs + rather than `[]uint8`. + +Enhancements: + +* [#307][]: Users can opt into colored output for log levels. +* [#353][]: In addition to hijacking the output of the standard library's + package-global logging functions, users can now construct a zap-backed + `log.Logger` instance. +* [#311][]: Frames from common runtime functions and some of zap's internal + machinery are now omitted from stacktraces. + +Thanks to @ansel1 and @suyash for their contributions to this release. + +## v1.0.0-rc.2 (21 Feb 2017) + +This is the second release candidate for zap's stable release. It includes two +breaking changes. + +Breaking changes: + +* [#316][]: Zap's global loggers are now fully concurrency-safe + (previously, users had to ensure that `ReplaceGlobals` was called before the + loggers were in use). However, they must now be accessed via the `L()` and + `S()` functions. Users can update their projects with + + ``` + gofmt -r "zap.L -> zap.L()" -w . + gofmt -r "zap.S -> zap.S()" -w . + ``` +* [#309][] and [#317][]: RC1 was mistakenly shipped with invalid + JSON and YAML struct tags on all config structs. This release fixes the tags + and adds static analysis to prevent similar bugs in the future. + +Bugfixes: + +* [#321][]: Redirecting the standard library's `log` output now + correctly reports the logger's caller. + +Enhancements: + +* [#325][] and [#333][]: Zap now transparently supports non-standard, rich + errors like those produced by `github.com/pkg/errors`. +* [#326][]: Though `New(nil)` continues to return a no-op logger, `NewNop()` is + now preferred. Users can update their projects with `gofmt -r 'zap.New(nil) -> + zap.NewNop()' -w .`. +* [#300][]: Incorrectly importing zap as `github.com/uber-go/zap` now returns a + more informative error. + +Thanks to @skipor and @chapsuk for their contributions to this release. + +## v1.0.0-rc.1 (14 Feb 2017) + +This is the first release candidate for zap's stable release. There are multiple +breaking changes and improvements from the pre-release version. Most notably: + +* **Zap's import path is now "go.uber.org/zap"** — all users will + need to update their code. +* User-facing types and functions remain in the `zap` package. Code relevant + largely to extension authors is now in the `zapcore` package. +* The `zapcore.Core` type makes it easy for third-party packages to use zap's + internals but provide a different user-facing API. +* `Logger` is now a concrete type instead of an interface. +* A less verbose (though slower) logging API is included by default. +* Package-global loggers `L` and `S` are included. +* A human-friendly console encoder is included. +* A declarative config struct allows common logger configurations to be managed + as configuration instead of code. +* Sampling is more accurate, and doesn't depend on the standard library's shared + timer heap. + +## v0.1.0-beta.1 (6 Feb 2017) + +This is a minor version, tagged to allow users to pin to the pre-1.0 APIs and +upgrade at their leisure. Since this is the first tagged release, there are no +backward compatibility concerns and all functionality is new. + +Early zap adopters should pin to the 0.1.x minor version until they're ready to +upgrade to the upcoming stable release. + +[#316]: https://github.com/uber-go/zap/pull/316 +[#309]: https://github.com/uber-go/zap/pull/309 +[#317]: https://github.com/uber-go/zap/pull/317 +[#321]: https://github.com/uber-go/zap/pull/321 +[#325]: https://github.com/uber-go/zap/pull/325 +[#333]: https://github.com/uber-go/zap/pull/333 +[#326]: https://github.com/uber-go/zap/pull/326 +[#300]: https://github.com/uber-go/zap/pull/300 +[#339]: https://github.com/uber-go/zap/pull/339 +[#307]: https://github.com/uber-go/zap/pull/307 +[#353]: https://github.com/uber-go/zap/pull/353 +[#311]: https://github.com/uber-go/zap/pull/311 +[#366]: https://github.com/uber-go/zap/pull/366 +[#364]: https://github.com/uber-go/zap/pull/364 +[#371]: https://github.com/uber-go/zap/pull/371 +[#362]: https://github.com/uber-go/zap/pull/362 +[#369]: https://github.com/uber-go/zap/pull/369 +[#347]: https://github.com/uber-go/zap/pull/347 +[#373]: https://github.com/uber-go/zap/pull/373 +[#348]: https://github.com/uber-go/zap/pull/348 +[#327]: https://github.com/uber-go/zap/pull/327 +[#376]: https://github.com/uber-go/zap/pull/376 +[#346]: https://github.com/uber-go/zap/pull/346 +[#365]: https://github.com/uber-go/zap/pull/365 +[#372]: https://github.com/uber-go/zap/pull/372 +[#385]: https://github.com/uber-go/zap/pull/385 +[#396]: https://github.com/uber-go/zap/pull/396 +[#386]: https://github.com/uber-go/zap/pull/386 +[#402]: https://github.com/uber-go/zap/pull/402 +[#415]: https://github.com/uber-go/zap/pull/415 +[#416]: https://github.com/uber-go/zap/pull/416 +[#424]: https://github.com/uber-go/zap/pull/424 +[#425]: https://github.com/uber-go/zap/pull/425 +[#431]: https://github.com/uber-go/zap/pull/431 +[#435]: https://github.com/uber-go/zap/pull/435 +[#444]: https://github.com/uber-go/zap/pull/444 +[#477]: https://github.com/uber-go/zap/pull/477 +[#465]: https://github.com/uber-go/zap/pull/465 +[#460]: https://github.com/uber-go/zap/pull/460 +[#470]: https://github.com/uber-go/zap/pull/470 +[#487]: https://github.com/uber-go/zap/pull/487 +[#490]: https://github.com/uber-go/zap/pull/490 +[#491]: https://github.com/uber-go/zap/pull/491 +[#504]: https://github.com/uber-go/zap/pull/504 +[#508]: https://github.com/uber-go/zap/pull/508 +[#518]: https://github.com/uber-go/zap/pull/518 +[#577]: https://github.com/uber-go/zap/pull/577 +[#574]: https://github.com/uber-go/zap/pull/574 +[#602]: https://github.com/uber-go/zap/pull/602 +[#572]: https://github.com/uber-go/zap/pull/572 +[#606]: https://github.com/uber-go/zap/pull/606 +[#614]: https://github.com/uber-go/zap/pull/614 +[#657]: https://github.com/uber-go/zap/pull/657 +[#706]: https://github.com/uber-go/zap/pull/706 +[#610]: https://github.com/uber-go/zap/pull/610 +[#675]: https://github.com/uber-go/zap/pull/675 +[#704]: https://github.com/uber-go/zap/pull/704 +[#725]: https://github.com/uber-go/zap/pull/725 +[#736]: https://github.com/uber-go/zap/pull/736 +[#751]: https://github.com/uber-go/zap/pull/751 +[#758]: https://github.com/uber-go/zap/pull/758 +[#771]: https://github.com/uber-go/zap/pull/771 +[#773]: https://github.com/uber-go/zap/pull/773 +[#775]: https://github.com/uber-go/zap/pull/775 +[#786]: https://github.com/uber-go/zap/pull/786 +[#791]: https://github.com/uber-go/zap/pull/791 +[#795]: https://github.com/uber-go/zap/pull/795 +[#799]: https://github.com/uber-go/zap/pull/799 +[#804]: https://github.com/uber-go/zap/pull/804 +[#812]: https://github.com/uber-go/zap/pull/812 +[#806]: https://github.com/uber-go/zap/pull/806 +[#813]: https://github.com/uber-go/zap/pull/813 diff --git a/vendor/go.uber.org/zap/CODE_OF_CONDUCT.md b/vendor/go.uber.org/zap/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..e327d9aa5c --- /dev/null +++ b/vendor/go.uber.org/zap/CODE_OF_CONDUCT.md @@ -0,0 +1,75 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, +body size, disability, ethnicity, gender identity and expression, level of +experience, nationality, personal appearance, race, religion, or sexual +identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an +appointed representative at an online or offline event. Representation of a +project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at oss-conduct@uber.com. The project +team will review and investigate all complaints, and will respond in a way +that it deems appropriate to the circumstances. The project team is obligated +to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +[http://contributor-covenant.org/version/1/4][version]. + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/go.uber.org/zap/CONTRIBUTING.md b/vendor/go.uber.org/zap/CONTRIBUTING.md new file mode 100644 index 0000000000..9454bbaf02 --- /dev/null +++ b/vendor/go.uber.org/zap/CONTRIBUTING.md @@ -0,0 +1,81 @@ +# Contributing + +We'd love your help making zap the very best structured logging library in Go! + +If you'd like to add new exported APIs, please [open an issue][open-issue] +describing your proposal — discussing API changes ahead of time makes +pull request review much smoother. In your issue, pull request, and any other +communications, please remember to treat your fellow contributors with +respect! We take our [code of conduct](CODE_OF_CONDUCT.md) seriously. + +Note that you'll need to sign [Uber's Contributor License Agreement][cla] +before we can accept any of your contributions. If necessary, a bot will remind +you to accept the CLA when you open your pull request. + +## Setup + +[Fork][fork], then clone the repository: + +``` +mkdir -p $GOPATH/src/go.uber.org +cd $GOPATH/src/go.uber.org +git clone git@github.com:your_github_username/zap.git +cd zap +git remote add upstream https://github.com/uber-go/zap.git +git fetch upstream +``` + +Install zap's dependencies: + +``` +make dependencies +``` + +Make sure that the tests and the linters pass: + +``` +make test +make lint +``` + +If you're not using the minor version of Go specified in the Makefile's +`LINTABLE_MINOR_VERSIONS` variable, `make lint` doesn't do anything. This is +fine, but it means that you'll only discover lint failures after you open your +pull request. + +## Making Changes + +Start by creating a new branch for your changes: + +``` +cd $GOPATH/src/go.uber.org/zap +git checkout master +git fetch upstream +git rebase upstream/master +git checkout -b cool_new_feature +``` + +Make your changes, then ensure that `make lint` and `make test` still pass. If +you're satisfied with your changes, push them to your fork. + +``` +git push origin cool_new_feature +``` + +Then use the GitHub UI to open a pull request. + +At this point, you're waiting on us to review your changes. We *try* to respond +to issues and pull requests within a few business days, and we may suggest some +improvements or alternatives. Once your changes are approved, one of the +project maintainers will merge them. + +We're much more likely to approve your changes if you: + +* Add tests for new functionality. +* Write a [good commit message][commit-message]. +* Maintain backward compatibility. + +[fork]: https://github.com/uber-go/zap/fork +[open-issue]: https://github.com/uber-go/zap/issues/new +[cla]: https://cla-assistant.io/uber-go/zap +[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html diff --git a/vendor/go.uber.org/zap/FAQ.md b/vendor/go.uber.org/zap/FAQ.md new file mode 100644 index 0000000000..4256d35c76 --- /dev/null +++ b/vendor/go.uber.org/zap/FAQ.md @@ -0,0 +1,155 @@ +# Frequently Asked Questions + +## Design + +### Why spend so much effort on logger performance? + +Of course, most applications won't notice the impact of a slow logger: they +already take tens or hundreds of milliseconds for each operation, so an extra +millisecond doesn't matter. + +On the other hand, why *not* make structured logging fast? The `SugaredLogger` +isn't any harder to use than other logging packages, and the `Logger` makes +structured logging possible in performance-sensitive contexts. Across a fleet +of Go microservices, making each application even slightly more efficient adds +up quickly. + +### Why aren't `Logger` and `SugaredLogger` interfaces? + +Unlike the familiar `io.Writer` and `http.Handler`, `Logger` and +`SugaredLogger` interfaces would include *many* methods. As [Rob Pike points +out][go-proverbs], "The bigger the interface, the weaker the abstraction." +Interfaces are also rigid — *any* change requires releasing a new major +version, since it breaks all third-party implementations. + +Making the `Logger` and `SugaredLogger` concrete types doesn't sacrifice much +abstraction, and it lets us add methods without introducing breaking changes. +Your applications should define and depend upon an interface that includes +just the methods you use. + +### Why sample application logs? + +Applications often experience runs of errors, either because of a bug or +because of a misbehaving user. Logging errors is usually a good idea, but it +can easily make this bad situation worse: not only is your application coping +with a flood of errors, it's also spending extra CPU cycles and I/O logging +those errors. Since writes are typically serialized, logging limits throughput +when you need it most. + +Sampling fixes this problem by dropping repetitive log entries. Under normal +conditions, your application writes out every entry. When similar entries are +logged hundreds or thousands of times each second, though, zap begins dropping +duplicates to preserve throughput. + +### Why do the structured logging APIs take a message in addition to fields? + +Subjectively, we find it helpful to accompany structured context with a brief +description. This isn't critical during development, but it makes debugging +and operating unfamiliar systems much easier. + +More concretely, zap's sampling algorithm uses the message to identify +duplicate entries. In our experience, this is a practical middle ground +between random sampling (which often drops the exact entry that you need while +debugging) and hashing the complete entry (which is prohibitively expensive). + +### Why include package-global loggers? + +Since so many other logging packages include a global logger, many +applications aren't designed to accept loggers as explicit parameters. +Changing function signatures is often a breaking change, so zap includes +global loggers to simplify migration. + +Avoid them where possible. + +### Why include dedicated Panic and Fatal log levels? + +In general, application code should handle errors gracefully instead of using +`panic` or `os.Exit`. However, every rule has exceptions, and it's common to +crash when an error is truly unrecoverable. To avoid losing any information +— especially the reason for the crash — the logger must flush any +buffered entries before the process exits. + +Zap makes this easy by offering `Panic` and `Fatal` logging methods that +automatically flush before exiting. Of course, this doesn't guarantee that +logs will never be lost, but it eliminates a common error. + +See the discussion in uber-go/zap#207 for more details. + +### What's `DPanic`? + +`DPanic` stands for "panic in development." In development, it logs at +`PanicLevel`; otherwise, it logs at `ErrorLevel`. `DPanic` makes it easier to +catch errors that are theoretically possible, but shouldn't actually happen, +*without* crashing in production. + +If you've ever written code like this, you need `DPanic`: + +```go +if err != nil { + panic(fmt.Sprintf("shouldn't ever get here: %v", err)) +} +``` + +## Installation + +### What does the error `expects import "go.uber.org/zap"` mean? + +Either zap was installed incorrectly or you're referencing the wrong package +name in your code. + +Zap's source code happens to be hosted on GitHub, but the [import +path][import-path] is `go.uber.org/zap`. This gives us, the project +maintainers, the freedom to move the source code if necessary. However, it +means that you need to take a little care when installing and using the +package. + +If you follow two simple rules, everything should work: install zap with `go +get -u go.uber.org/zap`, and always import it in your code with `import +"go.uber.org/zap"`. Your code shouldn't contain *any* references to +`github.com/uber-go/zap`. + +## Usage + +### Does zap support log rotation? + +Zap doesn't natively support rotating log files, since we prefer to leave this +to an external program like `logrotate`. + +However, it's easy to integrate a log rotation package like +[`gopkg.in/natefinch/lumberjack.v2`][lumberjack] as a `zapcore.WriteSyncer`. + +```go +// lumberjack.Logger is already safe for concurrent use, so we don't need to +// lock it. +w := zapcore.AddSync(&lumberjack.Logger{ + Filename: "/var/log/myapp/foo.log", + MaxSize: 500, // megabytes + MaxBackups: 3, + MaxAge: 28, // days +}) +core := zapcore.NewCore( + zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), + w, + zap.InfoLevel, +) +logger := zap.New(core) +``` + +## Extensions + +We'd love to support every logging need within zap itself, but we're only +familiar with a handful of log ingestion systems, flag-parsing packages, and +the like. Rather than merging code that we can't effectively debug and +support, we'd rather grow an ecosystem of zap extensions. + +We're aware of the following extensions, but haven't used them ourselves: + +| Package | Integration | +| --- | --- | +| `github.com/tchap/zapext` | Sentry, syslog | +| `github.com/fgrosse/zaptest` | Ginkgo | +| `github.com/blendle/zapdriver` | Stackdriver | + +[go-proverbs]: https://go-proverbs.github.io/ +[import-path]: https://golang.org/cmd/go/#hdr-Remote_import_paths +[lumberjack]: https://godoc.org/gopkg.in/natefinch/lumberjack.v2 diff --git a/vendor/go.uber.org/zap/LICENSE.txt b/vendor/go.uber.org/zap/LICENSE.txt new file mode 100644 index 0000000000..6652bed45f --- /dev/null +++ b/vendor/go.uber.org/zap/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2016-2017 Uber Technologies, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/go.uber.org/zap/Makefile b/vendor/go.uber.org/zap/Makefile new file mode 100644 index 0000000000..dfaf6406e9 --- /dev/null +++ b/vendor/go.uber.org/zap/Makefile @@ -0,0 +1,63 @@ +export GOBIN ?= $(shell pwd)/bin + +GOLINT = $(GOBIN)/golint +STATICCHECK = $(GOBIN)/staticcheck +BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem + +# Directories containing independent Go modules. +# +# We track coverage only for the main module. +MODULE_DIRS = . ./benchmarks + +# Many Go tools take file globs or directories as arguments instead of packages. +GO_FILES := $(shell \ + find . '(' -path '*/.*' -o -path './vendor' ')' -prune \ + -o -name '*.go' -print | cut -b3-) + +.PHONY: all +all: lint test + +.PHONY: lint +lint: $(GOLINT) $(STATICCHECK) + @rm -rf lint.log + @echo "Checking formatting..." + @gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log + @echo "Checking vet..." + @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go vet ./... 2>&1) &&) true | tee -a lint.log + @echo "Checking lint..." + @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(GOLINT) ./... 2>&1) &&) true | tee -a lint.log + @echo "Checking staticcheck..." + @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(STATICCHECK) ./... 2>&1) &&) true | tee -a lint.log + @echo "Checking for unresolved FIXMEs..." + @git grep -i fixme | grep -v -e Makefile | tee -a lint.log + @echo "Checking for license headers..." + @./checklicense.sh | tee -a lint.log + @[ ! -s lint.log ] + +$(GOLINT): + go install golang.org/x/lint/golint + +$(STATICCHECK): + go install honnef.co/go/tools/cmd/staticcheck + +.PHONY: test +test: + @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go test -race ./...) &&) true + +.PHONY: cover +cover: + go test -race -coverprofile=cover.out -coverpkg=./... ./... + go tool cover -html=cover.out -o cover.html + +.PHONY: bench +BENCH ?= . +bench: + @$(foreach dir,$(MODULE_DIRS), ( \ + cd $(dir) && \ + go list ./... | xargs -n1 go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS) \ + ) &&) true + +.PHONY: updatereadme +updatereadme: + rm -f README.md + cat .readme.tmpl | go run internal/readme/readme.go > README.md diff --git a/vendor/go.uber.org/zap/README.md b/vendor/go.uber.org/zap/README.md new file mode 100644 index 0000000000..bcea28a196 --- /dev/null +++ b/vendor/go.uber.org/zap/README.md @@ -0,0 +1,134 @@ +# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] + +Blazing fast, structured, leveled logging in Go. + +## Installation + +`go get -u go.uber.org/zap` + +Note that zap only supports the two most recent minor versions of Go. + +## Quick Start + +In contexts where performance is nice, but not critical, use the +`SugaredLogger`. It's 4-10x faster than other structured logging +packages and includes both structured and `printf`-style APIs. + +```go +logger, _ := zap.NewProduction() +defer logger.Sync() // flushes buffer, if any +sugar := logger.Sugar() +sugar.Infow("failed to fetch URL", + // Structured context as loosely typed key-value pairs. + "url", url, + "attempt", 3, + "backoff", time.Second, +) +sugar.Infof("Failed to fetch URL: %s", url) +``` + +When performance and type safety are critical, use the `Logger`. It's even +faster than the `SugaredLogger` and allocates far less, but it only supports +structured logging. + +```go +logger, _ := zap.NewProduction() +defer logger.Sync() +logger.Info("failed to fetch URL", + // Structured context as strongly typed Field values. + zap.String("url", url), + zap.Int("attempt", 3), + zap.Duration("backoff", time.Second), +) +``` + +See the [documentation][doc] and [FAQ](FAQ.md) for more details. + +## Performance + +For applications that log in the hot path, reflection-based serialization and +string formatting are prohibitively expensive — they're CPU-intensive +and make many small allocations. Put differently, using `encoding/json` and +`fmt.Fprintf` to log tons of `interface{}`s makes your application slow. + +Zap takes a different approach. It includes a reflection-free, zero-allocation +JSON encoder, and the base `Logger` strives to avoid serialization overhead +and allocations wherever possible. By building the high-level `SugaredLogger` +on that foundation, zap lets users *choose* when they need to count every +allocation and when they'd prefer a more familiar, loosely typed API. + +As measured by its own [benchmarking suite][], not only is zap more performant +than comparable structured logging packages — it's also faster than the +standard library. Like all benchmarks, take these with a grain of salt.[1](#footnote-versions) + +Log a message and 10 fields: + +| Package | Time | Time % to zap | Objects Allocated | +| :------ | :--: | :-----------: | :---------------: | +| :zap: zap | 862 ns/op | +0% | 5 allocs/op +| :zap: zap (sugared) | 1250 ns/op | +45% | 11 allocs/op +| zerolog | 4021 ns/op | +366% | 76 allocs/op +| go-kit | 4542 ns/op | +427% | 105 allocs/op +| apex/log | 26785 ns/op | +3007% | 115 allocs/op +| logrus | 29501 ns/op | +3322% | 125 allocs/op +| log15 | 29906 ns/op | +3369% | 122 allocs/op + +Log a message with a logger that already has 10 fields of context: + +| Package | Time | Time % to zap | Objects Allocated | +| :------ | :--: | :-----------: | :---------------: | +| :zap: zap | 126 ns/op | +0% | 0 allocs/op +| :zap: zap (sugared) | 187 ns/op | +48% | 2 allocs/op +| zerolog | 88 ns/op | -30% | 0 allocs/op +| go-kit | 5087 ns/op | +3937% | 103 allocs/op +| log15 | 18548 ns/op | +14621% | 73 allocs/op +| apex/log | 26012 ns/op | +20544% | 104 allocs/op +| logrus | 27236 ns/op | +21516% | 113 allocs/op + +Log a static string, without any context or `printf`-style templating: + +| Package | Time | Time % to zap | Objects Allocated | +| :------ | :--: | :-----------: | :---------------: | +| :zap: zap | 118 ns/op | +0% | 0 allocs/op +| :zap: zap (sugared) | 191 ns/op | +62% | 2 allocs/op +| zerolog | 93 ns/op | -21% | 0 allocs/op +| go-kit | 280 ns/op | +137% | 11 allocs/op +| standard library | 499 ns/op | +323% | 2 allocs/op +| apex/log | 1990 ns/op | +1586% | 10 allocs/op +| logrus | 3129 ns/op | +2552% | 24 allocs/op +| log15 | 3887 ns/op | +3194% | 23 allocs/op + +## Development Status: Stable + +All APIs are finalized, and no breaking changes will be made in the 1.x series +of releases. Users of semver-aware dependency management systems should pin +zap to `^1`. + +## Contributing + +We encourage and support an active, healthy community of contributors — +including you! Details are in the [contribution guide](CONTRIBUTING.md) and +the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on +issues and pull requests, but you can also report any negative conduct to +oss-conduct@uber.com. That email list is a private, safe space; even the zap +maintainers don't have access, so don't hesitate to hold us to a high +standard. + +
+ +Released under the [MIT License](LICENSE.txt). + +1 In particular, keep in mind that we may be +benchmarking against slightly older versions of other packages. Versions are +pinned in the [benchmarks/go.mod][] file. [↩](#anchor-versions) + +[doc-img]: https://godoc.org/go.uber.org/zap?status.svg +[doc]: https://godoc.org/go.uber.org/zap +[ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master +[ci]: https://travis-ci.com/uber-go/zap +[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg +[cov]: https://codecov.io/gh/uber-go/zap +[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks +[benchmarks/go.mod]: https://github.com/uber-go/zap/blob/master/benchmarks/go.mod + diff --git a/vendor/go.uber.org/zap/array.go b/vendor/go.uber.org/zap/array.go new file mode 100644 index 0000000000..5be3704a3e --- /dev/null +++ b/vendor/go.uber.org/zap/array.go @@ -0,0 +1,320 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "time" + + "go.uber.org/zap/zapcore" +) + +// Array constructs a field with the given key and ArrayMarshaler. It provides +// a flexible, but still type-safe and efficient, way to add array-like types +// to the logging context. The struct's MarshalLogArray method is called lazily. +func Array(key string, val zapcore.ArrayMarshaler) Field { + return Field{Key: key, Type: zapcore.ArrayMarshalerType, Interface: val} +} + +// Bools constructs a field that carries a slice of bools. +func Bools(key string, bs []bool) Field { + return Array(key, bools(bs)) +} + +// ByteStrings constructs a field that carries a slice of []byte, each of which +// must be UTF-8 encoded text. +func ByteStrings(key string, bss [][]byte) Field { + return Array(key, byteStringsArray(bss)) +} + +// Complex128s constructs a field that carries a slice of complex numbers. +func Complex128s(key string, nums []complex128) Field { + return Array(key, complex128s(nums)) +} + +// Complex64s constructs a field that carries a slice of complex numbers. +func Complex64s(key string, nums []complex64) Field { + return Array(key, complex64s(nums)) +} + +// Durations constructs a field that carries a slice of time.Durations. +func Durations(key string, ds []time.Duration) Field { + return Array(key, durations(ds)) +} + +// Float64s constructs a field that carries a slice of floats. +func Float64s(key string, nums []float64) Field { + return Array(key, float64s(nums)) +} + +// Float32s constructs a field that carries a slice of floats. +func Float32s(key string, nums []float32) Field { + return Array(key, float32s(nums)) +} + +// Ints constructs a field that carries a slice of integers. +func Ints(key string, nums []int) Field { + return Array(key, ints(nums)) +} + +// Int64s constructs a field that carries a slice of integers. +func Int64s(key string, nums []int64) Field { + return Array(key, int64s(nums)) +} + +// Int32s constructs a field that carries a slice of integers. +func Int32s(key string, nums []int32) Field { + return Array(key, int32s(nums)) +} + +// Int16s constructs a field that carries a slice of integers. +func Int16s(key string, nums []int16) Field { + return Array(key, int16s(nums)) +} + +// Int8s constructs a field that carries a slice of integers. +func Int8s(key string, nums []int8) Field { + return Array(key, int8s(nums)) +} + +// Strings constructs a field that carries a slice of strings. +func Strings(key string, ss []string) Field { + return Array(key, stringArray(ss)) +} + +// Times constructs a field that carries a slice of time.Times. +func Times(key string, ts []time.Time) Field { + return Array(key, times(ts)) +} + +// Uints constructs a field that carries a slice of unsigned integers. +func Uints(key string, nums []uint) Field { + return Array(key, uints(nums)) +} + +// Uint64s constructs a field that carries a slice of unsigned integers. +func Uint64s(key string, nums []uint64) Field { + return Array(key, uint64s(nums)) +} + +// Uint32s constructs a field that carries a slice of unsigned integers. +func Uint32s(key string, nums []uint32) Field { + return Array(key, uint32s(nums)) +} + +// Uint16s constructs a field that carries a slice of unsigned integers. +func Uint16s(key string, nums []uint16) Field { + return Array(key, uint16s(nums)) +} + +// Uint8s constructs a field that carries a slice of unsigned integers. +func Uint8s(key string, nums []uint8) Field { + return Array(key, uint8s(nums)) +} + +// Uintptrs constructs a field that carries a slice of pointer addresses. +func Uintptrs(key string, us []uintptr) Field { + return Array(key, uintptrs(us)) +} + +// Errors constructs a field that carries a slice of errors. +func Errors(key string, errs []error) Field { + return Array(key, errArray(errs)) +} + +type bools []bool + +func (bs bools) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range bs { + arr.AppendBool(bs[i]) + } + return nil +} + +type byteStringsArray [][]byte + +func (bss byteStringsArray) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range bss { + arr.AppendByteString(bss[i]) + } + return nil +} + +type complex128s []complex128 + +func (nums complex128s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendComplex128(nums[i]) + } + return nil +} + +type complex64s []complex64 + +func (nums complex64s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendComplex64(nums[i]) + } + return nil +} + +type durations []time.Duration + +func (ds durations) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range ds { + arr.AppendDuration(ds[i]) + } + return nil +} + +type float64s []float64 + +func (nums float64s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendFloat64(nums[i]) + } + return nil +} + +type float32s []float32 + +func (nums float32s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendFloat32(nums[i]) + } + return nil +} + +type ints []int + +func (nums ints) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendInt(nums[i]) + } + return nil +} + +type int64s []int64 + +func (nums int64s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendInt64(nums[i]) + } + return nil +} + +type int32s []int32 + +func (nums int32s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendInt32(nums[i]) + } + return nil +} + +type int16s []int16 + +func (nums int16s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendInt16(nums[i]) + } + return nil +} + +type int8s []int8 + +func (nums int8s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendInt8(nums[i]) + } + return nil +} + +type stringArray []string + +func (ss stringArray) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range ss { + arr.AppendString(ss[i]) + } + return nil +} + +type times []time.Time + +func (ts times) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range ts { + arr.AppendTime(ts[i]) + } + return nil +} + +type uints []uint + +func (nums uints) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendUint(nums[i]) + } + return nil +} + +type uint64s []uint64 + +func (nums uint64s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendUint64(nums[i]) + } + return nil +} + +type uint32s []uint32 + +func (nums uint32s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendUint32(nums[i]) + } + return nil +} + +type uint16s []uint16 + +func (nums uint16s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendUint16(nums[i]) + } + return nil +} + +type uint8s []uint8 + +func (nums uint8s) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendUint8(nums[i]) + } + return nil +} + +type uintptrs []uintptr + +func (nums uintptrs) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range nums { + arr.AppendUintptr(nums[i]) + } + return nil +} diff --git a/vendor/go.uber.org/zap/buffer/buffer.go b/vendor/go.uber.org/zap/buffer/buffer.go new file mode 100644 index 0000000000..3f4b86e081 --- /dev/null +++ b/vendor/go.uber.org/zap/buffer/buffer.go @@ -0,0 +1,123 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package buffer provides a thin wrapper around a byte slice. Unlike the +// standard library's bytes.Buffer, it supports a portion of the strconv +// package's zero-allocation formatters. +package buffer // import "go.uber.org/zap/buffer" + +import ( + "strconv" + "time" +) + +const _size = 1024 // by default, create 1 KiB buffers + +// Buffer is a thin wrapper around a byte slice. It's intended to be pooled, so +// the only way to construct one is via a Pool. +type Buffer struct { + bs []byte + pool Pool +} + +// AppendByte writes a single byte to the Buffer. +func (b *Buffer) AppendByte(v byte) { + b.bs = append(b.bs, v) +} + +// AppendString writes a string to the Buffer. +func (b *Buffer) AppendString(s string) { + b.bs = append(b.bs, s...) +} + +// AppendInt appends an integer to the underlying buffer (assuming base 10). +func (b *Buffer) AppendInt(i int64) { + b.bs = strconv.AppendInt(b.bs, i, 10) +} + +// AppendTime appends the time formatted using the specified layout. +func (b *Buffer) AppendTime(t time.Time, layout string) { + b.bs = t.AppendFormat(b.bs, layout) +} + +// AppendUint appends an unsigned integer to the underlying buffer (assuming +// base 10). +func (b *Buffer) AppendUint(i uint64) { + b.bs = strconv.AppendUint(b.bs, i, 10) +} + +// AppendBool appends a bool to the underlying buffer. +func (b *Buffer) AppendBool(v bool) { + b.bs = strconv.AppendBool(b.bs, v) +} + +// AppendFloat appends a float to the underlying buffer. It doesn't quote NaN +// or +/- Inf. +func (b *Buffer) AppendFloat(f float64, bitSize int) { + b.bs = strconv.AppendFloat(b.bs, f, 'f', -1, bitSize) +} + +// Len returns the length of the underlying byte slice. +func (b *Buffer) Len() int { + return len(b.bs) +} + +// Cap returns the capacity of the underlying byte slice. +func (b *Buffer) Cap() int { + return cap(b.bs) +} + +// Bytes returns a mutable reference to the underlying byte slice. +func (b *Buffer) Bytes() []byte { + return b.bs +} + +// String returns a string copy of the underlying byte slice. +func (b *Buffer) String() string { + return string(b.bs) +} + +// Reset resets the underlying byte slice. Subsequent writes re-use the slice's +// backing array. +func (b *Buffer) Reset() { + b.bs = b.bs[:0] +} + +// Write implements io.Writer. +func (b *Buffer) Write(bs []byte) (int, error) { + b.bs = append(b.bs, bs...) + return len(bs), nil +} + +// TrimNewline trims any final "\n" byte from the end of the buffer. +func (b *Buffer) TrimNewline() { + if i := len(b.bs) - 1; i >= 0 { + if b.bs[i] == '\n' { + b.bs = b.bs[:i] + } + } +} + +// Free returns the Buffer to its Pool. +// +// Callers must not retain references to the Buffer after calling Free. +func (b *Buffer) Free() { + b.pool.put(b) +} diff --git a/vendor/go.uber.org/zap/buffer/pool.go b/vendor/go.uber.org/zap/buffer/pool.go new file mode 100644 index 0000000000..8fb3e202cf --- /dev/null +++ b/vendor/go.uber.org/zap/buffer/pool.go @@ -0,0 +1,49 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package buffer + +import "sync" + +// A Pool is a type-safe wrapper around a sync.Pool. +type Pool struct { + p *sync.Pool +} + +// NewPool constructs a new Pool. +func NewPool() Pool { + return Pool{p: &sync.Pool{ + New: func() interface{} { + return &Buffer{bs: make([]byte, 0, _size)} + }, + }} +} + +// Get retrieves a Buffer from the pool, creating one if necessary. +func (p Pool) Get() *Buffer { + buf := p.p.Get().(*Buffer) + buf.Reset() + buf.pool = p + return buf +} + +func (p Pool) put(buf *Buffer) { + p.p.Put(buf) +} diff --git a/vendor/go.uber.org/zap/checklicense.sh b/vendor/go.uber.org/zap/checklicense.sh new file mode 100644 index 0000000000..345ac8b89a --- /dev/null +++ b/vendor/go.uber.org/zap/checklicense.sh @@ -0,0 +1,17 @@ +#!/bin/bash -e + +ERROR_COUNT=0 +while read -r file +do + case "$(head -1 "${file}")" in + *"Copyright (c) "*" Uber Technologies, Inc.") + # everything's cool + ;; + *) + echo "$file is missing license header." + (( ERROR_COUNT++ )) + ;; + esac +done < <(git ls-files "*\.go") + +exit $ERROR_COUNT diff --git a/vendor/go.uber.org/zap/config.go b/vendor/go.uber.org/zap/config.go new file mode 100644 index 0000000000..192fd1a947 --- /dev/null +++ b/vendor/go.uber.org/zap/config.go @@ -0,0 +1,262 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "fmt" + "sort" + "time" + + "go.uber.org/zap/zapcore" +) + +// SamplingConfig sets a sampling strategy for the logger. Sampling caps the +// global CPU and I/O load that logging puts on your process while attempting +// to preserve a representative subset of your logs. +// +// If specified, the Sampler will invoke the Hook after each decision. +// +// Values configured here are per-second. See zapcore.NewSamplerWithOptions for +// details. +type SamplingConfig struct { + Initial int `json:"initial" yaml:"initial"` + Thereafter int `json:"thereafter" yaml:"thereafter"` + Hook func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"` +} + +// Config offers a declarative way to construct a logger. It doesn't do +// anything that can't be done with New, Options, and the various +// zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to +// toggle common options. +// +// Note that Config intentionally supports only the most common options. More +// unusual logging setups (logging to network connections or message queues, +// splitting output between multiple files, etc.) are possible, but require +// direct use of the zapcore package. For sample code, see the package-level +// BasicConfiguration and AdvancedConfiguration examples. +// +// For an example showing runtime log level changes, see the documentation for +// AtomicLevel. +type Config struct { + // Level is the minimum enabled logging level. Note that this is a dynamic + // level, so calling Config.Level.SetLevel will atomically change the log + // level of all loggers descended from this config. + Level AtomicLevel `json:"level" yaml:"level"` + // Development puts the logger in development mode, which changes the + // behavior of DPanicLevel and takes stacktraces more liberally. + Development bool `json:"development" yaml:"development"` + // DisableCaller stops annotating logs with the calling function's file + // name and line number. By default, all logs are annotated. + DisableCaller bool `json:"disableCaller" yaml:"disableCaller"` + // DisableStacktrace completely disables automatic stacktrace capturing. By + // default, stacktraces are captured for WarnLevel and above logs in + // development and ErrorLevel and above in production. + DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"` + // Sampling sets a sampling policy. A nil SamplingConfig disables sampling. + Sampling *SamplingConfig `json:"sampling" yaml:"sampling"` + // Encoding sets the logger's encoding. Valid values are "json" and + // "console", as well as any third-party encodings registered via + // RegisterEncoder. + Encoding string `json:"encoding" yaml:"encoding"` + // EncoderConfig sets options for the chosen encoder. See + // zapcore.EncoderConfig for details. + EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"` + // OutputPaths is a list of URLs or file paths to write logging output to. + // See Open for details. + OutputPaths []string `json:"outputPaths" yaml:"outputPaths"` + // ErrorOutputPaths is a list of URLs to write internal logger errors to. + // The default is standard error. + // + // Note that this setting only affects internal errors; for sample code that + // sends error-level logs to a different location from info- and debug-level + // logs, see the package-level AdvancedConfiguration example. + ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"` + // InitialFields is a collection of fields to add to the root logger. + InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"` +} + +// NewProductionEncoderConfig returns an opinionated EncoderConfig for +// production environments. +func NewProductionEncoderConfig() zapcore.EncoderConfig { + return zapcore.EncoderConfig{ + TimeKey: "ts", + LevelKey: "level", + NameKey: "logger", + CallerKey: "caller", + MessageKey: "msg", + StacktraceKey: "stacktrace", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.LowercaseLevelEncoder, + EncodeTime: zapcore.EpochTimeEncoder, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, + } +} + +// NewProductionConfig is a reasonable production logging configuration. +// Logging is enabled at InfoLevel and above. +// +// It uses a JSON encoder, writes to standard error, and enables sampling. +// Stacktraces are automatically included on logs of ErrorLevel and above. +func NewProductionConfig() Config { + return Config{ + Level: NewAtomicLevelAt(InfoLevel), + Development: false, + Sampling: &SamplingConfig{ + Initial: 100, + Thereafter: 100, + }, + Encoding: "json", + EncoderConfig: NewProductionEncoderConfig(), + OutputPaths: []string{"stderr"}, + ErrorOutputPaths: []string{"stderr"}, + } +} + +// NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for +// development environments. +func NewDevelopmentEncoderConfig() zapcore.EncoderConfig { + return zapcore.EncoderConfig{ + // Keys can be anything except the empty string. + TimeKey: "T", + LevelKey: "L", + NameKey: "N", + CallerKey: "C", + MessageKey: "M", + StacktraceKey: "S", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.CapitalLevelEncoder, + EncodeTime: zapcore.ISO8601TimeEncoder, + EncodeDuration: zapcore.StringDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, + } +} + +// NewDevelopmentConfig is a reasonable development logging configuration. +// Logging is enabled at DebugLevel and above. +// +// It enables development mode (which makes DPanicLevel logs panic), uses a +// console encoder, writes to standard error, and disables sampling. +// Stacktraces are automatically included on logs of WarnLevel and above. +func NewDevelopmentConfig() Config { + return Config{ + Level: NewAtomicLevelAt(DebugLevel), + Development: true, + Encoding: "console", + EncoderConfig: NewDevelopmentEncoderConfig(), + OutputPaths: []string{"stderr"}, + ErrorOutputPaths: []string{"stderr"}, + } +} + +// Build constructs a logger from the Config and Options. +func (cfg Config) Build(opts ...Option) (*Logger, error) { + enc, err := cfg.buildEncoder() + if err != nil { + return nil, err + } + + sink, errSink, err := cfg.openSinks() + if err != nil { + return nil, err + } + + if cfg.Level == (AtomicLevel{}) { + return nil, fmt.Errorf("missing Level") + } + + log := New( + zapcore.NewCore(enc, sink, cfg.Level), + cfg.buildOptions(errSink)..., + ) + if len(opts) > 0 { + log = log.WithOptions(opts...) + } + return log, nil +} + +func (cfg Config) buildOptions(errSink zapcore.WriteSyncer) []Option { + opts := []Option{ErrorOutput(errSink)} + + if cfg.Development { + opts = append(opts, Development()) + } + + if !cfg.DisableCaller { + opts = append(opts, AddCaller()) + } + + stackLevel := ErrorLevel + if cfg.Development { + stackLevel = WarnLevel + } + if !cfg.DisableStacktrace { + opts = append(opts, AddStacktrace(stackLevel)) + } + + if scfg := cfg.Sampling; scfg != nil { + opts = append(opts, WrapCore(func(core zapcore.Core) zapcore.Core { + var samplerOpts []zapcore.SamplerOption + if scfg.Hook != nil { + samplerOpts = append(samplerOpts, zapcore.SamplerHook(scfg.Hook)) + } + return zapcore.NewSamplerWithOptions( + core, + time.Second, + cfg.Sampling.Initial, + cfg.Sampling.Thereafter, + samplerOpts..., + ) + })) + } + + if len(cfg.InitialFields) > 0 { + fs := make([]Field, 0, len(cfg.InitialFields)) + keys := make([]string, 0, len(cfg.InitialFields)) + for k := range cfg.InitialFields { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + fs = append(fs, Any(k, cfg.InitialFields[k])) + } + opts = append(opts, Fields(fs...)) + } + + return opts +} + +func (cfg Config) openSinks() (zapcore.WriteSyncer, zapcore.WriteSyncer, error) { + sink, closeOut, err := Open(cfg.OutputPaths...) + if err != nil { + return nil, nil, err + } + errSink, _, err := Open(cfg.ErrorOutputPaths...) + if err != nil { + closeOut() + return nil, nil, err + } + return sink, errSink, nil +} + +func (cfg Config) buildEncoder() (zapcore.Encoder, error) { + return newEncoder(cfg.Encoding, cfg.EncoderConfig) +} diff --git a/vendor/go.uber.org/zap/doc.go b/vendor/go.uber.org/zap/doc.go new file mode 100644 index 0000000000..8638dd1b96 --- /dev/null +++ b/vendor/go.uber.org/zap/doc.go @@ -0,0 +1,113 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package zap provides fast, structured, leveled logging. +// +// For applications that log in the hot path, reflection-based serialization +// and string formatting are prohibitively expensive - they're CPU-intensive +// and make many small allocations. Put differently, using json.Marshal and +// fmt.Fprintf to log tons of interface{} makes your application slow. +// +// Zap takes a different approach. It includes a reflection-free, +// zero-allocation JSON encoder, and the base Logger strives to avoid +// serialization overhead and allocations wherever possible. By building the +// high-level SugaredLogger on that foundation, zap lets users choose when +// they need to count every allocation and when they'd prefer a more familiar, +// loosely typed API. +// +// Choosing a Logger +// +// In contexts where performance is nice, but not critical, use the +// SugaredLogger. It's 4-10x faster than other structured logging packages and +// supports both structured and printf-style logging. Like log15 and go-kit, +// the SugaredLogger's structured logging APIs are loosely typed and accept a +// variadic number of key-value pairs. (For more advanced use cases, they also +// accept strongly typed fields - see the SugaredLogger.With documentation for +// details.) +// sugar := zap.NewExample().Sugar() +// defer sugar.Sync() +// sugar.Infow("failed to fetch URL", +// "url", "http://example.com", +// "attempt", 3, +// "backoff", time.Second, +// ) +// sugar.Infof("failed to fetch URL: %s", "http://example.com") +// +// By default, loggers are unbuffered. However, since zap's low-level APIs +// allow buffering, calling Sync before letting your process exit is a good +// habit. +// +// In the rare contexts where every microsecond and every allocation matter, +// use the Logger. It's even faster than the SugaredLogger and allocates far +// less, but it only supports strongly-typed, structured logging. +// logger := zap.NewExample() +// defer logger.Sync() +// logger.Info("failed to fetch URL", +// zap.String("url", "http://example.com"), +// zap.Int("attempt", 3), +// zap.Duration("backoff", time.Second), +// ) +// +// Choosing between the Logger and SugaredLogger doesn't need to be an +// application-wide decision: converting between the two is simple and +// inexpensive. +// logger := zap.NewExample() +// defer logger.Sync() +// sugar := logger.Sugar() +// plain := sugar.Desugar() +// +// Configuring Zap +// +// The simplest way to build a Logger is to use zap's opinionated presets: +// NewExample, NewProduction, and NewDevelopment. These presets build a logger +// with a single function call: +// logger, err := zap.NewProduction() +// if err != nil { +// log.Fatalf("can't initialize zap logger: %v", err) +// } +// defer logger.Sync() +// +// Presets are fine for small projects, but larger projects and organizations +// naturally require a bit more customization. For most users, zap's Config +// struct strikes the right balance between flexibility and convenience. See +// the package-level BasicConfiguration example for sample code. +// +// More unusual configurations (splitting output between files, sending logs +// to a message queue, etc.) are possible, but require direct use of +// go.uber.org/zap/zapcore. See the package-level AdvancedConfiguration +// example for sample code. +// +// Extending Zap +// +// The zap package itself is a relatively thin wrapper around the interfaces +// in go.uber.org/zap/zapcore. Extending zap to support a new encoding (e.g., +// BSON), a new log sink (e.g., Kafka), or something more exotic (perhaps an +// exception aggregation service, like Sentry or Rollbar) typically requires +// implementing the zapcore.Encoder, zapcore.WriteSyncer, or zapcore.Core +// interfaces. See the zapcore documentation for details. +// +// Similarly, package authors can use the high-performance Encoder and Core +// implementations in the zapcore package to build their own loggers. +// +// Frequently Asked Questions +// +// An FAQ covering everything from installation errors to design decisions is +// available at https://github.com/uber-go/zap/blob/master/FAQ.md. +package zap // import "go.uber.org/zap" diff --git a/vendor/go.uber.org/zap/encoder.go b/vendor/go.uber.org/zap/encoder.go new file mode 100644 index 0000000000..08ed833543 --- /dev/null +++ b/vendor/go.uber.org/zap/encoder.go @@ -0,0 +1,79 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "errors" + "fmt" + "sync" + + "go.uber.org/zap/zapcore" +) + +var ( + errNoEncoderNameSpecified = errors.New("no encoder name specified") + + _encoderNameToConstructor = map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error){ + "console": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) { + return zapcore.NewConsoleEncoder(encoderConfig), nil + }, + "json": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) { + return zapcore.NewJSONEncoder(encoderConfig), nil + }, + } + _encoderMutex sync.RWMutex +) + +// RegisterEncoder registers an encoder constructor, which the Config struct +// can then reference. By default, the "json" and "console" encoders are +// registered. +// +// Attempting to register an encoder whose name is already taken returns an +// error. +func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapcore.Encoder, error)) error { + _encoderMutex.Lock() + defer _encoderMutex.Unlock() + if name == "" { + return errNoEncoderNameSpecified + } + if _, ok := _encoderNameToConstructor[name]; ok { + return fmt.Errorf("encoder already registered for name %q", name) + } + _encoderNameToConstructor[name] = constructor + return nil +} + +func newEncoder(name string, encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) { + if encoderConfig.TimeKey != "" && encoderConfig.EncodeTime == nil { + return nil, fmt.Errorf("missing EncodeTime in EncoderConfig") + } + + _encoderMutex.RLock() + defer _encoderMutex.RUnlock() + if name == "" { + return nil, errNoEncoderNameSpecified + } + constructor, ok := _encoderNameToConstructor[name] + if !ok { + return nil, fmt.Errorf("no encoder registered for name %q", name) + } + return constructor(encoderConfig) +} diff --git a/vendor/go.uber.org/zap/error.go b/vendor/go.uber.org/zap/error.go new file mode 100644 index 0000000000..65982a51e5 --- /dev/null +++ b/vendor/go.uber.org/zap/error.go @@ -0,0 +1,80 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "sync" + + "go.uber.org/zap/zapcore" +) + +var _errArrayElemPool = sync.Pool{New: func() interface{} { + return &errArrayElem{} +}} + +// Error is shorthand for the common idiom NamedError("error", err). +func Error(err error) Field { + return NamedError("error", err) +} + +// NamedError constructs a field that lazily stores err.Error() under the +// provided key. Errors which also implement fmt.Formatter (like those produced +// by github.com/pkg/errors) will also have their verbose representation stored +// under key+"Verbose". If passed a nil error, the field is a no-op. +// +// For the common case in which the key is simply "error", the Error function +// is shorter and less repetitive. +func NamedError(key string, err error) Field { + if err == nil { + return Skip() + } + return Field{Key: key, Type: zapcore.ErrorType, Interface: err} +} + +type errArray []error + +func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range errs { + if errs[i] == nil { + continue + } + // To represent each error as an object with an "error" attribute and + // potentially an "errorVerbose" attribute, we need to wrap it in a + // type that implements LogObjectMarshaler. To prevent this from + // allocating, pool the wrapper type. + elem := _errArrayElemPool.Get().(*errArrayElem) + elem.error = errs[i] + arr.AppendObject(elem) + elem.error = nil + _errArrayElemPool.Put(elem) + } + return nil +} + +type errArrayElem struct { + error +} + +func (e *errArrayElem) MarshalLogObject(enc zapcore.ObjectEncoder) error { + // Re-use the error field's logic, which supports non-standard error types. + Error(e.error).AddTo(enc) + return nil +} diff --git a/vendor/go.uber.org/zap/field.go b/vendor/go.uber.org/zap/field.go new file mode 100644 index 0000000000..dd558fc231 --- /dev/null +++ b/vendor/go.uber.org/zap/field.go @@ -0,0 +1,533 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "fmt" + "math" + "time" + + "go.uber.org/zap/zapcore" +) + +// Field is an alias for Field. Aliasing this type dramatically +// improves the navigability of this package's API documentation. +type Field = zapcore.Field + +var ( + _minTimeInt64 = time.Unix(0, math.MinInt64) + _maxTimeInt64 = time.Unix(0, math.MaxInt64) +) + +// Skip constructs a no-op field, which is often useful when handling invalid +// inputs in other Field constructors. +func Skip() Field { + return Field{Type: zapcore.SkipType} +} + +// nilField returns a field which will marshal explicitly as nil. See motivation +// in https://github.com/uber-go/zap/issues/753 . If we ever make breaking +// changes and add zapcore.NilType and zapcore.ObjectEncoder.AddNil, the +// implementation here should be changed to reflect that. +func nilField(key string) Field { return Reflect(key, nil) } + +// Binary constructs a field that carries an opaque binary blob. +// +// Binary data is serialized in an encoding-appropriate format. For example, +// zap's JSON encoder base64-encodes binary blobs. To log UTF-8 encoded text, +// use ByteString. +func Binary(key string, val []byte) Field { + return Field{Key: key, Type: zapcore.BinaryType, Interface: val} +} + +// Bool constructs a field that carries a bool. +func Bool(key string, val bool) Field { + var ival int64 + if val { + ival = 1 + } + return Field{Key: key, Type: zapcore.BoolType, Integer: ival} +} + +// Boolp constructs a field that carries a *bool. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Boolp(key string, val *bool) Field { + if val == nil { + return nilField(key) + } + return Bool(key, *val) +} + +// ByteString constructs a field that carries UTF-8 encoded text as a []byte. +// To log opaque binary blobs (which aren't necessarily valid UTF-8), use +// Binary. +func ByteString(key string, val []byte) Field { + return Field{Key: key, Type: zapcore.ByteStringType, Interface: val} +} + +// Complex128 constructs a field that carries a complex number. Unlike most +// numeric fields, this costs an allocation (to convert the complex128 to +// interface{}). +func Complex128(key string, val complex128) Field { + return Field{Key: key, Type: zapcore.Complex128Type, Interface: val} +} + +// Complex128p constructs a field that carries a *complex128. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Complex128p(key string, val *complex128) Field { + if val == nil { + return nilField(key) + } + return Complex128(key, *val) +} + +// Complex64 constructs a field that carries a complex number. Unlike most +// numeric fields, this costs an allocation (to convert the complex64 to +// interface{}). +func Complex64(key string, val complex64) Field { + return Field{Key: key, Type: zapcore.Complex64Type, Interface: val} +} + +// Complex64p constructs a field that carries a *complex64. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Complex64p(key string, val *complex64) Field { + if val == nil { + return nilField(key) + } + return Complex64(key, *val) +} + +// Float64 constructs a field that carries a float64. The way the +// floating-point value is represented is encoder-dependent, so marshaling is +// necessarily lazy. +func Float64(key string, val float64) Field { + return Field{Key: key, Type: zapcore.Float64Type, Integer: int64(math.Float64bits(val))} +} + +// Float64p constructs a field that carries a *float64. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Float64p(key string, val *float64) Field { + if val == nil { + return nilField(key) + } + return Float64(key, *val) +} + +// Float32 constructs a field that carries a float32. The way the +// floating-point value is represented is encoder-dependent, so marshaling is +// necessarily lazy. +func Float32(key string, val float32) Field { + return Field{Key: key, Type: zapcore.Float32Type, Integer: int64(math.Float32bits(val))} +} + +// Float32p constructs a field that carries a *float32. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Float32p(key string, val *float32) Field { + if val == nil { + return nilField(key) + } + return Float32(key, *val) +} + +// Int constructs a field with the given key and value. +func Int(key string, val int) Field { + return Int64(key, int64(val)) +} + +// Intp constructs a field that carries a *int. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Intp(key string, val *int) Field { + if val == nil { + return nilField(key) + } + return Int(key, *val) +} + +// Int64 constructs a field with the given key and value. +func Int64(key string, val int64) Field { + return Field{Key: key, Type: zapcore.Int64Type, Integer: val} +} + +// Int64p constructs a field that carries a *int64. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Int64p(key string, val *int64) Field { + if val == nil { + return nilField(key) + } + return Int64(key, *val) +} + +// Int32 constructs a field with the given key and value. +func Int32(key string, val int32) Field { + return Field{Key: key, Type: zapcore.Int32Type, Integer: int64(val)} +} + +// Int32p constructs a field that carries a *int32. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Int32p(key string, val *int32) Field { + if val == nil { + return nilField(key) + } + return Int32(key, *val) +} + +// Int16 constructs a field with the given key and value. +func Int16(key string, val int16) Field { + return Field{Key: key, Type: zapcore.Int16Type, Integer: int64(val)} +} + +// Int16p constructs a field that carries a *int16. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Int16p(key string, val *int16) Field { + if val == nil { + return nilField(key) + } + return Int16(key, *val) +} + +// Int8 constructs a field with the given key and value. +func Int8(key string, val int8) Field { + return Field{Key: key, Type: zapcore.Int8Type, Integer: int64(val)} +} + +// Int8p constructs a field that carries a *int8. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Int8p(key string, val *int8) Field { + if val == nil { + return nilField(key) + } + return Int8(key, *val) +} + +// String constructs a field with the given key and value. +func String(key string, val string) Field { + return Field{Key: key, Type: zapcore.StringType, String: val} +} + +// Stringp constructs a field that carries a *string. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Stringp(key string, val *string) Field { + if val == nil { + return nilField(key) + } + return String(key, *val) +} + +// Uint constructs a field with the given key and value. +func Uint(key string, val uint) Field { + return Uint64(key, uint64(val)) +} + +// Uintp constructs a field that carries a *uint. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Uintp(key string, val *uint) Field { + if val == nil { + return nilField(key) + } + return Uint(key, *val) +} + +// Uint64 constructs a field with the given key and value. +func Uint64(key string, val uint64) Field { + return Field{Key: key, Type: zapcore.Uint64Type, Integer: int64(val)} +} + +// Uint64p constructs a field that carries a *uint64. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Uint64p(key string, val *uint64) Field { + if val == nil { + return nilField(key) + } + return Uint64(key, *val) +} + +// Uint32 constructs a field with the given key and value. +func Uint32(key string, val uint32) Field { + return Field{Key: key, Type: zapcore.Uint32Type, Integer: int64(val)} +} + +// Uint32p constructs a field that carries a *uint32. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Uint32p(key string, val *uint32) Field { + if val == nil { + return nilField(key) + } + return Uint32(key, *val) +} + +// Uint16 constructs a field with the given key and value. +func Uint16(key string, val uint16) Field { + return Field{Key: key, Type: zapcore.Uint16Type, Integer: int64(val)} +} + +// Uint16p constructs a field that carries a *uint16. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Uint16p(key string, val *uint16) Field { + if val == nil { + return nilField(key) + } + return Uint16(key, *val) +} + +// Uint8 constructs a field with the given key and value. +func Uint8(key string, val uint8) Field { + return Field{Key: key, Type: zapcore.Uint8Type, Integer: int64(val)} +} + +// Uint8p constructs a field that carries a *uint8. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Uint8p(key string, val *uint8) Field { + if val == nil { + return nilField(key) + } + return Uint8(key, *val) +} + +// Uintptr constructs a field with the given key and value. +func Uintptr(key string, val uintptr) Field { + return Field{Key: key, Type: zapcore.UintptrType, Integer: int64(val)} +} + +// Uintptrp constructs a field that carries a *uintptr. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Uintptrp(key string, val *uintptr) Field { + if val == nil { + return nilField(key) + } + return Uintptr(key, *val) +} + +// Reflect constructs a field with the given key and an arbitrary object. It uses +// an encoding-appropriate, reflection-based function to lazily serialize nearly +// any object into the logging context, but it's relatively slow and +// allocation-heavy. Outside tests, Any is always a better choice. +// +// If encoding fails (e.g., trying to serialize a map[int]string to JSON), Reflect +// includes the error message in the final log output. +func Reflect(key string, val interface{}) Field { + return Field{Key: key, Type: zapcore.ReflectType, Interface: val} +} + +// Namespace creates a named, isolated scope within the logger's context. All +// subsequent fields will be added to the new namespace. +// +// This helps prevent key collisions when injecting loggers into sub-components +// or third-party libraries. +func Namespace(key string) Field { + return Field{Key: key, Type: zapcore.NamespaceType} +} + +// Stringer constructs a field with the given key and the output of the value's +// String method. The Stringer's String method is called lazily. +func Stringer(key string, val fmt.Stringer) Field { + return Field{Key: key, Type: zapcore.StringerType, Interface: val} +} + +// Time constructs a Field with the given key and value. The encoder +// controls how the time is serialized. +func Time(key string, val time.Time) Field { + if val.Before(_minTimeInt64) || val.After(_maxTimeInt64) { + return Field{Key: key, Type: zapcore.TimeFullType, Interface: val} + } + return Field{Key: key, Type: zapcore.TimeType, Integer: val.UnixNano(), Interface: val.Location()} +} + +// Timep constructs a field that carries a *time.Time. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Timep(key string, val *time.Time) Field { + if val == nil { + return nilField(key) + } + return Time(key, *val) +} + +// Stack constructs a field that stores a stacktrace of the current goroutine +// under provided key. Keep in mind that taking a stacktrace is eager and +// expensive (relatively speaking); this function both makes an allocation and +// takes about two microseconds. +func Stack(key string) Field { + // Returning the stacktrace as a string costs an allocation, but saves us + // from expanding the zapcore.Field union struct to include a byte slice. Since + // taking a stacktrace is already so expensive (~10us), the extra allocation + // is okay. + return String(key, takeStacktrace()) +} + +// Duration constructs a field with the given key and value. The encoder +// controls how the duration is serialized. +func Duration(key string, val time.Duration) Field { + return Field{Key: key, Type: zapcore.DurationType, Integer: int64(val)} +} + +// Durationp constructs a field that carries a *time.Duration. The returned Field will safely +// and explicitly represent `nil` when appropriate. +func Durationp(key string, val *time.Duration) Field { + if val == nil { + return nilField(key) + } + return Duration(key, *val) +} + +// Object constructs a field with the given key and ObjectMarshaler. It +// provides a flexible, but still type-safe and efficient, way to add map- or +// struct-like user-defined types to the logging context. The struct's +// MarshalLogObject method is called lazily. +func Object(key string, val zapcore.ObjectMarshaler) Field { + return Field{Key: key, Type: zapcore.ObjectMarshalerType, Interface: val} +} + +// Any takes a key and an arbitrary value and chooses the best way to represent +// them as a field, falling back to a reflection-based approach only if +// necessary. +// +// Since byte/uint8 and rune/int32 are aliases, Any can't differentiate between +// them. To minimize surprises, []byte values are treated as binary blobs, byte +// values are treated as uint8, and runes are always treated as integers. +func Any(key string, value interface{}) Field { + switch val := value.(type) { + case zapcore.ObjectMarshaler: + return Object(key, val) + case zapcore.ArrayMarshaler: + return Array(key, val) + case bool: + return Bool(key, val) + case *bool: + return Boolp(key, val) + case []bool: + return Bools(key, val) + case complex128: + return Complex128(key, val) + case *complex128: + return Complex128p(key, val) + case []complex128: + return Complex128s(key, val) + case complex64: + return Complex64(key, val) + case *complex64: + return Complex64p(key, val) + case []complex64: + return Complex64s(key, val) + case float64: + return Float64(key, val) + case *float64: + return Float64p(key, val) + case []float64: + return Float64s(key, val) + case float32: + return Float32(key, val) + case *float32: + return Float32p(key, val) + case []float32: + return Float32s(key, val) + case int: + return Int(key, val) + case *int: + return Intp(key, val) + case []int: + return Ints(key, val) + case int64: + return Int64(key, val) + case *int64: + return Int64p(key, val) + case []int64: + return Int64s(key, val) + case int32: + return Int32(key, val) + case *int32: + return Int32p(key, val) + case []int32: + return Int32s(key, val) + case int16: + return Int16(key, val) + case *int16: + return Int16p(key, val) + case []int16: + return Int16s(key, val) + case int8: + return Int8(key, val) + case *int8: + return Int8p(key, val) + case []int8: + return Int8s(key, val) + case string: + return String(key, val) + case *string: + return Stringp(key, val) + case []string: + return Strings(key, val) + case uint: + return Uint(key, val) + case *uint: + return Uintp(key, val) + case []uint: + return Uints(key, val) + case uint64: + return Uint64(key, val) + case *uint64: + return Uint64p(key, val) + case []uint64: + return Uint64s(key, val) + case uint32: + return Uint32(key, val) + case *uint32: + return Uint32p(key, val) + case []uint32: + return Uint32s(key, val) + case uint16: + return Uint16(key, val) + case *uint16: + return Uint16p(key, val) + case []uint16: + return Uint16s(key, val) + case uint8: + return Uint8(key, val) + case *uint8: + return Uint8p(key, val) + case []byte: + return Binary(key, val) + case uintptr: + return Uintptr(key, val) + case *uintptr: + return Uintptrp(key, val) + case []uintptr: + return Uintptrs(key, val) + case time.Time: + return Time(key, val) + case *time.Time: + return Timep(key, val) + case []time.Time: + return Times(key, val) + case time.Duration: + return Duration(key, val) + case *time.Duration: + return Durationp(key, val) + case []time.Duration: + return Durations(key, val) + case error: + return NamedError(key, val) + case []error: + return Errors(key, val) + case fmt.Stringer: + return Stringer(key, val) + default: + return Reflect(key, val) + } +} diff --git a/vendor/go.uber.org/zap/flag.go b/vendor/go.uber.org/zap/flag.go new file mode 100644 index 0000000000..1312875072 --- /dev/null +++ b/vendor/go.uber.org/zap/flag.go @@ -0,0 +1,39 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "flag" + + "go.uber.org/zap/zapcore" +) + +// LevelFlag uses the standard library's flag.Var to declare a global flag +// with the specified name, default, and usage guidance. The returned value is +// a pointer to the value of the flag. +// +// If you don't want to use the flag package's global state, you can use any +// non-nil *Level as a flag.Value with your own *flag.FlagSet. +func LevelFlag(name string, defaultLevel zapcore.Level, usage string) *zapcore.Level { + lvl := defaultLevel + flag.Var(&lvl, name, usage) + return &lvl +} diff --git a/vendor/go.uber.org/zap/glide.yaml b/vendor/go.uber.org/zap/glide.yaml new file mode 100644 index 0000000000..8e1d05e9ab --- /dev/null +++ b/vendor/go.uber.org/zap/glide.yaml @@ -0,0 +1,34 @@ +package: go.uber.org/zap +license: MIT +import: +- package: go.uber.org/atomic + version: ^1 +- package: go.uber.org/multierr + version: ^1 +testImport: +- package: github.com/satori/go.uuid +- package: github.com/sirupsen/logrus +- package: github.com/apex/log + subpackages: + - handlers/json +- package: github.com/go-kit/kit + subpackages: + - log +- package: github.com/stretchr/testify + subpackages: + - assert + - require +- package: gopkg.in/inconshreveable/log15.v2 +- package: github.com/mattn/goveralls +- package: github.com/pborman/uuid +- package: github.com/pkg/errors +- package: github.com/rs/zerolog +- package: golang.org/x/tools + subpackages: + - cover +- package: golang.org/x/lint + subpackages: + - golint +- package: github.com/axw/gocov + subpackages: + - gocov diff --git a/vendor/go.uber.org/zap/global.go b/vendor/go.uber.org/zap/global.go new file mode 100644 index 0000000000..c1ac0507cd --- /dev/null +++ b/vendor/go.uber.org/zap/global.go @@ -0,0 +1,168 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "bytes" + "fmt" + "log" + "os" + "sync" + + "go.uber.org/zap/zapcore" +) + +const ( + _loggerWriterDepth = 2 + _programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " + + "https://github.com/uber-go/zap/issues/new and reference this error: %v" +) + +var ( + _globalMu sync.RWMutex + _globalL = NewNop() + _globalS = _globalL.Sugar() +) + +// L returns the global Logger, which can be reconfigured with ReplaceGlobals. +// It's safe for concurrent use. +func L() *Logger { + _globalMu.RLock() + l := _globalL + _globalMu.RUnlock() + return l +} + +// S returns the global SugaredLogger, which can be reconfigured with +// ReplaceGlobals. It's safe for concurrent use. +func S() *SugaredLogger { + _globalMu.RLock() + s := _globalS + _globalMu.RUnlock() + return s +} + +// ReplaceGlobals replaces the global Logger and SugaredLogger, and returns a +// function to restore the original values. It's safe for concurrent use. +func ReplaceGlobals(logger *Logger) func() { + _globalMu.Lock() + prev := _globalL + _globalL = logger + _globalS = logger.Sugar() + _globalMu.Unlock() + return func() { ReplaceGlobals(prev) } +} + +// NewStdLog returns a *log.Logger which writes to the supplied zap Logger at +// InfoLevel. To redirect the standard library's package-global logging +// functions, use RedirectStdLog instead. +func NewStdLog(l *Logger) *log.Logger { + logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth)) + f := logger.Info + return log.New(&loggerWriter{f}, "" /* prefix */, 0 /* flags */) +} + +// NewStdLogAt returns *log.Logger which writes to supplied zap logger at +// required level. +func NewStdLogAt(l *Logger, level zapcore.Level) (*log.Logger, error) { + logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth)) + logFunc, err := levelToFunc(logger, level) + if err != nil { + return nil, err + } + return log.New(&loggerWriter{logFunc}, "" /* prefix */, 0 /* flags */), nil +} + +// RedirectStdLog redirects output from the standard library's package-global +// logger to the supplied logger at InfoLevel. Since zap already handles caller +// annotations, timestamps, etc., it automatically disables the standard +// library's annotations and prefixing. +// +// It returns a function to restore the original prefix and flags and reset the +// standard library's output to os.Stderr. +func RedirectStdLog(l *Logger) func() { + f, err := redirectStdLogAt(l, InfoLevel) + if err != nil { + // Can't get here, since passing InfoLevel to redirectStdLogAt always + // works. + panic(fmt.Sprintf(_programmerErrorTemplate, err)) + } + return f +} + +// RedirectStdLogAt redirects output from the standard library's package-global +// logger to the supplied logger at the specified level. Since zap already +// handles caller annotations, timestamps, etc., it automatically disables the +// standard library's annotations and prefixing. +// +// It returns a function to restore the original prefix and flags and reset the +// standard library's output to os.Stderr. +func RedirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) { + return redirectStdLogAt(l, level) +} + +func redirectStdLogAt(l *Logger, level zapcore.Level) (func(), error) { + flags := log.Flags() + prefix := log.Prefix() + log.SetFlags(0) + log.SetPrefix("") + logger := l.WithOptions(AddCallerSkip(_stdLogDefaultDepth + _loggerWriterDepth)) + logFunc, err := levelToFunc(logger, level) + if err != nil { + return nil, err + } + log.SetOutput(&loggerWriter{logFunc}) + return func() { + log.SetFlags(flags) + log.SetPrefix(prefix) + log.SetOutput(os.Stderr) + }, nil +} + +func levelToFunc(logger *Logger, lvl zapcore.Level) (func(string, ...Field), error) { + switch lvl { + case DebugLevel: + return logger.Debug, nil + case InfoLevel: + return logger.Info, nil + case WarnLevel: + return logger.Warn, nil + case ErrorLevel: + return logger.Error, nil + case DPanicLevel: + return logger.DPanic, nil + case PanicLevel: + return logger.Panic, nil + case FatalLevel: + return logger.Fatal, nil + } + return nil, fmt.Errorf("unrecognized level: %q", lvl) +} + +type loggerWriter struct { + logFunc func(msg string, fields ...Field) +} + +func (l *loggerWriter) Write(p []byte) (int, error) { + p = bytes.TrimSpace(p) + l.logFunc(string(p)) + return len(p), nil +} diff --git a/vendor/go.uber.org/zap/global_go112.go b/vendor/go.uber.org/zap/global_go112.go new file mode 100644 index 0000000000..6b5dbda807 --- /dev/null +++ b/vendor/go.uber.org/zap/global_go112.go @@ -0,0 +1,26 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// See #682 for more information. +// +build go1.12 + +package zap + +const _stdLogDefaultDepth = 1 diff --git a/vendor/go.uber.org/zap/global_prego112.go b/vendor/go.uber.org/zap/global_prego112.go new file mode 100644 index 0000000000..d3ab9af933 --- /dev/null +++ b/vendor/go.uber.org/zap/global_prego112.go @@ -0,0 +1,26 @@ +// Copyright (c) 2019 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// See #682 for more information. +// +build !go1.12 + +package zap + +const _stdLogDefaultDepth = 2 diff --git a/vendor/go.uber.org/zap/go.mod b/vendor/go.uber.org/zap/go.mod new file mode 100644 index 0000000000..118abda151 --- /dev/null +++ b/vendor/go.uber.org/zap/go.mod @@ -0,0 +1,12 @@ +module go.uber.org/zap + +go 1.13 + +require ( + github.com/pkg/errors v0.8.1 + github.com/stretchr/testify v1.4.0 + go.uber.org/atomic v1.6.0 + go.uber.org/multierr v1.5.0 + golang.org/x/lint v0.0.0-20190930215403-16217165b5de + honnef.co/go/tools v0.0.1-2019.2.3 +) diff --git a/vendor/go.uber.org/zap/go.sum b/vendor/go.uber.org/zap/go.sum new file mode 100644 index 0000000000..99cdb93ea0 --- /dev/null +++ b/vendor/go.uber.org/zap/go.sum @@ -0,0 +1,56 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/go.uber.org/zap/http_handler.go b/vendor/go.uber.org/zap/http_handler.go new file mode 100644 index 0000000000..1b0ecaca9c --- /dev/null +++ b/vendor/go.uber.org/zap/http_handler.go @@ -0,0 +1,81 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "encoding/json" + "fmt" + "net/http" + + "go.uber.org/zap/zapcore" +) + +// ServeHTTP is a simple JSON endpoint that can report on or change the current +// logging level. +// +// GET requests return a JSON description of the current logging level. PUT +// requests change the logging level and expect a payload like: +// {"level":"info"} +// +// It's perfectly safe to change the logging level while a program is running. +func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) { + type errorResponse struct { + Error string `json:"error"` + } + type payload struct { + Level *zapcore.Level `json:"level"` + } + + enc := json.NewEncoder(w) + + switch r.Method { + + case http.MethodGet: + current := lvl.Level() + enc.Encode(payload{Level: ¤t}) + + case http.MethodPut: + var req payload + + if errmess := func() string { + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + return fmt.Sprintf("Request body must be well-formed JSON: %v", err) + } + if req.Level == nil { + return "Must specify a logging level." + } + return "" + }(); errmess != "" { + w.WriteHeader(http.StatusBadRequest) + enc.Encode(errorResponse{Error: errmess}) + return + } + + lvl.SetLevel(*req.Level) + enc.Encode(req) + + default: + w.WriteHeader(http.StatusMethodNotAllowed) + enc.Encode(errorResponse{ + Error: "Only GET and PUT are supported.", + }) + } +} diff --git a/vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go b/vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go new file mode 100644 index 0000000000..dad583aaa5 --- /dev/null +++ b/vendor/go.uber.org/zap/internal/bufferpool/bufferpool.go @@ -0,0 +1,31 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package bufferpool houses zap's shared internal buffer pool. Third-party +// packages can recreate the same functionality with buffers.NewPool. +package bufferpool + +import "go.uber.org/zap/buffer" + +var ( + _pool = buffer.NewPool() + // Get retrieves a buffer from the pool, creating one if necessary. + Get = _pool.Get +) diff --git a/vendor/go.uber.org/zap/internal/color/color.go b/vendor/go.uber.org/zap/internal/color/color.go new file mode 100644 index 0000000000..c4d5d02abc --- /dev/null +++ b/vendor/go.uber.org/zap/internal/color/color.go @@ -0,0 +1,44 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package color adds coloring functionality for TTY output. +package color + +import "fmt" + +// Foreground colors. +const ( + Black Color = iota + 30 + Red + Green + Yellow + Blue + Magenta + Cyan + White +) + +// Color represents a text color. +type Color uint8 + +// Add adds the coloring to the given string. +func (c Color) Add(s string) string { + return fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(c), s) +} diff --git a/vendor/go.uber.org/zap/internal/exit/exit.go b/vendor/go.uber.org/zap/internal/exit/exit.go new file mode 100644 index 0000000000..dfc5b05feb --- /dev/null +++ b/vendor/go.uber.org/zap/internal/exit/exit.go @@ -0,0 +1,64 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package exit provides stubs so that unit tests can exercise code that calls +// os.Exit(1). +package exit + +import "os" + +var real = func() { os.Exit(1) } + +// Exit normally terminates the process by calling os.Exit(1). If the package +// is stubbed, it instead records a call in the testing spy. +func Exit() { + real() +} + +// A StubbedExit is a testing fake for os.Exit. +type StubbedExit struct { + Exited bool + prev func() +} + +// Stub substitutes a fake for the call to os.Exit(1). +func Stub() *StubbedExit { + s := &StubbedExit{prev: real} + real = s.exit + return s +} + +// WithStub runs the supplied function with Exit stubbed. It returns the stub +// used, so that users can test whether the process would have crashed. +func WithStub(f func()) *StubbedExit { + s := Stub() + defer s.Unstub() + f() + return s +} + +// Unstub restores the previous exit function. +func (se *StubbedExit) Unstub() { + real = se.prev +} + +func (se *StubbedExit) exit() { + se.Exited = true +} diff --git a/vendor/go.uber.org/zap/level.go b/vendor/go.uber.org/zap/level.go new file mode 100644 index 0000000000..3567a9a1e6 --- /dev/null +++ b/vendor/go.uber.org/zap/level.go @@ -0,0 +1,132 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "go.uber.org/atomic" + "go.uber.org/zap/zapcore" +) + +const ( + // DebugLevel logs are typically voluminous, and are usually disabled in + // production. + DebugLevel = zapcore.DebugLevel + // InfoLevel is the default logging priority. + InfoLevel = zapcore.InfoLevel + // WarnLevel logs are more important than Info, but don't need individual + // human review. + WarnLevel = zapcore.WarnLevel + // ErrorLevel logs are high-priority. If an application is running smoothly, + // it shouldn't generate any error-level logs. + ErrorLevel = zapcore.ErrorLevel + // DPanicLevel logs are particularly important errors. In development the + // logger panics after writing the message. + DPanicLevel = zapcore.DPanicLevel + // PanicLevel logs a message, then panics. + PanicLevel = zapcore.PanicLevel + // FatalLevel logs a message, then calls os.Exit(1). + FatalLevel = zapcore.FatalLevel +) + +// LevelEnablerFunc is a convenient way to implement zapcore.LevelEnabler with +// an anonymous function. +// +// It's particularly useful when splitting log output between different +// outputs (e.g., standard error and standard out). For sample code, see the +// package-level AdvancedConfiguration example. +type LevelEnablerFunc func(zapcore.Level) bool + +// Enabled calls the wrapped function. +func (f LevelEnablerFunc) Enabled(lvl zapcore.Level) bool { return f(lvl) } + +// An AtomicLevel is an atomically changeable, dynamic logging level. It lets +// you safely change the log level of a tree of loggers (the root logger and +// any children created by adding context) at runtime. +// +// The AtomicLevel itself is an http.Handler that serves a JSON endpoint to +// alter its level. +// +// AtomicLevels must be created with the NewAtomicLevel constructor to allocate +// their internal atomic pointer. +type AtomicLevel struct { + l *atomic.Int32 +} + +// NewAtomicLevel creates an AtomicLevel with InfoLevel and above logging +// enabled. +func NewAtomicLevel() AtomicLevel { + return AtomicLevel{ + l: atomic.NewInt32(int32(InfoLevel)), + } +} + +// NewAtomicLevelAt is a convenience function that creates an AtomicLevel +// and then calls SetLevel with the given level. +func NewAtomicLevelAt(l zapcore.Level) AtomicLevel { + a := NewAtomicLevel() + a.SetLevel(l) + return a +} + +// Enabled implements the zapcore.LevelEnabler interface, which allows the +// AtomicLevel to be used in place of traditional static levels. +func (lvl AtomicLevel) Enabled(l zapcore.Level) bool { + return lvl.Level().Enabled(l) +} + +// Level returns the minimum enabled log level. +func (lvl AtomicLevel) Level() zapcore.Level { + return zapcore.Level(int8(lvl.l.Load())) +} + +// SetLevel alters the logging level. +func (lvl AtomicLevel) SetLevel(l zapcore.Level) { + lvl.l.Store(int32(l)) +} + +// String returns the string representation of the underlying Level. +func (lvl AtomicLevel) String() string { + return lvl.Level().String() +} + +// UnmarshalText unmarshals the text to an AtomicLevel. It uses the same text +// representations as the static zapcore.Levels ("debug", "info", "warn", +// "error", "dpanic", "panic", and "fatal"). +func (lvl *AtomicLevel) UnmarshalText(text []byte) error { + if lvl.l == nil { + lvl.l = &atomic.Int32{} + } + + var l zapcore.Level + if err := l.UnmarshalText(text); err != nil { + return err + } + + lvl.SetLevel(l) + return nil +} + +// MarshalText marshals the AtomicLevel to a byte slice. It uses the same +// text representation as the static zapcore.Levels ("debug", "info", "warn", +// "error", "dpanic", "panic", and "fatal"). +func (lvl AtomicLevel) MarshalText() (text []byte, err error) { + return lvl.Level().MarshalText() +} diff --git a/vendor/go.uber.org/zap/logger.go b/vendor/go.uber.org/zap/logger.go new file mode 100644 index 0000000000..cd6e19551a --- /dev/null +++ b/vendor/go.uber.org/zap/logger.go @@ -0,0 +1,311 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "fmt" + "io/ioutil" + "os" + "runtime" + "strings" + "time" + + "go.uber.org/zap/zapcore" +) + +// A Logger provides fast, leveled, structured logging. All methods are safe +// for concurrent use. +// +// The Logger is designed for contexts in which every microsecond and every +// allocation matters, so its API intentionally favors performance and type +// safety over brevity. For most applications, the SugaredLogger strikes a +// better balance between performance and ergonomics. +type Logger struct { + core zapcore.Core + + development bool + name string + errorOutput zapcore.WriteSyncer + + addCaller bool + addStack zapcore.LevelEnabler + + callerSkip int +} + +// New constructs a new Logger from the provided zapcore.Core and Options. If +// the passed zapcore.Core is nil, it falls back to using a no-op +// implementation. +// +// This is the most flexible way to construct a Logger, but also the most +// verbose. For typical use cases, the highly-opinionated presets +// (NewProduction, NewDevelopment, and NewExample) or the Config struct are +// more convenient. +// +// For sample code, see the package-level AdvancedConfiguration example. +func New(core zapcore.Core, options ...Option) *Logger { + if core == nil { + return NewNop() + } + log := &Logger{ + core: core, + errorOutput: zapcore.Lock(os.Stderr), + addStack: zapcore.FatalLevel + 1, + } + return log.WithOptions(options...) +} + +// NewNop returns a no-op Logger. It never writes out logs or internal errors, +// and it never runs user-defined hooks. +// +// Using WithOptions to replace the Core or error output of a no-op Logger can +// re-enable logging. +func NewNop() *Logger { + return &Logger{ + core: zapcore.NewNopCore(), + errorOutput: zapcore.AddSync(ioutil.Discard), + addStack: zapcore.FatalLevel + 1, + } +} + +// NewProduction builds a sensible production Logger that writes InfoLevel and +// above logs to standard error as JSON. +// +// It's a shortcut for NewProductionConfig().Build(...Option). +func NewProduction(options ...Option) (*Logger, error) { + return NewProductionConfig().Build(options...) +} + +// NewDevelopment builds a development Logger that writes DebugLevel and above +// logs to standard error in a human-friendly format. +// +// It's a shortcut for NewDevelopmentConfig().Build(...Option). +func NewDevelopment(options ...Option) (*Logger, error) { + return NewDevelopmentConfig().Build(options...) +} + +// NewExample builds a Logger that's designed for use in zap's testable +// examples. It writes DebugLevel and above logs to standard out as JSON, but +// omits the timestamp and calling function to keep example output +// short and deterministic. +func NewExample(options ...Option) *Logger { + encoderCfg := zapcore.EncoderConfig{ + MessageKey: "msg", + LevelKey: "level", + NameKey: "logger", + EncodeLevel: zapcore.LowercaseLevelEncoder, + EncodeTime: zapcore.ISO8601TimeEncoder, + EncodeDuration: zapcore.StringDurationEncoder, + } + core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel) + return New(core).WithOptions(options...) +} + +// Sugar wraps the Logger to provide a more ergonomic, but slightly slower, +// API. Sugaring a Logger is quite inexpensive, so it's reasonable for a +// single application to use both Loggers and SugaredLoggers, converting +// between them on the boundaries of performance-sensitive code. +func (log *Logger) Sugar() *SugaredLogger { + core := log.clone() + core.callerSkip += 2 + return &SugaredLogger{core} +} + +// Named adds a new path segment to the logger's name. Segments are joined by +// periods. By default, Loggers are unnamed. +func (log *Logger) Named(s string) *Logger { + if s == "" { + return log + } + l := log.clone() + if log.name == "" { + l.name = s + } else { + l.name = strings.Join([]string{l.name, s}, ".") + } + return l +} + +// WithOptions clones the current Logger, applies the supplied Options, and +// returns the resulting Logger. It's safe to use concurrently. +func (log *Logger) WithOptions(opts ...Option) *Logger { + c := log.clone() + for _, opt := range opts { + opt.apply(c) + } + return c +} + +// With creates a child logger and adds structured context to it. Fields added +// to the child don't affect the parent, and vice versa. +func (log *Logger) With(fields ...Field) *Logger { + if len(fields) == 0 { + return log + } + l := log.clone() + l.core = l.core.With(fields) + return l +} + +// Check returns a CheckedEntry if logging a message at the specified level +// is enabled. It's a completely optional optimization; in high-performance +// applications, Check can help avoid allocating a slice to hold fields. +func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { + return log.check(lvl, msg) +} + +// Debug logs a message at DebugLevel. The message includes any fields passed +// at the log site, as well as any fields accumulated on the logger. +func (log *Logger) Debug(msg string, fields ...Field) { + if ce := log.check(DebugLevel, msg); ce != nil { + ce.Write(fields...) + } +} + +// Info logs a message at InfoLevel. The message includes any fields passed +// at the log site, as well as any fields accumulated on the logger. +func (log *Logger) Info(msg string, fields ...Field) { + if ce := log.check(InfoLevel, msg); ce != nil { + ce.Write(fields...) + } +} + +// Warn logs a message at WarnLevel. The message includes any fields passed +// at the log site, as well as any fields accumulated on the logger. +func (log *Logger) Warn(msg string, fields ...Field) { + if ce := log.check(WarnLevel, msg); ce != nil { + ce.Write(fields...) + } +} + +// Error logs a message at ErrorLevel. The message includes any fields passed +// at the log site, as well as any fields accumulated on the logger. +func (log *Logger) Error(msg string, fields ...Field) { + if ce := log.check(ErrorLevel, msg); ce != nil { + ce.Write(fields...) + } +} + +// DPanic logs a message at DPanicLevel. The message includes any fields +// passed at the log site, as well as any fields accumulated on the logger. +// +// If the logger is in development mode, it then panics (DPanic means +// "development panic"). This is useful for catching errors that are +// recoverable, but shouldn't ever happen. +func (log *Logger) DPanic(msg string, fields ...Field) { + if ce := log.check(DPanicLevel, msg); ce != nil { + ce.Write(fields...) + } +} + +// Panic logs a message at PanicLevel. The message includes any fields passed +// at the log site, as well as any fields accumulated on the logger. +// +// The logger then panics, even if logging at PanicLevel is disabled. +func (log *Logger) Panic(msg string, fields ...Field) { + if ce := log.check(PanicLevel, msg); ce != nil { + ce.Write(fields...) + } +} + +// Fatal logs a message at FatalLevel. The message includes any fields passed +// at the log site, as well as any fields accumulated on the logger. +// +// The logger then calls os.Exit(1), even if logging at FatalLevel is +// disabled. +func (log *Logger) Fatal(msg string, fields ...Field) { + if ce := log.check(FatalLevel, msg); ce != nil { + ce.Write(fields...) + } +} + +// Sync calls the underlying Core's Sync method, flushing any buffered log +// entries. Applications should take care to call Sync before exiting. +func (log *Logger) Sync() error { + return log.core.Sync() +} + +// Core returns the Logger's underlying zapcore.Core. +func (log *Logger) Core() zapcore.Core { + return log.core +} + +func (log *Logger) clone() *Logger { + copy := *log + return © +} + +func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { + // check must always be called directly by a method in the Logger interface + // (e.g., Check, Info, Fatal). + const callerSkipOffset = 2 + + // Check the level first to reduce the cost of disabled log calls. + // Since Panic and higher may exit, we skip the optimization for those levels. + if lvl < zapcore.DPanicLevel && !log.core.Enabled(lvl) { + return nil + } + + // Create basic checked entry thru the core; this will be non-nil if the + // log message will actually be written somewhere. + ent := zapcore.Entry{ + LoggerName: log.name, + Time: time.Now(), + Level: lvl, + Message: msg, + } + ce := log.core.Check(ent, nil) + willWrite := ce != nil + + // Set up any required terminal behavior. + switch ent.Level { + case zapcore.PanicLevel: + ce = ce.Should(ent, zapcore.WriteThenPanic) + case zapcore.FatalLevel: + ce = ce.Should(ent, zapcore.WriteThenFatal) + case zapcore.DPanicLevel: + if log.development { + ce = ce.Should(ent, zapcore.WriteThenPanic) + } + } + + // Only do further annotation if we're going to write this message; checked + // entries that exist only for terminal behavior don't benefit from + // annotation. + if !willWrite { + return ce + } + + // Thread the error output through to the CheckedEntry. + ce.ErrorOutput = log.errorOutput + if log.addCaller { + ce.Entry.Caller = zapcore.NewEntryCaller(runtime.Caller(log.callerSkip + callerSkipOffset)) + if !ce.Entry.Caller.Defined { + fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC()) + log.errorOutput.Sync() + } + } + if log.addStack.Enabled(ce.Entry.Level) { + ce.Entry.Stack = Stack("").String + } + + return ce +} diff --git a/vendor/go.uber.org/zap/options.go b/vendor/go.uber.org/zap/options.go new file mode 100644 index 0000000000..59f1b54a04 --- /dev/null +++ b/vendor/go.uber.org/zap/options.go @@ -0,0 +1,133 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "fmt" + + "go.uber.org/zap/zapcore" +) + +// An Option configures a Logger. +type Option interface { + apply(*Logger) +} + +// optionFunc wraps a func so it satisfies the Option interface. +type optionFunc func(*Logger) + +func (f optionFunc) apply(log *Logger) { + f(log) +} + +// WrapCore wraps or replaces the Logger's underlying zapcore.Core. +func WrapCore(f func(zapcore.Core) zapcore.Core) Option { + return optionFunc(func(log *Logger) { + log.core = f(log.core) + }) +} + +// Hooks registers functions which will be called each time the Logger writes +// out an Entry. Repeated use of Hooks is additive. +// +// Hooks are useful for simple side effects, like capturing metrics for the +// number of emitted logs. More complex side effects, including anything that +// requires access to the Entry's structured fields, should be implemented as +// a zapcore.Core instead. See zapcore.RegisterHooks for details. +func Hooks(hooks ...func(zapcore.Entry) error) Option { + return optionFunc(func(log *Logger) { + log.core = zapcore.RegisterHooks(log.core, hooks...) + }) +} + +// Fields adds fields to the Logger. +func Fields(fs ...Field) Option { + return optionFunc(func(log *Logger) { + log.core = log.core.With(fs) + }) +} + +// ErrorOutput sets the destination for errors generated by the Logger. Note +// that this option only affects internal errors; for sample code that sends +// error-level logs to a different location from info- and debug-level logs, +// see the package-level AdvancedConfiguration example. +// +// The supplied WriteSyncer must be safe for concurrent use. The Open and +// zapcore.Lock functions are the simplest ways to protect files with a mutex. +func ErrorOutput(w zapcore.WriteSyncer) Option { + return optionFunc(func(log *Logger) { + log.errorOutput = w + }) +} + +// Development puts the logger in development mode, which makes DPanic-level +// logs panic instead of simply logging an error. +func Development() Option { + return optionFunc(func(log *Logger) { + log.development = true + }) +} + +// AddCaller configures the Logger to annotate each message with the filename +// and line number of zap's caller. See also WithCaller. +func AddCaller() Option { + return WithCaller(true) +} + +// WithCaller configures the Logger to annotate each message with the filename +// and line number of zap's caller, or not, depending on the value of enabled. +// This is a generalized form of AddCaller. +func WithCaller(enabled bool) Option { + return optionFunc(func(log *Logger) { + log.addCaller = enabled + }) +} + +// AddCallerSkip increases the number of callers skipped by caller annotation +// (as enabled by the AddCaller option). When building wrappers around the +// Logger and SugaredLogger, supplying this Option prevents zap from always +// reporting the wrapper code as the caller. +func AddCallerSkip(skip int) Option { + return optionFunc(func(log *Logger) { + log.callerSkip += skip + }) +} + +// AddStacktrace configures the Logger to record a stack trace for all messages at +// or above a given level. +func AddStacktrace(lvl zapcore.LevelEnabler) Option { + return optionFunc(func(log *Logger) { + log.addStack = lvl + }) +} + +// IncreaseLevel increase the level of the logger. It has no effect if +// the passed in level tries to decrease the level of the logger. +func IncreaseLevel(lvl zapcore.LevelEnabler) Option { + return optionFunc(func(log *Logger) { + core, err := zapcore.NewIncreaseLevelCore(log.core, lvl) + if err != nil { + fmt.Fprintf(log.errorOutput, "failed to IncreaseLevel: %v", err) + } else { + log.core = core + } + }) +} diff --git a/vendor/go.uber.org/zap/sink.go b/vendor/go.uber.org/zap/sink.go new file mode 100644 index 0000000000..ff0becfe5d --- /dev/null +++ b/vendor/go.uber.org/zap/sink.go @@ -0,0 +1,161 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "errors" + "fmt" + "io" + "net/url" + "os" + "strings" + "sync" + + "go.uber.org/zap/zapcore" +) + +const schemeFile = "file" + +var ( + _sinkMutex sync.RWMutex + _sinkFactories map[string]func(*url.URL) (Sink, error) // keyed by scheme +) + +func init() { + resetSinkRegistry() +} + +func resetSinkRegistry() { + _sinkMutex.Lock() + defer _sinkMutex.Unlock() + + _sinkFactories = map[string]func(*url.URL) (Sink, error){ + schemeFile: newFileSink, + } +} + +// Sink defines the interface to write to and close logger destinations. +type Sink interface { + zapcore.WriteSyncer + io.Closer +} + +type nopCloserSink struct{ zapcore.WriteSyncer } + +func (nopCloserSink) Close() error { return nil } + +type errSinkNotFound struct { + scheme string +} + +func (e *errSinkNotFound) Error() string { + return fmt.Sprintf("no sink found for scheme %q", e.scheme) +} + +// RegisterSink registers a user-supplied factory for all sinks with a +// particular scheme. +// +// All schemes must be ASCII, valid under section 3.1 of RFC 3986 +// (https://tools.ietf.org/html/rfc3986#section-3.1), and must not already +// have a factory registered. Zap automatically registers a factory for the +// "file" scheme. +func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { + _sinkMutex.Lock() + defer _sinkMutex.Unlock() + + if scheme == "" { + return errors.New("can't register a sink factory for empty string") + } + normalized, err := normalizeScheme(scheme) + if err != nil { + return fmt.Errorf("%q is not a valid scheme: %v", scheme, err) + } + if _, ok := _sinkFactories[normalized]; ok { + return fmt.Errorf("sink factory already registered for scheme %q", normalized) + } + _sinkFactories[normalized] = factory + return nil +} + +func newSink(rawURL string) (Sink, error) { + u, err := url.Parse(rawURL) + if err != nil { + return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err) + } + if u.Scheme == "" { + u.Scheme = schemeFile + } + + _sinkMutex.RLock() + factory, ok := _sinkFactories[u.Scheme] + _sinkMutex.RUnlock() + if !ok { + return nil, &errSinkNotFound{u.Scheme} + } + return factory(u) +} + +func newFileSink(u *url.URL) (Sink, error) { + if u.User != nil { + return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u) + } + if u.Fragment != "" { + return nil, fmt.Errorf("fragments not allowed with file URLs: got %v", u) + } + if u.RawQuery != "" { + return nil, fmt.Errorf("query parameters not allowed with file URLs: got %v", u) + } + // Error messages are better if we check hostname and port separately. + if u.Port() != "" { + return nil, fmt.Errorf("ports not allowed with file URLs: got %v", u) + } + if hn := u.Hostname(); hn != "" && hn != "localhost" { + return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u) + } + switch u.Path { + case "stdout": + return nopCloserSink{os.Stdout}, nil + case "stderr": + return nopCloserSink{os.Stderr}, nil + } + return os.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) +} + +func normalizeScheme(s string) (string, error) { + // https://tools.ietf.org/html/rfc3986#section-3.1 + s = strings.ToLower(s) + if first := s[0]; 'a' > first || 'z' < first { + return "", errors.New("must start with a letter") + } + for i := 1; i < len(s); i++ { // iterate over bytes, not runes + c := s[i] + switch { + case 'a' <= c && c <= 'z': + continue + case '0' <= c && c <= '9': + continue + case c == '.' || c == '+' || c == '-': + continue + } + return "", fmt.Errorf("may not contain %q", c) + } + return s, nil +} diff --git a/vendor/go.uber.org/zap/stacktrace.go b/vendor/go.uber.org/zap/stacktrace.go new file mode 100644 index 0000000000..100fac2168 --- /dev/null +++ b/vendor/go.uber.org/zap/stacktrace.go @@ -0,0 +1,126 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "runtime" + "strings" + "sync" + + "go.uber.org/zap/internal/bufferpool" +) + +const _zapPackage = "go.uber.org/zap" + +var ( + _stacktracePool = sync.Pool{ + New: func() interface{} { + return newProgramCounters(64) + }, + } + + // We add "." and "/" suffixes to the package name to ensure we only match + // the exact package and not any package with the same prefix. + _zapStacktracePrefixes = addPrefix(_zapPackage, ".", "/") + _zapStacktraceVendorContains = addPrefix("/vendor/", _zapStacktracePrefixes...) +) + +func takeStacktrace() string { + buffer := bufferpool.Get() + defer buffer.Free() + programCounters := _stacktracePool.Get().(*programCounters) + defer _stacktracePool.Put(programCounters) + + var numFrames int + for { + // Skip the call to runtime.Counters and takeStacktrace so that the + // program counters start at the caller of takeStacktrace. + numFrames = runtime.Callers(2, programCounters.pcs) + if numFrames < len(programCounters.pcs) { + break + } + // Don't put the too-short counter slice back into the pool; this lets + // the pool adjust if we consistently take deep stacktraces. + programCounters = newProgramCounters(len(programCounters.pcs) * 2) + } + + i := 0 + skipZapFrames := true // skip all consecutive zap frames at the beginning. + frames := runtime.CallersFrames(programCounters.pcs[:numFrames]) + + // Note: On the last iteration, frames.Next() returns false, with a valid + // frame, but we ignore this frame. The last frame is a a runtime frame which + // adds noise, since it's only either runtime.main or runtime.goexit. + for frame, more := frames.Next(); more; frame, more = frames.Next() { + if skipZapFrames && isZapFrame(frame.Function) { + continue + } else { + skipZapFrames = false + } + + if i != 0 { + buffer.AppendByte('\n') + } + i++ + buffer.AppendString(frame.Function) + buffer.AppendByte('\n') + buffer.AppendByte('\t') + buffer.AppendString(frame.File) + buffer.AppendByte(':') + buffer.AppendInt(int64(frame.Line)) + } + + return buffer.String() +} + +func isZapFrame(function string) bool { + for _, prefix := range _zapStacktracePrefixes { + if strings.HasPrefix(function, prefix) { + return true + } + } + + // We can't use a prefix match here since the location of the vendor + // directory affects the prefix. Instead we do a contains match. + for _, contains := range _zapStacktraceVendorContains { + if strings.Contains(function, contains) { + return true + } + } + + return false +} + +type programCounters struct { + pcs []uintptr +} + +func newProgramCounters(size int) *programCounters { + return &programCounters{make([]uintptr, size)} +} + +func addPrefix(prefix string, ss ...string) []string { + withPrefix := make([]string, len(ss)) + for i, s := range ss { + withPrefix[i] = prefix + s + } + return withPrefix +} diff --git a/vendor/go.uber.org/zap/sugar.go b/vendor/go.uber.org/zap/sugar.go new file mode 100644 index 0000000000..77ca227f47 --- /dev/null +++ b/vendor/go.uber.org/zap/sugar.go @@ -0,0 +1,304 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "fmt" + + "go.uber.org/zap/zapcore" + + "go.uber.org/multierr" +) + +const ( + _oddNumberErrMsg = "Ignored key without a value." + _nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys." +) + +// A SugaredLogger wraps the base Logger functionality in a slower, but less +// verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar +// method. +// +// Unlike the Logger, the SugaredLogger doesn't insist on structured logging. +// For each log level, it exposes three methods: one for loosely-typed +// structured logging, one for println-style formatting, and one for +// printf-style formatting. For example, SugaredLoggers can produce InfoLevel +// output with Infow ("info with" structured context), Info, or Infof. +type SugaredLogger struct { + base *Logger +} + +// Desugar unwraps a SugaredLogger, exposing the original Logger. Desugaring +// is quite inexpensive, so it's reasonable for a single application to use +// both Loggers and SugaredLoggers, converting between them on the boundaries +// of performance-sensitive code. +func (s *SugaredLogger) Desugar() *Logger { + base := s.base.clone() + base.callerSkip -= 2 + return base +} + +// Named adds a sub-scope to the logger's name. See Logger.Named for details. +func (s *SugaredLogger) Named(name string) *SugaredLogger { + return &SugaredLogger{base: s.base.Named(name)} +} + +// With adds a variadic number of fields to the logging context. It accepts a +// mix of strongly-typed Field objects and loosely-typed key-value pairs. When +// processing pairs, the first element of the pair is used as the field key +// and the second as the field value. +// +// For example, +// sugaredLogger.With( +// "hello", "world", +// "failure", errors.New("oh no"), +// Stack(), +// "count", 42, +// "user", User{Name: "alice"}, +// ) +// is the equivalent of +// unsugared.With( +// String("hello", "world"), +// String("failure", "oh no"), +// Stack(), +// Int("count", 42), +// Object("user", User{Name: "alice"}), +// ) +// +// Note that the keys in key-value pairs should be strings. In development, +// passing a non-string key panics. In production, the logger is more +// forgiving: a separate error is logged, but the key-value pair is skipped +// and execution continues. Passing an orphaned key triggers similar behavior: +// panics in development and errors in production. +func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger { + return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)} +} + +// Debug uses fmt.Sprint to construct and log a message. +func (s *SugaredLogger) Debug(args ...interface{}) { + s.log(DebugLevel, "", args, nil) +} + +// Info uses fmt.Sprint to construct and log a message. +func (s *SugaredLogger) Info(args ...interface{}) { + s.log(InfoLevel, "", args, nil) +} + +// Warn uses fmt.Sprint to construct and log a message. +func (s *SugaredLogger) Warn(args ...interface{}) { + s.log(WarnLevel, "", args, nil) +} + +// Error uses fmt.Sprint to construct and log a message. +func (s *SugaredLogger) Error(args ...interface{}) { + s.log(ErrorLevel, "", args, nil) +} + +// DPanic uses fmt.Sprint to construct and log a message. In development, the +// logger then panics. (See DPanicLevel for details.) +func (s *SugaredLogger) DPanic(args ...interface{}) { + s.log(DPanicLevel, "", args, nil) +} + +// Panic uses fmt.Sprint to construct and log a message, then panics. +func (s *SugaredLogger) Panic(args ...interface{}) { + s.log(PanicLevel, "", args, nil) +} + +// Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit. +func (s *SugaredLogger) Fatal(args ...interface{}) { + s.log(FatalLevel, "", args, nil) +} + +// Debugf uses fmt.Sprintf to log a templated message. +func (s *SugaredLogger) Debugf(template string, args ...interface{}) { + s.log(DebugLevel, template, args, nil) +} + +// Infof uses fmt.Sprintf to log a templated message. +func (s *SugaredLogger) Infof(template string, args ...interface{}) { + s.log(InfoLevel, template, args, nil) +} + +// Warnf uses fmt.Sprintf to log a templated message. +func (s *SugaredLogger) Warnf(template string, args ...interface{}) { + s.log(WarnLevel, template, args, nil) +} + +// Errorf uses fmt.Sprintf to log a templated message. +func (s *SugaredLogger) Errorf(template string, args ...interface{}) { + s.log(ErrorLevel, template, args, nil) +} + +// DPanicf uses fmt.Sprintf to log a templated message. In development, the +// logger then panics. (See DPanicLevel for details.) +func (s *SugaredLogger) DPanicf(template string, args ...interface{}) { + s.log(DPanicLevel, template, args, nil) +} + +// Panicf uses fmt.Sprintf to log a templated message, then panics. +func (s *SugaredLogger) Panicf(template string, args ...interface{}) { + s.log(PanicLevel, template, args, nil) +} + +// Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. +func (s *SugaredLogger) Fatalf(template string, args ...interface{}) { + s.log(FatalLevel, template, args, nil) +} + +// Debugw logs a message with some additional context. The variadic key-value +// pairs are treated as they are in With. +// +// When debug-level logging is disabled, this is much faster than +// s.With(keysAndValues).Debug(msg) +func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{}) { + s.log(DebugLevel, msg, nil, keysAndValues) +} + +// Infow logs a message with some additional context. The variadic key-value +// pairs are treated as they are in With. +func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{}) { + s.log(InfoLevel, msg, nil, keysAndValues) +} + +// Warnw logs a message with some additional context. The variadic key-value +// pairs are treated as they are in With. +func (s *SugaredLogger) Warnw(msg string, keysAndValues ...interface{}) { + s.log(WarnLevel, msg, nil, keysAndValues) +} + +// Errorw logs a message with some additional context. The variadic key-value +// pairs are treated as they are in With. +func (s *SugaredLogger) Errorw(msg string, keysAndValues ...interface{}) { + s.log(ErrorLevel, msg, nil, keysAndValues) +} + +// DPanicw logs a message with some additional context. In development, the +// logger then panics. (See DPanicLevel for details.) The variadic key-value +// pairs are treated as they are in With. +func (s *SugaredLogger) DPanicw(msg string, keysAndValues ...interface{}) { + s.log(DPanicLevel, msg, nil, keysAndValues) +} + +// Panicw logs a message with some additional context, then panics. The +// variadic key-value pairs are treated as they are in With. +func (s *SugaredLogger) Panicw(msg string, keysAndValues ...interface{}) { + s.log(PanicLevel, msg, nil, keysAndValues) +} + +// Fatalw logs a message with some additional context, then calls os.Exit. The +// variadic key-value pairs are treated as they are in With. +func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) { + s.log(FatalLevel, msg, nil, keysAndValues) +} + +// Sync flushes any buffered log entries. +func (s *SugaredLogger) Sync() error { + return s.base.Sync() +} + +func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) { + // If logging at this level is completely disabled, skip the overhead of + // string formatting. + if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) { + return + } + + // Format with Sprint, Sprintf, or neither. + msg := template + if msg == "" && len(fmtArgs) > 0 { + msg = fmt.Sprint(fmtArgs...) + } else if msg != "" && len(fmtArgs) > 0 { + msg = fmt.Sprintf(template, fmtArgs...) + } + + if ce := s.base.Check(lvl, msg); ce != nil { + ce.Write(s.sweetenFields(context)...) + } +} + +func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { + if len(args) == 0 { + return nil + } + + // Allocate enough space for the worst case; if users pass only structured + // fields, we shouldn't penalize them with extra allocations. + fields := make([]Field, 0, len(args)) + var invalid invalidPairs + + for i := 0; i < len(args); { + // This is a strongly-typed field. Consume it and move on. + if f, ok := args[i].(Field); ok { + fields = append(fields, f) + i++ + continue + } + + // Make sure this element isn't a dangling key. + if i == len(args)-1 { + s.base.DPanic(_oddNumberErrMsg, Any("ignored", args[i])) + break + } + + // Consume this value and the next, treating them as a key-value pair. If the + // key isn't a string, add this pair to the slice of invalid pairs. + key, val := args[i], args[i+1] + if keyStr, ok := key.(string); !ok { + // Subsequent errors are likely, so allocate once up front. + if cap(invalid) == 0 { + invalid = make(invalidPairs, 0, len(args)/2) + } + invalid = append(invalid, invalidPair{i, key, val}) + } else { + fields = append(fields, Any(keyStr, val)) + } + i += 2 + } + + // If we encountered any invalid key-value pairs, log an error. + if len(invalid) > 0 { + s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid)) + } + return fields +} + +type invalidPair struct { + position int + key, value interface{} +} + +func (p invalidPair) MarshalLogObject(enc zapcore.ObjectEncoder) error { + enc.AddInt64("position", int64(p.position)) + Any("key", p.key).AddTo(enc) + Any("value", p.value).AddTo(enc) + return nil +} + +type invalidPairs []invalidPair + +func (ps invalidPairs) MarshalLogArray(enc zapcore.ArrayEncoder) error { + var err error + for i := range ps { + err = multierr.Append(err, enc.AppendObject(ps[i])) + } + return err +} diff --git a/vendor/go.uber.org/zap/time.go b/vendor/go.uber.org/zap/time.go new file mode 100644 index 0000000000..c5a1f16225 --- /dev/null +++ b/vendor/go.uber.org/zap/time.go @@ -0,0 +1,27 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import "time" + +func timeToMillis(t time.Time) int64 { + return t.UnixNano() / int64(time.Millisecond) +} diff --git a/vendor/go.uber.org/zap/writer.go b/vendor/go.uber.org/zap/writer.go new file mode 100644 index 0000000000..86a709ab0b --- /dev/null +++ b/vendor/go.uber.org/zap/writer.go @@ -0,0 +1,99 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zap + +import ( + "fmt" + "io" + "io/ioutil" + + "go.uber.org/zap/zapcore" + + "go.uber.org/multierr" +) + +// Open is a high-level wrapper that takes a variadic number of URLs, opens or +// creates each of the specified resources, and combines them into a locked +// WriteSyncer. It also returns any error encountered and a function to close +// any opened files. +// +// Passing no URLs returns a no-op WriteSyncer. Zap handles URLs without a +// scheme and URLs with the "file" scheme. Third-party code may register +// factories for other schemes using RegisterSink. +// +// URLs with the "file" scheme must use absolute paths on the local +// filesystem. No user, password, port, fragments, or query parameters are +// allowed, and the hostname must be empty or "localhost". +// +// Since it's common to write logs to the local filesystem, URLs without a +// scheme (e.g., "/var/log/foo.log") are treated as local file paths. Without +// a scheme, the special paths "stdout" and "stderr" are interpreted as +// os.Stdout and os.Stderr. When specified without a scheme, relative file +// paths also work. +func Open(paths ...string) (zapcore.WriteSyncer, func(), error) { + writers, close, err := open(paths) + if err != nil { + return nil, nil, err + } + + writer := CombineWriteSyncers(writers...) + return writer, close, nil +} + +func open(paths []string) ([]zapcore.WriteSyncer, func(), error) { + writers := make([]zapcore.WriteSyncer, 0, len(paths)) + closers := make([]io.Closer, 0, len(paths)) + close := func() { + for _, c := range closers { + c.Close() + } + } + + var openErr error + for _, path := range paths { + sink, err := newSink(path) + if err != nil { + openErr = multierr.Append(openErr, fmt.Errorf("couldn't open sink %q: %v", path, err)) + continue + } + writers = append(writers, sink) + closers = append(closers, sink) + } + if openErr != nil { + close() + return writers, nil, openErr + } + + return writers, close, nil +} + +// CombineWriteSyncers is a utility that combines multiple WriteSyncers into a +// single, locked WriteSyncer. If no inputs are supplied, it returns a no-op +// WriteSyncer. +// +// It's provided purely as a convenience; the result is no different from +// using zapcore.NewMultiWriteSyncer and zapcore.Lock individually. +func CombineWriteSyncers(writers ...zapcore.WriteSyncer) zapcore.WriteSyncer { + if len(writers) == 0 { + return zapcore.AddSync(ioutil.Discard) + } + return zapcore.Lock(zapcore.NewMultiWriteSyncer(writers...)) +} diff --git a/vendor/go.uber.org/zap/zapcore/console_encoder.go b/vendor/go.uber.org/zap/zapcore/console_encoder.go new file mode 100644 index 0000000000..b7875966f4 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/console_encoder.go @@ -0,0 +1,147 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "fmt" + "sync" + + "go.uber.org/zap/buffer" + "go.uber.org/zap/internal/bufferpool" +) + +var _sliceEncoderPool = sync.Pool{ + New: func() interface{} { + return &sliceArrayEncoder{elems: make([]interface{}, 0, 2)} + }, +} + +func getSliceEncoder() *sliceArrayEncoder { + return _sliceEncoderPool.Get().(*sliceArrayEncoder) +} + +func putSliceEncoder(e *sliceArrayEncoder) { + e.elems = e.elems[:0] + _sliceEncoderPool.Put(e) +} + +type consoleEncoder struct { + *jsonEncoder +} + +// NewConsoleEncoder creates an encoder whose output is designed for human - +// rather than machine - consumption. It serializes the core log entry data +// (message, level, timestamp, etc.) in a plain-text format and leaves the +// structured context as JSON. +// +// Note that although the console encoder doesn't use the keys specified in the +// encoder configuration, it will omit any element whose key is set to the empty +// string. +func NewConsoleEncoder(cfg EncoderConfig) Encoder { + return consoleEncoder{newJSONEncoder(cfg, true)} +} + +func (c consoleEncoder) Clone() Encoder { + return consoleEncoder{c.jsonEncoder.Clone().(*jsonEncoder)} +} + +func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) { + line := bufferpool.Get() + + // We don't want the entry's metadata to be quoted and escaped (if it's + // encoded as strings), which means that we can't use the JSON encoder. The + // simplest option is to use the memory encoder and fmt.Fprint. + // + // If this ever becomes a performance bottleneck, we can implement + // ArrayEncoder for our plain-text format. + arr := getSliceEncoder() + if c.TimeKey != "" && c.EncodeTime != nil { + c.EncodeTime(ent.Time, arr) + } + if c.LevelKey != "" && c.EncodeLevel != nil { + c.EncodeLevel(ent.Level, arr) + } + if ent.LoggerName != "" && c.NameKey != "" { + nameEncoder := c.EncodeName + + if nameEncoder == nil { + // Fall back to FullNameEncoder for backward compatibility. + nameEncoder = FullNameEncoder + } + + nameEncoder(ent.LoggerName, arr) + } + if ent.Caller.Defined && c.CallerKey != "" && c.EncodeCaller != nil { + c.EncodeCaller(ent.Caller, arr) + } + for i := range arr.elems { + if i > 0 { + line.AppendByte('\t') + } + fmt.Fprint(line, arr.elems[i]) + } + putSliceEncoder(arr) + + // Add the message itself. + if c.MessageKey != "" { + c.addTabIfNecessary(line) + line.AppendString(ent.Message) + } + + // Add any structured context. + c.writeContext(line, fields) + + // If there's no stacktrace key, honor that; this allows users to force + // single-line output. + if ent.Stack != "" && c.StacktraceKey != "" { + line.AppendByte('\n') + line.AppendString(ent.Stack) + } + + if c.LineEnding != "" { + line.AppendString(c.LineEnding) + } else { + line.AppendString(DefaultLineEnding) + } + return line, nil +} + +func (c consoleEncoder) writeContext(line *buffer.Buffer, extra []Field) { + context := c.jsonEncoder.Clone().(*jsonEncoder) + defer context.buf.Free() + + addFields(context, extra) + context.closeOpenNamespaces() + if context.buf.Len() == 0 { + return + } + + c.addTabIfNecessary(line) + line.AppendByte('{') + line.Write(context.buf.Bytes()) + line.AppendByte('}') +} + +func (c consoleEncoder) addTabIfNecessary(line *buffer.Buffer) { + if line.Len() > 0 { + line.AppendByte('\t') + } +} diff --git a/vendor/go.uber.org/zap/zapcore/core.go b/vendor/go.uber.org/zap/zapcore/core.go new file mode 100644 index 0000000000..a1ef8b034b --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/core.go @@ -0,0 +1,113 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +// Core is a minimal, fast logger interface. It's designed for library authors +// to wrap in a more user-friendly API. +type Core interface { + LevelEnabler + + // With adds structured context to the Core. + With([]Field) Core + // Check determines whether the supplied Entry should be logged (using the + // embedded LevelEnabler and possibly some extra logic). If the entry + // should be logged, the Core adds itself to the CheckedEntry and returns + // the result. + // + // Callers must use Check before calling Write. + Check(Entry, *CheckedEntry) *CheckedEntry + // Write serializes the Entry and any Fields supplied at the log site and + // writes them to their destination. + // + // If called, Write should always log the Entry and Fields; it should not + // replicate the logic of Check. + Write(Entry, []Field) error + // Sync flushes buffered logs (if any). + Sync() error +} + +type nopCore struct{} + +// NewNopCore returns a no-op Core. +func NewNopCore() Core { return nopCore{} } +func (nopCore) Enabled(Level) bool { return false } +func (n nopCore) With([]Field) Core { return n } +func (nopCore) Check(_ Entry, ce *CheckedEntry) *CheckedEntry { return ce } +func (nopCore) Write(Entry, []Field) error { return nil } +func (nopCore) Sync() error { return nil } + +// NewCore creates a Core that writes logs to a WriteSyncer. +func NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core { + return &ioCore{ + LevelEnabler: enab, + enc: enc, + out: ws, + } +} + +type ioCore struct { + LevelEnabler + enc Encoder + out WriteSyncer +} + +func (c *ioCore) With(fields []Field) Core { + clone := c.clone() + addFields(clone.enc, fields) + return clone +} + +func (c *ioCore) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { + if c.Enabled(ent.Level) { + return ce.AddCore(ent, c) + } + return ce +} + +func (c *ioCore) Write(ent Entry, fields []Field) error { + buf, err := c.enc.EncodeEntry(ent, fields) + if err != nil { + return err + } + _, err = c.out.Write(buf.Bytes()) + buf.Free() + if err != nil { + return err + } + if ent.Level > ErrorLevel { + // Since we may be crashing the program, sync the output. Ignore Sync + // errors, pending a clean solution to issue #370. + c.Sync() + } + return nil +} + +func (c *ioCore) Sync() error { + return c.out.Sync() +} + +func (c *ioCore) clone() *ioCore { + return &ioCore{ + LevelEnabler: c.LevelEnabler, + enc: c.enc.Clone(), + out: c.out, + } +} diff --git a/vendor/go.uber.org/zap/zapcore/doc.go b/vendor/go.uber.org/zap/zapcore/doc.go new file mode 100644 index 0000000000..31000e91f7 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/doc.go @@ -0,0 +1,24 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package zapcore defines and implements the low-level interfaces upon which +// zap is built. By providing alternate implementations of these interfaces, +// external packages can extend zap's capabilities. +package zapcore // import "go.uber.org/zap/zapcore" diff --git a/vendor/go.uber.org/zap/zapcore/encoder.go b/vendor/go.uber.org/zap/zapcore/encoder.go new file mode 100644 index 0000000000..6c78f7e49a --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/encoder.go @@ -0,0 +1,401 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "time" + + "go.uber.org/zap/buffer" +) + +// DefaultLineEnding defines the default line ending when writing logs. +// Alternate line endings specified in EncoderConfig can override this +// behavior. +const DefaultLineEnding = "\n" + +// OmitKey defines the key to use when callers want to remove a key from log output. +const OmitKey = "" + +// A LevelEncoder serializes a Level to a primitive type. +type LevelEncoder func(Level, PrimitiveArrayEncoder) + +// LowercaseLevelEncoder serializes a Level to a lowercase string. For example, +// InfoLevel is serialized to "info". +func LowercaseLevelEncoder(l Level, enc PrimitiveArrayEncoder) { + enc.AppendString(l.String()) +} + +// LowercaseColorLevelEncoder serializes a Level to a lowercase string and adds coloring. +// For example, InfoLevel is serialized to "info" and colored blue. +func LowercaseColorLevelEncoder(l Level, enc PrimitiveArrayEncoder) { + s, ok := _levelToLowercaseColorString[l] + if !ok { + s = _unknownLevelColor.Add(l.String()) + } + enc.AppendString(s) +} + +// CapitalLevelEncoder serializes a Level to an all-caps string. For example, +// InfoLevel is serialized to "INFO". +func CapitalLevelEncoder(l Level, enc PrimitiveArrayEncoder) { + enc.AppendString(l.CapitalString()) +} + +// CapitalColorLevelEncoder serializes a Level to an all-caps string and adds color. +// For example, InfoLevel is serialized to "INFO" and colored blue. +func CapitalColorLevelEncoder(l Level, enc PrimitiveArrayEncoder) { + s, ok := _levelToCapitalColorString[l] + if !ok { + s = _unknownLevelColor.Add(l.CapitalString()) + } + enc.AppendString(s) +} + +// UnmarshalText unmarshals text to a LevelEncoder. "capital" is unmarshaled to +// CapitalLevelEncoder, "coloredCapital" is unmarshaled to CapitalColorLevelEncoder, +// "colored" is unmarshaled to LowercaseColorLevelEncoder, and anything else +// is unmarshaled to LowercaseLevelEncoder. +func (e *LevelEncoder) UnmarshalText(text []byte) error { + switch string(text) { + case "capital": + *e = CapitalLevelEncoder + case "capitalColor": + *e = CapitalColorLevelEncoder + case "color": + *e = LowercaseColorLevelEncoder + default: + *e = LowercaseLevelEncoder + } + return nil +} + +// A TimeEncoder serializes a time.Time to a primitive type. +type TimeEncoder func(time.Time, PrimitiveArrayEncoder) + +// EpochTimeEncoder serializes a time.Time to a floating-point number of seconds +// since the Unix epoch. +func EpochTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { + nanos := t.UnixNano() + sec := float64(nanos) / float64(time.Second) + enc.AppendFloat64(sec) +} + +// EpochMillisTimeEncoder serializes a time.Time to a floating-point number of +// milliseconds since the Unix epoch. +func EpochMillisTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { + nanos := t.UnixNano() + millis := float64(nanos) / float64(time.Millisecond) + enc.AppendFloat64(millis) +} + +// EpochNanosTimeEncoder serializes a time.Time to an integer number of +// nanoseconds since the Unix epoch. +func EpochNanosTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { + enc.AppendInt64(t.UnixNano()) +} + +func encodeTimeLayout(t time.Time, layout string, enc PrimitiveArrayEncoder) { + type appendTimeEncoder interface { + AppendTimeLayout(time.Time, string) + } + + if enc, ok := enc.(appendTimeEncoder); ok { + enc.AppendTimeLayout(t, layout) + return + } + + enc.AppendString(t.Format(layout)) +} + +// ISO8601TimeEncoder serializes a time.Time to an ISO8601-formatted string +// with millisecond precision. +// +// If enc supports AppendTimeLayout(t time.Time,layout string), it's used +// instead of appending a pre-formatted string value. +func ISO8601TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { + encodeTimeLayout(t, "2006-01-02T15:04:05.000Z0700", enc) +} + +// RFC3339TimeEncoder serializes a time.Time to an RFC3339-formatted string. +// +// If enc supports AppendTimeLayout(t time.Time,layout string), it's used +// instead of appending a pre-formatted string value. +func RFC3339TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { + encodeTimeLayout(t, time.RFC3339, enc) +} + +// RFC3339NanoTimeEncoder serializes a time.Time to an RFC3339-formatted string +// with nanosecond precision. +// +// If enc supports AppendTimeLayout(t time.Time,layout string), it's used +// instead of appending a pre-formatted string value. +func RFC3339NanoTimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { + encodeTimeLayout(t, time.RFC3339Nano, enc) +} + +// UnmarshalText unmarshals text to a TimeEncoder. +// "rfc3339nano" and "RFC3339Nano" are unmarshaled to RFC3339NanoTimeEncoder. +// "rfc3339" and "RFC3339" are unmarshaled to RFC3339TimeEncoder. +// "iso8601" and "ISO8601" are unmarshaled to ISO8601TimeEncoder. +// "millis" is unmarshaled to EpochMillisTimeEncoder. +// "nanos" is unmarshaled to EpochNanosEncoder. +// Anything else is unmarshaled to EpochTimeEncoder. +func (e *TimeEncoder) UnmarshalText(text []byte) error { + switch string(text) { + case "rfc3339nano", "RFC3339Nano": + *e = RFC3339NanoTimeEncoder + case "rfc3339", "RFC3339": + *e = RFC3339TimeEncoder + case "iso8601", "ISO8601": + *e = ISO8601TimeEncoder + case "millis": + *e = EpochMillisTimeEncoder + case "nanos": + *e = EpochNanosTimeEncoder + default: + *e = EpochTimeEncoder + } + return nil +} + +// A DurationEncoder serializes a time.Duration to a primitive type. +type DurationEncoder func(time.Duration, PrimitiveArrayEncoder) + +// SecondsDurationEncoder serializes a time.Duration to a floating-point number of seconds elapsed. +func SecondsDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) { + enc.AppendFloat64(float64(d) / float64(time.Second)) +} + +// NanosDurationEncoder serializes a time.Duration to an integer number of +// nanoseconds elapsed. +func NanosDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) { + enc.AppendInt64(int64(d)) +} + +// MillisDurationEncoder serializes a time.Duration to an integer number of +// milliseconds elapsed. +func MillisDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) { + enc.AppendInt64(d.Nanoseconds() / 1e6) +} + +// StringDurationEncoder serializes a time.Duration using its built-in String +// method. +func StringDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) { + enc.AppendString(d.String()) +} + +// UnmarshalText unmarshals text to a DurationEncoder. "string" is unmarshaled +// to StringDurationEncoder, and anything else is unmarshaled to +// NanosDurationEncoder. +func (e *DurationEncoder) UnmarshalText(text []byte) error { + switch string(text) { + case "string": + *e = StringDurationEncoder + case "nanos": + *e = NanosDurationEncoder + case "ms": + *e = MillisDurationEncoder + default: + *e = SecondsDurationEncoder + } + return nil +} + +// A CallerEncoder serializes an EntryCaller to a primitive type. +type CallerEncoder func(EntryCaller, PrimitiveArrayEncoder) + +// FullCallerEncoder serializes a caller in /full/path/to/package/file:line +// format. +func FullCallerEncoder(caller EntryCaller, enc PrimitiveArrayEncoder) { + // TODO: consider using a byte-oriented API to save an allocation. + enc.AppendString(caller.String()) +} + +// ShortCallerEncoder serializes a caller in package/file:line format, trimming +// all but the final directory from the full path. +func ShortCallerEncoder(caller EntryCaller, enc PrimitiveArrayEncoder) { + // TODO: consider using a byte-oriented API to save an allocation. + enc.AppendString(caller.TrimmedPath()) +} + +// UnmarshalText unmarshals text to a CallerEncoder. "full" is unmarshaled to +// FullCallerEncoder and anything else is unmarshaled to ShortCallerEncoder. +func (e *CallerEncoder) UnmarshalText(text []byte) error { + switch string(text) { + case "full": + *e = FullCallerEncoder + default: + *e = ShortCallerEncoder + } + return nil +} + +// A NameEncoder serializes a period-separated logger name to a primitive +// type. +type NameEncoder func(string, PrimitiveArrayEncoder) + +// FullNameEncoder serializes the logger name as-is. +func FullNameEncoder(loggerName string, enc PrimitiveArrayEncoder) { + enc.AppendString(loggerName) +} + +// UnmarshalText unmarshals text to a NameEncoder. Currently, everything is +// unmarshaled to FullNameEncoder. +func (e *NameEncoder) UnmarshalText(text []byte) error { + switch string(text) { + case "full": + *e = FullNameEncoder + default: + *e = FullNameEncoder + } + return nil +} + +// An EncoderConfig allows users to configure the concrete encoders supplied by +// zapcore. +type EncoderConfig struct { + // Set the keys used for each log entry. If any key is empty, that portion + // of the entry is omitted. + MessageKey string `json:"messageKey" yaml:"messageKey"` + LevelKey string `json:"levelKey" yaml:"levelKey"` + TimeKey string `json:"timeKey" yaml:"timeKey"` + NameKey string `json:"nameKey" yaml:"nameKey"` + CallerKey string `json:"callerKey" yaml:"callerKey"` + StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"` + LineEnding string `json:"lineEnding" yaml:"lineEnding"` + // Configure the primitive representations of common complex types. For + // example, some users may want all time.Times serialized as floating-point + // seconds since epoch, while others may prefer ISO8601 strings. + EncodeLevel LevelEncoder `json:"levelEncoder" yaml:"levelEncoder"` + EncodeTime TimeEncoder `json:"timeEncoder" yaml:"timeEncoder"` + EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"` + EncodeCaller CallerEncoder `json:"callerEncoder" yaml:"callerEncoder"` + // Unlike the other primitive type encoders, EncodeName is optional. The + // zero value falls back to FullNameEncoder. + EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"` +} + +// ObjectEncoder is a strongly-typed, encoding-agnostic interface for adding a +// map- or struct-like object to the logging context. Like maps, ObjectEncoders +// aren't safe for concurrent use (though typical use shouldn't require locks). +type ObjectEncoder interface { + // Logging-specific marshalers. + AddArray(key string, marshaler ArrayMarshaler) error + AddObject(key string, marshaler ObjectMarshaler) error + + // Built-in types. + AddBinary(key string, value []byte) // for arbitrary bytes + AddByteString(key string, value []byte) // for UTF-8 encoded bytes + AddBool(key string, value bool) + AddComplex128(key string, value complex128) + AddComplex64(key string, value complex64) + AddDuration(key string, value time.Duration) + AddFloat64(key string, value float64) + AddFloat32(key string, value float32) + AddInt(key string, value int) + AddInt64(key string, value int64) + AddInt32(key string, value int32) + AddInt16(key string, value int16) + AddInt8(key string, value int8) + AddString(key, value string) + AddTime(key string, value time.Time) + AddUint(key string, value uint) + AddUint64(key string, value uint64) + AddUint32(key string, value uint32) + AddUint16(key string, value uint16) + AddUint8(key string, value uint8) + AddUintptr(key string, value uintptr) + + // AddReflected uses reflection to serialize arbitrary objects, so it can be + // slow and allocation-heavy. + AddReflected(key string, value interface{}) error + // OpenNamespace opens an isolated namespace where all subsequent fields will + // be added. Applications can use namespaces to prevent key collisions when + // injecting loggers into sub-components or third-party libraries. + OpenNamespace(key string) +} + +// ArrayEncoder is a strongly-typed, encoding-agnostic interface for adding +// array-like objects to the logging context. Of note, it supports mixed-type +// arrays even though they aren't typical in Go. Like slices, ArrayEncoders +// aren't safe for concurrent use (though typical use shouldn't require locks). +type ArrayEncoder interface { + // Built-in types. + PrimitiveArrayEncoder + + // Time-related types. + AppendDuration(time.Duration) + AppendTime(time.Time) + + // Logging-specific marshalers. + AppendArray(ArrayMarshaler) error + AppendObject(ObjectMarshaler) error + + // AppendReflected uses reflection to serialize arbitrary objects, so it's + // slow and allocation-heavy. + AppendReflected(value interface{}) error +} + +// PrimitiveArrayEncoder is the subset of the ArrayEncoder interface that deals +// only in Go's built-in types. It's included only so that Duration- and +// TimeEncoders cannot trigger infinite recursion. +type PrimitiveArrayEncoder interface { + // Built-in types. + AppendBool(bool) + AppendByteString([]byte) // for UTF-8 encoded bytes + AppendComplex128(complex128) + AppendComplex64(complex64) + AppendFloat64(float64) + AppendFloat32(float32) + AppendInt(int) + AppendInt64(int64) + AppendInt32(int32) + AppendInt16(int16) + AppendInt8(int8) + AppendString(string) + AppendUint(uint) + AppendUint64(uint64) + AppendUint32(uint32) + AppendUint16(uint16) + AppendUint8(uint8) + AppendUintptr(uintptr) +} + +// Encoder is a format-agnostic interface for all log entry marshalers. Since +// log encoders don't need to support the same wide range of use cases as +// general-purpose marshalers, it's possible to make them faster and +// lower-allocation. +// +// Implementations of the ObjectEncoder interface's methods can, of course, +// freely modify the receiver. However, the Clone and EncodeEntry methods will +// be called concurrently and shouldn't modify the receiver. +type Encoder interface { + ObjectEncoder + + // Clone copies the encoder, ensuring that adding fields to the copy doesn't + // affect the original. + Clone() Encoder + + // EncodeEntry encodes an entry and fields, along with any accumulated + // context, into a byte buffer and returns it. Any fields that are empty, + // including fields on the `Entry` type, should be omitted. + EncodeEntry(Entry, []Field) (*buffer.Buffer, error) +} diff --git a/vendor/go.uber.org/zap/zapcore/entry.go b/vendor/go.uber.org/zap/zapcore/entry.go new file mode 100644 index 0000000000..8273abdf07 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/entry.go @@ -0,0 +1,258 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "fmt" + "strings" + "sync" + "time" + + "go.uber.org/zap/internal/bufferpool" + "go.uber.org/zap/internal/exit" + + "go.uber.org/multierr" +) + +var ( + _cePool = sync.Pool{New: func() interface{} { + // Pre-allocate some space for cores. + return &CheckedEntry{ + cores: make([]Core, 4), + } + }} +) + +func getCheckedEntry() *CheckedEntry { + ce := _cePool.Get().(*CheckedEntry) + ce.reset() + return ce +} + +func putCheckedEntry(ce *CheckedEntry) { + if ce == nil { + return + } + _cePool.Put(ce) +} + +// NewEntryCaller makes an EntryCaller from the return signature of +// runtime.Caller. +func NewEntryCaller(pc uintptr, file string, line int, ok bool) EntryCaller { + if !ok { + return EntryCaller{} + } + return EntryCaller{ + PC: pc, + File: file, + Line: line, + Defined: true, + } +} + +// EntryCaller represents the caller of a logging function. +type EntryCaller struct { + Defined bool + PC uintptr + File string + Line int +} + +// String returns the full path and line number of the caller. +func (ec EntryCaller) String() string { + return ec.FullPath() +} + +// FullPath returns a /full/path/to/package/file:line description of the +// caller. +func (ec EntryCaller) FullPath() string { + if !ec.Defined { + return "undefined" + } + buf := bufferpool.Get() + buf.AppendString(ec.File) + buf.AppendByte(':') + buf.AppendInt(int64(ec.Line)) + caller := buf.String() + buf.Free() + return caller +} + +// TrimmedPath returns a package/file:line description of the caller, +// preserving only the leaf directory name and file name. +func (ec EntryCaller) TrimmedPath() string { + if !ec.Defined { + return "undefined" + } + // nb. To make sure we trim the path correctly on Windows too, we + // counter-intuitively need to use '/' and *not* os.PathSeparator here, + // because the path given originates from Go stdlib, specifically + // runtime.Caller() which (as of Mar/17) returns forward slashes even on + // Windows. + // + // See https://github.com/golang/go/issues/3335 + // and https://github.com/golang/go/issues/18151 + // + // for discussion on the issue on Go side. + // + // Find the last separator. + // + idx := strings.LastIndexByte(ec.File, '/') + if idx == -1 { + return ec.FullPath() + } + // Find the penultimate separator. + idx = strings.LastIndexByte(ec.File[:idx], '/') + if idx == -1 { + return ec.FullPath() + } + buf := bufferpool.Get() + // Keep everything after the penultimate separator. + buf.AppendString(ec.File[idx+1:]) + buf.AppendByte(':') + buf.AppendInt(int64(ec.Line)) + caller := buf.String() + buf.Free() + return caller +} + +// An Entry represents a complete log message. The entry's structured context +// is already serialized, but the log level, time, message, and call site +// information are available for inspection and modification. Any fields left +// empty will be omitted when encoding. +// +// Entries are pooled, so any functions that accept them MUST be careful not to +// retain references to them. +type Entry struct { + Level Level + Time time.Time + LoggerName string + Message string + Caller EntryCaller + Stack string +} + +// CheckWriteAction indicates what action to take after a log entry is +// processed. Actions are ordered in increasing severity. +type CheckWriteAction uint8 + +const ( + // WriteThenNoop indicates that nothing special needs to be done. It's the + // default behavior. + WriteThenNoop CheckWriteAction = iota + // WriteThenPanic causes a panic after Write. + WriteThenPanic + // WriteThenFatal causes a fatal os.Exit after Write. + WriteThenFatal +) + +// CheckedEntry is an Entry together with a collection of Cores that have +// already agreed to log it. +// +// CheckedEntry references should be created by calling AddCore or Should on a +// nil *CheckedEntry. References are returned to a pool after Write, and MUST +// NOT be retained after calling their Write method. +type CheckedEntry struct { + Entry + ErrorOutput WriteSyncer + dirty bool // best-effort detection of pool misuse + should CheckWriteAction + cores []Core +} + +func (ce *CheckedEntry) reset() { + ce.Entry = Entry{} + ce.ErrorOutput = nil + ce.dirty = false + ce.should = WriteThenNoop + for i := range ce.cores { + // don't keep references to cores + ce.cores[i] = nil + } + ce.cores = ce.cores[:0] +} + +// Write writes the entry to the stored Cores, returns any errors, and returns +// the CheckedEntry reference to a pool for immediate re-use. Finally, it +// executes any required CheckWriteAction. +func (ce *CheckedEntry) Write(fields ...Field) { + if ce == nil { + return + } + + if ce.dirty { + if ce.ErrorOutput != nil { + // Make a best effort to detect unsafe re-use of this CheckedEntry. + // If the entry is dirty, log an internal error; because the + // CheckedEntry is being used after it was returned to the pool, + // the message may be an amalgamation from multiple call sites. + fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", time.Now(), ce.Entry) + ce.ErrorOutput.Sync() + } + return + } + ce.dirty = true + + var err error + for i := range ce.cores { + err = multierr.Append(err, ce.cores[i].Write(ce.Entry, fields)) + } + if ce.ErrorOutput != nil { + if err != nil { + fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", time.Now(), err) + ce.ErrorOutput.Sync() + } + } + + should, msg := ce.should, ce.Message + putCheckedEntry(ce) + + switch should { + case WriteThenPanic: + panic(msg) + case WriteThenFatal: + exit.Exit() + } +} + +// AddCore adds a Core that has agreed to log this CheckedEntry. It's intended to be +// used by Core.Check implementations, and is safe to call on nil CheckedEntry +// references. +func (ce *CheckedEntry) AddCore(ent Entry, core Core) *CheckedEntry { + if ce == nil { + ce = getCheckedEntry() + ce.Entry = ent + } + ce.cores = append(ce.cores, core) + return ce +} + +// Should sets this CheckedEntry's CheckWriteAction, which controls whether a +// Core will panic or fatal after writing this log entry. Like AddCore, it's +// safe to call on nil CheckedEntry references. +func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry { + if ce == nil { + ce = getCheckedEntry() + ce.Entry = ent + } + ce.should = should + return ce +} diff --git a/vendor/go.uber.org/zap/zapcore/error.go b/vendor/go.uber.org/zap/zapcore/error.go new file mode 100644 index 0000000000..9ba2272c3f --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/error.go @@ -0,0 +1,115 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "fmt" + "sync" +) + +// Encodes the given error into fields of an object. A field with the given +// name is added for the error message. +// +// If the error implements fmt.Formatter, a field with the name ${key}Verbose +// is also added with the full verbose error message. +// +// Finally, if the error implements errorGroup (from go.uber.org/multierr) or +// causer (from github.com/pkg/errors), a ${key}Causes field is added with an +// array of objects containing the errors this error was comprised of. +// +// { +// "error": err.Error(), +// "errorVerbose": fmt.Sprintf("%+v", err), +// "errorCauses": [ +// ... +// ], +// } +func encodeError(key string, err error, enc ObjectEncoder) error { + basic := err.Error() + enc.AddString(key, basic) + + switch e := err.(type) { + case errorGroup: + return enc.AddArray(key+"Causes", errArray(e.Errors())) + case fmt.Formatter: + verbose := fmt.Sprintf("%+v", e) + if verbose != basic { + // This is a rich error type, like those produced by + // github.com/pkg/errors. + enc.AddString(key+"Verbose", verbose) + } + } + return nil +} + +type errorGroup interface { + // Provides read-only access to the underlying list of errors, preferably + // without causing any allocs. + Errors() []error +} + +// Note that errArry and errArrayElem are very similar to the version +// implemented in the top-level error.go file. We can't re-use this because +// that would require exporting errArray as part of the zapcore API. + +// Encodes a list of errors using the standard error encoding logic. +type errArray []error + +func (errs errArray) MarshalLogArray(arr ArrayEncoder) error { + for i := range errs { + if errs[i] == nil { + continue + } + + el := newErrArrayElem(errs[i]) + arr.AppendObject(el) + el.Free() + } + return nil +} + +var _errArrayElemPool = sync.Pool{New: func() interface{} { + return &errArrayElem{} +}} + +// Encodes any error into a {"error": ...} re-using the same errors logic. +// +// May be passed in place of an array to build a single-element array. +type errArrayElem struct{ err error } + +func newErrArrayElem(err error) *errArrayElem { + e := _errArrayElemPool.Get().(*errArrayElem) + e.err = err + return e +} + +func (e *errArrayElem) MarshalLogArray(arr ArrayEncoder) error { + return arr.AppendObject(e) +} + +func (e *errArrayElem) MarshalLogObject(enc ObjectEncoder) error { + return encodeError("error", e.err, enc) +} + +func (e *errArrayElem) Free() { + e.err = nil + _errArrayElemPool.Put(e) +} diff --git a/vendor/go.uber.org/zap/zapcore/field.go b/vendor/go.uber.org/zap/zapcore/field.go new file mode 100644 index 0000000000..6e05f831ff --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/field.go @@ -0,0 +1,217 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "bytes" + "fmt" + "math" + "reflect" + "time" +) + +// A FieldType indicates which member of the Field union struct should be used +// and how it should be serialized. +type FieldType uint8 + +const ( + // UnknownType is the default field type. Attempting to add it to an encoder will panic. + UnknownType FieldType = iota + // ArrayMarshalerType indicates that the field carries an ArrayMarshaler. + ArrayMarshalerType + // ObjectMarshalerType indicates that the field carries an ObjectMarshaler. + ObjectMarshalerType + // BinaryType indicates that the field carries an opaque binary blob. + BinaryType + // BoolType indicates that the field carries a bool. + BoolType + // ByteStringType indicates that the field carries UTF-8 encoded bytes. + ByteStringType + // Complex128Type indicates that the field carries a complex128. + Complex128Type + // Complex64Type indicates that the field carries a complex128. + Complex64Type + // DurationType indicates that the field carries a time.Duration. + DurationType + // Float64Type indicates that the field carries a float64. + Float64Type + // Float32Type indicates that the field carries a float32. + Float32Type + // Int64Type indicates that the field carries an int64. + Int64Type + // Int32Type indicates that the field carries an int32. + Int32Type + // Int16Type indicates that the field carries an int16. + Int16Type + // Int8Type indicates that the field carries an int8. + Int8Type + // StringType indicates that the field carries a string. + StringType + // TimeType indicates that the field carries a time.Time that is + // representable by a UnixNano() stored as an int64. + TimeType + // TimeFullType indicates that the field carries a time.Time stored as-is. + TimeFullType + // Uint64Type indicates that the field carries a uint64. + Uint64Type + // Uint32Type indicates that the field carries a uint32. + Uint32Type + // Uint16Type indicates that the field carries a uint16. + Uint16Type + // Uint8Type indicates that the field carries a uint8. + Uint8Type + // UintptrType indicates that the field carries a uintptr. + UintptrType + // ReflectType indicates that the field carries an interface{}, which should + // be serialized using reflection. + ReflectType + // NamespaceType signals the beginning of an isolated namespace. All + // subsequent fields should be added to the new namespace. + NamespaceType + // StringerType indicates that the field carries a fmt.Stringer. + StringerType + // ErrorType indicates that the field carries an error. + ErrorType + // SkipType indicates that the field is a no-op. + SkipType +) + +// A Field is a marshaling operation used to add a key-value pair to a logger's +// context. Most fields are lazily marshaled, so it's inexpensive to add fields +// to disabled debug-level log statements. +type Field struct { + Key string + Type FieldType + Integer int64 + String string + Interface interface{} +} + +// AddTo exports a field through the ObjectEncoder interface. It's primarily +// useful to library authors, and shouldn't be necessary in most applications. +func (f Field) AddTo(enc ObjectEncoder) { + var err error + + switch f.Type { + case ArrayMarshalerType: + err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler)) + case ObjectMarshalerType: + err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler)) + case BinaryType: + enc.AddBinary(f.Key, f.Interface.([]byte)) + case BoolType: + enc.AddBool(f.Key, f.Integer == 1) + case ByteStringType: + enc.AddByteString(f.Key, f.Interface.([]byte)) + case Complex128Type: + enc.AddComplex128(f.Key, f.Interface.(complex128)) + case Complex64Type: + enc.AddComplex64(f.Key, f.Interface.(complex64)) + case DurationType: + enc.AddDuration(f.Key, time.Duration(f.Integer)) + case Float64Type: + enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer))) + case Float32Type: + enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer))) + case Int64Type: + enc.AddInt64(f.Key, f.Integer) + case Int32Type: + enc.AddInt32(f.Key, int32(f.Integer)) + case Int16Type: + enc.AddInt16(f.Key, int16(f.Integer)) + case Int8Type: + enc.AddInt8(f.Key, int8(f.Integer)) + case StringType: + enc.AddString(f.Key, f.String) + case TimeType: + if f.Interface != nil { + enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location))) + } else { + // Fall back to UTC if location is nil. + enc.AddTime(f.Key, time.Unix(0, f.Integer)) + } + case TimeFullType: + enc.AddTime(f.Key, f.Interface.(time.Time)) + case Uint64Type: + enc.AddUint64(f.Key, uint64(f.Integer)) + case Uint32Type: + enc.AddUint32(f.Key, uint32(f.Integer)) + case Uint16Type: + enc.AddUint16(f.Key, uint16(f.Integer)) + case Uint8Type: + enc.AddUint8(f.Key, uint8(f.Integer)) + case UintptrType: + enc.AddUintptr(f.Key, uintptr(f.Integer)) + case ReflectType: + err = enc.AddReflected(f.Key, f.Interface) + case NamespaceType: + enc.OpenNamespace(f.Key) + case StringerType: + err = encodeStringer(f.Key, f.Interface, enc) + case ErrorType: + encodeError(f.Key, f.Interface.(error), enc) + case SkipType: + break + default: + panic(fmt.Sprintf("unknown field type: %v", f)) + } + + if err != nil { + enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error()) + } +} + +// Equals returns whether two fields are equal. For non-primitive types such as +// errors, marshalers, or reflect types, it uses reflect.DeepEqual. +func (f Field) Equals(other Field) bool { + if f.Type != other.Type { + return false + } + if f.Key != other.Key { + return false + } + + switch f.Type { + case BinaryType, ByteStringType: + return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte)) + case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType: + return reflect.DeepEqual(f.Interface, other.Interface) + default: + return f == other + } +} + +func addFields(enc ObjectEncoder, fields []Field) { + for i := range fields { + fields[i].AddTo(enc) + } +} + +func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (err error) { + defer func() { + if v := recover(); v != nil { + err = fmt.Errorf("PANIC=%v", v) + } + }() + + enc.AddString(key, stringer.(fmt.Stringer).String()) + return +} diff --git a/vendor/go.uber.org/zap/zapcore/hook.go b/vendor/go.uber.org/zap/zapcore/hook.go new file mode 100644 index 0000000000..5db4afb302 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/hook.go @@ -0,0 +1,68 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import "go.uber.org/multierr" + +type hooked struct { + Core + funcs []func(Entry) error +} + +// RegisterHooks wraps a Core and runs a collection of user-defined callback +// hooks each time a message is logged. Execution of the callbacks is blocking. +// +// This offers users an easy way to register simple callbacks (e.g., metrics +// collection) without implementing the full Core interface. +func RegisterHooks(core Core, hooks ...func(Entry) error) Core { + funcs := append([]func(Entry) error{}, hooks...) + return &hooked{ + Core: core, + funcs: funcs, + } +} + +func (h *hooked) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { + // Let the wrapped Core decide whether to log this message or not. This + // also gives the downstream a chance to register itself directly with the + // CheckedEntry. + if downstream := h.Core.Check(ent, ce); downstream != nil { + return downstream.AddCore(ent, h) + } + return ce +} + +func (h *hooked) With(fields []Field) Core { + return &hooked{ + Core: h.Core.With(fields), + funcs: h.funcs, + } +} + +func (h *hooked) Write(ent Entry, _ []Field) error { + // Since our downstream had a chance to register itself directly with the + // CheckedMessage, we don't need to call it here. + var err error + for i := range h.funcs { + err = multierr.Append(err, h.funcs[i](ent)) + } + return err +} diff --git a/vendor/go.uber.org/zap/zapcore/increase_level.go b/vendor/go.uber.org/zap/zapcore/increase_level.go new file mode 100644 index 0000000000..5a1749261a --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/increase_level.go @@ -0,0 +1,66 @@ +// Copyright (c) 2020 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import "fmt" + +type levelFilterCore struct { + core Core + level LevelEnabler +} + +// NewIncreaseLevelCore creates a core that can be used to increase the level of +// an existing Core. It cannot be used to decrease the logging level, as it acts +// as a filter before calling the underlying core. If level decreases the log level, +// an error is returned. +func NewIncreaseLevelCore(core Core, level LevelEnabler) (Core, error) { + for l := _maxLevel; l >= _minLevel; l-- { + if !core.Enabled(l) && level.Enabled(l) { + return nil, fmt.Errorf("invalid increase level, as level %q is allowed by increased level, but not by existing core", l) + } + } + + return &levelFilterCore{core, level}, nil +} + +func (c *levelFilterCore) Enabled(lvl Level) bool { + return c.level.Enabled(lvl) +} + +func (c *levelFilterCore) With(fields []Field) Core { + return &levelFilterCore{c.core.With(fields), c.level} +} + +func (c *levelFilterCore) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { + if !c.Enabled(ent.Level) { + return ce + } + + return c.core.Check(ent, ce) +} + +func (c *levelFilterCore) Write(ent Entry, fields []Field) error { + return c.core.Write(ent, fields) +} + +func (c *levelFilterCore) Sync() error { + return c.core.Sync() +} diff --git a/vendor/go.uber.org/zap/zapcore/json_encoder.go b/vendor/go.uber.org/zap/zapcore/json_encoder.go new file mode 100644 index 0000000000..7facc1b36b --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/json_encoder.go @@ -0,0 +1,524 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "encoding/base64" + "encoding/json" + "math" + "sync" + "time" + "unicode/utf8" + + "go.uber.org/zap/buffer" + "go.uber.org/zap/internal/bufferpool" +) + +// For JSON-escaping; see jsonEncoder.safeAddString below. +const _hex = "0123456789abcdef" + +var _jsonPool = sync.Pool{New: func() interface{} { + return &jsonEncoder{} +}} + +func getJSONEncoder() *jsonEncoder { + return _jsonPool.Get().(*jsonEncoder) +} + +func putJSONEncoder(enc *jsonEncoder) { + if enc.reflectBuf != nil { + enc.reflectBuf.Free() + } + enc.EncoderConfig = nil + enc.buf = nil + enc.spaced = false + enc.openNamespaces = 0 + enc.reflectBuf = nil + enc.reflectEnc = nil + _jsonPool.Put(enc) +} + +type jsonEncoder struct { + *EncoderConfig + buf *buffer.Buffer + spaced bool // include spaces after colons and commas + openNamespaces int + + // for encoding generic values by reflection + reflectBuf *buffer.Buffer + reflectEnc *json.Encoder +} + +// NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder +// appropriately escapes all field keys and values. +// +// Note that the encoder doesn't deduplicate keys, so it's possible to produce +// a message like +// {"foo":"bar","foo":"baz"} +// This is permitted by the JSON specification, but not encouraged. Many +// libraries will ignore duplicate key-value pairs (typically keeping the last +// pair) when unmarshaling, but users should attempt to avoid adding duplicate +// keys. +func NewJSONEncoder(cfg EncoderConfig) Encoder { + return newJSONEncoder(cfg, false) +} + +func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder { + return &jsonEncoder{ + EncoderConfig: &cfg, + buf: bufferpool.Get(), + spaced: spaced, + } +} + +func (enc *jsonEncoder) AddArray(key string, arr ArrayMarshaler) error { + enc.addKey(key) + return enc.AppendArray(arr) +} + +func (enc *jsonEncoder) AddObject(key string, obj ObjectMarshaler) error { + enc.addKey(key) + return enc.AppendObject(obj) +} + +func (enc *jsonEncoder) AddBinary(key string, val []byte) { + enc.AddString(key, base64.StdEncoding.EncodeToString(val)) +} + +func (enc *jsonEncoder) AddByteString(key string, val []byte) { + enc.addKey(key) + enc.AppendByteString(val) +} + +func (enc *jsonEncoder) AddBool(key string, val bool) { + enc.addKey(key) + enc.AppendBool(val) +} + +func (enc *jsonEncoder) AddComplex128(key string, val complex128) { + enc.addKey(key) + enc.AppendComplex128(val) +} + +func (enc *jsonEncoder) AddDuration(key string, val time.Duration) { + enc.addKey(key) + enc.AppendDuration(val) +} + +func (enc *jsonEncoder) AddFloat64(key string, val float64) { + enc.addKey(key) + enc.AppendFloat64(val) +} + +func (enc *jsonEncoder) AddInt64(key string, val int64) { + enc.addKey(key) + enc.AppendInt64(val) +} + +func (enc *jsonEncoder) resetReflectBuf() { + if enc.reflectBuf == nil { + enc.reflectBuf = bufferpool.Get() + enc.reflectEnc = json.NewEncoder(enc.reflectBuf) + + // For consistency with our custom JSON encoder. + enc.reflectEnc.SetEscapeHTML(false) + } else { + enc.reflectBuf.Reset() + } +} + +var nullLiteralBytes = []byte("null") + +// Only invoke the standard JSON encoder if there is actually something to +// encode; otherwise write JSON null literal directly. +func (enc *jsonEncoder) encodeReflected(obj interface{}) ([]byte, error) { + if obj == nil { + return nullLiteralBytes, nil + } + enc.resetReflectBuf() + if err := enc.reflectEnc.Encode(obj); err != nil { + return nil, err + } + enc.reflectBuf.TrimNewline() + return enc.reflectBuf.Bytes(), nil +} + +func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error { + valueBytes, err := enc.encodeReflected(obj) + if err != nil { + return err + } + enc.addKey(key) + _, err = enc.buf.Write(valueBytes) + return err +} + +func (enc *jsonEncoder) OpenNamespace(key string) { + enc.addKey(key) + enc.buf.AppendByte('{') + enc.openNamespaces++ +} + +func (enc *jsonEncoder) AddString(key, val string) { + enc.addKey(key) + enc.AppendString(val) +} + +func (enc *jsonEncoder) AddTime(key string, val time.Time) { + enc.addKey(key) + enc.AppendTime(val) +} + +func (enc *jsonEncoder) AddUint64(key string, val uint64) { + enc.addKey(key) + enc.AppendUint64(val) +} + +func (enc *jsonEncoder) AppendArray(arr ArrayMarshaler) error { + enc.addElementSeparator() + enc.buf.AppendByte('[') + err := arr.MarshalLogArray(enc) + enc.buf.AppendByte(']') + return err +} + +func (enc *jsonEncoder) AppendObject(obj ObjectMarshaler) error { + enc.addElementSeparator() + enc.buf.AppendByte('{') + err := obj.MarshalLogObject(enc) + enc.buf.AppendByte('}') + return err +} + +func (enc *jsonEncoder) AppendBool(val bool) { + enc.addElementSeparator() + enc.buf.AppendBool(val) +} + +func (enc *jsonEncoder) AppendByteString(val []byte) { + enc.addElementSeparator() + enc.buf.AppendByte('"') + enc.safeAddByteString(val) + enc.buf.AppendByte('"') +} + +func (enc *jsonEncoder) AppendComplex128(val complex128) { + enc.addElementSeparator() + // Cast to a platform-independent, fixed-size type. + r, i := float64(real(val)), float64(imag(val)) + enc.buf.AppendByte('"') + // Because we're always in a quoted string, we can use strconv without + // special-casing NaN and +/-Inf. + enc.buf.AppendFloat(r, 64) + enc.buf.AppendByte('+') + enc.buf.AppendFloat(i, 64) + enc.buf.AppendByte('i') + enc.buf.AppendByte('"') +} + +func (enc *jsonEncoder) AppendDuration(val time.Duration) { + cur := enc.buf.Len() + enc.EncodeDuration(val, enc) + if cur == enc.buf.Len() { + // User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep + // JSON valid. + enc.AppendInt64(int64(val)) + } +} + +func (enc *jsonEncoder) AppendInt64(val int64) { + enc.addElementSeparator() + enc.buf.AppendInt(val) +} + +func (enc *jsonEncoder) AppendReflected(val interface{}) error { + valueBytes, err := enc.encodeReflected(val) + if err != nil { + return err + } + enc.addElementSeparator() + _, err = enc.buf.Write(valueBytes) + return err +} + +func (enc *jsonEncoder) AppendString(val string) { + enc.addElementSeparator() + enc.buf.AppendByte('"') + enc.safeAddString(val) + enc.buf.AppendByte('"') +} + +func (enc *jsonEncoder) AppendTimeLayout(time time.Time, layout string) { + enc.addElementSeparator() + enc.buf.AppendByte('"') + enc.buf.AppendTime(time, layout) + enc.buf.AppendByte('"') +} + +func (enc *jsonEncoder) AppendTime(val time.Time) { + cur := enc.buf.Len() + enc.EncodeTime(val, enc) + if cur == enc.buf.Len() { + // User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep + // output JSON valid. + enc.AppendInt64(val.UnixNano()) + } +} + +func (enc *jsonEncoder) AppendUint64(val uint64) { + enc.addElementSeparator() + enc.buf.AppendUint(val) +} + +func (enc *jsonEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) } +func (enc *jsonEncoder) AddFloat32(k string, v float32) { enc.AddFloat64(k, float64(v)) } +func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) } +func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } +func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } +func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } + +func (enc *jsonEncoder) Clone() Encoder { + clone := enc.clone() + clone.buf.Write(enc.buf.Bytes()) + return clone +} + +func (enc *jsonEncoder) clone() *jsonEncoder { + clone := getJSONEncoder() + clone.EncoderConfig = enc.EncoderConfig + clone.spaced = enc.spaced + clone.openNamespaces = enc.openNamespaces + clone.buf = bufferpool.Get() + return clone +} + +func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) { + final := enc.clone() + final.buf.AppendByte('{') + + if final.LevelKey != "" { + final.addKey(final.LevelKey) + cur := final.buf.Len() + final.EncodeLevel(ent.Level, final) + if cur == final.buf.Len() { + // User-supplied EncodeLevel was a no-op. Fall back to strings to keep + // output JSON valid. + final.AppendString(ent.Level.String()) + } + } + if final.TimeKey != "" { + final.AddTime(final.TimeKey, ent.Time) + } + if ent.LoggerName != "" && final.NameKey != "" { + final.addKey(final.NameKey) + cur := final.buf.Len() + nameEncoder := final.EncodeName + + // if no name encoder provided, fall back to FullNameEncoder for backwards + // compatibility + if nameEncoder == nil { + nameEncoder = FullNameEncoder + } + + nameEncoder(ent.LoggerName, final) + if cur == final.buf.Len() { + // User-supplied EncodeName was a no-op. Fall back to strings to + // keep output JSON valid. + final.AppendString(ent.LoggerName) + } + } + if ent.Caller.Defined && final.CallerKey != "" { + final.addKey(final.CallerKey) + cur := final.buf.Len() + final.EncodeCaller(ent.Caller, final) + if cur == final.buf.Len() { + // User-supplied EncodeCaller was a no-op. Fall back to strings to + // keep output JSON valid. + final.AppendString(ent.Caller.String()) + } + } + if final.MessageKey != "" { + final.addKey(enc.MessageKey) + final.AppendString(ent.Message) + } + if enc.buf.Len() > 0 { + final.addElementSeparator() + final.buf.Write(enc.buf.Bytes()) + } + addFields(final, fields) + final.closeOpenNamespaces() + if ent.Stack != "" && final.StacktraceKey != "" { + final.AddString(final.StacktraceKey, ent.Stack) + } + final.buf.AppendByte('}') + if final.LineEnding != "" { + final.buf.AppendString(final.LineEnding) + } else { + final.buf.AppendString(DefaultLineEnding) + } + + ret := final.buf + putJSONEncoder(final) + return ret, nil +} + +func (enc *jsonEncoder) truncate() { + enc.buf.Reset() +} + +func (enc *jsonEncoder) closeOpenNamespaces() { + for i := 0; i < enc.openNamespaces; i++ { + enc.buf.AppendByte('}') + } +} + +func (enc *jsonEncoder) addKey(key string) { + enc.addElementSeparator() + enc.buf.AppendByte('"') + enc.safeAddString(key) + enc.buf.AppendByte('"') + enc.buf.AppendByte(':') + if enc.spaced { + enc.buf.AppendByte(' ') + } +} + +func (enc *jsonEncoder) addElementSeparator() { + last := enc.buf.Len() - 1 + if last < 0 { + return + } + switch enc.buf.Bytes()[last] { + case '{', '[', ':', ',', ' ': + return + default: + enc.buf.AppendByte(',') + if enc.spaced { + enc.buf.AppendByte(' ') + } + } +} + +func (enc *jsonEncoder) appendFloat(val float64, bitSize int) { + enc.addElementSeparator() + switch { + case math.IsNaN(val): + enc.buf.AppendString(`"NaN"`) + case math.IsInf(val, 1): + enc.buf.AppendString(`"+Inf"`) + case math.IsInf(val, -1): + enc.buf.AppendString(`"-Inf"`) + default: + enc.buf.AppendFloat(val, bitSize) + } +} + +// safeAddString JSON-escapes a string and appends it to the internal buffer. +// Unlike the standard library's encoder, it doesn't attempt to protect the +// user from browser vulnerabilities or JSONP-related problems. +func (enc *jsonEncoder) safeAddString(s string) { + for i := 0; i < len(s); { + if enc.tryAddRuneSelf(s[i]) { + i++ + continue + } + r, size := utf8.DecodeRuneInString(s[i:]) + if enc.tryAddRuneError(r, size) { + i++ + continue + } + enc.buf.AppendString(s[i : i+size]) + i += size + } +} + +// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte. +func (enc *jsonEncoder) safeAddByteString(s []byte) { + for i := 0; i < len(s); { + if enc.tryAddRuneSelf(s[i]) { + i++ + continue + } + r, size := utf8.DecodeRune(s[i:]) + if enc.tryAddRuneError(r, size) { + i++ + continue + } + enc.buf.Write(s[i : i+size]) + i += size + } +} + +// tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte. +func (enc *jsonEncoder) tryAddRuneSelf(b byte) bool { + if b >= utf8.RuneSelf { + return false + } + if 0x20 <= b && b != '\\' && b != '"' { + enc.buf.AppendByte(b) + return true + } + switch b { + case '\\', '"': + enc.buf.AppendByte('\\') + enc.buf.AppendByte(b) + case '\n': + enc.buf.AppendByte('\\') + enc.buf.AppendByte('n') + case '\r': + enc.buf.AppendByte('\\') + enc.buf.AppendByte('r') + case '\t': + enc.buf.AppendByte('\\') + enc.buf.AppendByte('t') + default: + // Encode bytes < 0x20, except for the escape sequences above. + enc.buf.AppendString(`\u00`) + enc.buf.AppendByte(_hex[b>>4]) + enc.buf.AppendByte(_hex[b&0xF]) + } + return true +} + +func (enc *jsonEncoder) tryAddRuneError(r rune, size int) bool { + if r == utf8.RuneError && size == 1 { + enc.buf.AppendString(`\ufffd`) + return true + } + return false +} diff --git a/vendor/go.uber.org/zap/zapcore/level.go b/vendor/go.uber.org/zap/zapcore/level.go new file mode 100644 index 0000000000..e575c9f432 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/level.go @@ -0,0 +1,175 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "bytes" + "errors" + "fmt" +) + +var errUnmarshalNilLevel = errors.New("can't unmarshal a nil *Level") + +// A Level is a logging priority. Higher levels are more important. +type Level int8 + +const ( + // DebugLevel logs are typically voluminous, and are usually disabled in + // production. + DebugLevel Level = iota - 1 + // InfoLevel is the default logging priority. + InfoLevel + // WarnLevel logs are more important than Info, but don't need individual + // human review. + WarnLevel + // ErrorLevel logs are high-priority. If an application is running smoothly, + // it shouldn't generate any error-level logs. + ErrorLevel + // DPanicLevel logs are particularly important errors. In development the + // logger panics after writing the message. + DPanicLevel + // PanicLevel logs a message, then panics. + PanicLevel + // FatalLevel logs a message, then calls os.Exit(1). + FatalLevel + + _minLevel = DebugLevel + _maxLevel = FatalLevel +) + +// String returns a lower-case ASCII representation of the log level. +func (l Level) String() string { + switch l { + case DebugLevel: + return "debug" + case InfoLevel: + return "info" + case WarnLevel: + return "warn" + case ErrorLevel: + return "error" + case DPanicLevel: + return "dpanic" + case PanicLevel: + return "panic" + case FatalLevel: + return "fatal" + default: + return fmt.Sprintf("Level(%d)", l) + } +} + +// CapitalString returns an all-caps ASCII representation of the log level. +func (l Level) CapitalString() string { + // Printing levels in all-caps is common enough that we should export this + // functionality. + switch l { + case DebugLevel: + return "DEBUG" + case InfoLevel: + return "INFO" + case WarnLevel: + return "WARN" + case ErrorLevel: + return "ERROR" + case DPanicLevel: + return "DPANIC" + case PanicLevel: + return "PANIC" + case FatalLevel: + return "FATAL" + default: + return fmt.Sprintf("LEVEL(%d)", l) + } +} + +// MarshalText marshals the Level to text. Note that the text representation +// drops the -Level suffix (see example). +func (l Level) MarshalText() ([]byte, error) { + return []byte(l.String()), nil +} + +// UnmarshalText unmarshals text to a level. Like MarshalText, UnmarshalText +// expects the text representation of a Level to drop the -Level suffix (see +// example). +// +// In particular, this makes it easy to configure logging levels using YAML, +// TOML, or JSON files. +func (l *Level) UnmarshalText(text []byte) error { + if l == nil { + return errUnmarshalNilLevel + } + if !l.unmarshalText(text) && !l.unmarshalText(bytes.ToLower(text)) { + return fmt.Errorf("unrecognized level: %q", text) + } + return nil +} + +func (l *Level) unmarshalText(text []byte) bool { + switch string(text) { + case "debug", "DEBUG": + *l = DebugLevel + case "info", "INFO", "": // make the zero value useful + *l = InfoLevel + case "warn", "WARN": + *l = WarnLevel + case "error", "ERROR": + *l = ErrorLevel + case "dpanic", "DPANIC": + *l = DPanicLevel + case "panic", "PANIC": + *l = PanicLevel + case "fatal", "FATAL": + *l = FatalLevel + default: + return false + } + return true +} + +// Set sets the level for the flag.Value interface. +func (l *Level) Set(s string) error { + return l.UnmarshalText([]byte(s)) +} + +// Get gets the level for the flag.Getter interface. +func (l *Level) Get() interface{} { + return *l +} + +// Enabled returns true if the given level is at or above this level. +func (l Level) Enabled(lvl Level) bool { + return lvl >= l +} + +// LevelEnabler decides whether a given logging level is enabled when logging a +// message. +// +// Enablers are intended to be used to implement deterministic filters; +// concerns like sampling are better implemented as a Core. +// +// Each concrete Level value implements a static LevelEnabler which returns +// true for itself and all higher logging levels. For example WarnLevel.Enabled() +// will return true for WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, and +// FatalLevel, but return false for InfoLevel and DebugLevel. +type LevelEnabler interface { + Enabled(Level) bool +} diff --git a/vendor/go.uber.org/zap/zapcore/level_strings.go b/vendor/go.uber.org/zap/zapcore/level_strings.go new file mode 100644 index 0000000000..7af8dadcb3 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/level_strings.go @@ -0,0 +1,46 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import "go.uber.org/zap/internal/color" + +var ( + _levelToColor = map[Level]color.Color{ + DebugLevel: color.Magenta, + InfoLevel: color.Blue, + WarnLevel: color.Yellow, + ErrorLevel: color.Red, + DPanicLevel: color.Red, + PanicLevel: color.Red, + FatalLevel: color.Red, + } + _unknownLevelColor = color.Red + + _levelToLowercaseColorString = make(map[Level]string, len(_levelToColor)) + _levelToCapitalColorString = make(map[Level]string, len(_levelToColor)) +) + +func init() { + for level, color := range _levelToColor { + _levelToLowercaseColorString[level] = color.Add(level.String()) + _levelToCapitalColorString[level] = color.Add(level.CapitalString()) + } +} diff --git a/vendor/go.uber.org/zap/zapcore/marshaler.go b/vendor/go.uber.org/zap/zapcore/marshaler.go new file mode 100644 index 0000000000..2627a653df --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/marshaler.go @@ -0,0 +1,53 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +// ObjectMarshaler allows user-defined types to efficiently add themselves to the +// logging context, and to selectively omit information which shouldn't be +// included in logs (e.g., passwords). +type ObjectMarshaler interface { + MarshalLogObject(ObjectEncoder) error +} + +// ObjectMarshalerFunc is a type adapter that turns a function into an +// ObjectMarshaler. +type ObjectMarshalerFunc func(ObjectEncoder) error + +// MarshalLogObject calls the underlying function. +func (f ObjectMarshalerFunc) MarshalLogObject(enc ObjectEncoder) error { + return f(enc) +} + +// ArrayMarshaler allows user-defined types to efficiently add themselves to the +// logging context, and to selectively omit information which shouldn't be +// included in logs (e.g., passwords). +type ArrayMarshaler interface { + MarshalLogArray(ArrayEncoder) error +} + +// ArrayMarshalerFunc is a type adapter that turns a function into an +// ArrayMarshaler. +type ArrayMarshalerFunc func(ArrayEncoder) error + +// MarshalLogArray calls the underlying function. +func (f ArrayMarshalerFunc) MarshalLogArray(enc ArrayEncoder) error { + return f(enc) +} diff --git a/vendor/go.uber.org/zap/zapcore/memory_encoder.go b/vendor/go.uber.org/zap/zapcore/memory_encoder.go new file mode 100644 index 0000000000..dfead0829d --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/memory_encoder.go @@ -0,0 +1,179 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import "time" + +// MapObjectEncoder is an ObjectEncoder backed by a simple +// map[string]interface{}. It's not fast enough for production use, but it's +// helpful in tests. +type MapObjectEncoder struct { + // Fields contains the entire encoded log context. + Fields map[string]interface{} + // cur is a pointer to the namespace we're currently writing to. + cur map[string]interface{} +} + +// NewMapObjectEncoder creates a new map-backed ObjectEncoder. +func NewMapObjectEncoder() *MapObjectEncoder { + m := make(map[string]interface{}) + return &MapObjectEncoder{ + Fields: m, + cur: m, + } +} + +// AddArray implements ObjectEncoder. +func (m *MapObjectEncoder) AddArray(key string, v ArrayMarshaler) error { + arr := &sliceArrayEncoder{elems: make([]interface{}, 0)} + err := v.MarshalLogArray(arr) + m.cur[key] = arr.elems + return err +} + +// AddObject implements ObjectEncoder. +func (m *MapObjectEncoder) AddObject(k string, v ObjectMarshaler) error { + newMap := NewMapObjectEncoder() + m.cur[k] = newMap.Fields + return v.MarshalLogObject(newMap) +} + +// AddBinary implements ObjectEncoder. +func (m *MapObjectEncoder) AddBinary(k string, v []byte) { m.cur[k] = v } + +// AddByteString implements ObjectEncoder. +func (m *MapObjectEncoder) AddByteString(k string, v []byte) { m.cur[k] = string(v) } + +// AddBool implements ObjectEncoder. +func (m *MapObjectEncoder) AddBool(k string, v bool) { m.cur[k] = v } + +// AddDuration implements ObjectEncoder. +func (m MapObjectEncoder) AddDuration(k string, v time.Duration) { m.cur[k] = v } + +// AddComplex128 implements ObjectEncoder. +func (m *MapObjectEncoder) AddComplex128(k string, v complex128) { m.cur[k] = v } + +// AddComplex64 implements ObjectEncoder. +func (m *MapObjectEncoder) AddComplex64(k string, v complex64) { m.cur[k] = v } + +// AddFloat64 implements ObjectEncoder. +func (m *MapObjectEncoder) AddFloat64(k string, v float64) { m.cur[k] = v } + +// AddFloat32 implements ObjectEncoder. +func (m *MapObjectEncoder) AddFloat32(k string, v float32) { m.cur[k] = v } + +// AddInt implements ObjectEncoder. +func (m *MapObjectEncoder) AddInt(k string, v int) { m.cur[k] = v } + +// AddInt64 implements ObjectEncoder. +func (m *MapObjectEncoder) AddInt64(k string, v int64) { m.cur[k] = v } + +// AddInt32 implements ObjectEncoder. +func (m *MapObjectEncoder) AddInt32(k string, v int32) { m.cur[k] = v } + +// AddInt16 implements ObjectEncoder. +func (m *MapObjectEncoder) AddInt16(k string, v int16) { m.cur[k] = v } + +// AddInt8 implements ObjectEncoder. +func (m *MapObjectEncoder) AddInt8(k string, v int8) { m.cur[k] = v } + +// AddString implements ObjectEncoder. +func (m *MapObjectEncoder) AddString(k string, v string) { m.cur[k] = v } + +// AddTime implements ObjectEncoder. +func (m MapObjectEncoder) AddTime(k string, v time.Time) { m.cur[k] = v } + +// AddUint implements ObjectEncoder. +func (m *MapObjectEncoder) AddUint(k string, v uint) { m.cur[k] = v } + +// AddUint64 implements ObjectEncoder. +func (m *MapObjectEncoder) AddUint64(k string, v uint64) { m.cur[k] = v } + +// AddUint32 implements ObjectEncoder. +func (m *MapObjectEncoder) AddUint32(k string, v uint32) { m.cur[k] = v } + +// AddUint16 implements ObjectEncoder. +func (m *MapObjectEncoder) AddUint16(k string, v uint16) { m.cur[k] = v } + +// AddUint8 implements ObjectEncoder. +func (m *MapObjectEncoder) AddUint8(k string, v uint8) { m.cur[k] = v } + +// AddUintptr implements ObjectEncoder. +func (m *MapObjectEncoder) AddUintptr(k string, v uintptr) { m.cur[k] = v } + +// AddReflected implements ObjectEncoder. +func (m *MapObjectEncoder) AddReflected(k string, v interface{}) error { + m.cur[k] = v + return nil +} + +// OpenNamespace implements ObjectEncoder. +func (m *MapObjectEncoder) OpenNamespace(k string) { + ns := make(map[string]interface{}) + m.cur[k] = ns + m.cur = ns +} + +// sliceArrayEncoder is an ArrayEncoder backed by a simple []interface{}. Like +// the MapObjectEncoder, it's not designed for production use. +type sliceArrayEncoder struct { + elems []interface{} +} + +func (s *sliceArrayEncoder) AppendArray(v ArrayMarshaler) error { + enc := &sliceArrayEncoder{} + err := v.MarshalLogArray(enc) + s.elems = append(s.elems, enc.elems) + return err +} + +func (s *sliceArrayEncoder) AppendObject(v ObjectMarshaler) error { + m := NewMapObjectEncoder() + err := v.MarshalLogObject(m) + s.elems = append(s.elems, m.Fields) + return err +} + +func (s *sliceArrayEncoder) AppendReflected(v interface{}) error { + s.elems = append(s.elems, v) + return nil +} + +func (s *sliceArrayEncoder) AppendBool(v bool) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendByteString(v []byte) { s.elems = append(s.elems, string(v)) } +func (s *sliceArrayEncoder) AppendComplex128(v complex128) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendComplex64(v complex64) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendDuration(v time.Duration) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendFloat64(v float64) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendFloat32(v float32) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendInt(v int) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendInt64(v int64) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendInt32(v int32) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendInt16(v int16) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendInt8(v int8) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendString(v string) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendTime(v time.Time) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendUint(v uint) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendUint64(v uint64) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendUint32(v uint32) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendUint16(v uint16) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendUint8(v uint8) { s.elems = append(s.elems, v) } +func (s *sliceArrayEncoder) AppendUintptr(v uintptr) { s.elems = append(s.elems, v) } diff --git a/vendor/go.uber.org/zap/zapcore/sampler.go b/vendor/go.uber.org/zap/zapcore/sampler.go new file mode 100644 index 0000000000..25f10ca1d7 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/sampler.go @@ -0,0 +1,208 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "time" + + "go.uber.org/atomic" +) + +const ( + _numLevels = _maxLevel - _minLevel + 1 + _countersPerLevel = 4096 +) + +type counter struct { + resetAt atomic.Int64 + counter atomic.Uint64 +} + +type counters [_numLevels][_countersPerLevel]counter + +func newCounters() *counters { + return &counters{} +} + +func (cs *counters) get(lvl Level, key string) *counter { + i := lvl - _minLevel + j := fnv32a(key) % _countersPerLevel + return &cs[i][j] +} + +// fnv32a, adapted from "hash/fnv", but without a []byte(string) alloc +func fnv32a(s string) uint32 { + const ( + offset32 = 2166136261 + prime32 = 16777619 + ) + hash := uint32(offset32) + for i := 0; i < len(s); i++ { + hash ^= uint32(s[i]) + hash *= prime32 + } + return hash +} + +func (c *counter) IncCheckReset(t time.Time, tick time.Duration) uint64 { + tn := t.UnixNano() + resetAfter := c.resetAt.Load() + if resetAfter > tn { + return c.counter.Inc() + } + + c.counter.Store(1) + + newResetAfter := tn + tick.Nanoseconds() + if !c.resetAt.CAS(resetAfter, newResetAfter) { + // We raced with another goroutine trying to reset, and it also reset + // the counter to 1, so we need to reincrement the counter. + return c.counter.Inc() + } + + return 1 +} + +// SamplingDecision is a decision represented as a bit field made by sampler. +// More decisions may be added in the future. +type SamplingDecision uint32 + +const ( + // LogDropped indicates that the Sampler dropped a log entry. + LogDropped SamplingDecision = 1 << iota + // LogSampled indicates that the Sampler sampled a log entry. + LogSampled +) + +// optionFunc wraps a func so it satisfies the SamplerOption interface. +type optionFunc func(*sampler) + +func (f optionFunc) apply(s *sampler) { + f(s) +} + +// SamplerOption configures a Sampler. +type SamplerOption interface { + apply(*sampler) +} + +// nopSamplingHook is the default hook used by sampler. +func nopSamplingHook(Entry, SamplingDecision) {} + +// SamplerHook registers a function which will be called when Sampler makes a +// decision. +// +// This hook may be used to get visibility into the performance of the sampler. +// For example, use it to track metrics of dropped versus sampled logs. +// +// var dropped atomic.Int64 +// zapcore.SamplerHook(func(ent zapcore.Entry, dec zapcore.SamplingDecision) { +// if dec&zapcore.LogDropped > 0 { +// dropped.Inc() +// } +// }) +func SamplerHook(hook func(entry Entry, dec SamplingDecision)) SamplerOption { + return optionFunc(func(s *sampler) { + s.hook = hook + }) +} + +// NewSamplerWithOptions creates a Core that samples incoming entries, which +// caps the CPU and I/O load of logging while attempting to preserve a +// representative subset of your logs. +// +// Zap samples by logging the first N entries with a given level and message +// each tick. If more Entries with the same level and message are seen during +// the same interval, every Mth message is logged and the rest are dropped. +// +// Sampler can be configured to report sampling decisions with the SamplerHook +// option. +// +// Keep in mind that zap's sampling implementation is optimized for speed over +// absolute precision; under load, each tick may be slightly over- or +// under-sampled. +func NewSamplerWithOptions(core Core, tick time.Duration, first, thereafter int, opts ...SamplerOption) Core { + s := &sampler{ + Core: core, + tick: tick, + counts: newCounters(), + first: uint64(first), + thereafter: uint64(thereafter), + hook: nopSamplingHook, + } + for _, opt := range opts { + opt.apply(s) + } + + return s +} + +type sampler struct { + Core + + counts *counters + tick time.Duration + first, thereafter uint64 + hook func(Entry, SamplingDecision) +} + +// NewSampler creates a Core that samples incoming entries, which +// caps the CPU and I/O load of logging while attempting to preserve a +// representative subset of your logs. +// +// Zap samples by logging the first N entries with a given level and message +// each tick. If more Entries with the same level and message are seen during +// the same interval, every Mth message is logged and the rest are dropped. +// +// Keep in mind that zap's sampling implementation is optimized for speed over +// absolute precision; under load, each tick may be slightly over- or +// under-sampled. +// +// Deprecated: use NewSamplerWithOptions. +func NewSampler(core Core, tick time.Duration, first, thereafter int) Core { + return NewSamplerWithOptions(core, tick, first, thereafter) +} + +func (s *sampler) With(fields []Field) Core { + return &sampler{ + Core: s.Core.With(fields), + tick: s.tick, + counts: s.counts, + first: s.first, + thereafter: s.thereafter, + hook: s.hook, + } +} + +func (s *sampler) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { + if !s.Enabled(ent.Level) { + return ce + } + + counter := s.counts.get(ent.Level, ent.Message) + n := counter.IncCheckReset(ent.Time, s.tick) + if n > s.first && (n-s.first)%s.thereafter != 0 { + s.hook(ent, LogDropped) + return ce + } + s.hook(ent, LogSampled) + return s.Core.Check(ent, ce) +} diff --git a/vendor/go.uber.org/zap/zapcore/tee.go b/vendor/go.uber.org/zap/zapcore/tee.go new file mode 100644 index 0000000000..07a32eef9a --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/tee.go @@ -0,0 +1,81 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import "go.uber.org/multierr" + +type multiCore []Core + +// NewTee creates a Core that duplicates log entries into two or more +// underlying Cores. +// +// Calling it with a single Core returns the input unchanged, and calling +// it with no input returns a no-op Core. +func NewTee(cores ...Core) Core { + switch len(cores) { + case 0: + return NewNopCore() + case 1: + return cores[0] + default: + return multiCore(cores) + } +} + +func (mc multiCore) With(fields []Field) Core { + clone := make(multiCore, len(mc)) + for i := range mc { + clone[i] = mc[i].With(fields) + } + return clone +} + +func (mc multiCore) Enabled(lvl Level) bool { + for i := range mc { + if mc[i].Enabled(lvl) { + return true + } + } + return false +} + +func (mc multiCore) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { + for i := range mc { + ce = mc[i].Check(ent, ce) + } + return ce +} + +func (mc multiCore) Write(ent Entry, fields []Field) error { + var err error + for i := range mc { + err = multierr.Append(err, mc[i].Write(ent, fields)) + } + return err +} + +func (mc multiCore) Sync() error { + var err error + for i := range mc { + err = multierr.Append(err, mc[i].Sync()) + } + return err +} diff --git a/vendor/go.uber.org/zap/zapcore/write_syncer.go b/vendor/go.uber.org/zap/zapcore/write_syncer.go new file mode 100644 index 0000000000..209e25fe22 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/write_syncer.go @@ -0,0 +1,123 @@ +// Copyright (c) 2016 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package zapcore + +import ( + "io" + "sync" + + "go.uber.org/multierr" +) + +// A WriteSyncer is an io.Writer that can also flush any buffered data. Note +// that *os.File (and thus, os.Stderr and os.Stdout) implement WriteSyncer. +type WriteSyncer interface { + io.Writer + Sync() error +} + +// AddSync converts an io.Writer to a WriteSyncer. It attempts to be +// intelligent: if the concrete type of the io.Writer implements WriteSyncer, +// we'll use the existing Sync method. If it doesn't, we'll add a no-op Sync. +func AddSync(w io.Writer) WriteSyncer { + switch w := w.(type) { + case WriteSyncer: + return w + default: + return writerWrapper{w} + } +} + +type lockedWriteSyncer struct { + sync.Mutex + ws WriteSyncer +} + +// Lock wraps a WriteSyncer in a mutex to make it safe for concurrent use. In +// particular, *os.Files must be locked before use. +func Lock(ws WriteSyncer) WriteSyncer { + if _, ok := ws.(*lockedWriteSyncer); ok { + // no need to layer on another lock + return ws + } + return &lockedWriteSyncer{ws: ws} +} + +func (s *lockedWriteSyncer) Write(bs []byte) (int, error) { + s.Lock() + n, err := s.ws.Write(bs) + s.Unlock() + return n, err +} + +func (s *lockedWriteSyncer) Sync() error { + s.Lock() + err := s.ws.Sync() + s.Unlock() + return err +} + +type writerWrapper struct { + io.Writer +} + +func (w writerWrapper) Sync() error { + return nil +} + +type multiWriteSyncer []WriteSyncer + +// NewMultiWriteSyncer creates a WriteSyncer that duplicates its writes +// and sync calls, much like io.MultiWriter. +func NewMultiWriteSyncer(ws ...WriteSyncer) WriteSyncer { + if len(ws) == 1 { + return ws[0] + } + // Copy to protect against https://github.com/golang/go/issues/7809 + return multiWriteSyncer(append([]WriteSyncer(nil), ws...)) +} + +// See https://golang.org/src/io/multi.go +// When not all underlying syncers write the same number of bytes, +// the smallest number is returned even though Write() is called on +// all of them. +func (ws multiWriteSyncer) Write(p []byte) (int, error) { + var writeErr error + nWritten := 0 + for _, w := range ws { + n, err := w.Write(p) + writeErr = multierr.Append(writeErr, err) + if nWritten == 0 && n != 0 { + nWritten = n + } else if n < nWritten { + nWritten = n + } + } + return nWritten, writeErr +} + +func (ws multiWriteSyncer) Sync() error { + var err error + for _, w := range ws { + err = multierr.Append(err, w.Sync()) + } + return err +} From c37c81c5b74f53e2a82f9107194c93847c14beed Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Wed, 22 Jul 2020 08:03:08 -0400 Subject: [PATCH 16/52] Update version --- .travis.yml | 2 +- Dockerfile | 2 +- Godeps/Godeps.json | 6 +----- repo/db/txns_test.go | 6 +++--- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc57e48c61..3b5ebdcaf2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - "1.11" + - "1.13" sudo: required services: - docker diff --git a/Dockerfile b/Dockerfile index 11729c0c96..47d057e8cd 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage - Use a full build environment to create a static binary -FROM golang:1.11 +FROM golang:1.13 COPY . /go/src/github.com/OpenBazaar/openbazaar-go RUN go build --ldflags '-extldflags "-static"' -o /opt/openbazaard /go/src/github.com/OpenBazaar/openbazaar-go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 868699cf77..5f750518e3 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,6 @@ { "ImportPath": "github.com/OpenBazaar/openbazaar-go", - "GoVersion": "go1.11", + "GoVersion": "go1.13", "GodepVersion": "v80", "Deps": [ { @@ -2501,11 +2501,7 @@ }, { "ImportPath": "github.com/OpenBazaar/multiwallet/client/errors", -<<<<<<< HEAD - "Rev": "2b4be2cd7336e77e7ceffe0bce05e8ebec3be287" -======= "Rev": "e2e450015927ced1aa82ded74eba802ec0b3ddf1" ->>>>>>> master }, { "ImportPath": "github.com/OpenBazaar/multiwallet/vendor/github.com/OpenBazaar/wallet-interface", diff --git a/repo/db/txns_test.go b/repo/db/txns_test.go index 696451b038..061f2adaac 100644 --- a/repo/db/txns_test.go +++ b/repo/db/txns_test.go @@ -100,7 +100,7 @@ func TestTxnsGet(t *testing.T) { if err != nil { t.Error(err) } - txn, err := txdb.Get(tx.TxHash()) + txn, err := txdb.Get(tx.TxHash().String()) if err != nil { t.Error(err) } @@ -208,11 +208,11 @@ func TestTxnsDB_UpdateHeight(t *testing.T) { if err != nil { t.Error(err) } - err = txdb.UpdateHeight(tx.TxHash(), -1, time.Now()) + err = txdb.UpdateHeight(tx.TxHash().String(), -1, time.Now()) if err != nil { t.Error(err) } - txn, err := txdb.Get(tx.TxHash()) + txn, err := txdb.Get(tx.TxHash().String()) if err != nil { t.Error(err) } From 291314b1ec82e86a3fcbb36fe80b4d990face630 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Wed, 22 Jul 2020 08:09:42 -0400 Subject: [PATCH 17/52] Print golangci-lint errors --- vendor/github.com/OpenBazaar/multiwallet/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/github.com/OpenBazaar/multiwallet/.travis.yml b/vendor/github.com/OpenBazaar/multiwallet/.travis.yml index cf81ad5677..77f37c8225 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/.travis.yml +++ b/vendor/github.com/OpenBazaar/multiwallet/.travis.yml @@ -11,7 +11,7 @@ before_install: - go get github.com/tcnksm/ghr - go get github.com/axw/gocov/gocov - go get github.com/mattn/goveralls - - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.15.0 + - GL_DEBUG=linters_output GOPACKAGESPRINTGOLISTERRORS=1 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.15.0 install: - dep ensure script: From 793790d055af339071a64539fa8935a4e19a31f6 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 23 Jul 2020 14:36:43 -0400 Subject: [PATCH 18/52] Fix Delete chainhash --- vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go b/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go index 4539888cb4..4b7a1f6bd9 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go +++ b/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go @@ -398,14 +398,14 @@ func (m *MockTxnStore) UpdateHeight(txid string, height int, timestamp time.Time return nil } -func (m *MockTxnStore) Delete(txid *chainhash.Hash) error { +func (m *MockTxnStore) Delete(txid string) error { m.Lock() defer m.Unlock() - _, ok := m.txns[txid.String()] + _, ok := m.txns[txid] if !ok { return errors.New("Not found") } - delete(m.txns, txid.String()) + delete(m.txns, txid) return nil } From a2b8cfc2f20a2172349287ace34adb315dfab554 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 23 Jul 2020 14:37:38 -0400 Subject: [PATCH 19/52] Remove unused import --- vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go b/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go index 4b7a1f6bd9..07cbed0d38 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go +++ b/vendor/github.com/OpenBazaar/multiwallet/datastore/mock.go @@ -11,7 +11,6 @@ import ( "github.com/OpenBazaar/wallet-interface" "github.com/btcsuite/btcd/btcec" - "github.com/btcsuite/btcd/chaincfg/chainhash" ) type MockDatastore struct { From 2f2f1184fe3a6caa61e61dd1acfe29ba847cd2c8 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 23 Jul 2020 15:02:53 -0400 Subject: [PATCH 20/52] Update codebase for option wallet interfaces --- api/jsonapi.go | 7 +- core/completion.go | 12 ++- core/confirmation.go | 12 ++- core/disputes.go | 21 +++++- core/fulfillment.go | 6 +- core/order.go | 30 ++++++-- core/refunds.go | 6 +- net/service/handlers.go | 28 +++++-- repo/db/txns.go | 5 +- .../OpenBazaar/go-ethwallet/wallet/wallet.go | 2 +- .../OpenBazaar/wallet-interface/datastore.go | 2 +- .../OpenBazaar/wallet-interface/wallet.go | 75 +------------------ 12 files changed, 105 insertions(+), 101 deletions(-) diff --git a/api/jsonapi.go b/api/jsonapi.go index 92f59c257c..c54d5966b1 100644 --- a/api/jsonapi.go +++ b/api/jsonapi.go @@ -3381,7 +3381,12 @@ func (i *jsonAPIHandler) POSTBumpFee(w http.ResponseWriter, r *http.Request) { ErrorResponse(w, http.StatusBadRequest, "transaction not found in any wallet") return } - newTxid, err := wal.BumpFee(txHash.String()) + feeBumper, ok := wal.(wallet.WalletCanBumpFee) + if !ok { + ErrorResponse(w, http.StatusBadRequest, "wallet does not support bumping fees") + return + } + newTxid, err := feeBumper.BumpFee(txHash.String()) if err != nil { if err == spvwallet.BumpFeeAlreadyConfirmedError { ErrorResponse(w, http.StatusBadRequest, err.Error()) diff --git a/core/completion.go b/core/completion.go index f1f06f3f13..587197c1fd 100644 --- a/core/completion.go +++ b/core/completion.go @@ -177,6 +177,10 @@ func (n *OpenBazaarNode) CompleteOrder(orderRatings *OrderRatings, contract *pb. // Payout order if moderated and not disputed if order.Payment.Method == pb.Order_Payment_MODERATED && contract.DisputeResolution == nil { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } var ins []wallet.TransactionInput outValue := new(big.Int) for _, r := range records { @@ -230,7 +234,7 @@ func (n *OpenBazaarNode) CompleteOrder(orderRatings *OrderRatings, contract *pb. if !ok { return errors.New("invalid payout fee per byte value") } - buyerSignatures, err := wal.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, buyerKey, redeemScript, *n) + buyerSignatures, err := escrowWallet.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, buyerKey, redeemScript, *n) if err != nil { return err } @@ -318,6 +322,10 @@ func (n *OpenBazaarNode) ReleaseFundsAfterTimeout(contract *pb.RicardianContract if err != nil { return err } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } defn, err := repo.AllCurrencies().Lookup(order.Payment.AmountCurrency.Code) if err != nil { log.Errorf("Failed ReleaseFundsAfterTimeout(): %s", err.Error()) @@ -382,7 +390,7 @@ func (n *OpenBazaarNode) ReleaseFundsAfterTimeout(contract *pb.RicardianContract if err != nil { return err } - _, err = wal.SweepAddress(txInputs, nil, vendorKey, &redeemScript, wallet.NORMAL) + _, err = escrowWallet.SweepAddress(txInputs, nil, vendorKey, &redeemScript, wallet.NORMAL) if err != nil { return err } diff --git a/core/confirmation.go b/core/confirmation.go index 74d5aa3bab..3c16458d6e 100644 --- a/core/confirmation.go +++ b/core/confirmation.go @@ -127,6 +127,10 @@ func (n *OpenBazaarNode) ConfirmOfflineOrder(oldState pb.OrderState, contract *p } if confirmedContract.BuyerOrder.Payment.Method != pb.Order_Payment_MODERATED { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } // Sweep the temp address into our wallet var txInputs []wallet.TransactionInput for _, r := range records { @@ -176,7 +180,7 @@ func (n *OpenBazaarNode) ConfirmOfflineOrder(oldState pb.OrderState, contract *p recoverState() return err } - _, err = wal.SweepAddress(txInputs, nil, vendorKey, &redeemScript, wallet.NORMAL) + _, err = escrowWallet.SweepAddress(txInputs, nil, vendorKey, &redeemScript, wallet.NORMAL) if err != nil { recoverState() return err @@ -213,6 +217,10 @@ func (n *OpenBazaarNode) RejectOfflineOrder(contract *pb.RicardianContract, reco } rejectMsg.Timestamp = ts if order.Payment.Method == pb.Order_Payment_MODERATED { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } var ins []wallet.TransactionInput outValue := *big.NewInt(0) for _, r := range records { @@ -265,7 +273,7 @@ func (n *OpenBazaarNode) RejectOfflineOrder(contract *pb.RicardianContract, reco if !ok { return errors.New("invalid refund fee value") } - signatures, err := wal.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, vendorKey, redeemScript, *fee) + signatures, err := escrowWallet.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, vendorKey, redeemScript, *fee) if err != nil { return fmt.Errorf("generate multisig: %s", err.Error()) } diff --git a/core/disputes.go b/core/disputes.go index 317715e353..c1c23f7bad 100644 --- a/core/disputes.go +++ b/core/disputes.go @@ -592,6 +592,10 @@ func (n *OpenBazaarNode) CloseDispute(orderID string, buyerPercentage, vendorPer if err != nil { return fmt.Errorf("currency (%s) not supported by wallet", preferredOrder.Payment.AmountCurrency.Code) } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } // Create outputs using full value. We will subtract the fee off each output later. outMap := make(map[string]wallet.TransactionOutput) @@ -743,7 +747,7 @@ func (n *OpenBazaarNode) CloseDispute(orderID string, buyerPercentage, vendorPer return err } - sigs, err := wal.CreateMultisigSignature(inputs, outs, moderatorKey, redeemScriptBytes, *big.NewInt(0)) + sigs, err := escrowWallet.CreateMultisigSignature(inputs, outs, moderatorKey, redeemScriptBytes, *big.NewInt(0)) if err != nil { return err } @@ -982,6 +986,11 @@ func (n *OpenBazaarNode) ValidateCaseContract(contract *pb.RicardianContract) [] validationErrors = append(validationErrors, "Contract uses a coin not found in wallet") return validationErrors } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + validationErrors = append(validationErrors, "Wallet does not support escrow") + return validationErrors + } chaincode, err := hex.DecodeString(order.Payment.Chaincode) if err != nil { validationErrors = append(validationErrors, "Error validating bitcoin address and redeem script") @@ -1008,7 +1017,7 @@ func (n *OpenBazaarNode) ValidateCaseContract(contract *pb.RicardianContract) [] return validationErrors } timeout, _ := time.ParseDuration(strconv.Itoa(int(contract.VendorListings[0].Metadata.EscrowTimeoutHours)) + "h") - addr, redeemScript, err := wal.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey, *moderatorKey}, 2, timeout, vendorKey) + addr, redeemScript, err := escrowWallet.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey, *moderatorKey}, 2, timeout, vendorKey) if err != nil { validationErrors = append(validationErrors, "Error generating multisig script") return validationErrors @@ -1150,6 +1159,10 @@ func (n *OpenBazaarNode) ReleaseFunds(contract *pb.RicardianContract, records [] if err != nil { return err } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } // Create outputs var outputs []wallet.TransactionOutput @@ -1222,7 +1235,7 @@ func (n *OpenBazaarNode) ReleaseFunds(contract *pb.RicardianContract, records [] return err } - mySigs, err := wal.CreateMultisigSignature(inputs, outputs, signingKey, redeemScriptBytes, *big.NewInt(0)) + mySigs, err := escrowWallet.CreateMultisigSignature(inputs, outputs, signingKey, redeemScriptBytes, *big.NewInt(0)) if err != nil { return err } @@ -1249,7 +1262,7 @@ func (n *OpenBazaarNode) ReleaseFunds(contract *pb.RicardianContract, records [] peerID := order.BuyerID.PeerID // Build, sign, and broadcast transaction - txnID, err := wal.Multisign(inputs, outputs, mySigs, moderatorSigs, redeemScriptBytes, *big.NewInt(0), true) + txnID, err := escrowWallet.Multisign(inputs, outputs, mySigs, moderatorSigs, redeemScriptBytes, *big.NewInt(0), true) if err != nil { return err } diff --git a/core/fulfillment.go b/core/fulfillment.go index 8190ca45ac..2b73deb185 100644 --- a/core/fulfillment.go +++ b/core/fulfillment.go @@ -37,6 +37,10 @@ func (n *OpenBazaarNode) FulfillOrder(fulfillment *pb.OrderFulfillment, contract if err != nil { return err } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } currentAddress := wal.CurrentAddress(wallet.EXTERNAL) payout.PayoutAddress = currentAddress.String() f := wal.GetFeePerByte(wallet.NORMAL) @@ -79,7 +83,7 @@ func (n *OpenBazaarNode) FulfillOrder(fulfillment *pb.OrderFulfillment, contract if !ok { return errors.New("invalid payout fee value") } - signatures, err := wal.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, vendorKey, redeemScript, *fee) + signatures, err := escrowWallet.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, vendorKey, redeemScript, *fee) if err != nil { return err } diff --git a/core/order.go b/core/order.go index a4734c00fd..74b679c0f8 100644 --- a/core/order.go +++ b/core/order.go @@ -212,6 +212,10 @@ func (n *OpenBazaarNode) Purchase(data *repo.PurchaseData) (orderID string, paym } func prepareModeratedOrderContract(data *repo.PurchaseData, n *OpenBazaarNode, contract *pb.RicardianContract, wal wallet.Wallet) (*pb.RicardianContract, error) { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return nil, errors.New("wallet does not support escrow") + } if data.Moderator == n.IpfsNode.Identity.Pretty() { return nil, errors.New("cannot select self as moderator") } @@ -303,7 +307,7 @@ func prepareModeratedOrderContract(data *repo.PurchaseData, n *OpenBazaarNode, c if err != nil { return nil, err } - addr, redeemScript, err := wal.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey, *moderatorKey}, 2, timeout, vendorKey) + addr, redeemScript, err := escrowWallet.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey, *moderatorKey}, 2, timeout, vendorKey) if err != nil { return nil, err } @@ -379,6 +383,10 @@ func processOnlineDirectOrder(resp *pb.Message, n *OpenBazaarNode, wal wallet.Wa } func processOfflineDirectOrder(n *OpenBazaarNode, wal wallet.Wallet, contract *pb.RicardianContract, payment *pb.Order_Payment) (string, string, big.Int, error) { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return "", "", big.Int{}, errors.New("wallet does not support escrow") + } // Vendor offline // Change payment code to direct v5Order, err := repo.ToV5Order(contract.BuyerOrder, nil) @@ -414,7 +422,7 @@ func processOfflineDirectOrder(n *OpenBazaarNode, wal wallet.Wallet, contract *p if err != nil { return "", "", *big.NewInt(0), err } - addr, redeemScript, err := wal.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey}, 1, time.Duration(0), nil) + addr, redeemScript, err := escrowWallet.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey}, 1, time.Duration(0), nil) if err != nil { return "", "", *big.NewInt(0), err } @@ -1095,6 +1103,10 @@ func (n *OpenBazaarNode) CancelOfflineOrder(contract *pb.RicardianContract, reco if err != nil { return err } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } // Sweep the temp address into our wallet var utxos []wallet.TransactionInput for _, r := range records { @@ -1141,7 +1153,7 @@ func (n *OpenBazaarNode) CancelOfflineOrder(contract *pb.RicardianContract, reco if err != nil { return err } - _, err = wal.SweepAddress(utxos, &refundAddress, buyerKey, &redeemScript, wallet.NORMAL) + _, err = escrowWallet.SweepAddress(utxos, &refundAddress, buyerKey, &redeemScript, wallet.NORMAL) if err != nil { return err } @@ -1838,6 +1850,10 @@ func (n *OpenBazaarNode) ValidateDirectPaymentAddress(order *pb.Order) error { if err != nil { return err } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } mECKey, err := n.MasterPrivateKey.ECPubKey() if err != nil { return err @@ -1850,7 +1866,7 @@ func (n *OpenBazaarNode) ValidateDirectPaymentAddress(order *pb.Order) error { if err != nil { return err } - addr, redeemScript, err := wal.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey}, 1, time.Duration(0), nil) + addr, redeemScript, err := escrowWallet.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey}, 1, time.Duration(0), nil) if err != nil { return err } @@ -1870,6 +1886,10 @@ func (n *OpenBazaarNode) ValidateModeratedPaymentAddress(order *pb.Order, timeou if err != nil { return err } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } ipnsPath := ipfspath.FromString(order.Payment.Moderator + "/profile.json") profileBytes, err := ipfs.ResolveThenCat(n.IpfsNode, ipnsPath, time.Minute, n.IPNSQuorumSize, true) if err != nil { @@ -1912,7 +1932,7 @@ func (n *OpenBazaarNode) ValidateModeratedPaymentAddress(order *pb.Order, timeou if !bytes.Equal(order.Payment.ModeratorKey, modPub.SerializeCompressed()) { return errors.New("invalid moderator key") } - addr, redeemScript, err := wal.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey, *moderatorKey}, 2, timeout, vendorKey) + addr, redeemScript, err := escrowWallet.GenerateMultisigScript([]hd.ExtendedKey{*buyerKey, *vendorKey, *moderatorKey}, 2, timeout, vendorKey) if err != nil { return err } diff --git a/core/refunds.go b/core/refunds.go index d6e4270b5f..4b082554ea 100644 --- a/core/refunds.go +++ b/core/refunds.go @@ -35,6 +35,10 @@ func (n *OpenBazaarNode) RefundOrder(contract *pb.RicardianContract, records []* if err != nil { return err } + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return errors.New("wallet does not support escrow") + } if order.Payment.Method == pb.Order_Payment_MODERATED { var ins []wallet.TransactionInput outValue := big.NewInt(0) @@ -76,7 +80,7 @@ func (n *OpenBazaarNode) RefundOrder(contract *pb.RicardianContract, records []* return err } f, _ := new(big.Int).SetString(order.BigRefundFee, 10) - signatures, err := wal.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, vendorKey, redeemScript, *f) + signatures, err := escrowWallet.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, vendorKey, redeemScript, *f) if err != nil { return err } diff --git a/net/service/handlers.go b/net/service/handlers.go index 4403cc01d4..2db2742c20 100644 --- a/net/service/handlers.go +++ b/net/service/handlers.go @@ -731,6 +731,10 @@ func (service *OpenBazaarService) handleReject(p peer.ID, pmes *pb.Message, opti } if order.Payment.Method != pb.Order_Payment_MODERATED { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return nil, errors.New("wallet does not support escrow") + } // Sweep the address into our wallet var txInputs []wallet.TransactionInput for _, r := range records { @@ -774,11 +778,15 @@ func (service *OpenBazaarService) handleReject(p peer.ID, pmes *pb.Message, opti if err != nil { return nil, err } - _, err = wal.SweepAddress(txInputs, &refundAddress, buyerKey, &redeemScript, wallet.NORMAL) + _, err = escrowWallet.SweepAddress(txInputs, &refundAddress, buyerKey, &redeemScript, wallet.NORMAL) if err != nil { return nil, err } } else { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return nil, errors.New("wallet does not support escrow") + } var ins []wallet.TransactionInput outValue := big.NewInt(0) for _, r := range records { @@ -822,7 +830,7 @@ func (service *OpenBazaarService) handleReject(p peer.ID, pmes *pb.Message, opti if !ok { return nil, errors.New("invalid amount") } - buyerSignatures, err := wal.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, buyerKey, redeemScript, *fee) + buyerSignatures, err := escrowWallet.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, buyerKey, redeemScript, *fee) if err != nil { return nil, err } @@ -831,7 +839,7 @@ func (service *OpenBazaarService) handleReject(p peer.ID, pmes *pb.Message, opti sig := wallet.Signature{InputIndex: s.InputIndex, Signature: s.Signature} vendorSignatures = append(vendorSignatures, sig) } - _, err = wal.Multisign(ins, []wallet.TransactionOutput{output}, buyerSignatures, vendorSignatures, redeemScript, *fee, true) + _, err = escrowWallet.Multisign(ins, []wallet.TransactionOutput{output}, buyerSignatures, vendorSignatures, redeemScript, *fee, true) if err != nil { return nil, err } @@ -926,6 +934,10 @@ func (service *OpenBazaarService) handleRefund(p peer.ID, pmes *pb.Message, opti } if order.Payment.Method == pb.Order_Payment_MODERATED { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return nil, errors.New("wallet does not support escrow") + } var ins []wallet.TransactionInput outValue := big.NewInt(0) for _, r := range records { @@ -969,7 +981,7 @@ func (service *OpenBazaarService) handleRefund(p peer.ID, pmes *pb.Message, opti if !ok { return nil, errors.New("invalid amount") } - buyerSignatures, err := wal.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, buyerKey, redeemScript, *fee) + buyerSignatures, err := escrowWallet.CreateMultisigSignature(ins, []wallet.TransactionOutput{output}, buyerKey, redeemScript, *fee) if err != nil { return nil, err } @@ -978,7 +990,7 @@ func (service *OpenBazaarService) handleRefund(p peer.ID, pmes *pb.Message, opti sig := wallet.Signature{InputIndex: s.InputIndex, Signature: s.Signature} vendorSignatures = append(vendorSignatures, sig) } - _, err = wal.Multisign(ins, []wallet.TransactionOutput{output}, buyerSignatures, vendorSignatures, redeemScript, *fee, true) + _, err = escrowWallet.Multisign(ins, []wallet.TransactionOutput{output}, buyerSignatures, vendorSignatures, redeemScript, *fee, true) if err != nil { return nil, err } @@ -1191,6 +1203,10 @@ func (service *OpenBazaarService) handleOrderCompletion(p peer.ID, pmes *pb.Mess return nil, err } if order.Payment.Method == pb.Order_Payment_MODERATED && state != pb.OrderState_DISPUTED && state != pb.OrderState_DECIDED && state != pb.OrderState_RESOLVED && state != pb.OrderState_PAYMENT_FINALIZED { + escrowWallet, ok := wal.(wallet.EscrowWallet) + if !ok { + return nil, errors.New("wallet does not support escrow") + } var ins []wallet.TransactionInput outValue := big.NewInt(0) for _, r := range records { @@ -1243,7 +1259,7 @@ func (service *OpenBazaarService) handleOrderCompletion(p peer.ID, pmes *pb.Mess if !ok { return nil, errors.New("invalid amount") } - _, err = wal.Multisign(ins, []wallet.TransactionOutput{output}, buyerSignatures, vendorSignatures, redeemScript, *payoutFee, true) + _, err = escrowWallet.Multisign(ins, []wallet.TransactionOutput{output}, buyerSignatures, vendorSignatures, redeemScript, *payoutFee, true) if err != nil { if err.Error() == "ERROR_INSUFFICIENT_FUNDS" { err0 := service.node.Datastore.Messages().Put( diff --git a/repo/db/txns.go b/repo/db/txns.go index c8555e1a30..4b23cf5a19 100644 --- a/repo/db/txns.go +++ b/repo/db/txns.go @@ -8,7 +8,6 @@ import ( "github.com/OpenBazaar/openbazaar-go/repo" "github.com/OpenBazaar/wallet-interface" - "github.com/btcsuite/btcd/chaincfg/chainhash" ) type TxnsDB struct { @@ -117,10 +116,10 @@ func (t *TxnsDB) GetAll(includeWatchOnly bool) ([]wallet.Txn, error) { return ret, nil } -func (t *TxnsDB) Delete(txid *chainhash.Hash) error { +func (t *TxnsDB) Delete(txid string) error { t.lock.Lock() defer t.lock.Unlock() - _, err := t.db.Exec("delete from txns where txid=? and coin=?", txid.String(), t.coinType.CurrencyCode()) + _, err := t.db.Exec("delete from txns where txid=? and coin=?", txid, t.coinType.CurrencyCode()) if err != nil { return err } diff --git a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go index 8bb4a340db..f6d437ae1d 100644 --- a/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go +++ b/vendor/github.com/OpenBazaar/go-ethwallet/wallet/wallet.go @@ -831,7 +831,7 @@ func (wallet *EthereumWallet) checkTxnRcpt(hash *common.Hash, data []byte) (*com if err != nil { return nil, err } - err = wallet.db.Txns().Delete(chash) + err = wallet.db.Txns().Delete(chash.String()) if err != nil { log.Errorf("err deleting the pending txn : %v", err) } diff --git a/vendor/github.com/OpenBazaar/wallet-interface/datastore.go b/vendor/github.com/OpenBazaar/wallet-interface/datastore.go index 30af2eefe6..fc3e16848b 100644 --- a/vendor/github.com/OpenBazaar/wallet-interface/datastore.go +++ b/vendor/github.com/OpenBazaar/wallet-interface/datastore.go @@ -143,7 +143,7 @@ type Txns interface { UpdateHeight(txid string, height int, timestamp time.Time) error // Delete a transactions from the db - Delete(txid *chainhash.Hash) error + Delete(txid string) error } // Keys provides a database interface for the wallet to save key material, track diff --git a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go index 7ef7124529..6cc2d7ca9b 100644 --- a/vendor/github.com/OpenBazaar/wallet-interface/wallet.go +++ b/vendor/github.com/OpenBazaar/wallet-interface/wallet.go @@ -45,9 +45,7 @@ import ( // escrowed payment. type Wallet interface { walletMustManager - walletMustKeysmither walletMustBanker - walletCanBumpFee } var ( @@ -135,8 +133,6 @@ type EscrowWallet interface { Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) } - - type walletMustManager interface { // Start is called when the openbazaar-go daemon starts up. At this point in time // the wallet implementation should start syncing and/or updating balances, but @@ -231,66 +227,14 @@ type walletMustManager interface { // function leaves it up the wallet implementation to decide how to derive the child key // so long as it's deterministic and uses the chaincode and the returned key is pseudorandom. ChildKey(keyBytes []byte, chaincode []byte, isPrivateKey bool) (*hd.ExtendedKey, error) -} - -type walletMustKeysmither interface { // HasKey returns whether or not the wallet has the key for the given address. This method // is called by openbazaar-go when validating payouts from multisigs. It makes sure the // transaction that the other party(s) signed does indeed pay to an address that we // control. HasKey(addr btc.Address) bool - - // GenerateMultisigScript should deterministically create a redeem script and address from the information provided. - // This method should be strictly limited to taking the input data, combining it to produce the redeem script and - // address and that's it. There is no need to interact with the network or make any transactions when this is called. - // - // Openbazaar-go will call this method in the following situations: - // 1) When the buyer places an order he passes in the relevant keys for each party to get back the address where - // the funds should be sent and the redeem script. The redeem script is saved in order (and openbazaar-go database). - // - // 2) The vendor calls this method when he receives and order so as to validate that the address they buyer is sending - // funds to is indeed correctly constructed. If this method fails to return the same values for the vendor as it - // did the buyer, the vendor will reject the order. - // - // 3) The moderator calls this function upon receiving a dispute so that he can validate the payment address for the - // order and make sure neither party is trying to maliciously lie about the details of the dispute to get the moderator - // to release the funds. - // - // Note that according to the order flow, this method is called by the buyer *before* the order is sent to the vendor, - // and before the vendor validates the order. Only after the buyer hears back from the vendor does the buyer send - // funds (either from an external wallet or via the `Spend` method) to the address specified in this method's return. - // - // `threshold` is the number of keys required to release the funds from the address. If `threshold` is two and len(keys) - // is three, this is a two of three multisig. If `timeoutKey` is not nil, then the script should allow the funds to - // be released with a signature from the `timeoutKey` after the `timeout` duration has passed. - // For example: - // OP_IF 2 3 OP_ELSE OP_CHECKSEQUENCEVERIFY OP_CHECKSIG OP_ENDIF - // - // If `timeoutKey` is nil then the a normal multisig without a timeout should be created. - GenerateMultisigScript(keys []hd.ExtendedKey, threshold int, timeout time.Duration, timeoutKey *hd.ExtendedKey) (addr btc.Address, redeemScript []byte, err error) - - // CreateMultisigSignature should build a transaction using the given inputs and outputs and sign it with the - // provided key. A list of signatures (one for each input) should be returned. - // - // This method is called by openbazaar-go by each party whenever they decide to release the funds from escrow. - // This method should not actually move any funds or make any transactions, only create necessary signatures to - // do so. The caller will then take the signature and share it with the other parties. Once all parties have shared - // their signatures, the person who wants to release the funds collects them and uses them as an input to the - // `Multisign` method. - CreateMultisigSignature(ins []TransactionInput, outs []TransactionOutput, key *hd.ExtendedKey, redeemScript []byte, feePerByte big.Int) ([]Signature, error) - - // Multisign collects all of the signatures generated by the `CreateMultisigSignature` function and builds a final - // transaction that can then be broadcast to the blockchain. The []byte return is the raw transaction. It should be - // broadcasted if `broadcast` is true. If the signatures combine and produce an invalid transaction then an error - // should be returned. - // - // This method is called by openbazaar-go by whichever party to the escrow is trying to release the funds only after - // all needed parties have signed using `CreateMultisigSignature` and have shared their signatures with each other. - Multisign(ins []TransactionInput, outs []TransactionOutput, sigs1 []Signature, sigs2 []Signature, redeemScript []byte, feePerByte big.Int, broadcast bool) ([]byte, error) } - type walletMustBanker interface { // GetFeePerByte returns the current fee per byte for the given fee level. There // are three fee levels ― priority, normal, and economic. @@ -324,26 +268,9 @@ type walletMustBanker interface { // // All amounts should be in the coin's base unit (for example: satoshis). EstimateSpendFee(amount big.Int, feeLevel FeeLevel) (big.Int, error) - - // SweepAddress should sweep all the funds from the provided inputs into the provided `address` using the given - // `key`. If `address` is nil, the funds should be swept into an internal address own by this wallet. - // If the `redeemScript` is not nil, this should be treated as a multisig (p2sh) address and signed accordingly. - // - // This method is called by openbazaar-go in the following scenarios: - // 1) The buyer placed a direct order to a vendor who was offline. The buyer sent funds into a 1 of 2 multisig. - // Upon returning online the vendor accepts the order and calls SweepAddress to move the funds into his wallet. - // - // 2) Same as above but the buyer wishes to cancel the order before the vendor comes online. He calls SweepAddress - // to return the funds from the 1 of 2 multisig back into has wallet. - // - // 3) Same as above but rather than accepting the order, the vendor rejects it. When the buyer receives the reject - // message he calls SweepAddress to move the funds back into his wallet. - // - // 4) The timeout has expired on a 2 of 3 multisig. The vendor calls SweepAddress to claim the funds. - SweepAddress(ins []TransactionInput, address *btc.Address, key *hd.ExtendedKey, redeemScript *[]byte, feeLevel FeeLevel) (string, error) } -type walletCanBumpFee interface { +type WalletCanBumpFee interface { // BumpFee should attempt to bump the fee on a given unconfirmed transaction (if possible) to // try to get it confirmed and return the txid of the new transaction (if one exists). // Since this method is only called in response to user action, it is acceptable to From 6a1605264f42eaec25a8e8d0c1c259d691e04bd8 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 26 Jul 2020 16:20:36 -0400 Subject: [PATCH 21/52] Update multiwallet dep --- .../OpenBazaar/multiwallet/filecoin/wallet.go | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go b/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go index 623ba28668..83025e3175 100644 --- a/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go +++ b/vendor/github.com/OpenBazaar/multiwallet/filecoin/wallet.go @@ -336,6 +336,30 @@ func (w *FilecoinWallet) Spend(amount big.Int, addr btcutil.Address, feeLevel wi return "", err } + myAddr, err := NewFilecoinAddress(w.addr.String()) + if err != nil { + return "", err + } + w.AssociateTransactionWithOrder(wi.TransactionCallback{ + Timestamp: time.Now(), + Outputs: []wi.TransactionOutput{ + { + Address: addr, + Value: amount, + OrderID: referenceID, + }, + }, + Inputs: []wi.TransactionInput{ + { + Value: amount, + OrderID: referenceID, + LinkedAddress: myAddr, + }, + }, + Value: *amount.Mul(&amount, big.NewInt(-1)), + Txid: id.String(), + }) + return id.String(), nil } From 2d8d5a24ee4a6ffcab254c8735a6f800f1983cb7 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Thu, 23 Jul 2020 16:12:40 -0400 Subject: [PATCH 22/52] Remove chainhash code --- core/utils.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/utils.go b/core/utils.go index 256bb18713..57f2fcd702 100644 --- a/core/utils.go +++ b/core/utils.go @@ -48,11 +48,8 @@ func (n *OpenBazaarNode) BuildTransactionRecords(contract *pb.RicardianContract, return paymentRecords, nil, err } tx.Timestamp = ts - ch, err := chainhash.NewHashFromStr(strings.TrimPrefix(tx.Txid, "0x")) - if err != nil { - return paymentRecords, nil, err - } - confirmations, height, err := wal.GetConfirmations(ch.String()) + + confirmations, height, err := wal.GetConfirmations(tx.Txid) if err != nil { return paymentRecords, nil, err } From 5c35c76ab333c3694845f40e979862d9fc79a607 Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Tue, 28 Jul 2020 07:18:36 -0400 Subject: [PATCH 23/52] Add opentracing --- .../opentracing/opentracing-go/.gitignore | 1 + .../opentracing/opentracing-go/.travis.yml | 20 + .../opentracing/opentracing-go/CHANGELOG.md | 63 +++ .../opentracing/opentracing-go/LICENSE | 201 ++++++++ .../opentracing/opentracing-go/Makefile | 20 + .../opentracing/opentracing-go/README.md | 171 +++++++ .../opentracing/opentracing-go/ext.go | 24 + .../opentracing/opentracing-go/ext/field.go | 17 + .../opentracing-go/ext/field_test.go | 50 ++ .../opentracing/opentracing-go/ext/tags.go | 215 ++++++++ .../opentracing-go/ext/tags_test.go | 148 ++++++ .../opentracing-go/globaltracer.go | 42 ++ .../opentracing-go/globaltracer_test.go | 26 + .../opentracing/opentracing-go/go.mod | 5 + .../opentracing/opentracing-go/go.sum | 7 + .../opentracing/opentracing-go/gocontext.go | 65 +++ .../opentracing-go/gocontext_test.go | 121 +++++ .../opentracing-go/harness/api_checkers.go | 472 ++++++++++++++++++ .../opentracing-go/harness/noop_api_test.go | 17 + .../opentracing/opentracing-go/log/field.go | 282 +++++++++++ .../opentracing-go/log/field_test.go | 59 +++ .../opentracing/opentracing-go/log/util.go | 61 +++ .../opentracing-go/log/util_test.go | 86 ++++ .../mocktracer/mocklogrecord.go | 105 ++++ .../opentracing-go/mocktracer/mockspan.go | 284 +++++++++++ .../opentracing-go/mocktracer/mocktracer.go | 105 ++++ .../mocktracer/mocktracer_test.go | 284 +++++++++++ .../opentracing-go/mocktracer/propagation.go | 120 +++++ .../opentracing/opentracing-go/noop.go | 64 +++ .../opentracing-go/options_test.go | 31 ++ .../opentracing/opentracing-go/propagation.go | 176 +++++++ .../opentracing-go/propagation_test.go | 93 ++++ .../opentracing/opentracing-go/span.go | 189 +++++++ .../opentracing-go/testtracer_test.go | 138 +++++ .../opentracing/opentracing-go/tracer.go | 304 +++++++++++ 35 files changed, 4066 insertions(+) create mode 100644 vendor/github.com/opentracing/opentracing-go/.gitignore create mode 100644 vendor/github.com/opentracing/opentracing-go/.travis.yml create mode 100644 vendor/github.com/opentracing/opentracing-go/CHANGELOG.md create mode 100644 vendor/github.com/opentracing/opentracing-go/LICENSE create mode 100644 vendor/github.com/opentracing/opentracing-go/Makefile create mode 100644 vendor/github.com/opentracing/opentracing-go/README.md create mode 100644 vendor/github.com/opentracing/opentracing-go/ext.go create mode 100644 vendor/github.com/opentracing/opentracing-go/ext/field.go create mode 100644 vendor/github.com/opentracing/opentracing-go/ext/field_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/ext/tags.go create mode 100644 vendor/github.com/opentracing/opentracing-go/ext/tags_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/globaltracer.go create mode 100644 vendor/github.com/opentracing/opentracing-go/globaltracer_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/go.mod create mode 100644 vendor/github.com/opentracing/opentracing-go/go.sum create mode 100644 vendor/github.com/opentracing/opentracing-go/gocontext.go create mode 100644 vendor/github.com/opentracing/opentracing-go/gocontext_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/harness/api_checkers.go create mode 100644 vendor/github.com/opentracing/opentracing-go/harness/noop_api_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/log/field.go create mode 100644 vendor/github.com/opentracing/opentracing-go/log/field_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/log/util.go create mode 100644 vendor/github.com/opentracing/opentracing-go/log/util_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/mocktracer/mocklogrecord.go create mode 100644 vendor/github.com/opentracing/opentracing-go/mocktracer/mockspan.go create mode 100644 vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer.go create mode 100644 vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/mocktracer/propagation.go create mode 100644 vendor/github.com/opentracing/opentracing-go/noop.go create mode 100644 vendor/github.com/opentracing/opentracing-go/options_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/propagation.go create mode 100644 vendor/github.com/opentracing/opentracing-go/propagation_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/span.go create mode 100644 vendor/github.com/opentracing/opentracing-go/testtracer_test.go create mode 100644 vendor/github.com/opentracing/opentracing-go/tracer.go diff --git a/vendor/github.com/opentracing/opentracing-go/.gitignore b/vendor/github.com/opentracing/opentracing-go/.gitignore new file mode 100644 index 0000000000..c57100a595 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/.gitignore @@ -0,0 +1 @@ +coverage.txt diff --git a/vendor/github.com/opentracing/opentracing-go/.travis.yml b/vendor/github.com/opentracing/opentracing-go/.travis.yml new file mode 100644 index 0000000000..b950e42965 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/.travis.yml @@ -0,0 +1,20 @@ +language: go + +matrix: + include: + - go: "1.13.x" + - go: "1.14.x" + - go: "tip" + env: + - LINT=true + - COVERAGE=true + +install: + - if [ "$LINT" == true ]; then go get -u golang.org/x/lint/golint/... ; else echo 'skipping lint'; fi + - go get -u github.com/stretchr/testify/... + +script: + - make test + - go build ./... + - if [ "$LINT" == true ]; then make lint ; else echo 'skipping lint'; fi + - if [ "$COVERAGE" == true ]; then make cover && bash <(curl -s https://codecov.io/bash) ; else echo 'skipping coverage'; fi diff --git a/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md new file mode 100644 index 0000000000..d3bfcf6235 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/CHANGELOG.md @@ -0,0 +1,63 @@ +Changes by Version +================== + + +1.2.0 (2020-07-01) +------------------- + +* Restore the ability to reset the current span in context to nil (#231) -- Yuri Shkuro +* Use error.object per OpenTracing Semantic Conventions (#179) -- Rahman Syed +* Convert nil pointer log field value to string "nil" (#230) -- Cyril Tovena +* Add Go module support (#215) -- Zaba505 +* Make SetTag helper types in ext public (#229) -- Blake Edwards +* Add log/fields helpers for keys from specification (#226) -- Dmitry Monakhov +* Improve noop impementation (#223) -- chanxuehong +* Add an extension to Tracer interface for custom go context creation (#220) -- Krzesimir Nowak +* Fix typo in comments (#222) -- meteorlxy +* Improve documentation for log.Object() to emphasize the requirement to pass immutable arguments (#219) -- 疯狂的小企鹅 +* [mock] Return ErrInvalidSpanContext if span context is not MockSpanContext (#216) -- Milad Irannejad + + +1.1.0 (2019-03-23) +------------------- + +Notable changes: +- The library is now released under Apache 2.0 license +- Use Set() instead of Add() in HTTPHeadersCarrier is functionally a breaking change (fixes issue [#159](https://github.com/opentracing/opentracing-go/issues/159)) +- 'golang.org/x/net/context' is replaced with 'context' from the standard library + +List of all changes: + +- Export StartSpanFromContextWithTracer (#214) +- Add IsGlobalTracerRegistered() to indicate if a tracer has been registered (#201) +- Use Set() instead of Add() in HTTPHeadersCarrier (#191) +- Update license to Apache 2.0 (#181) +- Replace 'golang.org/x/net/context' with 'context' (#176) +- Port of Python opentracing/harness/api_check.py to Go (#146) +- Fix race condition in MockSpan.Context() (#170) +- Add PeerHostIPv4.SetString() (#155) +- Add a Noop log field type to log to allow for optional fields (#150) + + +1.0.2 (2017-04-26) +------------------- + +- Add more semantic tags (#139) + + +1.0.1 (2017-02-06) +------------------- + +- Correct spelling in comments +- Address race in nextMockID() (#123) +- log: avoid panic marshaling nil error (#131) +- Deprecate InitGlobalTracer in favor of SetGlobalTracer (#128) +- Drop Go 1.5 that fails in Travis (#129) +- Add convenience methods Key() and Value() to log.Field +- Add convenience methods to log.Field (2 years, 6 months ago) + +1.0.0 (2016-09-26) +------------------- + +- This release implements OpenTracing Specification 1.0 (https://opentracing.io/spec) + diff --git a/vendor/github.com/opentracing/opentracing-go/LICENSE b/vendor/github.com/opentracing/opentracing-go/LICENSE new file mode 100644 index 0000000000..f0027349e8 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 The OpenTracing Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/opentracing/opentracing-go/Makefile b/vendor/github.com/opentracing/opentracing-go/Makefile new file mode 100644 index 0000000000..62abb63f58 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/Makefile @@ -0,0 +1,20 @@ +.DEFAULT_GOAL := test-and-lint + +.PHONY: test-and-lint +test-and-lint: test lint + +.PHONY: test +test: + go test -v -cover -race ./... + +.PHONY: cover +cover: + go test -v -coverprofile=coverage.txt -covermode=atomic -race ./... + +.PHONY: lint +lint: + go fmt ./... + golint ./... + @# Run again with magic to exit non-zero if golint outputs anything. + @! (golint ./... | read dummy) + go vet ./... diff --git a/vendor/github.com/opentracing/opentracing-go/README.md b/vendor/github.com/opentracing/opentracing-go/README.md new file mode 100644 index 0000000000..6ef1d7c9d2 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/README.md @@ -0,0 +1,171 @@ +[![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/opentracing/public) [![Build Status](https://travis-ci.org/opentracing/opentracing-go.svg?branch=master)](https://travis-ci.org/opentracing/opentracing-go) [![GoDoc](https://godoc.org/github.com/opentracing/opentracing-go?status.svg)](http://godoc.org/github.com/opentracing/opentracing-go) +[![Sourcegraph Badge](https://sourcegraph.com/github.com/opentracing/opentracing-go/-/badge.svg)](https://sourcegraph.com/github.com/opentracing/opentracing-go?badge) + +# OpenTracing API for Go + +This package is a Go platform API for OpenTracing. + +## Required Reading + +In order to understand the Go platform API, one must first be familiar with the +[OpenTracing project](https://opentracing.io) and +[terminology](https://opentracing.io/specification/) more specifically. + +## API overview for those adding instrumentation + +Everyday consumers of this `opentracing` package really only need to worry +about a couple of key abstractions: the `StartSpan` function, the `Span` +interface, and binding a `Tracer` at `main()`-time. Here are code snippets +demonstrating some important use cases. + +#### Singleton initialization + +The simplest starting point is `./default_tracer.go`. As early as possible, call + +```go + import "github.com/opentracing/opentracing-go" + import ".../some_tracing_impl" + + func main() { + opentracing.SetGlobalTracer( + // tracing impl specific: + some_tracing_impl.New(...), + ) + ... + } +``` + +#### Non-Singleton initialization + +If you prefer direct control to singletons, manage ownership of the +`opentracing.Tracer` implementation explicitly. + +#### Creating a Span given an existing Go `context.Context` + +If you use `context.Context` in your application, OpenTracing's Go library will +happily rely on it for `Span` propagation. To start a new (blocking child) +`Span`, you can use `StartSpanFromContext`. + +```go + func xyz(ctx context.Context, ...) { + ... + span, ctx := opentracing.StartSpanFromContext(ctx, "operation_name") + defer span.Finish() + span.LogFields( + log.String("event", "soft error"), + log.String("type", "cache timeout"), + log.Int("waited.millis", 1500)) + ... + } +``` + +#### Starting an empty trace by creating a "root span" + +It's always possible to create a "root" `Span` with no parent or other causal +reference. + +```go + func xyz() { + ... + sp := opentracing.StartSpan("operation_name") + defer sp.Finish() + ... + } +``` + +#### Creating a (child) Span given an existing (parent) Span + +```go + func xyz(parentSpan opentracing.Span, ...) { + ... + sp := opentracing.StartSpan( + "operation_name", + opentracing.ChildOf(parentSpan.Context())) + defer sp.Finish() + ... + } +``` + +#### Serializing to the wire + +```go + func makeSomeRequest(ctx context.Context) ... { + if span := opentracing.SpanFromContext(ctx); span != nil { + httpClient := &http.Client{} + httpReq, _ := http.NewRequest("GET", "http://myservice/", nil) + + // Transmit the span's TraceContext as HTTP headers on our + // outbound request. + opentracing.GlobalTracer().Inject( + span.Context(), + opentracing.HTTPHeaders, + opentracing.HTTPHeadersCarrier(httpReq.Header)) + + resp, err := httpClient.Do(httpReq) + ... + } + ... + } +``` + +#### Deserializing from the wire + +```go + http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + var serverSpan opentracing.Span + appSpecificOperationName := ... + wireContext, err := opentracing.GlobalTracer().Extract( + opentracing.HTTPHeaders, + opentracing.HTTPHeadersCarrier(req.Header)) + if err != nil { + // Optionally record something about err here + } + + // Create the span referring to the RPC client if available. + // If wireContext == nil, a root span will be created. + serverSpan = opentracing.StartSpan( + appSpecificOperationName, + ext.RPCServerOption(wireContext)) + + defer serverSpan.Finish() + + ctx := opentracing.ContextWithSpan(context.Background(), serverSpan) + ... + } +``` + +#### Conditionally capture a field using `log.Noop` + +In some situations, you may want to dynamically decide whether or not +to log a field. For example, you may want to capture additional data, +such as a customer ID, in non-production environments: + +```go + func Customer(order *Order) log.Field { + if os.Getenv("ENVIRONMENT") == "dev" { + return log.String("customer", order.Customer.ID) + } + return log.Noop() + } +``` + +#### Goroutine-safety + +The entire public API is goroutine-safe and does not require external +synchronization. + +## API pointers for those implementing a tracing system + +Tracing system implementors may be able to reuse or copy-paste-modify the `basictracer` package, found [here](https://github.com/opentracing/basictracer-go). In particular, see `basictracer.New(...)`. + +## API compatibility + +For the time being, "mild" backwards-incompatible changes may be made without changing the major version number. As OpenTracing and `opentracing-go` mature, backwards compatibility will become more of a priority. + +## Tracer test suite + +A test suite is available in the [harness](https://godoc.org/github.com/opentracing/opentracing-go/harness) package that can assist Tracer implementors to assert that their Tracer is working correctly. + +## Licensing + +[Apache 2.0 License](./LICENSE). diff --git a/vendor/github.com/opentracing/opentracing-go/ext.go b/vendor/github.com/opentracing/opentracing-go/ext.go new file mode 100644 index 0000000000..e11977ebe8 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/ext.go @@ -0,0 +1,24 @@ +package opentracing + +import ( + "context" +) + +// TracerContextWithSpanExtension is an extension interface that the +// implementation of the Tracer interface may want to implement. It +// allows to have some control over the go context when the +// ContextWithSpan is invoked. +// +// The primary purpose of this extension are adapters from opentracing +// API to some other tracing API. +type TracerContextWithSpanExtension interface { + // ContextWithSpanHook gets called by the ContextWithSpan + // function, when the Tracer implementation also implements + // this interface. It allows to put extra information into the + // context and make it available to the callers of the + // ContextWithSpan. + // + // This hook is invoked before the ContextWithSpan function + // actually puts the span into the context. + ContextWithSpanHook(ctx context.Context, span Span) context.Context +} diff --git a/vendor/github.com/opentracing/opentracing-go/ext/field.go b/vendor/github.com/opentracing/opentracing-go/ext/field.go new file mode 100644 index 0000000000..8282bd7584 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/ext/field.go @@ -0,0 +1,17 @@ +package ext + +import ( + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/log" +) + +// LogError sets the error=true tag on the Span and logs err as an "error" event. +func LogError(span opentracing.Span, err error, fields ...log.Field) { + Error.Set(span, true) + ef := []log.Field{ + log.Event("error"), + log.Error(err), + } + ef = append(ef, fields...) + span.LogFields(ef...) +} diff --git a/vendor/github.com/opentracing/opentracing-go/ext/field_test.go b/vendor/github.com/opentracing/opentracing-go/ext/field_test.go new file mode 100644 index 0000000000..d4f633e355 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/ext/field_test.go @@ -0,0 +1,50 @@ +package ext_test + +import ( + "fmt" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/opentracing/opentracing-go/ext" + "github.com/opentracing/opentracing-go/log" + "github.com/opentracing/opentracing-go/mocktracer" +) + +func TestLogError(t *testing.T) { + tracer := mocktracer.New() + span := tracer.StartSpan("my-trace") + ext.Component.Set(span, "my-awesome-library") + ext.SamplingPriority.Set(span, 1) + err := fmt.Errorf("my error") + ext.LogError(span, err, log.Message("my optional msg text")) + + span.Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "component": "my-awesome-library", + "error": true, + }, rawSpan.Tags()) + + assert.Equal(t, len(rawSpan.Logs()), 1) + fields := rawSpan.Logs()[0].Fields + assert.Equal(t, []mocktracer.MockKeyValue{ + { + Key: "event", + ValueKind: reflect.String, + ValueString: "error", + }, + { + Key: "error.object", + ValueKind: reflect.String, + ValueString: err.Error(), + }, + { + Key: "message", + ValueKind: reflect.String, + ValueString: "my optional msg text", + }, + }, fields) +} diff --git a/vendor/github.com/opentracing/opentracing-go/ext/tags.go b/vendor/github.com/opentracing/opentracing-go/ext/tags.go new file mode 100644 index 0000000000..a414b5951f --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/ext/tags.go @@ -0,0 +1,215 @@ +package ext + +import "github.com/opentracing/opentracing-go" + +// These constants define common tag names recommended for better portability across +// tracing systems and languages/platforms. +// +// The tag names are defined as typed strings, so that in addition to the usual use +// +// span.setTag(TagName, value) +// +// they also support value type validation via this additional syntax: +// +// TagName.Set(span, value) +// +var ( + ////////////////////////////////////////////////////////////////////// + // SpanKind (client/server or producer/consumer) + ////////////////////////////////////////////////////////////////////// + + // SpanKind hints at relationship between spans, e.g. client/server + SpanKind = spanKindTagName("span.kind") + + // SpanKindRPCClient marks a span representing the client-side of an RPC + // or other remote call + SpanKindRPCClientEnum = SpanKindEnum("client") + SpanKindRPCClient = opentracing.Tag{Key: string(SpanKind), Value: SpanKindRPCClientEnum} + + // SpanKindRPCServer marks a span representing the server-side of an RPC + // or other remote call + SpanKindRPCServerEnum = SpanKindEnum("server") + SpanKindRPCServer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindRPCServerEnum} + + // SpanKindProducer marks a span representing the producer-side of a + // message bus + SpanKindProducerEnum = SpanKindEnum("producer") + SpanKindProducer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindProducerEnum} + + // SpanKindConsumer marks a span representing the consumer-side of a + // message bus + SpanKindConsumerEnum = SpanKindEnum("consumer") + SpanKindConsumer = opentracing.Tag{Key: string(SpanKind), Value: SpanKindConsumerEnum} + + ////////////////////////////////////////////////////////////////////// + // Component name + ////////////////////////////////////////////////////////////////////// + + // Component is a low-cardinality identifier of the module, library, + // or package that is generating a span. + Component = StringTagName("component") + + ////////////////////////////////////////////////////////////////////// + // Sampling hint + ////////////////////////////////////////////////////////////////////// + + // SamplingPriority determines the priority of sampling this Span. + SamplingPriority = Uint16TagName("sampling.priority") + + ////////////////////////////////////////////////////////////////////// + // Peer tags. These tags can be emitted by either client-side or + // server-side to describe the other side/service in a peer-to-peer + // communications, like an RPC call. + ////////////////////////////////////////////////////////////////////// + + // PeerService records the service name of the peer. + PeerService = StringTagName("peer.service") + + // PeerAddress records the address name of the peer. This may be a "ip:port", + // a bare "hostname", a FQDN or even a database DSN substring + // like "mysql://username@127.0.0.1:3306/dbname" + PeerAddress = StringTagName("peer.address") + + // PeerHostname records the host name of the peer + PeerHostname = StringTagName("peer.hostname") + + // PeerHostIPv4 records IP v4 host address of the peer + PeerHostIPv4 = IPv4TagName("peer.ipv4") + + // PeerHostIPv6 records IP v6 host address of the peer + PeerHostIPv6 = StringTagName("peer.ipv6") + + // PeerPort records port number of the peer + PeerPort = Uint16TagName("peer.port") + + ////////////////////////////////////////////////////////////////////// + // HTTP Tags + ////////////////////////////////////////////////////////////////////// + + // HTTPUrl should be the URL of the request being handled in this segment + // of the trace, in standard URI format. The protocol is optional. + HTTPUrl = StringTagName("http.url") + + // HTTPMethod is the HTTP method of the request, and is case-insensitive. + HTTPMethod = StringTagName("http.method") + + // HTTPStatusCode is the numeric HTTP status code (200, 404, etc) of the + // HTTP response. + HTTPStatusCode = Uint16TagName("http.status_code") + + ////////////////////////////////////////////////////////////////////// + // DB Tags + ////////////////////////////////////////////////////////////////////// + + // DBInstance is database instance name. + DBInstance = StringTagName("db.instance") + + // DBStatement is a database statement for the given database type. + // It can be a query or a prepared statement (i.e., before substitution). + DBStatement = StringTagName("db.statement") + + // DBType is a database type. For any SQL database, "sql". + // For others, the lower-case database category, e.g. "redis" + DBType = StringTagName("db.type") + + // DBUser is a username for accessing database. + DBUser = StringTagName("db.user") + + ////////////////////////////////////////////////////////////////////// + // Message Bus Tag + ////////////////////////////////////////////////////////////////////// + + // MessageBusDestination is an address at which messages can be exchanged + MessageBusDestination = StringTagName("message_bus.destination") + + ////////////////////////////////////////////////////////////////////// + // Error Tag + ////////////////////////////////////////////////////////////////////// + + // Error indicates that operation represented by the span resulted in an error. + Error = BoolTagName("error") +) + +// --- + +// SpanKindEnum represents common span types +type SpanKindEnum string + +type spanKindTagName string + +// Set adds a string tag to the `span` +func (tag spanKindTagName) Set(span opentracing.Span, value SpanKindEnum) { + span.SetTag(string(tag), value) +} + +type rpcServerOption struct { + clientContext opentracing.SpanContext +} + +func (r rpcServerOption) Apply(o *opentracing.StartSpanOptions) { + if r.clientContext != nil { + opentracing.ChildOf(r.clientContext).Apply(o) + } + SpanKindRPCServer.Apply(o) +} + +// RPCServerOption returns a StartSpanOption appropriate for an RPC server span +// with `client` representing the metadata for the remote peer Span if available. +// In case client == nil, due to the client not being instrumented, this RPC +// server span will be a root span. +func RPCServerOption(client opentracing.SpanContext) opentracing.StartSpanOption { + return rpcServerOption{client} +} + +// --- + +// StringTagName is a common tag name to be set to a string value +type StringTagName string + +// Set adds a string tag to the `span` +func (tag StringTagName) Set(span opentracing.Span, value string) { + span.SetTag(string(tag), value) +} + +// --- + +// Uint32TagName is a common tag name to be set to a uint32 value +type Uint32TagName string + +// Set adds a uint32 tag to the `span` +func (tag Uint32TagName) Set(span opentracing.Span, value uint32) { + span.SetTag(string(tag), value) +} + +// --- + +// Uint16TagName is a common tag name to be set to a uint16 value +type Uint16TagName string + +// Set adds a uint16 tag to the `span` +func (tag Uint16TagName) Set(span opentracing.Span, value uint16) { + span.SetTag(string(tag), value) +} + +// --- + +// BoolTagName is a common tag name to be set to a bool value +type BoolTagName string + +// Set adds a bool tag to the `span` +func (tag BoolTagName) Set(span opentracing.Span, value bool) { + span.SetTag(string(tag), value) +} + +// IPv4TagName is a common tag name to be set to an ipv4 value +type IPv4TagName string + +// Set adds IP v4 host address of the peer as an uint32 value to the `span`, keep this for backward and zipkin compatibility +func (tag IPv4TagName) Set(span opentracing.Span, value uint32) { + span.SetTag(string(tag), value) +} + +// SetString records IP v4 host address of the peer as a .-separated tuple to the `span`. E.g., "127.0.0.1" +func (tag IPv4TagName) SetString(span opentracing.Span, value string) { + span.SetTag(string(tag), value) +} diff --git a/vendor/github.com/opentracing/opentracing-go/ext/tags_test.go b/vendor/github.com/opentracing/opentracing-go/ext/tags_test.go new file mode 100644 index 0000000000..ea9af335c7 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/ext/tags_test.go @@ -0,0 +1,148 @@ +package ext_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/opentracing/opentracing-go/mocktracer" +) + +func TestPeerTags(t *testing.T) { + if ext.PeerService != "peer.service" { + t.Fatalf("Invalid PeerService %v", ext.PeerService) + } + tracer := mocktracer.New() + span := tracer.StartSpan("my-trace") + ext.PeerService.Set(span, "my-service") + ext.PeerAddress.Set(span, "my-hostname:8080") + ext.PeerHostname.Set(span, "my-hostname") + ext.PeerHostIPv4.Set(span, uint32(127<<24|1)) + ext.PeerHostIPv6.Set(span, "::") + ext.PeerPort.Set(span, uint16(8080)) + ext.SamplingPriority.Set(span, uint16(1)) + ext.SpanKind.Set(span, ext.SpanKindRPCServerEnum) + ext.SpanKindRPCClient.Set(span) + span.Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "peer.service": "my-service", + "peer.address": "my-hostname:8080", + "peer.hostname": "my-hostname", + "peer.ipv4": uint32(127<<24 | 1), + "peer.ipv6": "::", + "peer.port": uint16(8080), + "span.kind": ext.SpanKindRPCClientEnum, + }, rawSpan.Tags()) + assert.True(t, span.Context().(mocktracer.MockSpanContext).Sampled) + ext.SamplingPriority.Set(span, uint16(0)) + assert.False(t, span.Context().(mocktracer.MockSpanContext).Sampled) +} + +func TestHTTPTags(t *testing.T) { + tracer := mocktracer.New() + span := tracer.StartSpan("my-trace", ext.SpanKindRPCServer) + ext.HTTPUrl.Set(span, "test.biz/uri?protocol=false") + ext.HTTPMethod.Set(span, "GET") + ext.HTTPStatusCode.Set(span, 301) + span.Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "http.url": "test.biz/uri?protocol=false", + "http.method": "GET", + "http.status_code": uint16(301), + "span.kind": ext.SpanKindRPCServerEnum, + }, rawSpan.Tags()) +} + +func TestDBTags(t *testing.T) { + tracer := mocktracer.New() + span := tracer.StartSpan("my-trace", ext.SpanKindRPCClient) + ext.DBInstance.Set(span, "127.0.0.1:3306/customers") + ext.DBStatement.Set(span, "SELECT * FROM user_table") + ext.DBType.Set(span, "sql") + ext.DBUser.Set(span, "customer_user") + span.Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "db.instance": "127.0.0.1:3306/customers", + "db.statement": "SELECT * FROM user_table", + "db.type": "sql", + "db.user": "customer_user", + "span.kind": ext.SpanKindRPCClientEnum, + }, rawSpan.Tags()) +} + +func TestMiscTags(t *testing.T) { + tracer := mocktracer.New() + span := tracer.StartSpan("my-trace") + ext.Component.Set(span, "my-awesome-library") + ext.SamplingPriority.Set(span, 1) + ext.Error.Set(span, true) + + span.Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "component": "my-awesome-library", + "error": true, + }, rawSpan.Tags()) +} + +func TestRPCServerOption(t *testing.T) { + tracer := mocktracer.New() + parent := tracer.StartSpan("my-trace") + parent.SetBaggageItem("bag", "gage") + + carrier := opentracing.HTTPHeadersCarrier{} + err := tracer.Inject(parent.Context(), opentracing.HTTPHeaders, carrier) + if err != nil { + t.Fatal(err) + } + + parCtx, err := tracer.Extract(opentracing.HTTPHeaders, carrier) + if err != nil { + t.Fatal(err) + } + + tracer.StartSpan("my-child", ext.RPCServerOption(parCtx)).Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "span.kind": ext.SpanKindRPCServerEnum, + }, rawSpan.Tags()) + assert.Equal(t, map[string]string{ + "bag": "gage", + }, rawSpan.Context().(mocktracer.MockSpanContext).Baggage) +} + +func TestMessageBusProducerTags(t *testing.T) { + tracer := mocktracer.New() + span := tracer.StartSpan("my-trace", ext.SpanKindProducer) + ext.MessageBusDestination.Set(span, "topic name") + span.Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "message_bus.destination": "topic name", + "span.kind": ext.SpanKindProducerEnum, + }, rawSpan.Tags()) +} + +func TestMessageBusConsumerTags(t *testing.T) { + tracer := mocktracer.New() + span := tracer.StartSpan("my-trace", ext.SpanKindConsumer) + ext.MessageBusDestination.Set(span, "topic name") + span.Finish() + + rawSpan := tracer.FinishedSpans()[0] + assert.Equal(t, map[string]interface{}{ + "message_bus.destination": "topic name", + "span.kind": ext.SpanKindConsumerEnum, + }, rawSpan.Tags()) +} diff --git a/vendor/github.com/opentracing/opentracing-go/globaltracer.go b/vendor/github.com/opentracing/opentracing-go/globaltracer.go new file mode 100644 index 0000000000..4f7066a925 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/globaltracer.go @@ -0,0 +1,42 @@ +package opentracing + +type registeredTracer struct { + tracer Tracer + isRegistered bool +} + +var ( + globalTracer = registeredTracer{NoopTracer{}, false} +) + +// SetGlobalTracer sets the [singleton] opentracing.Tracer returned by +// GlobalTracer(). Those who use GlobalTracer (rather than directly manage an +// opentracing.Tracer instance) should call SetGlobalTracer as early as +// possible in main(), prior to calling the `StartSpan` global func below. +// Prior to calling `SetGlobalTracer`, any Spans started via the `StartSpan` +// (etc) globals are noops. +func SetGlobalTracer(tracer Tracer) { + globalTracer = registeredTracer{tracer, true} +} + +// GlobalTracer returns the global singleton `Tracer` implementation. +// Before `SetGlobalTracer()` is called, the `GlobalTracer()` is a noop +// implementation that drops all data handed to it. +func GlobalTracer() Tracer { + return globalTracer.tracer +} + +// StartSpan defers to `Tracer.StartSpan`. See `GlobalTracer()`. +func StartSpan(operationName string, opts ...StartSpanOption) Span { + return globalTracer.tracer.StartSpan(operationName, opts...) +} + +// InitGlobalTracer is deprecated. Please use SetGlobalTracer. +func InitGlobalTracer(tracer Tracer) { + SetGlobalTracer(tracer) +} + +// IsGlobalTracerRegistered returns a `bool` to indicate if a tracer has been globally registered +func IsGlobalTracerRegistered() bool { + return globalTracer.isRegistered +} diff --git a/vendor/github.com/opentracing/opentracing-go/globaltracer_test.go b/vendor/github.com/opentracing/opentracing-go/globaltracer_test.go new file mode 100644 index 0000000000..59fb3b4f7b --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/globaltracer_test.go @@ -0,0 +1,26 @@ +package opentracing + +import ( + "reflect" + "testing" +) + +func TestIsGlobalTracerRegisteredDefaultIsFalse(t *testing.T) { + if IsGlobalTracerRegistered() { + t.Errorf("Should return false when no global tracer is registered.") + } +} + +func TestAfterSettingGlobalTracerIsGlobalTracerRegisteredReturnsTrue(t *testing.T) { + SetGlobalTracer(NoopTracer{}) + + if !IsGlobalTracerRegistered() { + t.Errorf("Should return true after a tracer has been registered.") + } +} + +func TestDefaultTracerIsNoopTracer(t *testing.T) { + if reflect.TypeOf(GlobalTracer()) != reflect.TypeOf(NoopTracer{}) { + t.Errorf("Should return false when no global tracer is registered.") + } +} diff --git a/vendor/github.com/opentracing/opentracing-go/go.mod b/vendor/github.com/opentracing/opentracing-go/go.mod new file mode 100644 index 0000000000..bf48bb5d73 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/go.mod @@ -0,0 +1,5 @@ +module github.com/opentracing/opentracing-go + +go 1.14 + +require github.com/stretchr/testify v1.3.0 diff --git a/vendor/github.com/opentracing/opentracing-go/go.sum b/vendor/github.com/opentracing/opentracing-go/go.sum new file mode 100644 index 0000000000..4347755afe --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/go.sum @@ -0,0 +1,7 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/opentracing/opentracing-go/gocontext.go b/vendor/github.com/opentracing/opentracing-go/gocontext.go new file mode 100644 index 0000000000..1831bc9b26 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/gocontext.go @@ -0,0 +1,65 @@ +package opentracing + +import "context" + +type contextKey struct{} + +var activeSpanKey = contextKey{} + +// ContextWithSpan returns a new `context.Context` that holds a reference to +// the span. If span is nil, a new context without an active span is returned. +func ContextWithSpan(ctx context.Context, span Span) context.Context { + if span != nil { + if tracerWithHook, ok := span.Tracer().(TracerContextWithSpanExtension); ok { + ctx = tracerWithHook.ContextWithSpanHook(ctx, span) + } + } + return context.WithValue(ctx, activeSpanKey, span) +} + +// SpanFromContext returns the `Span` previously associated with `ctx`, or +// `nil` if no such `Span` could be found. +// +// NOTE: context.Context != SpanContext: the former is Go's intra-process +// context propagation mechanism, and the latter houses OpenTracing's per-Span +// identity and baggage information. +func SpanFromContext(ctx context.Context) Span { + val := ctx.Value(activeSpanKey) + if sp, ok := val.(Span); ok { + return sp + } + return nil +} + +// StartSpanFromContext starts and returns a Span with `operationName`, using +// any Span found within `ctx` as a ChildOfRef. If no such parent could be +// found, StartSpanFromContext creates a root (parentless) Span. +// +// The second return value is a context.Context object built around the +// returned Span. +// +// Example usage: +// +// SomeFunction(ctx context.Context, ...) { +// sp, ctx := opentracing.StartSpanFromContext(ctx, "SomeFunction") +// defer sp.Finish() +// ... +// } +func StartSpanFromContext(ctx context.Context, operationName string, opts ...StartSpanOption) (Span, context.Context) { + return StartSpanFromContextWithTracer(ctx, GlobalTracer(), operationName, opts...) +} + +// StartSpanFromContextWithTracer starts and returns a span with `operationName` +// using a span found within the context as a ChildOfRef. If that doesn't exist +// it creates a root span. It also returns a context.Context object built +// around the returned span. +// +// It's behavior is identical to StartSpanFromContext except that it takes an explicit +// tracer as opposed to using the global tracer. +func StartSpanFromContextWithTracer(ctx context.Context, tracer Tracer, operationName string, opts ...StartSpanOption) (Span, context.Context) { + if parentSpan := SpanFromContext(ctx); parentSpan != nil { + opts = append(opts, ChildOf(parentSpan.Context())) + } + span := tracer.StartSpan(operationName, opts...) + return span, ContextWithSpan(ctx, span) +} diff --git a/vendor/github.com/opentracing/opentracing-go/gocontext_test.go b/vendor/github.com/opentracing/opentracing-go/gocontext_test.go new file mode 100644 index 0000000000..c6bbad4e4b --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/gocontext_test.go @@ -0,0 +1,121 @@ +package opentracing + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestContextWithSpan(t *testing.T) { + span := &noopSpan{} + ctx := ContextWithSpan(context.Background(), span) + span2 := SpanFromContext(ctx) + if span != span2 { + t.Errorf("Not the same span returned from context, expected=%+v, actual=%+v", span, span2) + } + + ctx = context.Background() + span2 = SpanFromContext(ctx) + if span2 != nil { + t.Errorf("Expected nil span, found %+v", span2) + } + + ctx = ContextWithSpan(ctx, span) + span2 = SpanFromContext(ctx) + if span != span2 { + t.Errorf("Not the same span returned from context, expected=%+v, actual=%+v", span, span2) + } + + ctx = ContextWithSpan(ctx, nil) + if s := SpanFromContext(ctx); s != nil { + t.Errorf("Not able to reset span in context, expected=nil, actual=%+v", s) + } +} + +type noopExtTracer struct { + NoopTracer +} + +type noopExtTracerCtxType struct{} + +func (noopExtTracer) ContextWithSpanHook(ctx context.Context, span Span) context.Context { + return context.WithValue(ctx, noopExtTracerCtxType{}, noopExtTracerCtxType{}) +} + +var _ Tracer = noopExtTracer{} +var _ TracerContextWithSpanExtension = noopExtTracer{} + +type noopExtSpan struct { + noopSpan +} + +func (noopExtSpan) Tracer() Tracer { + return noopExtTracer{} +} + +var _ Span = noopExtSpan{} + +func TestContextWithSpanWithExtension(t *testing.T) { + span := &noopExtSpan{} + ctx := ContextWithSpan(context.Background(), span) + span2 := SpanFromContext(ctx) + if span != span2 { + t.Errorf("Not the same span returned from context, expected=%+v, actual=%+v", span, span2) + } + if _, ok := ctx.Value(noopExtTracerCtxType{}).(noopExtTracerCtxType); !ok { + t.Error("ContextWithSpanHook was not called") + } +} + +func TestStartSpanFromContext(t *testing.T) { + testTracer := testTracer{} + + // Test the case where there *is* a Span in the Context. + { + parentSpan := &testSpan{} + parentCtx := ContextWithSpan(context.Background(), parentSpan) + childSpan, childCtx := StartSpanFromContextWithTracer(parentCtx, testTracer, "child") + if !childSpan.Context().(testSpanContext).HasParent { + t.Errorf("Failed to find parent: %v", childSpan) + } + if !childSpan.(testSpan).Equal(SpanFromContext(childCtx)) { + t.Errorf("Unable to find child span in context: %v", childCtx) + } + } + + // Test the case where there *is not* a Span in the Context. + { + emptyCtx := context.Background() + childSpan, childCtx := StartSpanFromContextWithTracer(emptyCtx, testTracer, "child") + if childSpan.Context().(testSpanContext).HasParent { + t.Errorf("Should not have found parent: %v", childSpan) + } + if !childSpan.(testSpan).Equal(SpanFromContext(childCtx)) { + t.Errorf("Unable to find child span in context: %v", childCtx) + } + } +} + +func TestStartSpanFromContextOptions(t *testing.T) { + testTracer := testTracer{} + + // Test options are passed to tracer + + startTime := time.Now().Add(-10 * time.Second) // ten seconds ago + span, ctx := StartSpanFromContextWithTracer( + context.Background(), testTracer, "parent", StartTime(startTime), Tag{"component", "test"}) + + assert.Equal(t, "test", span.(testSpan).Tags["component"]) + assert.Equal(t, startTime, span.(testSpan).StartTime) + + // Test it also works for a child span + + childStartTime := startTime.Add(3 * time.Second) + childSpan, _ := StartSpanFromContextWithTracer( + ctx, testTracer, "child", StartTime(childStartTime)) + + assert.Equal(t, childSpan.(testSpan).Tags["component"], nil) + assert.Equal(t, childSpan.(testSpan).StartTime, childStartTime) +} diff --git a/vendor/github.com/opentracing/opentracing-go/harness/api_checkers.go b/vendor/github.com/opentracing/opentracing-go/harness/api_checkers.go new file mode 100644 index 0000000000..5ae7fb0252 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/harness/api_checkers.go @@ -0,0 +1,472 @@ +/* + +Package harness provides a suite of API compatibility checks. They were originally ported from the +OpenTracing Python library's "harness" module. + +To run this test suite against your tracer, call harness.RunAPIChecks and provide it a function +that returns a Tracer implementation and a function to call to close it. The function will be +called to create a new tracer before each test in the suite is run, and the returned closer function +will be called after each test is finished. + +Several options provide additional checks for your Tracer's behavior: CheckBaggageValues(true) +indicates your tracer supports baggage propagation, CheckExtract(true) tells the suite to test if +the Tracer can extract a trace context from text and binary carriers, and CheckInject(true) tests +if the Tracer can inject the trace context into a carrier. + +The UseProbe option provides an APICheckProbe implementation that allows the test suite to +additionally check if two Spans are part of the same trace, and if a Span and a SpanContext +are part of the same trace. Implementing an APICheckProbe provides additional assertions that +your tracer is working properly. + +*/ +package harness + +import ( + "bytes" + "testing" + "time" + + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/log" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +// APICheckCapabilities describes capabilities of a Tracer that should be checked by APICheckSuite. +type APICheckCapabilities struct { + CheckBaggageValues bool // whether to check for propagation of baggage values + CheckExtract bool // whether to check if extracting contexts from carriers works + CheckInject bool // whether to check if injecting contexts works + Probe APICheckProbe // optional interface providing methods to check recorded data +} + +// APICheckProbe exposes methods for testing data recorded by a Tracer. +type APICheckProbe interface { + // SameTrace helps tests assert that this tracer's spans are from the same trace. + SameTrace(first, second opentracing.Span) bool + // SameSpanContext helps tests assert that a span and a context are from the same trace and span. + SameSpanContext(opentracing.Span, opentracing.SpanContext) bool +} + +// APICheckSuite is a testify suite for checking a Tracer against the OpenTracing API. +type APICheckSuite struct { + suite.Suite + opts APICheckCapabilities + newTracer func() (tracer opentracing.Tracer, closer func()) + tracer opentracing.Tracer + closer func() +} + +// RunAPIChecks runs a test suite to check a Tracer against the OpenTracing API. +// It is provided a function that will be executed to create and destroy a tracer for each test +// in the suite, and the given APICheckOption functional options `opts`. +func RunAPIChecks( + t *testing.T, + newTracer func() (tracer opentracing.Tracer, closer func()), + opts ...APICheckOption, +) { + s := &APICheckSuite{newTracer: newTracer} + for _, opt := range opts { + opt(s) + } + suite.Run(t, s) +} + +// APICheckOption instances may be passed to NewAPICheckSuite. +type APICheckOption func(*APICheckSuite) + +// CheckBaggageValues returns an option that sets whether to check for propagation of baggage values. +func CheckBaggageValues(val bool) APICheckOption { + return func(s *APICheckSuite) { + s.opts.CheckBaggageValues = val + } +} + +// CheckExtract returns an option that sets whether to check if extracting contexts from carriers works. +func CheckExtract(val bool) APICheckOption { + return func(s *APICheckSuite) { + s.opts.CheckExtract = val + } +} + +// CheckInject returns an option that sets whether to check if injecting contexts works. +func CheckInject(val bool) APICheckOption { + return func(s *APICheckSuite) { + s.opts.CheckInject = val + } +} + +// CheckEverything returns an option that enables all API checks. +func CheckEverything() APICheckOption { + return func(s *APICheckSuite) { + s.opts.CheckBaggageValues = true + s.opts.CheckExtract = true + s.opts.CheckInject = true + } +} + +// UseProbe returns an option that specifies an APICheckProbe implementation to use. +func UseProbe(probe APICheckProbe) APICheckOption { + return func(s *APICheckSuite) { + s.opts.Probe = probe + } +} + +// SetupTest creates a tracer for this specific test invocation. +func (s *APICheckSuite) SetupTest() { + s.tracer, s.closer = s.newTracer() + if s.tracer == nil { + s.T().Fatalf("newTracer returned nil Tracer") + } +} + +// TearDownTest closes the tracer, and clears the test-specific tracer. +func (s *APICheckSuite) TearDownTest() { + if s.closer != nil { + s.closer() + } + s.tracer, s.closer = nil, nil +} + +// TestStartSpan checks if a Tracer can start a span and calls some span API methods. +func (s *APICheckSuite) TestStartSpan() { + span := s.tracer.StartSpan( + "Fry", + opentracing.Tag{Key: "birthday", Value: "August 14 1974"}) + span.LogFields( + log.String("hospital", "Brooklyn Pre-Med Hospital"), + log.String("city", "Old New York")) + span.Finish() +} + +// TestStartSpanWithParent checks if a Tracer can start a span with a specified parent. +func (s *APICheckSuite) TestStartSpanWithParent() { + parentSpan := s.tracer.StartSpan("Turanga Munda") + s.NotNil(parentSpan) + + childFns := []func(opentracing.SpanContext) opentracing.SpanReference{ + opentracing.ChildOf, + opentracing.FollowsFrom, + } + for _, childFn := range childFns { + span := s.tracer.StartSpan( + "Leela", + childFn(parentSpan.Context()), + opentracing.Tag{Key: "birthplace", Value: "sewers"}) + span.Finish() + if s.opts.Probe != nil { + s.True(s.opts.Probe.SameTrace(parentSpan, span)) + } else { + s.T().Log("harness.Probe not specified, skipping") + } + } + + parentSpan.Finish() +} + +// TestSetOperationName attempts to set the operation name on a span after it has been created. +func (s *APICheckSuite) TestSetOperationName() { + span := s.tracer.StartSpan("").SetOperationName("Farnsworth") + span.Finish() +} + +// TestSpanTagValueTypes sets tags using values of different types. +func (s *APICheckSuite) TestSpanTagValueTypes() { + span := s.tracer.StartSpan("ManyTypes") + span. + SetTag("an_int", 9). + SetTag("a_bool", true). + SetTag("a_string", "aoeuidhtns") +} + +// TestSpanTagsWithChaining tests chaining of calls to SetTag. +func (s *APICheckSuite) TestSpanTagsWithChaining() { + span := s.tracer.StartSpan("Farnsworth") + span. + SetTag("birthday", "9 April, 2841"). + SetTag("loves", "different lengths of wires") + span. + SetTag("unicode_val", "non-ascii: \u200b"). + SetTag("unicode_key_\u200b", "ascii val") + span.Finish() +} + +// TestSpanLogs tests calls to log keys and values with spans. +func (s *APICheckSuite) TestSpanLogs() { + span := s.tracer.StartSpan("Fry") + span.LogKV( + "event", "frozen", + "year", 1999, + "place", "Cryogenics Labs") + span.LogKV( + "event", "defrosted", + "year", 2999, + "place", "Cryogenics Labs") + + ts := time.Now() + span.FinishWithOptions(opentracing.FinishOptions{ + LogRecords: []opentracing.LogRecord{ + { + Timestamp: ts, + Fields: []log.Field{ + log.String("event", "job-assignment"), + log.String("type", "delivery boy"), + }, + }, + }}) + + // Test deprecated log methods + span.LogEvent("an arbitrary event") + span.LogEventWithPayload("y", "z") + span.Log(opentracing.LogData{Event: "y", Payload: "z"}) +} + +func assertEmptyBaggage(t *testing.T, spanContext opentracing.SpanContext) { + if !assert.NotNil(t, spanContext, "assertEmptyBaggage got empty context") { + return + } + spanContext.ForeachBaggageItem(func(k, v string) bool { + assert.Fail(t, "new span shouldn't have baggage") + return false + }) +} + +// TestSpanBaggage tests calls to set and get span baggage, and if the CheckBaggageValues option +// is set, asserts that baggage values were successfully retrieved. +func (s *APICheckSuite) TestSpanBaggage() { + span := s.tracer.StartSpan("Fry") + assertEmptyBaggage(s.T(), span.Context()) + + spanRef := span.SetBaggageItem("Kiff-loves", "Amy") + s.Exactly(spanRef, span) + + val := span.BaggageItem("Kiff-loves") + if s.opts.CheckBaggageValues { + s.Equal("Amy", val) + } else { + s.T().Log("CheckBaggageValues capability not set, skipping") + } + span.Finish() +} + +// TestContextBaggage tests calls to set and get span baggage, and if the CheckBaggageValues option +// is set, asserts that baggage values were successfully retrieved from the span's SpanContext. +func (s *APICheckSuite) TestContextBaggage() { + span := s.tracer.StartSpan("Fry") + assertEmptyBaggage(s.T(), span.Context()) + + span.SetBaggageItem("Kiff-loves", "Amy") + if s.opts.CheckBaggageValues { + called := false + span.Context().ForeachBaggageItem(func(k, v string) bool { + s.False(called) + called = true + s.Equal("Kiff-loves", k) + s.Equal("Amy", v) + return true + }) + } else { + s.T().Log("CheckBaggageValues capability not set, skipping") + } + span.Finish() +} + +// TestTextPropagation tests if the Tracer can Inject a span into a TextMapCarrier, and later Extract it. +// If CheckExtract is set, it will check if Extract was successful (returned no error). If a Probe is set, +// it will check if the extracted context is in the same trace as the original span. +func (s *APICheckSuite) TestTextPropagation() { + span := s.tracer.StartSpan("Bender") + textCarrier := opentracing.TextMapCarrier{} + err := span.Tracer().Inject(span.Context(), opentracing.TextMap, textCarrier) + assert.NoError(s.T(), err) + + extractedContext, err := s.tracer.Extract(opentracing.TextMap, textCarrier) + if s.opts.CheckExtract { + s.NoError(err) + assertEmptyBaggage(s.T(), extractedContext) + } else { + s.T().Log("CheckExtract capability not set, skipping") + } + if s.opts.Probe != nil { + s.True(s.opts.Probe.SameSpanContext(span, extractedContext)) + } else { + s.T().Log("harness.Probe not specified, skipping") + } + span.Finish() +} + +// TestHTTPPropagation tests if the Tracer can Inject a span into HTTP headers, and later Extract it. +// If CheckExtract is set, it will check if Extract was successful (returned no error). If a Probe is set, +// it will check if the extracted context is in the same trace as the original span. +func (s *APICheckSuite) TestHTTPPropagation() { + span := s.tracer.StartSpan("Bender") + textCarrier := opentracing.HTTPHeadersCarrier{} + err := span.Tracer().Inject(span.Context(), opentracing.HTTPHeaders, textCarrier) + s.NoError(err) + + extractedContext, err := s.tracer.Extract(opentracing.HTTPHeaders, textCarrier) + if s.opts.CheckExtract { + s.NoError(err) + assertEmptyBaggage(s.T(), extractedContext) + } else { + s.T().Log("CheckExtract capability not set, skipping") + } + if s.opts.Probe != nil { + s.True(s.opts.Probe.SameSpanContext(span, extractedContext)) + } else { + s.T().Log("harness.Probe not specified, skipping") + } + span.Finish() +} + +// TestBinaryPropagation tests if the Tracer can Inject a span into a binary buffer, and later Extract it. +// If CheckExtract is set, it will check if Extract was successful (returned no error). If a Probe is set, +// it will check if the extracted context is in the same trace as the original span. +func (s *APICheckSuite) TestBinaryPropagation() { + span := s.tracer.StartSpan("Bender") + buf := new(bytes.Buffer) + err := span.Tracer().Inject(span.Context(), opentracing.Binary, buf) + s.NoError(err) + + extractedContext, err := s.tracer.Extract(opentracing.Binary, buf) + if s.opts.CheckExtract { + s.NoError(err) + assertEmptyBaggage(s.T(), extractedContext) + } else { + s.T().Log("CheckExtract capability not set, skipping") + } + if s.opts.Probe != nil { + s.True(s.opts.Probe.SameSpanContext(span, extractedContext)) + } else { + s.T().Log("harness.Probe not specified, skipping") + } + span.Finish() +} + +// TestMandatoryFormats tests if all mandatory carrier formats are supported. If CheckExtract is set, it +// will check if the call to Extract was successful (returned no error such as ErrUnsupportedFormat). +func (s *APICheckSuite) TestMandatoryFormats() { + formats := []struct{ Format, Carrier interface{} }{ + {opentracing.TextMap, opentracing.TextMapCarrier{}}, + {opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier{}}, + {opentracing.Binary, new(bytes.Buffer)}, + } + span := s.tracer.StartSpan("Bender") + for _, fmtCarrier := range formats { + err := span.Tracer().Inject(span.Context(), fmtCarrier.Format, fmtCarrier.Carrier) + s.NoError(err) + spanCtx, err := s.tracer.Extract(fmtCarrier.Format, fmtCarrier.Carrier) + if s.opts.CheckExtract { + s.NoError(err) + assertEmptyBaggage(s.T(), spanCtx) + } else { + s.T().Log("CheckExtract capability not set, skipping") + } + } +} + +// TestUnknownFormat checks if attempting to Inject or Extract using an unsupported format +// returns ErrUnsupportedFormat, if CheckInject and CheckExtract are set. +func (s *APICheckSuite) TestUnknownFormat() { + customFormat := "kiss my shiny metal ..." + span := s.tracer.StartSpan("Bender") + + err := span.Tracer().Inject(span.Context(), customFormat, nil) + if s.opts.CheckInject { + s.Equal(opentracing.ErrUnsupportedFormat, err) + } else { + s.T().Log("CheckInject capability not set, skipping") + } + ctx, err := s.tracer.Extract(customFormat, nil) + s.Nil(ctx) + if s.opts.CheckExtract { + s.Equal(opentracing.ErrUnsupportedFormat, err) + } else { + s.T().Log("CheckExtract capability not set, skipping") + } +} + +// ForeignSpanContext satisfies the opentracing.SpanContext interface, but otherwise does nothing. +type ForeignSpanContext struct{} + +// ForeachBaggageItem could call handler for each baggage KV, but does nothing. +func (f ForeignSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {} + +// NotACarrier does not satisfy any of the opentracing carrier interfaces. +type NotACarrier struct{} + +// TestInvalidInject checks if errors are returned when Inject is called with invalid inputs. +func (s *APICheckSuite) TestInvalidInject() { + if !s.opts.CheckInject { + s.T().Skip("CheckInject capability not set, skipping") + } + span := s.tracer.StartSpan("op") + + // binary inject + err := span.Tracer().Inject(ForeignSpanContext{}, opentracing.Binary, new(bytes.Buffer)) + s.Equal(opentracing.ErrInvalidSpanContext, err, "Foreign SpanContext should return invalid error") + err = span.Tracer().Inject(span.Context(), opentracing.Binary, NotACarrier{}) + s.Equal(opentracing.ErrInvalidCarrier, err, "Carrier that's not io.Writer should return error") + + // text inject + err = span.Tracer().Inject(ForeignSpanContext{}, opentracing.TextMap, opentracing.TextMapCarrier{}) + s.Equal(opentracing.ErrInvalidSpanContext, err, "Foreign SpanContext should return invalid error") + err = span.Tracer().Inject(span.Context(), opentracing.TextMap, NotACarrier{}) + s.Equal(opentracing.ErrInvalidCarrier, err, "Carrier that's not TextMapWriter should return error") + + // HTTP inject + err = span.Tracer().Inject(ForeignSpanContext{}, opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier{}) + s.Equal(opentracing.ErrInvalidSpanContext, err, "Foreign SpanContext should return invalid error") + err = span.Tracer().Inject(span.Context(), opentracing.HTTPHeaders, NotACarrier{}) + s.Equal(opentracing.ErrInvalidCarrier, err, "Carrier that's not TextMapWriter should return error") +} + +// TestInvalidExtract checks if errors are returned when Extract is called with invalid inputs. +func (s *APICheckSuite) TestInvalidExtract() { + if !s.opts.CheckExtract { + s.T().Skip("CheckExtract capability not set, skipping") + } + span := s.tracer.StartSpan("op") + + // binary extract + ctx, err := span.Tracer().Extract(opentracing.Binary, NotACarrier{}) + s.Equal(opentracing.ErrInvalidCarrier, err, "Carrier that's not io.Reader should return error") + s.Nil(ctx) + + // text extract + ctx, err = span.Tracer().Extract(opentracing.TextMap, NotACarrier{}) + s.Equal(opentracing.ErrInvalidCarrier, err, "Carrier that's not TextMapReader should return error") + s.Nil(ctx) + + // HTTP extract + ctx, err = span.Tracer().Extract(opentracing.HTTPHeaders, NotACarrier{}) + s.Equal(opentracing.ErrInvalidCarrier, err, "Carrier that's not TextMapReader should return error") + s.Nil(ctx) + + span.Finish() +} + +// TestMultiBaggage tests calls to set multiple baggage items, and if the CheckBaggageValues option +// is set, asserts that a baggage value was successfully retrieved from the span's SpanContext. +// It also ensures that returning false from the ForeachBaggageItem handler aborts iteration. +func (s *APICheckSuite) TestMultiBaggage() { + span := s.tracer.StartSpan("op") + assertEmptyBaggage(s.T(), span.Context()) + + span.SetBaggageItem("Bag1", "BaggageVal1") + span.SetBaggageItem("Bag2", "BaggageVal2") + if s.opts.CheckBaggageValues { + s.Equal("BaggageVal1", span.BaggageItem("Bag1")) + s.Equal("BaggageVal2", span.BaggageItem("Bag2")) + called := false + span.Context().ForeachBaggageItem(func(k, v string) bool { + s.False(called) // should only be called once + called = true + return false + }) + s.True(called) + } else { + s.T().Log("CheckBaggageValues capability not set, skipping") + } + span.Finish() +} diff --git a/vendor/github.com/opentracing/opentracing-go/harness/noop_api_test.go b/vendor/github.com/opentracing/opentracing-go/harness/noop_api_test.go new file mode 100644 index 0000000000..b66e647599 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/harness/noop_api_test.go @@ -0,0 +1,17 @@ +package harness + +import ( + "testing" + + "github.com/opentracing/opentracing-go" +) + +func TestAPI(t *testing.T) { + RunAPIChecks(t, func() (tracer opentracing.Tracer, closer func()) { + return opentracing.NoopTracer{}, nil + }, // NoopTracer doesn't do much + CheckBaggageValues(false), + CheckInject(false), + CheckExtract(false), + ) +} diff --git a/vendor/github.com/opentracing/opentracing-go/log/field.go b/vendor/github.com/opentracing/opentracing-go/log/field.go new file mode 100644 index 0000000000..f222ded797 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/log/field.go @@ -0,0 +1,282 @@ +package log + +import ( + "fmt" + "math" +) + +type fieldType int + +const ( + stringType fieldType = iota + boolType + intType + int32Type + uint32Type + int64Type + uint64Type + float32Type + float64Type + errorType + objectType + lazyLoggerType + noopType +) + +// Field instances are constructed via LogBool, LogString, and so on. +// Tracing implementations may then handle them via the Field.Marshal +// method. +// +// "heavily influenced by" (i.e., partially stolen from) +// https://github.com/uber-go/zap +type Field struct { + key string + fieldType fieldType + numericVal int64 + stringVal string + interfaceVal interface{} +} + +// String adds a string-valued key:value pair to a Span.LogFields() record +func String(key, val string) Field { + return Field{ + key: key, + fieldType: stringType, + stringVal: val, + } +} + +// Bool adds a bool-valued key:value pair to a Span.LogFields() record +func Bool(key string, val bool) Field { + var numericVal int64 + if val { + numericVal = 1 + } + return Field{ + key: key, + fieldType: boolType, + numericVal: numericVal, + } +} + +// Int adds an int-valued key:value pair to a Span.LogFields() record +func Int(key string, val int) Field { + return Field{ + key: key, + fieldType: intType, + numericVal: int64(val), + } +} + +// Int32 adds an int32-valued key:value pair to a Span.LogFields() record +func Int32(key string, val int32) Field { + return Field{ + key: key, + fieldType: int32Type, + numericVal: int64(val), + } +} + +// Int64 adds an int64-valued key:value pair to a Span.LogFields() record +func Int64(key string, val int64) Field { + return Field{ + key: key, + fieldType: int64Type, + numericVal: val, + } +} + +// Uint32 adds a uint32-valued key:value pair to a Span.LogFields() record +func Uint32(key string, val uint32) Field { + return Field{ + key: key, + fieldType: uint32Type, + numericVal: int64(val), + } +} + +// Uint64 adds a uint64-valued key:value pair to a Span.LogFields() record +func Uint64(key string, val uint64) Field { + return Field{ + key: key, + fieldType: uint64Type, + numericVal: int64(val), + } +} + +// Float32 adds a float32-valued key:value pair to a Span.LogFields() record +func Float32(key string, val float32) Field { + return Field{ + key: key, + fieldType: float32Type, + numericVal: int64(math.Float32bits(val)), + } +} + +// Float64 adds a float64-valued key:value pair to a Span.LogFields() record +func Float64(key string, val float64) Field { + return Field{ + key: key, + fieldType: float64Type, + numericVal: int64(math.Float64bits(val)), + } +} + +// Error adds an error with the key "error.object" to a Span.LogFields() record +func Error(err error) Field { + return Field{ + key: "error.object", + fieldType: errorType, + interfaceVal: err, + } +} + +// Object adds an object-valued key:value pair to a Span.LogFields() record +// Please pass in an immutable object, otherwise there may be concurrency issues. +// Such as passing in the map, log.Object may result in "fatal error: concurrent map iteration and map write". +// Because span is sent asynchronously, it is possible that this map will also be modified. +func Object(key string, obj interface{}) Field { + return Field{ + key: key, + fieldType: objectType, + interfaceVal: obj, + } +} + +// Event creates a string-valued Field for span logs with key="event" and value=val. +func Event(val string) Field { + return String("event", val) +} + +// Message creates a string-valued Field for span logs with key="message" and value=val. +func Message(val string) Field { + return String("message", val) +} + +// LazyLogger allows for user-defined, late-bound logging of arbitrary data +type LazyLogger func(fv Encoder) + +// Lazy adds a LazyLogger to a Span.LogFields() record; the tracing +// implementation will call the LazyLogger function at an indefinite time in +// the future (after Lazy() returns). +func Lazy(ll LazyLogger) Field { + return Field{ + fieldType: lazyLoggerType, + interfaceVal: ll, + } +} + +// Noop creates a no-op log field that should be ignored by the tracer. +// It can be used to capture optional fields, for example those that should +// only be logged in non-production environment: +// +// func customerField(order *Order) log.Field { +// if os.Getenv("ENVIRONMENT") == "dev" { +// return log.String("customer", order.Customer.ID) +// } +// return log.Noop() +// } +// +// span.LogFields(log.String("event", "purchase"), customerField(order)) +// +func Noop() Field { + return Field{ + fieldType: noopType, + } +} + +// Encoder allows access to the contents of a Field (via a call to +// Field.Marshal). +// +// Tracer implementations typically provide an implementation of Encoder; +// OpenTracing callers typically do not need to concern themselves with it. +type Encoder interface { + EmitString(key, value string) + EmitBool(key string, value bool) + EmitInt(key string, value int) + EmitInt32(key string, value int32) + EmitInt64(key string, value int64) + EmitUint32(key string, value uint32) + EmitUint64(key string, value uint64) + EmitFloat32(key string, value float32) + EmitFloat64(key string, value float64) + EmitObject(key string, value interface{}) + EmitLazyLogger(value LazyLogger) +} + +// Marshal passes a Field instance through to the appropriate +// field-type-specific method of an Encoder. +func (lf Field) Marshal(visitor Encoder) { + switch lf.fieldType { + case stringType: + visitor.EmitString(lf.key, lf.stringVal) + case boolType: + visitor.EmitBool(lf.key, lf.numericVal != 0) + case intType: + visitor.EmitInt(lf.key, int(lf.numericVal)) + case int32Type: + visitor.EmitInt32(lf.key, int32(lf.numericVal)) + case int64Type: + visitor.EmitInt64(lf.key, int64(lf.numericVal)) + case uint32Type: + visitor.EmitUint32(lf.key, uint32(lf.numericVal)) + case uint64Type: + visitor.EmitUint64(lf.key, uint64(lf.numericVal)) + case float32Type: + visitor.EmitFloat32(lf.key, math.Float32frombits(uint32(lf.numericVal))) + case float64Type: + visitor.EmitFloat64(lf.key, math.Float64frombits(uint64(lf.numericVal))) + case errorType: + if err, ok := lf.interfaceVal.(error); ok { + visitor.EmitString(lf.key, err.Error()) + } else { + visitor.EmitString(lf.key, "") + } + case objectType: + visitor.EmitObject(lf.key, lf.interfaceVal) + case lazyLoggerType: + visitor.EmitLazyLogger(lf.interfaceVal.(LazyLogger)) + case noopType: + // intentionally left blank + } +} + +// Key returns the field's key. +func (lf Field) Key() string { + return lf.key +} + +// Value returns the field's value as interface{}. +func (lf Field) Value() interface{} { + switch lf.fieldType { + case stringType: + return lf.stringVal + case boolType: + return lf.numericVal != 0 + case intType: + return int(lf.numericVal) + case int32Type: + return int32(lf.numericVal) + case int64Type: + return int64(lf.numericVal) + case uint32Type: + return uint32(lf.numericVal) + case uint64Type: + return uint64(lf.numericVal) + case float32Type: + return math.Float32frombits(uint32(lf.numericVal)) + case float64Type: + return math.Float64frombits(uint64(lf.numericVal)) + case errorType, objectType, lazyLoggerType: + return lf.interfaceVal + case noopType: + return nil + default: + return nil + } +} + +// String returns a string representation of the key and value. +func (lf Field) String() string { + return fmt.Sprint(lf.key, ":", lf.Value()) +} diff --git a/vendor/github.com/opentracing/opentracing-go/log/field_test.go b/vendor/github.com/opentracing/opentracing-go/log/field_test.go new file mode 100644 index 0000000000..61a3321f56 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/log/field_test.go @@ -0,0 +1,59 @@ +package log + +import ( + "fmt" + "testing" +) + +func TestFieldString(t *testing.T) { + testCases := []struct { + field Field + expected string + }{ + { + field: String("key", "value"), + expected: "key:value", + }, + { + field: Bool("key", true), + expected: "key:true", + }, + { + field: Int("key", 5), + expected: "key:5", + }, + { + field: Error(fmt.Errorf("err msg")), + expected: "error.object:err msg", + }, + { + field: Error(nil), + expected: "error.object:", + }, + { + field: Noop(), + expected: ":", + }, + { + field: Event("test"), + expected: "event:test", + }, + { + field: Message("test2"), + expected: "message:test2", + }, + } + for i, tc := range testCases { + if str := tc.field.String(); str != tc.expected { + t.Errorf("%d: expected '%s', got '%s'", i, tc.expected, str) + } + } +} + +func TestNoopDoesNotMarshal(t *testing.T) { + mockEncoder := struct { + Encoder + }{} + f := Noop() + f.Marshal(mockEncoder) // panics if any Encoder method is invoked +} diff --git a/vendor/github.com/opentracing/opentracing-go/log/util.go b/vendor/github.com/opentracing/opentracing-go/log/util.go new file mode 100644 index 0000000000..d57e28aa57 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/log/util.go @@ -0,0 +1,61 @@ +package log + +import ( + "fmt" + "reflect" +) + +// InterleavedKVToFields converts keyValues a la Span.LogKV() to a Field slice +// a la Span.LogFields(). +func InterleavedKVToFields(keyValues ...interface{}) ([]Field, error) { + if len(keyValues)%2 != 0 { + return nil, fmt.Errorf("non-even keyValues len: %d", len(keyValues)) + } + fields := make([]Field, len(keyValues)/2) + for i := 0; i*2 < len(keyValues); i++ { + key, ok := keyValues[i*2].(string) + if !ok { + return nil, fmt.Errorf( + "non-string key (pair #%d): %T", + i, keyValues[i*2]) + } + switch typedVal := keyValues[i*2+1].(type) { + case bool: + fields[i] = Bool(key, typedVal) + case string: + fields[i] = String(key, typedVal) + case int: + fields[i] = Int(key, typedVal) + case int8: + fields[i] = Int32(key, int32(typedVal)) + case int16: + fields[i] = Int32(key, int32(typedVal)) + case int32: + fields[i] = Int32(key, typedVal) + case int64: + fields[i] = Int64(key, typedVal) + case uint: + fields[i] = Uint64(key, uint64(typedVal)) + case uint64: + fields[i] = Uint64(key, typedVal) + case uint8: + fields[i] = Uint32(key, uint32(typedVal)) + case uint16: + fields[i] = Uint32(key, uint32(typedVal)) + case uint32: + fields[i] = Uint32(key, typedVal) + case float32: + fields[i] = Float32(key, typedVal) + case float64: + fields[i] = Float64(key, typedVal) + default: + if typedVal == nil || (reflect.ValueOf(typedVal).Kind() == reflect.Ptr && reflect.ValueOf(typedVal).IsNil()) { + fields[i] = String(key, "nil") + continue + } + // When in doubt, coerce to a string + fields[i] = String(key, fmt.Sprint(typedVal)) + } + } + return fields, nil +} diff --git a/vendor/github.com/opentracing/opentracing-go/log/util_test.go b/vendor/github.com/opentracing/opentracing-go/log/util_test.go new file mode 100644 index 0000000000..882cff3b53 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/log/util_test.go @@ -0,0 +1,86 @@ +package log + +import ( + "errors" + "io" + "testing" + + "github.com/stretchr/testify/assert" +) + +var nilInterface io.Reader + +func TestInterleavedKVToFields(t *testing.T) { + + tests := []struct { + name string + keyValues []interface{} + want []Field + wantErr bool + }{ + { + "incorrect pair", + []interface{}{"test"}, + nil, + true, + }, + { + "non string key", + []interface{}{struct{}{}, "foo"}, + nil, + true, + }, + { + "happy path", + []interface{}{ + "bool", true, + "string", "string", + "int", int(1), + "int8", int8(2), + "int16", int16(3), + "int64", int64(4), + "uint", uint(5), + "uint64", uint64(6), + "uint8", uint8(7), + "uint16", uint16(8), + "uint32", uint32(9), + "float32", float32(10), + "float64", float64(11), + "int32", int32(12), + "stringer", errors.New("err"), + "nilInterface", nilInterface, + "nil", nil, + }, + []Field{ + Bool("bool", true), + String("string", "string"), + Int("int", int(1)), + Int32("int8", int32(2)), + Int32("int16", int32(3)), + Int64("int64", int64(4)), + Uint64("uint", uint64(5)), + Uint64("uint64", uint64(6)), + Uint32("uint8", uint32(7)), + Uint32("uint16", uint32(8)), + Uint32("uint32", uint32(9)), + Float32("float32", float32(10)), + Float64("float64", float64(11)), + Int32("int32", int32(12)), + String("stringer", errors.New("err").Error()), + String("nilInterface", "nil"), + String("nil", "nil"), + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := InterleavedKVToFields(tt.keyValues...) + if (err != nil) != tt.wantErr { + t.Errorf("InterleavedKVToFields() error = %v, wantErr %v", err, tt.wantErr) + return + } + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/vendor/github.com/opentracing/opentracing-go/mocktracer/mocklogrecord.go b/vendor/github.com/opentracing/opentracing-go/mocktracer/mocklogrecord.go new file mode 100644 index 0000000000..2ce96d9d38 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/mocktracer/mocklogrecord.go @@ -0,0 +1,105 @@ +package mocktracer + +import ( + "fmt" + "reflect" + "time" + + "github.com/opentracing/opentracing-go/log" +) + +// MockLogRecord represents data logged to a Span via Span.LogFields or +// Span.LogKV. +type MockLogRecord struct { + Timestamp time.Time + Fields []MockKeyValue +} + +// MockKeyValue represents a single key:value pair. +type MockKeyValue struct { + Key string + + // All MockLogRecord values are coerced to strings via fmt.Sprint(), though + // we retain their type separately. + ValueKind reflect.Kind + ValueString string +} + +// EmitString belongs to the log.Encoder interface +func (m *MockKeyValue) EmitString(key, value string) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitBool belongs to the log.Encoder interface +func (m *MockKeyValue) EmitBool(key string, value bool) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitInt belongs to the log.Encoder interface +func (m *MockKeyValue) EmitInt(key string, value int) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitInt32 belongs to the log.Encoder interface +func (m *MockKeyValue) EmitInt32(key string, value int32) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitInt64 belongs to the log.Encoder interface +func (m *MockKeyValue) EmitInt64(key string, value int64) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitUint32 belongs to the log.Encoder interface +func (m *MockKeyValue) EmitUint32(key string, value uint32) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitUint64 belongs to the log.Encoder interface +func (m *MockKeyValue) EmitUint64(key string, value uint64) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitFloat32 belongs to the log.Encoder interface +func (m *MockKeyValue) EmitFloat32(key string, value float32) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitFloat64 belongs to the log.Encoder interface +func (m *MockKeyValue) EmitFloat64(key string, value float64) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitObject belongs to the log.Encoder interface +func (m *MockKeyValue) EmitObject(key string, value interface{}) { + m.Key = key + m.ValueKind = reflect.TypeOf(value).Kind() + m.ValueString = fmt.Sprint(value) +} + +// EmitLazyLogger belongs to the log.Encoder interface +func (m *MockKeyValue) EmitLazyLogger(value log.LazyLogger) { + var meta MockKeyValue + value(&meta) + m.Key = meta.Key + m.ValueKind = meta.ValueKind + m.ValueString = meta.ValueString +} diff --git a/vendor/github.com/opentracing/opentracing-go/mocktracer/mockspan.go b/vendor/github.com/opentracing/opentracing-go/mocktracer/mockspan.go new file mode 100644 index 0000000000..8c7932ce65 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/mocktracer/mockspan.go @@ -0,0 +1,284 @@ +package mocktracer + +import ( + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/opentracing/opentracing-go/log" +) + +// MockSpanContext is an opentracing.SpanContext implementation. +// +// It is entirely unsuitable for production use, but appropriate for tests +// that want to verify tracing behavior in other frameworks/applications. +// +// By default all spans have Sampled=true flag, unless {"sampling.priority": 0} +// tag is set. +type MockSpanContext struct { + TraceID int + SpanID int + Sampled bool + Baggage map[string]string +} + +var mockIDSource = uint32(42) + +func nextMockID() int { + return int(atomic.AddUint32(&mockIDSource, 1)) +} + +// ForeachBaggageItem belongs to the SpanContext interface +func (c MockSpanContext) ForeachBaggageItem(handler func(k, v string) bool) { + for k, v := range c.Baggage { + if !handler(k, v) { + break + } + } +} + +// WithBaggageItem creates a new context with an extra baggage item. +func (c MockSpanContext) WithBaggageItem(key, value string) MockSpanContext { + var newBaggage map[string]string + if c.Baggage == nil { + newBaggage = map[string]string{key: value} + } else { + newBaggage = make(map[string]string, len(c.Baggage)+1) + for k, v := range c.Baggage { + newBaggage[k] = v + } + newBaggage[key] = value + } + // Use positional parameters so the compiler will help catch new fields. + return MockSpanContext{c.TraceID, c.SpanID, c.Sampled, newBaggage} +} + +// MockSpan is an opentracing.Span implementation that exports its internal +// state for testing purposes. +type MockSpan struct { + sync.RWMutex + + ParentID int + + OperationName string + StartTime time.Time + FinishTime time.Time + + // All of the below are protected by the embedded RWMutex. + SpanContext MockSpanContext + tags map[string]interface{} + logs []MockLogRecord + tracer *MockTracer +} + +func newMockSpan(t *MockTracer, name string, opts opentracing.StartSpanOptions) *MockSpan { + tags := opts.Tags + if tags == nil { + tags = map[string]interface{}{} + } + traceID := nextMockID() + parentID := int(0) + var baggage map[string]string + sampled := true + if len(opts.References) > 0 { + traceID = opts.References[0].ReferencedContext.(MockSpanContext).TraceID + parentID = opts.References[0].ReferencedContext.(MockSpanContext).SpanID + sampled = opts.References[0].ReferencedContext.(MockSpanContext).Sampled + baggage = opts.References[0].ReferencedContext.(MockSpanContext).Baggage + } + spanContext := MockSpanContext{traceID, nextMockID(), sampled, baggage} + startTime := opts.StartTime + if startTime.IsZero() { + startTime = time.Now() + } + return &MockSpan{ + ParentID: parentID, + OperationName: name, + StartTime: startTime, + tags: tags, + logs: []MockLogRecord{}, + SpanContext: spanContext, + + tracer: t, + } +} + +// Tags returns a copy of tags accumulated by the span so far +func (s *MockSpan) Tags() map[string]interface{} { + s.RLock() + defer s.RUnlock() + tags := make(map[string]interface{}) + for k, v := range s.tags { + tags[k] = v + } + return tags +} + +// Tag returns a single tag +func (s *MockSpan) Tag(k string) interface{} { + s.RLock() + defer s.RUnlock() + return s.tags[k] +} + +// Logs returns a copy of logs accumulated in the span so far +func (s *MockSpan) Logs() []MockLogRecord { + s.RLock() + defer s.RUnlock() + logs := make([]MockLogRecord, len(s.logs)) + copy(logs, s.logs) + return logs +} + +// Context belongs to the Span interface +func (s *MockSpan) Context() opentracing.SpanContext { + s.Lock() + defer s.Unlock() + return s.SpanContext +} + +// SetTag belongs to the Span interface +func (s *MockSpan) SetTag(key string, value interface{}) opentracing.Span { + s.Lock() + defer s.Unlock() + if key == string(ext.SamplingPriority) { + if v, ok := value.(uint16); ok { + s.SpanContext.Sampled = v > 0 + return s + } + if v, ok := value.(int); ok { + s.SpanContext.Sampled = v > 0 + return s + } + } + s.tags[key] = value + return s +} + +// SetBaggageItem belongs to the Span interface +func (s *MockSpan) SetBaggageItem(key, val string) opentracing.Span { + s.Lock() + defer s.Unlock() + s.SpanContext = s.SpanContext.WithBaggageItem(key, val) + return s +} + +// BaggageItem belongs to the Span interface +func (s *MockSpan) BaggageItem(key string) string { + s.RLock() + defer s.RUnlock() + return s.SpanContext.Baggage[key] +} + +// Finish belongs to the Span interface +func (s *MockSpan) Finish() { + s.Lock() + s.FinishTime = time.Now() + s.Unlock() + s.tracer.recordSpan(s) +} + +// FinishWithOptions belongs to the Span interface +func (s *MockSpan) FinishWithOptions(opts opentracing.FinishOptions) { + s.Lock() + s.FinishTime = opts.FinishTime + s.Unlock() + + // Handle any late-bound LogRecords. + for _, lr := range opts.LogRecords { + s.logFieldsWithTimestamp(lr.Timestamp, lr.Fields...) + } + // Handle (deprecated) BulkLogData. + for _, ld := range opts.BulkLogData { + if ld.Payload != nil { + s.logFieldsWithTimestamp( + ld.Timestamp, + log.String("event", ld.Event), + log.Object("payload", ld.Payload)) + } else { + s.logFieldsWithTimestamp( + ld.Timestamp, + log.String("event", ld.Event)) + } + } + + s.tracer.recordSpan(s) +} + +// String allows printing span for debugging +func (s *MockSpan) String() string { + return fmt.Sprintf( + "traceId=%d, spanId=%d, parentId=%d, sampled=%t, name=%s", + s.SpanContext.TraceID, s.SpanContext.SpanID, s.ParentID, + s.SpanContext.Sampled, s.OperationName) +} + +// LogFields belongs to the Span interface +func (s *MockSpan) LogFields(fields ...log.Field) { + s.logFieldsWithTimestamp(time.Now(), fields...) +} + +// The caller MUST NOT hold s.Lock +func (s *MockSpan) logFieldsWithTimestamp(ts time.Time, fields ...log.Field) { + lr := MockLogRecord{ + Timestamp: ts, + Fields: make([]MockKeyValue, len(fields)), + } + for i, f := range fields { + outField := &(lr.Fields[i]) + f.Marshal(outField) + } + + s.Lock() + defer s.Unlock() + s.logs = append(s.logs, lr) +} + +// LogKV belongs to the Span interface. +// +// This implementations coerces all "values" to strings, though that is not +// something all implementations need to do. Indeed, a motivated person can and +// probably should have this do a typed switch on the values. +func (s *MockSpan) LogKV(keyValues ...interface{}) { + if len(keyValues)%2 != 0 { + s.LogFields(log.Error(fmt.Errorf("Non-even keyValues len: %v", len(keyValues)))) + return + } + fields, err := log.InterleavedKVToFields(keyValues...) + if err != nil { + s.LogFields(log.Error(err), log.String("function", "LogKV")) + return + } + s.LogFields(fields...) +} + +// LogEvent belongs to the Span interface +func (s *MockSpan) LogEvent(event string) { + s.LogFields(log.String("event", event)) +} + +// LogEventWithPayload belongs to the Span interface +func (s *MockSpan) LogEventWithPayload(event string, payload interface{}) { + s.LogFields(log.String("event", event), log.Object("payload", payload)) +} + +// Log belongs to the Span interface +func (s *MockSpan) Log(data opentracing.LogData) { + panic("MockSpan.Log() no longer supported") +} + +// SetOperationName belongs to the Span interface +func (s *MockSpan) SetOperationName(operationName string) opentracing.Span { + s.Lock() + defer s.Unlock() + s.OperationName = operationName + return s +} + +// Tracer belongs to the Span interface +func (s *MockSpan) Tracer() opentracing.Tracer { + return s.tracer +} diff --git a/vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer.go b/vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer.go new file mode 100644 index 0000000000..4533da7b1f --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer.go @@ -0,0 +1,105 @@ +package mocktracer + +import ( + "sync" + + "github.com/opentracing/opentracing-go" +) + +// New returns a MockTracer opentracing.Tracer implementation that's intended +// to facilitate tests of OpenTracing instrumentation. +func New() *MockTracer { + t := &MockTracer{ + finishedSpans: []*MockSpan{}, + injectors: make(map[interface{}]Injector), + extractors: make(map[interface{}]Extractor), + } + + // register default injectors/extractors + textPropagator := new(TextMapPropagator) + t.RegisterInjector(opentracing.TextMap, textPropagator) + t.RegisterExtractor(opentracing.TextMap, textPropagator) + + httpPropagator := &TextMapPropagator{HTTPHeaders: true} + t.RegisterInjector(opentracing.HTTPHeaders, httpPropagator) + t.RegisterExtractor(opentracing.HTTPHeaders, httpPropagator) + + return t +} + +// MockTracer is only intended for testing OpenTracing instrumentation. +// +// It is entirely unsuitable for production use, but appropriate for tests +// that want to verify tracing behavior in other frameworks/applications. +type MockTracer struct { + sync.RWMutex + finishedSpans []*MockSpan + injectors map[interface{}]Injector + extractors map[interface{}]Extractor +} + +// FinishedSpans returns all spans that have been Finish()'ed since the +// MockTracer was constructed or since the last call to its Reset() method. +func (t *MockTracer) FinishedSpans() []*MockSpan { + t.RLock() + defer t.RUnlock() + spans := make([]*MockSpan, len(t.finishedSpans)) + copy(spans, t.finishedSpans) + return spans +} + +// Reset clears the internally accumulated finished spans. Note that any +// extant MockSpans will still append to finishedSpans when they Finish(), +// even after a call to Reset(). +func (t *MockTracer) Reset() { + t.Lock() + defer t.Unlock() + t.finishedSpans = []*MockSpan{} +} + +// StartSpan belongs to the Tracer interface. +func (t *MockTracer) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span { + sso := opentracing.StartSpanOptions{} + for _, o := range opts { + o.Apply(&sso) + } + return newMockSpan(t, operationName, sso) +} + +// RegisterInjector registers injector for given format +func (t *MockTracer) RegisterInjector(format interface{}, injector Injector) { + t.injectors[format] = injector +} + +// RegisterExtractor registers extractor for given format +func (t *MockTracer) RegisterExtractor(format interface{}, extractor Extractor) { + t.extractors[format] = extractor +} + +// Inject belongs to the Tracer interface. +func (t *MockTracer) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error { + spanContext, ok := sm.(MockSpanContext) + if !ok { + return opentracing.ErrInvalidSpanContext + } + injector, ok := t.injectors[format] + if !ok { + return opentracing.ErrUnsupportedFormat + } + return injector.Inject(spanContext, carrier) +} + +// Extract belongs to the Tracer interface. +func (t *MockTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) { + extractor, ok := t.extractors[format] + if !ok { + return nil, opentracing.ErrUnsupportedFormat + } + return extractor.Extract(carrier) +} + +func (t *MockTracer) recordSpan(span *MockSpan) { + t.Lock() + defer t.Unlock() + t.finishedSpans = append(t.finishedSpans, span) +} diff --git a/vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer_test.go b/vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer_test.go new file mode 100644 index 0000000000..14c04d8c7f --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/mocktracer/mocktracer_test.go @@ -0,0 +1,284 @@ +package mocktracer + +import ( + "net/http" + "reflect" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/ext" + "github.com/opentracing/opentracing-go/log" +) + +func TestMockTracer_StartSpan(t *testing.T) { + tracer := New() + span1 := tracer.StartSpan( + "a", + opentracing.Tags(map[string]interface{}{"x": "y"})) + + span2 := span1.Tracer().StartSpan( + "", opentracing.ChildOf(span1.Context())) + span2.Finish() + span1.Finish() + spans := tracer.FinishedSpans() + assert.Equal(t, 2, len(spans)) + + parent := spans[1] + child := spans[0] + assert.Equal(t, map[string]interface{}{"x": "y"}, parent.Tags()) + assert.Equal(t, child.ParentID, parent.Context().(MockSpanContext).SpanID) +} + +func TestMockSpan_SetOperationName(t *testing.T) { + tracer := New() + span := tracer.StartSpan("") + span.SetOperationName("x") + assert.Equal(t, "x", span.(*MockSpan).OperationName) +} + +func TestMockSpanContext_Baggage(t *testing.T) { + tracer := New() + span := tracer.StartSpan("x") + span.SetBaggageItem("x", "y") + assert.Equal(t, "y", span.BaggageItem("x")) + assert.Equal(t, map[string]string{"x": "y"}, span.Context().(MockSpanContext).Baggage) + + baggage := make(map[string]string) + span.Context().ForeachBaggageItem(func(k, v string) bool { + baggage[k] = v + return true + }) + assert.Equal(t, map[string]string{"x": "y"}, baggage) + + span.SetBaggageItem("a", "b") + baggage = make(map[string]string) + span.Context().ForeachBaggageItem(func(k, v string) bool { + baggage[k] = v + return false // exit early + }) + assert.Equal(t, 2, len(span.Context().(MockSpanContext).Baggage)) + assert.Equal(t, 1, len(baggage)) +} + +func TestMockSpan_Tag(t *testing.T) { + tracer := New() + span := tracer.StartSpan("x") + span.SetTag("x", "y") + assert.Equal(t, "y", span.(*MockSpan).Tag("x")) +} + +func TestMockSpan_Tags(t *testing.T) { + tracer := New() + span := tracer.StartSpan("x") + span.SetTag("x", "y") + assert.Equal(t, map[string]interface{}{"x": "y"}, span.(*MockSpan).Tags()) +} + +func TestMockTracer_FinishedSpans_and_Reset(t *testing.T) { + tracer := New() + span := tracer.StartSpan("x") + span.SetTag("x", "y") + span.Finish() + spans := tracer.FinishedSpans() + assert.Equal(t, 1, len(spans)) + assert.Equal(t, map[string]interface{}{"x": "y"}, spans[0].Tags()) + + tracer.Reset() + spans = tracer.FinishedSpans() + assert.Equal(t, 0, len(spans)) +} + +func zeroOutTimestamps(recs []MockLogRecord) { + for i := range recs { + recs[i].Timestamp = time.Time{} + } +} + +func TestMockSpan_LogKV(t *testing.T) { + tracer := New() + span := tracer.StartSpan("s") + span.LogKV("key0", "string0") + span.LogKV("key1", "string1", "key2", uint32(42)) + span.Finish() + spans := tracer.FinishedSpans() + assert.Equal(t, 1, len(spans)) + actual := spans[0].Logs() + zeroOutTimestamps(actual) + assert.Equal(t, []MockLogRecord{ + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "key0", ValueKind: reflect.String, ValueString: "string0"}, + }, + }, + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "key1", ValueKind: reflect.String, ValueString: "string1"}, + MockKeyValue{Key: "key2", ValueKind: reflect.Uint32, ValueString: "42"}, + }, + }, + }, actual) +} + +func TestMockSpan_LogFields(t *testing.T) { + tracer := New() + span := tracer.StartSpan("s") + span.LogFields(log.String("key0", "string0")) + span.LogFields(log.String("key1", "string1"), log.Uint32("key2", uint32(42))) + span.LogFields(log.Lazy(func(fv log.Encoder) { + fv.EmitInt("key_lazy", 12) + })) + span.FinishWithOptions(opentracing.FinishOptions{ + LogRecords: []opentracing.LogRecord{ + {Timestamp: time.Now(), Fields: []log.Field{log.String("key9", "finish")}}, + }}) + spans := tracer.FinishedSpans() + assert.Equal(t, 1, len(spans)) + actual := spans[0].Logs() + zeroOutTimestamps(actual) + assert.Equal(t, []MockLogRecord{ + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "key0", ValueKind: reflect.String, ValueString: "string0"}, + }, + }, + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "key1", ValueKind: reflect.String, ValueString: "string1"}, + MockKeyValue{Key: "key2", ValueKind: reflect.Uint32, ValueString: "42"}, + }, + }, + MockLogRecord{ + Fields: []MockKeyValue{ + // Note that the LazyLogger gets to control the key as well as the value. + MockKeyValue{Key: "key_lazy", ValueKind: reflect.Int, ValueString: "12"}, + }, + }, + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "key9", ValueKind: reflect.String, ValueString: "finish"}, + }, + }, + }, actual) +} + +func TestMockSpan_DeprecatedLogs(t *testing.T) { + tracer := New() + span := tracer.StartSpan("x") + span.LogEvent("x") + span.LogEventWithPayload("y", "z") + span.LogEvent("a") + span.FinishWithOptions(opentracing.FinishOptions{ + BulkLogData: []opentracing.LogData{{Event: "f"}}}) + spans := tracer.FinishedSpans() + assert.Equal(t, 1, len(spans)) + actual := spans[0].Logs() + zeroOutTimestamps(actual) + assert.Equal(t, []MockLogRecord{ + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "event", ValueKind: reflect.String, ValueString: "x"}, + }, + }, + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "event", ValueKind: reflect.String, ValueString: "y"}, + MockKeyValue{Key: "payload", ValueKind: reflect.String, ValueString: "z"}, + }, + }, + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "event", ValueKind: reflect.String, ValueString: "a"}, + }, + }, + MockLogRecord{ + Fields: []MockKeyValue{ + MockKeyValue{Key: "event", ValueKind: reflect.String, ValueString: "f"}, + }, + }, + }, actual) +} + +func TestMockTracer_Propagation(t *testing.T) { + textCarrier := func() interface{} { + return opentracing.TextMapCarrier(make(map[string]string)) + } + textLen := func(c interface{}) int { + return len(c.(opentracing.TextMapCarrier)) + } + + httpCarrier := func() interface{} { + httpHeaders := http.Header(make(map[string][]string)) + return opentracing.HTTPHeadersCarrier(httpHeaders) + } + httpLen := func(c interface{}) int { + return len(c.(opentracing.HTTPHeadersCarrier)) + } + + tests := []struct { + sampled bool + format opentracing.BuiltinFormat + carrier func() interface{} + len func(interface{}) int + }{ + {sampled: true, format: opentracing.TextMap, carrier: textCarrier, len: textLen}, + {sampled: false, format: opentracing.TextMap, carrier: textCarrier, len: textLen}, + {sampled: true, format: opentracing.HTTPHeaders, carrier: httpCarrier, len: httpLen}, + {sampled: false, format: opentracing.HTTPHeaders, carrier: httpCarrier, len: httpLen}, + } + for _, test := range tests { + tracer := New() + span := tracer.StartSpan("x") + span.SetBaggageItem("x", "y:z") // colon should be URL encoded as %3A + if !test.sampled { + ext.SamplingPriority.Set(span, 0) + } + mSpan := span.(*MockSpan) + + assert.Equal(t, opentracing.ErrUnsupportedFormat, + tracer.Inject(span.Context(), opentracing.Binary, nil)) + assert.Equal(t, opentracing.ErrInvalidCarrier, + tracer.Inject(span.Context(), opentracing.TextMap, span)) + + carrier := test.carrier() + + err := tracer.Inject(span.Context(), test.format, carrier) + require.NoError(t, err) + assert.Equal(t, 4, test.len(carrier), "expect baggage + 2 ids + sampled") + if test.format == opentracing.HTTPHeaders { + c := carrier.(opentracing.HTTPHeadersCarrier) + assert.Equal(t, "y%3Az", c["Mockpfx-Baggage-X"][0]) + } + + _, err = tracer.Extract(opentracing.Binary, nil) + assert.Equal(t, opentracing.ErrUnsupportedFormat, err) + _, err = tracer.Extract(opentracing.TextMap, tracer) + assert.Equal(t, opentracing.ErrInvalidCarrier, err) + + extractedContext, err := tracer.Extract(test.format, carrier) + require.NoError(t, err) + assert.Equal(t, mSpan.SpanContext.TraceID, extractedContext.(MockSpanContext).TraceID) + assert.Equal(t, mSpan.SpanContext.SpanID, extractedContext.(MockSpanContext).SpanID) + assert.Equal(t, test.sampled, extractedContext.(MockSpanContext).Sampled) + assert.Equal(t, "y:z", extractedContext.(MockSpanContext).Baggage["x"]) + } +} + +func TestMockSpan_Races(t *testing.T) { + span := New().StartSpan("x") + var wg sync.WaitGroup + wg.Add(2) + go func() { + defer wg.Done() + span.SetBaggageItem("test_key", "test_value") + }() + go func() { + defer wg.Done() + span.Context() + }() + wg.Wait() +} diff --git a/vendor/github.com/opentracing/opentracing-go/mocktracer/propagation.go b/vendor/github.com/opentracing/opentracing-go/mocktracer/propagation.go new file mode 100644 index 0000000000..8364f1d182 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/mocktracer/propagation.go @@ -0,0 +1,120 @@ +package mocktracer + +import ( + "fmt" + "net/url" + "strconv" + "strings" + + "github.com/opentracing/opentracing-go" +) + +const mockTextMapIdsPrefix = "mockpfx-ids-" +const mockTextMapBaggagePrefix = "mockpfx-baggage-" + +var emptyContext = MockSpanContext{} + +// Injector is responsible for injecting SpanContext instances in a manner suitable +// for propagation via a format-specific "carrier" object. Typically the +// injection will take place across an RPC boundary, but message queues and +// other IPC mechanisms are also reasonable places to use an Injector. +type Injector interface { + // Inject takes `SpanContext` and injects it into `carrier`. The actual type + // of `carrier` depends on the `format` passed to `Tracer.Inject()`. + // + // Implementations may return opentracing.ErrInvalidCarrier or any other + // implementation-specific error if injection fails. + Inject(ctx MockSpanContext, carrier interface{}) error +} + +// Extractor is responsible for extracting SpanContext instances from a +// format-specific "carrier" object. Typically the extraction will take place +// on the server side of an RPC boundary, but message queues and other IPC +// mechanisms are also reasonable places to use an Extractor. +type Extractor interface { + // Extract decodes a SpanContext instance from the given `carrier`, + // or (nil, opentracing.ErrSpanContextNotFound) if no context could + // be found in the `carrier`. + Extract(carrier interface{}) (MockSpanContext, error) +} + +// TextMapPropagator implements Injector/Extractor for TextMap and HTTPHeaders formats. +type TextMapPropagator struct { + HTTPHeaders bool +} + +// Inject implements the Injector interface +func (t *TextMapPropagator) Inject(spanContext MockSpanContext, carrier interface{}) error { + writer, ok := carrier.(opentracing.TextMapWriter) + if !ok { + return opentracing.ErrInvalidCarrier + } + // Ids: + writer.Set(mockTextMapIdsPrefix+"traceid", strconv.Itoa(spanContext.TraceID)) + writer.Set(mockTextMapIdsPrefix+"spanid", strconv.Itoa(spanContext.SpanID)) + writer.Set(mockTextMapIdsPrefix+"sampled", fmt.Sprint(spanContext.Sampled)) + // Baggage: + for baggageKey, baggageVal := range spanContext.Baggage { + safeVal := baggageVal + if t.HTTPHeaders { + safeVal = url.QueryEscape(baggageVal) + } + writer.Set(mockTextMapBaggagePrefix+baggageKey, safeVal) + } + return nil +} + +// Extract implements the Extractor interface +func (t *TextMapPropagator) Extract(carrier interface{}) (MockSpanContext, error) { + reader, ok := carrier.(opentracing.TextMapReader) + if !ok { + return emptyContext, opentracing.ErrInvalidCarrier + } + rval := MockSpanContext{0, 0, true, nil} + err := reader.ForeachKey(func(key, val string) error { + lowerKey := strings.ToLower(key) + switch { + case lowerKey == mockTextMapIdsPrefix+"traceid": + // Ids: + i, err := strconv.Atoi(val) + if err != nil { + return err + } + rval.TraceID = i + case lowerKey == mockTextMapIdsPrefix+"spanid": + // Ids: + i, err := strconv.Atoi(val) + if err != nil { + return err + } + rval.SpanID = i + case lowerKey == mockTextMapIdsPrefix+"sampled": + b, err := strconv.ParseBool(val) + if err != nil { + return err + } + rval.Sampled = b + case strings.HasPrefix(lowerKey, mockTextMapBaggagePrefix): + // Baggage: + if rval.Baggage == nil { + rval.Baggage = make(map[string]string) + } + safeVal := val + if t.HTTPHeaders { + // unescape errors are ignored, nothing can be done + if rawVal, err := url.QueryUnescape(val); err == nil { + safeVal = rawVal + } + } + rval.Baggage[lowerKey[len(mockTextMapBaggagePrefix):]] = safeVal + } + return nil + }) + if rval.TraceID == 0 || rval.SpanID == 0 { + return emptyContext, opentracing.ErrSpanContextNotFound + } + if err != nil { + return emptyContext, err + } + return rval, nil +} diff --git a/vendor/github.com/opentracing/opentracing-go/noop.go b/vendor/github.com/opentracing/opentracing-go/noop.go new file mode 100644 index 0000000000..f9b680a213 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/noop.go @@ -0,0 +1,64 @@ +package opentracing + +import "github.com/opentracing/opentracing-go/log" + +// A NoopTracer is a trivial, minimum overhead implementation of Tracer +// for which all operations are no-ops. +// +// The primary use of this implementation is in libraries, such as RPC +// frameworks, that make tracing an optional feature controlled by the +// end user. A no-op implementation allows said libraries to use it +// as the default Tracer and to write instrumentation that does +// not need to keep checking if the tracer instance is nil. +// +// For the same reason, the NoopTracer is the default "global" tracer +// (see GlobalTracer and SetGlobalTracer functions). +// +// WARNING: NoopTracer does not support baggage propagation. +type NoopTracer struct{} + +type noopSpan struct{} +type noopSpanContext struct{} + +var ( + defaultNoopSpanContext SpanContext = noopSpanContext{} + defaultNoopSpan Span = noopSpan{} + defaultNoopTracer Tracer = NoopTracer{} +) + +const ( + emptyString = "" +) + +// noopSpanContext: +func (n noopSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {} + +// noopSpan: +func (n noopSpan) Context() SpanContext { return defaultNoopSpanContext } +func (n noopSpan) SetBaggageItem(key, val string) Span { return n } +func (n noopSpan) BaggageItem(key string) string { return emptyString } +func (n noopSpan) SetTag(key string, value interface{}) Span { return n } +func (n noopSpan) LogFields(fields ...log.Field) {} +func (n noopSpan) LogKV(keyVals ...interface{}) {} +func (n noopSpan) Finish() {} +func (n noopSpan) FinishWithOptions(opts FinishOptions) {} +func (n noopSpan) SetOperationName(operationName string) Span { return n } +func (n noopSpan) Tracer() Tracer { return defaultNoopTracer } +func (n noopSpan) LogEvent(event string) {} +func (n noopSpan) LogEventWithPayload(event string, payload interface{}) {} +func (n noopSpan) Log(data LogData) {} + +// StartSpan belongs to the Tracer interface. +func (n NoopTracer) StartSpan(operationName string, opts ...StartSpanOption) Span { + return defaultNoopSpan +} + +// Inject belongs to the Tracer interface. +func (n NoopTracer) Inject(sp SpanContext, format interface{}, carrier interface{}) error { + return nil +} + +// Extract belongs to the Tracer interface. +func (n NoopTracer) Extract(format interface{}, carrier interface{}) (SpanContext, error) { + return nil, ErrSpanContextNotFound +} diff --git a/vendor/github.com/opentracing/opentracing-go/options_test.go b/vendor/github.com/opentracing/opentracing-go/options_test.go new file mode 100644 index 0000000000..56a543bfe5 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/options_test.go @@ -0,0 +1,31 @@ +package opentracing + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestChildOfAndFollowsFrom(t *testing.T) { + tests := []struct { + newOpt func(SpanContext) SpanReference + refType SpanReferenceType + name string + }{ + {ChildOf, ChildOfRef, "ChildOf"}, + {FollowsFrom, FollowsFromRef, "FollowsFrom"}, + } + + for _, test := range tests { + opts := new(StartSpanOptions) + + test.newOpt(nil).Apply(opts) + require.Nil(t, opts.References, "%s(nil) must not append a reference", test.name) + + ctx := new(noopSpanContext) + test.newOpt(ctx).Apply(opts) + require.Equal(t, []SpanReference{ + SpanReference{ReferencedContext: ctx, Type: test.refType}, + }, opts.References, "%s(ctx) must append a reference", test.name) + } +} diff --git a/vendor/github.com/opentracing/opentracing-go/propagation.go b/vendor/github.com/opentracing/opentracing-go/propagation.go new file mode 100644 index 0000000000..b0c275eb05 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/propagation.go @@ -0,0 +1,176 @@ +package opentracing + +import ( + "errors" + "net/http" +) + +/////////////////////////////////////////////////////////////////////////////// +// CORE PROPAGATION INTERFACES: +/////////////////////////////////////////////////////////////////////////////// + +var ( + // ErrUnsupportedFormat occurs when the `format` passed to Tracer.Inject() or + // Tracer.Extract() is not recognized by the Tracer implementation. + ErrUnsupportedFormat = errors.New("opentracing: Unknown or unsupported Inject/Extract format") + + // ErrSpanContextNotFound occurs when the `carrier` passed to + // Tracer.Extract() is valid and uncorrupted but has insufficient + // information to extract a SpanContext. + ErrSpanContextNotFound = errors.New("opentracing: SpanContext not found in Extract carrier") + + // ErrInvalidSpanContext errors occur when Tracer.Inject() is asked to + // operate on a SpanContext which it is not prepared to handle (for + // example, since it was created by a different tracer implementation). + ErrInvalidSpanContext = errors.New("opentracing: SpanContext type incompatible with tracer") + + // ErrInvalidCarrier errors occur when Tracer.Inject() or Tracer.Extract() + // implementations expect a different type of `carrier` than they are + // given. + ErrInvalidCarrier = errors.New("opentracing: Invalid Inject/Extract carrier") + + // ErrSpanContextCorrupted occurs when the `carrier` passed to + // Tracer.Extract() is of the expected type but is corrupted. + ErrSpanContextCorrupted = errors.New("opentracing: SpanContext data corrupted in Extract carrier") +) + +/////////////////////////////////////////////////////////////////////////////// +// BUILTIN PROPAGATION FORMATS: +/////////////////////////////////////////////////////////////////////////////// + +// BuiltinFormat is used to demarcate the values within package `opentracing` +// that are intended for use with the Tracer.Inject() and Tracer.Extract() +// methods. +type BuiltinFormat byte + +const ( + // Binary represents SpanContexts as opaque binary data. + // + // For Tracer.Inject(): the carrier must be an `io.Writer`. + // + // For Tracer.Extract(): the carrier must be an `io.Reader`. + Binary BuiltinFormat = iota + + // TextMap represents SpanContexts as key:value string pairs. + // + // Unlike HTTPHeaders, the TextMap format does not restrict the key or + // value character sets in any way. + // + // For Tracer.Inject(): the carrier must be a `TextMapWriter`. + // + // For Tracer.Extract(): the carrier must be a `TextMapReader`. + TextMap + + // HTTPHeaders represents SpanContexts as HTTP header string pairs. + // + // Unlike TextMap, the HTTPHeaders format requires that the keys and values + // be valid as HTTP headers as-is (i.e., character casing may be unstable + // and special characters are disallowed in keys, values should be + // URL-escaped, etc). + // + // For Tracer.Inject(): the carrier must be a `TextMapWriter`. + // + // For Tracer.Extract(): the carrier must be a `TextMapReader`. + // + // See HTTPHeadersCarrier for an implementation of both TextMapWriter + // and TextMapReader that defers to an http.Header instance for storage. + // For example, Inject(): + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // err := span.Tracer().Inject( + // span.Context(), opentracing.HTTPHeaders, carrier) + // + // Or Extract(): + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // clientContext, err := tracer.Extract( + // opentracing.HTTPHeaders, carrier) + // + HTTPHeaders +) + +// TextMapWriter is the Inject() carrier for the TextMap builtin format. With +// it, the caller can encode a SpanContext for propagation as entries in a map +// of unicode strings. +type TextMapWriter interface { + // Set a key:value pair to the carrier. Multiple calls to Set() for the + // same key leads to undefined behavior. + // + // NOTE: The backing store for the TextMapWriter may contain data unrelated + // to SpanContext. As such, Inject() and Extract() implementations that + // call the TextMapWriter and TextMapReader interfaces must agree on a + // prefix or other convention to distinguish their own key:value pairs. + Set(key, val string) +} + +// TextMapReader is the Extract() carrier for the TextMap builtin format. With it, +// the caller can decode a propagated SpanContext as entries in a map of +// unicode strings. +type TextMapReader interface { + // ForeachKey returns TextMap contents via repeated calls to the `handler` + // function. If any call to `handler` returns a non-nil error, ForeachKey + // terminates and returns that error. + // + // NOTE: The backing store for the TextMapReader may contain data unrelated + // to SpanContext. As such, Inject() and Extract() implementations that + // call the TextMapWriter and TextMapReader interfaces must agree on a + // prefix or other convention to distinguish their own key:value pairs. + // + // The "foreach" callback pattern reduces unnecessary copying in some cases + // and also allows implementations to hold locks while the map is read. + ForeachKey(handler func(key, val string) error) error +} + +// TextMapCarrier allows the use of regular map[string]string +// as both TextMapWriter and TextMapReader. +type TextMapCarrier map[string]string + +// ForeachKey conforms to the TextMapReader interface. +func (c TextMapCarrier) ForeachKey(handler func(key, val string) error) error { + for k, v := range c { + if err := handler(k, v); err != nil { + return err + } + } + return nil +} + +// Set implements Set() of opentracing.TextMapWriter +func (c TextMapCarrier) Set(key, val string) { + c[key] = val +} + +// HTTPHeadersCarrier satisfies both TextMapWriter and TextMapReader. +// +// Example usage for server side: +// +// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) +// clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier) +// +// Example usage for client side: +// +// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) +// err := tracer.Inject( +// span.Context(), +// opentracing.HTTPHeaders, +// carrier) +// +type HTTPHeadersCarrier http.Header + +// Set conforms to the TextMapWriter interface. +func (c HTTPHeadersCarrier) Set(key, val string) { + h := http.Header(c) + h.Set(key, val) +} + +// ForeachKey conforms to the TextMapReader interface. +func (c HTTPHeadersCarrier) ForeachKey(handler func(key, val string) error) error { + for k, vals := range c { + for _, v := range vals { + if err := handler(k, v); err != nil { + return err + } + } + } + return nil +} diff --git a/vendor/github.com/opentracing/opentracing-go/propagation_test.go b/vendor/github.com/opentracing/opentracing-go/propagation_test.go new file mode 100644 index 0000000000..e3dad55978 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/propagation_test.go @@ -0,0 +1,93 @@ +package opentracing + +import ( + "net/http" + "strconv" + "testing" +) + +const testHeaderPrefix = "testprefix-" + +func TestTextMapCarrierInject(t *testing.T) { + m := make(map[string]string) + m["NotOT"] = "blah" + m["opname"] = "AlsoNotOT" + tracer := testTracer{} + span := tracer.StartSpan("someSpan") + fakeID := span.Context().(testSpanContext).FakeID + + carrier := TextMapCarrier(m) + if err := span.Tracer().Inject(span.Context(), TextMap, carrier); err != nil { + t.Fatal(err) + } + + if len(m) != 3 { + t.Errorf("Unexpected header length: %v", len(m)) + } + // The prefix comes from just above; the suffix comes from + // testTracer.Inject(). + if m["testprefix-fakeid"] != strconv.Itoa(fakeID) { + t.Errorf("Could not find fakeid at expected key") + } +} + +func TestTextMapCarrierExtract(t *testing.T) { + m := make(map[string]string) + m["NotOT"] = "blah" + m["opname"] = "AlsoNotOT" + m["testprefix-fakeid"] = "42" + tracer := testTracer{} + + carrier := TextMapCarrier(m) + extractedContext, err := tracer.Extract(TextMap, carrier) + if err != nil { + t.Fatal(err) + } + + if extractedContext.(testSpanContext).FakeID != 42 { + t.Errorf("Failed to read testprefix-fakeid correctly") + } +} + +func TestHTTPHeaderInject(t *testing.T) { + h := http.Header{} + h.Add("NotOT", "blah") + h.Add("opname", "AlsoNotOT") + tracer := testTracer{} + span := tracer.StartSpan("someSpan") + fakeID := span.Context().(testSpanContext).FakeID + + // Use HTTPHeadersCarrier to wrap around `h`. + carrier := HTTPHeadersCarrier(h) + if err := span.Tracer().Inject(span.Context(), HTTPHeaders, carrier); err != nil { + t.Fatal(err) + } + + if len(h) != 3 { + t.Errorf("Unexpected header length: %v", len(h)) + } + // The prefix comes from just above; the suffix comes from + // testTracer.Inject(). + if h.Get("testprefix-fakeid") != strconv.Itoa(fakeID) { + t.Errorf("Could not find fakeid at expected key") + } +} + +func TestHTTPHeaderExtract(t *testing.T) { + h := http.Header{} + h.Add("NotOT", "blah") + h.Add("opname", "AlsoNotOT") + h.Add("testprefix-fakeid", "42") + tracer := testTracer{} + + // Use HTTPHeadersCarrier to wrap around `h`. + carrier := HTTPHeadersCarrier(h) + spanContext, err := tracer.Extract(HTTPHeaders, carrier) + if err != nil { + t.Fatal(err) + } + + if spanContext.(testSpanContext).FakeID != 42 { + t.Errorf("Failed to read testprefix-fakeid correctly") + } +} diff --git a/vendor/github.com/opentracing/opentracing-go/span.go b/vendor/github.com/opentracing/opentracing-go/span.go new file mode 100644 index 0000000000..0d3fb53418 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/span.go @@ -0,0 +1,189 @@ +package opentracing + +import ( + "time" + + "github.com/opentracing/opentracing-go/log" +) + +// SpanContext represents Span state that must propagate to descendant Spans and across process +// boundaries (e.g., a tuple). +type SpanContext interface { + // ForeachBaggageItem grants access to all baggage items stored in the + // SpanContext. + // The handler function will be called for each baggage key/value pair. + // The ordering of items is not guaranteed. + // + // The bool return value indicates if the handler wants to continue iterating + // through the rest of the baggage items; for example if the handler is trying to + // find some baggage item by pattern matching the name, it can return false + // as soon as the item is found to stop further iterations. + ForeachBaggageItem(handler func(k, v string) bool) +} + +// Span represents an active, un-finished span in the OpenTracing system. +// +// Spans are created by the Tracer interface. +type Span interface { + // Sets the end timestamp and finalizes Span state. + // + // With the exception of calls to Context() (which are always allowed), + // Finish() must be the last call made to any span instance, and to do + // otherwise leads to undefined behavior. + Finish() + // FinishWithOptions is like Finish() but with explicit control over + // timestamps and log data. + FinishWithOptions(opts FinishOptions) + + // Context() yields the SpanContext for this Span. Note that the return + // value of Context() is still valid after a call to Span.Finish(), as is + // a call to Span.Context() after a call to Span.Finish(). + Context() SpanContext + + // Sets or changes the operation name. + // + // Returns a reference to this Span for chaining. + SetOperationName(operationName string) Span + + // Adds a tag to the span. + // + // If there is a pre-existing tag set for `key`, it is overwritten. + // + // Tag values can be numeric types, strings, or bools. The behavior of + // other tag value types is undefined at the OpenTracing level. If a + // tracing system does not know how to handle a particular value type, it + // may ignore the tag, but shall not panic. + // + // Returns a reference to this Span for chaining. + SetTag(key string, value interface{}) Span + + // LogFields is an efficient and type-checked way to record key:value + // logging data about a Span, though the programming interface is a little + // more verbose than LogKV(). Here's an example: + // + // span.LogFields( + // log.String("event", "soft error"), + // log.String("type", "cache timeout"), + // log.Int("waited.millis", 1500)) + // + // Also see Span.FinishWithOptions() and FinishOptions.BulkLogData. + LogFields(fields ...log.Field) + + // LogKV is a concise, readable way to record key:value logging data about + // a Span, though unfortunately this also makes it less efficient and less + // type-safe than LogFields(). Here's an example: + // + // span.LogKV( + // "event", "soft error", + // "type", "cache timeout", + // "waited.millis", 1500) + // + // For LogKV (as opposed to LogFields()), the parameters must appear as + // key-value pairs, like + // + // span.LogKV(key1, val1, key2, val2, key3, val3, ...) + // + // The keys must all be strings. The values may be strings, numeric types, + // bools, Go error instances, or arbitrary structs. + // + // (Note to implementors: consider the log.InterleavedKVToFields() helper) + LogKV(alternatingKeyValues ...interface{}) + + // SetBaggageItem sets a key:value pair on this Span and its SpanContext + // that also propagates to descendants of this Span. + // + // SetBaggageItem() enables powerful functionality given a full-stack + // opentracing integration (e.g., arbitrary application data from a mobile + // app can make it, transparently, all the way into the depths of a storage + // system), and with it some powerful costs: use this feature with care. + // + // IMPORTANT NOTE #1: SetBaggageItem() will only propagate baggage items to + // *future* causal descendants of the associated Span. + // + // IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and + // value is copied into every local *and remote* child of the associated + // Span, and that can add up to a lot of network and cpu overhead. + // + // Returns a reference to this Span for chaining. + SetBaggageItem(restrictedKey, value string) Span + + // Gets the value for a baggage item given its key. Returns the empty string + // if the value isn't found in this Span. + BaggageItem(restrictedKey string) string + + // Provides access to the Tracer that created this Span. + Tracer() Tracer + + // Deprecated: use LogFields or LogKV + LogEvent(event string) + // Deprecated: use LogFields or LogKV + LogEventWithPayload(event string, payload interface{}) + // Deprecated: use LogFields or LogKV + Log(data LogData) +} + +// LogRecord is data associated with a single Span log. Every LogRecord +// instance must specify at least one Field. +type LogRecord struct { + Timestamp time.Time + Fields []log.Field +} + +// FinishOptions allows Span.FinishWithOptions callers to override the finish +// timestamp and provide log data via a bulk interface. +type FinishOptions struct { + // FinishTime overrides the Span's finish time, or implicitly becomes + // time.Now() if FinishTime.IsZero(). + // + // FinishTime must resolve to a timestamp that's >= the Span's StartTime + // (per StartSpanOptions). + FinishTime time.Time + + // LogRecords allows the caller to specify the contents of many LogFields() + // calls with a single slice. May be nil. + // + // None of the LogRecord.Timestamp values may be .IsZero() (i.e., they must + // be set explicitly). Also, they must be >= the Span's start timestamp and + // <= the FinishTime (or time.Now() if FinishTime.IsZero()). Otherwise the + // behavior of FinishWithOptions() is undefined. + // + // If specified, the caller hands off ownership of LogRecords at + // FinishWithOptions() invocation time. + // + // If specified, the (deprecated) BulkLogData must be nil or empty. + LogRecords []LogRecord + + // BulkLogData is DEPRECATED. + BulkLogData []LogData +} + +// LogData is DEPRECATED +type LogData struct { + Timestamp time.Time + Event string + Payload interface{} +} + +// ToLogRecord converts a deprecated LogData to a non-deprecated LogRecord +func (ld *LogData) ToLogRecord() LogRecord { + var literalTimestamp time.Time + if ld.Timestamp.IsZero() { + literalTimestamp = time.Now() + } else { + literalTimestamp = ld.Timestamp + } + rval := LogRecord{ + Timestamp: literalTimestamp, + } + if ld.Payload == nil { + rval.Fields = []log.Field{ + log.String("event", ld.Event), + } + } else { + rval.Fields = []log.Field{ + log.String("event", ld.Event), + log.Object("payload", ld.Payload), + } + } + return rval +} diff --git a/vendor/github.com/opentracing/opentracing-go/testtracer_test.go b/vendor/github.com/opentracing/opentracing-go/testtracer_test.go new file mode 100644 index 0000000000..dd13788cf0 --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/testtracer_test.go @@ -0,0 +1,138 @@ +package opentracing + +import ( + "strconv" + "strings" + "time" + + "github.com/opentracing/opentracing-go/log" +) + +const testHTTPHeaderPrefix = "testprefix-" + +// testTracer is a most-noop Tracer implementation that makes it possible for +// unittests to verify whether certain methods were / were not called. +type testTracer struct{} + +var fakeIDSource = 1 + +func nextFakeID() int { + fakeIDSource++ + return fakeIDSource +} + +type testSpanContext struct { + HasParent bool + FakeID int +} + +func (n testSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {} + +type testSpan struct { + spanContext testSpanContext + OperationName string + StartTime time.Time + Tags map[string]interface{} +} + +func (n testSpan) Equal(os Span) bool { + other, ok := os.(testSpan) + if !ok { + return false + } + if n.spanContext != other.spanContext { + return false + } + if n.OperationName != other.OperationName { + return false + } + if !n.StartTime.Equal(other.StartTime) { + return false + } + if len(n.Tags) != len(other.Tags) { + return false + } + + for k, v := range n.Tags { + if ov, ok := other.Tags[k]; !ok || ov != v { + return false + } + } + + return true +} + +// testSpan: +func (n testSpan) Context() SpanContext { return n.spanContext } +func (n testSpan) SetTag(key string, value interface{}) Span { return n } +func (n testSpan) Finish() {} +func (n testSpan) FinishWithOptions(opts FinishOptions) {} +func (n testSpan) LogFields(fields ...log.Field) {} +func (n testSpan) LogKV(kvs ...interface{}) {} +func (n testSpan) SetOperationName(operationName string) Span { return n } +func (n testSpan) Tracer() Tracer { return testTracer{} } +func (n testSpan) SetBaggageItem(key, val string) Span { return n } +func (n testSpan) BaggageItem(key string) string { return "" } +func (n testSpan) LogEvent(event string) {} +func (n testSpan) LogEventWithPayload(event string, payload interface{}) {} +func (n testSpan) Log(data LogData) {} + +// StartSpan belongs to the Tracer interface. +func (n testTracer) StartSpan(operationName string, opts ...StartSpanOption) Span { + sso := StartSpanOptions{} + for _, o := range opts { + o.Apply(&sso) + } + return n.startSpanWithOptions(operationName, sso) +} + +func (n testTracer) startSpanWithOptions(name string, opts StartSpanOptions) Span { + fakeID := nextFakeID() + if len(opts.References) > 0 { + fakeID = opts.References[0].ReferencedContext.(testSpanContext).FakeID + } + + return testSpan{ + OperationName: name, + StartTime: opts.StartTime, + Tags: opts.Tags, + spanContext: testSpanContext{ + HasParent: len(opts.References) > 0, + FakeID: fakeID, + }, + } +} + +// Inject belongs to the Tracer interface. +func (n testTracer) Inject(sp SpanContext, format interface{}, carrier interface{}) error { + spanContext := sp.(testSpanContext) + switch format { + case HTTPHeaders, TextMap: + carrier.(TextMapWriter).Set(testHTTPHeaderPrefix+"fakeid", strconv.Itoa(spanContext.FakeID)) + return nil + } + return ErrUnsupportedFormat +} + +// Extract belongs to the Tracer interface. +func (n testTracer) Extract(format interface{}, carrier interface{}) (SpanContext, error) { + switch format { + case HTTPHeaders, TextMap: + // Just for testing purposes... generally not a worthwhile thing to + // propagate. + sm := testSpanContext{} + err := carrier.(TextMapReader).ForeachKey(func(key, val string) error { + switch strings.ToLower(key) { + case testHTTPHeaderPrefix + "fakeid": + i, err := strconv.Atoi(val) + if err != nil { + return err + } + sm.FakeID = i + } + return nil + }) + return sm, err + } + return nil, ErrSpanContextNotFound +} diff --git a/vendor/github.com/opentracing/opentracing-go/tracer.go b/vendor/github.com/opentracing/opentracing-go/tracer.go new file mode 100644 index 0000000000..715f0cedfb --- /dev/null +++ b/vendor/github.com/opentracing/opentracing-go/tracer.go @@ -0,0 +1,304 @@ +package opentracing + +import "time" + +// Tracer is a simple, thin interface for Span creation and SpanContext +// propagation. +type Tracer interface { + + // Create, start, and return a new Span with the given `operationName` and + // incorporate the given StartSpanOption `opts`. (Note that `opts` borrows + // from the "functional options" pattern, per + // http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis) + // + // A Span with no SpanReference options (e.g., opentracing.ChildOf() or + // opentracing.FollowsFrom()) becomes the root of its own trace. + // + // Examples: + // + // var tracer opentracing.Tracer = ... + // + // // The root-span case: + // sp := tracer.StartSpan("GetFeed") + // + // // The vanilla child span case: + // sp := tracer.StartSpan( + // "GetFeed", + // opentracing.ChildOf(parentSpan.Context())) + // + // // All the bells and whistles: + // sp := tracer.StartSpan( + // "GetFeed", + // opentracing.ChildOf(parentSpan.Context()), + // opentracing.Tag{"user_agent", loggedReq.UserAgent}, + // opentracing.StartTime(loggedReq.Timestamp), + // ) + // + StartSpan(operationName string, opts ...StartSpanOption) Span + + // Inject() takes the `sm` SpanContext instance and injects it for + // propagation within `carrier`. The actual type of `carrier` depends on + // the value of `format`. + // + // OpenTracing defines a common set of `format` values (see BuiltinFormat), + // and each has an expected carrier type. + // + // Other packages may declare their own `format` values, much like the keys + // used by `context.Context` (see https://godoc.org/context#WithValue). + // + // Example usage (sans error handling): + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // err := tracer.Inject( + // span.Context(), + // opentracing.HTTPHeaders, + // carrier) + // + // NOTE: All opentracing.Tracer implementations MUST support all + // BuiltinFormats. + // + // Implementations may return opentracing.ErrUnsupportedFormat if `format` + // is not supported by (or not known by) the implementation. + // + // Implementations may return opentracing.ErrInvalidCarrier or any other + // implementation-specific error if the format is supported but injection + // fails anyway. + // + // See Tracer.Extract(). + Inject(sm SpanContext, format interface{}, carrier interface{}) error + + // Extract() returns a SpanContext instance given `format` and `carrier`. + // + // OpenTracing defines a common set of `format` values (see BuiltinFormat), + // and each has an expected carrier type. + // + // Other packages may declare their own `format` values, much like the keys + // used by `context.Context` (see + // https://godoc.org/golang.org/x/net/context#WithValue). + // + // Example usage (with StartSpan): + // + // + // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) + // clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier) + // + // // ... assuming the ultimate goal here is to resume the trace with a + // // server-side Span: + // var serverSpan opentracing.Span + // if err == nil { + // span = tracer.StartSpan( + // rpcMethodName, ext.RPCServerOption(clientContext)) + // } else { + // span = tracer.StartSpan(rpcMethodName) + // } + // + // + // NOTE: All opentracing.Tracer implementations MUST support all + // BuiltinFormats. + // + // Return values: + // - A successful Extract returns a SpanContext instance and a nil error + // - If there was simply no SpanContext to extract in `carrier`, Extract() + // returns (nil, opentracing.ErrSpanContextNotFound) + // - If `format` is unsupported or unrecognized, Extract() returns (nil, + // opentracing.ErrUnsupportedFormat) + // - If there are more fundamental problems with the `carrier` object, + // Extract() may return opentracing.ErrInvalidCarrier, + // opentracing.ErrSpanContextCorrupted, or implementation-specific + // errors. + // + // See Tracer.Inject(). + Extract(format interface{}, carrier interface{}) (SpanContext, error) +} + +// StartSpanOptions allows Tracer.StartSpan() callers and implementors a +// mechanism to override the start timestamp, specify Span References, and make +// a single Tag or multiple Tags available at Span start time. +// +// StartSpan() callers should look at the StartSpanOption interface and +// implementations available in this package. +// +// Tracer implementations can convert a slice of `StartSpanOption` instances +// into a `StartSpanOptions` struct like so: +// +// func StartSpan(opName string, opts ...opentracing.StartSpanOption) { +// sso := opentracing.StartSpanOptions{} +// for _, o := range opts { +// o.Apply(&sso) +// } +// ... +// } +// +type StartSpanOptions struct { + // Zero or more causal references to other Spans (via their SpanContext). + // If empty, start a "root" Span (i.e., start a new trace). + References []SpanReference + + // StartTime overrides the Span's start time, or implicitly becomes + // time.Now() if StartTime.IsZero(). + StartTime time.Time + + // Tags may have zero or more entries; the restrictions on map values are + // identical to those for Span.SetTag(). May be nil. + // + // If specified, the caller hands off ownership of Tags at + // StartSpan() invocation time. + Tags map[string]interface{} +} + +// StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan. +// +// StartSpanOption borrows from the "functional options" pattern, per +// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis +type StartSpanOption interface { + Apply(*StartSpanOptions) +} + +// SpanReferenceType is an enum type describing different categories of +// relationships between two Spans. If Span-2 refers to Span-1, the +// SpanReferenceType describes Span-1 from Span-2's perspective. For example, +// ChildOfRef means that Span-1 created Span-2. +// +// NOTE: Span-1 and Span-2 do *not* necessarily depend on each other for +// completion; e.g., Span-2 may be part of a background job enqueued by Span-1, +// or Span-2 may be sitting in a distributed queue behind Span-1. +type SpanReferenceType int + +const ( + // ChildOfRef refers to a parent Span that caused *and* somehow depends + // upon the new child Span. Often (but not always), the parent Span cannot + // finish until the child Span does. + // + // An timing diagram for a ChildOfRef that's blocked on the new Span: + // + // [-Parent Span---------] + // [-Child Span----] + // + // See http://opentracing.io/spec/ + // + // See opentracing.ChildOf() + ChildOfRef SpanReferenceType = iota + + // FollowsFromRef refers to a parent Span that does not depend in any way + // on the result of the new child Span. For instance, one might use + // FollowsFromRefs to describe pipeline stages separated by queues, + // or a fire-and-forget cache insert at the tail end of a web request. + // + // A FollowsFromRef Span is part of the same logical trace as the new Span: + // i.e., the new Span is somehow caused by the work of its FollowsFromRef. + // + // All of the following could be valid timing diagrams for children that + // "FollowFrom" a parent. + // + // [-Parent Span-] [-Child Span-] + // + // + // [-Parent Span--] + // [-Child Span-] + // + // + // [-Parent Span-] + // [-Child Span-] + // + // See http://opentracing.io/spec/ + // + // See opentracing.FollowsFrom() + FollowsFromRef +) + +// SpanReference is a StartSpanOption that pairs a SpanReferenceType and a +// referenced SpanContext. See the SpanReferenceType documentation for +// supported relationships. If SpanReference is created with +// ReferencedContext==nil, it has no effect. Thus it allows for a more concise +// syntax for starting spans: +// +// sc, _ := tracer.Extract(someFormat, someCarrier) +// span := tracer.StartSpan("operation", opentracing.ChildOf(sc)) +// +// The `ChildOf(sc)` option above will not panic if sc == nil, it will just +// not add the parent span reference to the options. +type SpanReference struct { + Type SpanReferenceType + ReferencedContext SpanContext +} + +// Apply satisfies the StartSpanOption interface. +func (r SpanReference) Apply(o *StartSpanOptions) { + if r.ReferencedContext != nil { + o.References = append(o.References, r) + } +} + +// ChildOf returns a StartSpanOption pointing to a dependent parent span. +// If sc == nil, the option has no effect. +// +// See ChildOfRef, SpanReference +func ChildOf(sc SpanContext) SpanReference { + return SpanReference{ + Type: ChildOfRef, + ReferencedContext: sc, + } +} + +// FollowsFrom returns a StartSpanOption pointing to a parent Span that caused +// the child Span but does not directly depend on its result in any way. +// If sc == nil, the option has no effect. +// +// See FollowsFromRef, SpanReference +func FollowsFrom(sc SpanContext) SpanReference { + return SpanReference{ + Type: FollowsFromRef, + ReferencedContext: sc, + } +} + +// StartTime is a StartSpanOption that sets an explicit start timestamp for the +// new Span. +type StartTime time.Time + +// Apply satisfies the StartSpanOption interface. +func (t StartTime) Apply(o *StartSpanOptions) { + o.StartTime = time.Time(t) +} + +// Tags are a generic map from an arbitrary string key to an opaque value type. +// The underlying tracing system is responsible for interpreting and +// serializing the values. +type Tags map[string]interface{} + +// Apply satisfies the StartSpanOption interface. +func (t Tags) Apply(o *StartSpanOptions) { + if o.Tags == nil { + o.Tags = make(map[string]interface{}) + } + for k, v := range t { + o.Tags[k] = v + } +} + +// Tag may be passed as a StartSpanOption to add a tag to new spans, +// or its Set method may be used to apply the tag to an existing Span, +// for example: +// +// tracer.StartSpan("opName", Tag{"Key", value}) +// +// or +// +// Tag{"key", value}.Set(span) +type Tag struct { + Key string + Value interface{} +} + +// Apply satisfies the StartSpanOption interface. +func (t Tag) Apply(o *StartSpanOptions) { + if o.Tags == nil { + o.Tags = make(map[string]interface{}) + } + o.Tags[t.Key] = t.Value +} + +// Set applies the tag to an existing Span. +func (t Tag) Set(s Span) { + s.SetTag(t.Key, t.Value) +} From be25913b14d7fa3d743611089aa6cb7a5d352f5a Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Tue, 28 Jul 2020 07:39:30 -0400 Subject: [PATCH 24/52] Remove filecoin submodule --- vendor/github.com/filecoin-project | 1 - 1 file changed, 1 deletion(-) delete mode 160000 vendor/github.com/filecoin-project diff --git a/vendor/github.com/filecoin-project b/vendor/github.com/filecoin-project deleted file mode 160000 index 8b6f2fb2b3..0000000000 --- a/vendor/github.com/filecoin-project +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8b6f2fb2b3efffb57f42d57f41532339e3938072 From 33f2e925b86a87c57136a64be1df2af60d02ed0c Mon Sep 17 00:00:00 2001 From: Brian Hoffman Date: Tue, 28 Jul 2020 07:40:00 -0400 Subject: [PATCH 25/52] Commit filecoin vendor --- .../go-address/.circleci/config.yml | 185 + .../go-address/CONTRIBUTING.md | 77 + .../filecoin-project/go-address/COPYRIGHT | 3 + .../go-address/LICENSE-APACHE | 13 + .../filecoin-project/go-address/LICENSE-MIT | 19 + .../filecoin-project/go-address/Makefile | 7 + .../filecoin-project/go-address/README.md | 43 + .../filecoin-project/go-address/address.go | 410 + .../go-address/address_test.go | 506 + .../filecoin-project/go-address/bench_test.go | 94 + .../filecoin-project/go-address/constants.go | 71 + .../filecoin-project/go-address/go.mod | 14 + .../filecoin-project/go-address/go.sum | 98 + .../filecoin-project/go-address/testing.go | 20 + .../go-amt-ipld/v2/LICENSE-APACHE | 5 + .../go-amt-ipld/v2/LICENSE-MIT | 19 + .../filecoin-project/go-amt-ipld/v2/README.md | 8 + .../filecoin-project/go-amt-ipld/v2/amt.go | 556 + .../go-amt-ipld/v2/cbor_gen.go | 261 + .../filecoin-project/go-amt-ipld/v2/go.mod | 13 + .../filecoin-project/go-amt-ipld/v2/go.sum | 143 + .../go-bitfield/.github/workflows/go.yml | 35 + .../go-bitfield/LICENSE-APACHE | 5 + .../filecoin-project/go-bitfield/LICENSE-MIT | 19 + .../filecoin-project/go-bitfield/README.md | 14 + .../filecoin-project/go-bitfield/bitfield.go | 668 + .../go-bitfield/bitfield_benchmark_test.go | 66 + .../go-bitfield/bitfield_test.go | 522 + .../filecoin-project/go-bitfield/go.mod | 11 + .../filecoin-project/go-bitfield/go.sum | 75 + .../filecoin-project/go-bitfield/rle/bits.go | 195 + .../go-bitfield/rle/bits_test.go | 86 + .../go-bitfield/rle/bitvec.go | 114 + .../go-bitfield/rle/bitvec_test.go | 21 + .../go-bitfield/rle/interface.go | 25 + .../rle/internal/rleplus/bitvector.go | 154 + .../rle/internal/rleplus/bitvector_test.go | 134 + .../rle/internal/rleplus/rleplus.go | 202 + .../rle/internal/rleplus/rleplus_test.go | 211 + .../go-bitfield/rle/joinclose.go | 65 + .../go-bitfield/rle/joinclose_test.go | 34 + .../filecoin-project/go-bitfield/rle/merge.go | 31 + .../go-bitfield/rle/rleplus.go | 125 + .../go-bitfield/rle/rleplus_golden_test.go | 3 + .../go-bitfield/rle/rleplus_reader.go | 77 + .../go-bitfield/rle/rleplus_test.go | 184 + .../go-bitfield/rle/rleplus_writer.go | 63 + .../filecoin-project/go-bitfield/rle/runs.go | 393 + .../go-bitfield/rle/runs_test.go | 177 + .../go-cbor-util/.circleci/config.yml | 161 + .../go-cbor-util/CONTRIBUTING.md | 52 + .../filecoin-project/go-cbor-util/COPYRIGHT | 3 + .../go-cbor-util/LICENSE-APACHE | 13 + .../filecoin-project/go-cbor-util/LICENSE-MIT | 19 + .../filecoin-project/go-cbor-util/README.md | 56 + .../filecoin-project/go-cbor-util/go.mod | 10 + .../filecoin-project/go-cbor-util/go.sum | 77 + .../filecoin-project/go-cbor-util/rpc.go | 88 + .../go-crypto/.circleci/config.yml | 161 + .../filecoin-project/go-crypto/COPYRIGHT | 3 + .../filecoin-project/go-crypto/LICENSE-APACHE | 13 + .../filecoin-project/go-crypto/LICENSE-MIT | 19 + .../filecoin-project/go-crypto/README.md | 8 + .../filecoin-project/go-crypto/crypto.go | 70 + .../filecoin-project/go-crypto/crypto_test.go | 61 + .../filecoin-project/go-crypto/go.mod | 12 + .../filecoin-project/go-crypto/go.sum | 21 + .../go-data-transfer/.circleci/config.yml | 161 + .../go-data-transfer/CONTRIBUTING.md | 67 + .../go-data-transfer/COPYRIGHT | 3 + .../go-data-transfer/LICENSE-APACHE | 13 + .../go-data-transfer/LICENSE-MIT | 19 + .../go-data-transfer/Makefile | 17 + .../go-data-transfer/README.md | 180 + .../go-data-transfer/channels/channels.go | 171 + .../channels/channels_test.go | 102 + .../go-data-transfer/encoding/encoding.go | 122 + .../encoding/encoding_test.go | 37 + .../encoding/testdata/testdata.go | 37 + .../encoding/testdata/testdata_cbor_gen.go | 84 + .../filecoin-project/go-data-transfer/go.mod | 32 + .../filecoin-project/go-data-transfer/go.sum | 700 + .../impl/dagservice/dagservice.go | 87 + .../impl/graphsync/extension/gsextension.go | 62 + .../extension/gsextension_cbor_gen.go | 107 + .../impl/graphsync/graphsync_impl.go | 307 + .../impl/graphsync/graphsync_impl_test.go | 1066 ++ .../impl/graphsync/graphsync_receiver.go | 153 + .../impl/graphsync/graphsync_receiver_test.go | 182 + .../impl/graphsync/hooks/hooks.go | 174 + .../impl/graphsync/hooks/hooks_test.go | 377 + .../go-data-transfer/message/message.go | 90 + .../go-data-transfer/message/message_test.go | 196 + .../message/transfer_message.go | 36 + .../message/transfer_message_cbor_gen.go | 116 + .../message/transfer_request.go | 108 + .../message/transfer_request_cbor_gen.go | 240 + .../message/transfer_response.go | 40 + .../message/transfer_response_cbor_gen.go | 85 + .../go-data-transfer/network/interface.go | 56 + .../go-data-transfer/network/libp2p_impl.go | 165 + .../network/libp2p_impl_test.go | 138 + .../go-data-transfer/registry/registry.go | 68 + .../registry/registry_test.go | 42 + .../go-data-transfer/testutil/fakedttype.go | 52 + .../testutil/fakedttype_cbor_gen.go | 64 + .../testutil/fakegraphsync.go | 228 + .../testutil/fixtures/lorem.txt | 49 + .../go-data-transfer/testutil/gstestdata.go | 242 + .../go-data-transfer/testutil/testutil.go | 95 + .../go-data-transfer/tools.go | 7 + .../go-data-transfer/types.go | 169 + .../go-fil-markets/.circleci/config.yml | 198 + .../go-fil-markets/CHANGELOG.md | 440 + .../go-fil-markets/CONTRIBUTING.md | 91 + .../filecoin-project/go-fil-markets/COPYRIGHT | 3 + .../go-fil-markets/LICENSE-APACHE | 13 + .../go-fil-markets/LICENSE-MIT | 19 + .../filecoin-project/go-fil-markets/Makefile | 61 + .../filecoin-project/go-fil-markets/README.md | 53 + .../go-fil-markets/codecov.yml | 10 + .../go-fil-markets/docs/retrievalclient.mmd | 74 + .../docs/retrievalclient.mmd.png | Bin 0 -> 521600 bytes .../docs/retrievalclient.mmd.svg | 6 + .../go-fil-markets/docs/retrievalprovider.mmd | 53 + .../docs/retrievalprovider.mmd.png | Bin 0 -> 291898 bytes .../docs/retrievalprovider.mmd.svg | 6 + .../go-fil-markets/docs/storageclient.mmd | 62 + .../go-fil-markets/docs/storageclient.mmd.png | Bin 0 -> 360921 bytes .../go-fil-markets/docs/storageclient.mmd.svg | 6 + .../go-fil-markets/docs/storageprovider.mmd | 82 + .../docs/storageprovider.mmd.png | Bin 0 -> 551481 bytes .../docs/storageprovider.mmd.svg | 6 + .../go-fil-markets/docsgen/main.go | 95 + .../go-fil-markets/filestore/README.md | 29 + .../go-fil-markets/filestore/file.go | 39 + .../go-fil-markets/filestore/filestore.go | 75 + .../filestore/filestore_test.go | 178 + .../go-fil-markets/filestore/mocks/File.go | 133 + .../filestore/mocks/FileStore.go | 118 + .../go-fil-markets/filestore/types.go | 36 + .../filecoin-project/go-fil-markets/go.mod | 48 + .../filecoin-project/go-fil-markets/go.sum | 815 + .../go-fil-markets/mkreleaselog | 248 + .../go-fil-markets/package-lock.json | 381 + .../go-fil-markets/package.json | 25 + .../go-fil-markets/pieceio/README.md | 54 + .../go-fil-markets/pieceio/cario/cario.go | 46 + .../go-fil-markets/pieceio/mocks/CarIO.go | 81 + .../go-fil-markets/pieceio/mocks/PieceIO.go | 63 + .../pieceio/mocks/PreparedCar.go | 42 + .../go-fil-markets/pieceio/mocks/ReadStore.go | 37 + .../pieceio/mocks/SectorCalculator.go | 37 + .../pieceio/mocks/WriteStore.go | 27 + .../go-fil-markets/pieceio/pieceio.go | 131 + .../go-fil-markets/pieceio/pieceio_test.go | 337 + .../go-fil-markets/pieceio/tempDir/.gitkeep | 0 .../go-fil-markets/pieceio/types.go | 32 + .../go-fil-markets/piecestore/README.md | 48 + .../go-fil-markets/piecestore/piecestore.go | 124 + .../piecestore/piecestore_test.go | 173 + .../go-fil-markets/piecestore/types.go | 57 + .../piecestore/types_cbor_gen.go | 436 + .../go-fil-markets/retrievalmarket/README.md | 303 + .../go-fil-markets/retrievalmarket/common.go | 22 + .../retrievalmarket/discovery/discovery.go | 15 + .../retrievalmarket/discovery/local.go | 80 + .../retrievalmarket/discovery/local_test.go | 57 + .../go-fil-markets/retrievalmarket/doc.go | 108 + .../retrievalmarket/impl/blockio/doc.go | 4 + .../retrievalmarket/impl/blockio/reader.go | 61 + .../impl/blockio/reader_test.go | 55 + .../retrievalmarket/impl/blockio/traverser.go | 170 + .../impl/blockio/traverser_test.go | 48 + .../retrievalmarket/impl/blockio/verify.go | 56 + .../impl/blockio/verify_test.go | 84 + .../impl/blockunsealing/blockunsealing.go | 130 + .../blockunsealing/blockunsealing_test.go | 248 + .../retrievalmarket/impl/client.go | 327 + .../retrievalmarket/impl/client_test.go | 192 + .../impl/clientstates/client_fsm.go | 198 + .../impl/clientstates/client_states.go | 205 + .../impl/clientstates/client_states_test.go | 657 + .../retrievalmarket/impl/clientstates/doc.go | 13 + .../retrievalmarket/impl/doc.go | 6 + .../retrievalmarket/impl/fixtures/lorem.txt | 49 + .../impl/fixtures/lorem_under_1_block.txt | 1 + .../retrievalmarket/impl/integration_test.go | 481 + .../retrievalmarket/impl/provider.go | 427 + .../retrievalmarket/impl/provider_test.go | 281 + .../impl/providerstates/doc.go | 13 + .../impl/providerstates/provider_fsm.go | 109 + .../impl/providerstates/provider_states.go | 192 + .../providerstates/provider_states_test.go | 485 + .../retrievalmarket/impl/testnodes/doc.go | 4 + .../testnodes/test_retrieval_client_node.go | 120 + .../testnodes/test_retrieval_provider_node.go | 163 + .../retrievalmarket/network/deal_stream.go | 67 + .../retrievalmarket/network/doc.go | 9 + .../retrievalmarket/network/libp2p_impl.go | 93 + .../network/libp2p_impl_test.go | 424 + .../retrievalmarket/network/network.go | 62 + .../retrievalmarket/network/query_stream.go | 54 + .../storage_retrieval_integration_test.go | 423 + .../testing/test_provider_deal_environment.go | 160 + .../go-fil-markets/retrievalmarket/types.go | 717 + .../retrievalmarket/types_cbor_gen.go | 1398 ++ .../retrievalmarket/types_test.go | 38 + .../go-fil-markets/shared/selectors.go | 16 + .../go-fil-markets/shared/types.go | 7 + .../shared_testutil/generators.go | 315 + .../go-fil-markets/shared_testutil/mocknet.go | 227 + .../shared_testutil/test_filestore.go | 176 + .../shared_testutil/test_ipld_tree.go | 147 + .../shared_testutil/test_network_types.go | 679 + .../shared_testutil/test_piecestore.go | 138 + .../shared_testutil/testutil.go | 114 + .../go-fil-markets/storagemarket/README.md | 396 + .../go-fil-markets/storagemarket/client.go | 54 + .../storagemarket/dealstatus.go | 127 + .../go-fil-markets/storagemarket/doc.go | 124 + .../go-fil-markets/storagemarket/events.go | 260 + .../storagemarket/fixtures/payload.txt | 49 + .../impl/blockrecorder/blockrecorder.go | 55 + .../blockrecorder/blockrecorder_cbor_gen.go | 101 + .../impl/blockrecorder/blockrecorder_test.go | 80 + .../storagemarket/impl/client.go | 552 + .../storagemarket/impl/client_test.go | 19 + .../impl/clientstates/client_fsm.go | 157 + .../impl/clientstates/client_states.go | 261 + .../impl/clientstates/client_states_test.go | 638 + .../storagemarket/impl/clientstates/doc.go | 13 + .../impl/clientutils/clientutils.go | 58 + .../impl/clientutils/clientutils_test.go | 128 + .../impl/connmanager/connmanager.go | 63 + .../impl/connmanager/connmanager_test.go | 103 + .../go-fil-markets/storagemarket/impl/doc.go | 6 + .../storagemarket/impl/dtutils/dtutils.go | 90 + .../impl/dtutils/dtutils_test.go | 161 + .../storagemarket/impl/provider.go | 672 + .../storagemarket/impl/provider_test.go | 25 + .../storagemarket/impl/providerstates/doc.go | 13 + .../impl/providerstates/provider_fsm.go | 174 + .../impl/providerstates/provider_states.go | 410 + .../providerstates/provider_states_test.go | 1136 ++ .../impl/providerutils/providerutils.go | 116 + .../impl/providerutils/providerutils_test.go | 255 + .../impl/requestvalidation/common.go | 88 + .../impl/requestvalidation/doc.go | 3 + .../request_validation_test.go | 274 + .../impl/requestvalidation/types.go | 52 + .../impl/requestvalidation/types_cbor_gen.go | 61 + .../unified_request_validator.go | 60 + .../storagemarket/impl/storedask/storedask.go | 172 + .../impl/storedask/storedask_test.go | 88 + .../storagemarket/integration_test.go | 461 + .../storagemarket/network/ask_stream.go | 52 + .../network/deal_status_stream.go | 54 + .../storagemarket/network/deal_stream.go | 65 + .../storagemarket/network/doc.go | 11 + .../storagemarket/network/libp2p_impl.go | 116 + .../storagemarket/network/libp2p_impl_test.go | 485 + .../storagemarket/network/network.go | 64 + .../storagemarket/network/types.go | 80 + .../storagemarket/network/types_cbor_gen.go | 530 + .../go-fil-markets/storagemarket/nodes.go | 107 + .../go-fil-markets/storagemarket/provider.go | 51 + .../storagemarket/testnodes/testnodes.go | 335 + .../go-fil-markets/storagemarket/types.go | 165 + .../storagemarket/types_cbor_gen.go | 1499 ++ .../go-fil-markets/tools/tools.go | 7 + .../go-statestore/.circleci/config.yml | 159 + .../go-statestore/LICENSE-APACHE | 5 + .../go-statestore/LICENSE-MIT | 19 + .../filecoin-project/go-statestore/Makefile | 16 + .../filecoin-project/go-statestore/README.md | 7 + .../filecoin-project/go-statestore/go.mod | 24 + .../filecoin-project/go-statestore/go.sum | 147 + .../filecoin-project/go-statestore/state.go | 93 + .../filecoin-project/go-statestore/store.go | 96 + .../go-statestore/store_test.go | 83 + .../lotus/.circleci/config.yml | 359 + .../filecoin-project/lotus/.codecov.yml | 3 + .../filecoin-project/lotus/.dockerignore | 1 + .../.github/ISSUE_TEMPLATE/bug_report.md | 27 + .../.github/ISSUE_TEMPLATE/sealingfailed.md | 34 + .../filecoin-project/lotus/.golangci.yml | 51 + .../filecoin-project/lotus/CHANGELOG.md | 7 + .../filecoin-project/lotus/LICENSE-APACHE | 5 + .../filecoin-project/lotus/LICENSE-MIT | 19 + .../filecoin-project/lotus/Makefile | 235 + .../filecoin-project/lotus/README.md | 26 + .../filecoin-project/lotus/SECURITY.md | 29 + .../filecoin-project/lotus/api/api_common.go | 67 + .../filecoin-project/lotus/api/api_full.go | 609 + .../filecoin-project/lotus/api/api_storage.go | 133 + .../filecoin-project/lotus/api/api_test.go | 34 + .../filecoin-project/lotus/api/api_worker.go | 36 + .../lotus/api/apibstore/apibstore.go | 67 + .../lotus/api/apistruct/permissioned.go | 38 + .../lotus/api/apistruct/struct.go | 1000 ++ .../lotus/api/apistruct/struct_test.go | 9 + .../filecoin-project/lotus/api/cbor_gen.go | 731 + .../lotus/api/client/client.go | 61 + .../lotus/api/docgen/docgen.go | 379 + .../filecoin-project/lotus/api/test/deals.go | 255 + .../filecoin-project/lotus/api/test/mining.go | 200 + .../filecoin-project/lotus/api/test/test.go | 126 + .../lotus/api/test/window_post.go | 169 + .../filecoin-project/lotus/api/types.go | 77 + .../filecoin-project/lotus/api/utils.go | 28 + .../filecoin-project/lotus/build/bootstrap.go | 49 + .../lotus/build/bootstrap/.gitkeep | 0 .../lotus/build/bootstrap/bootstrappers.pi | 12 + .../filecoin-project/lotus/build/flags.go | 15 + .../filecoin-project/lotus/build/forks.go | 1 + .../filecoin-project/lotus/build/genesis.go | 23 + .../lotus/build/genesis/.gitkeep | 0 .../lotus/build/genesis/devnet.car | Bin 0 -> 25893 bytes .../lotus/build/parameters.go | 7 + .../filecoin-project/lotus/build/params_2k.go | 34 + .../lotus/build/params_debug.go | 10 + .../lotus/build/params_shared_funcs.go | 38 + .../lotus/build/params_shared_vals.go | 97 + .../lotus/build/params_testground.go | 73 + .../lotus/build/params_testnet.go | 25 + .../lotus/build/proof-params/parameters.json | 152 + .../lotus/build/testing_flags.go | 3 + .../filecoin-project/lotus/build/tools.go | 7 + .../filecoin-project/lotus/build/version.go | 67 + .../lotus/chain/actors/aerrors/error.go | 69 + .../lotus/chain/actors/aerrors/error_test.go | 36 + .../lotus/chain/actors/aerrors/wrap.go | 203 + .../lotus/chain/actors/params.go | 17 + .../lotus/chain/badtscache.go | 35 + .../lotus/chain/beacon/beacon.go | 93 + .../lotus/chain/beacon/drand/drand.go | 192 + .../lotus/chain/beacon/drand/drand_test.go | 25 + .../lotus/chain/beacon/mock.go | 64 + .../lotus/chain/block_receipt_tracker.go | 71 + .../lotus/chain/blocksync/blocksync.go | 276 + .../lotus/chain/blocksync/blocksync_client.go | 602 + .../lotus/chain/blocksync/cbor_gen.go | 578 + .../lotus/chain/blocksync/graphsync_client.go | 151 + .../lotus/chain/events/events.go | 179 + .../lotus/chain/events/events_called.go | 611 + .../lotus/chain/events/events_height.go | 200 + .../lotus/chain/events/events_test.go | 1314 ++ .../lotus/chain/events/state/predicates.go | 137 + .../chain/events/state/predicates_test.go | 201 + .../lotus/chain/events/tscache.go | 129 + .../lotus/chain/events/tscache_test.go | 122 + .../lotus/chain/events/utils.go | 44 + .../filecoin-project/lotus/chain/gen/gen.go | 618 + .../lotus/chain/gen/gen_test.go | 62 + .../lotus/chain/gen/genesis/genesis.go | 370 + .../lotus/chain/gen/genesis/miners.go | 263 + .../lotus/chain/gen/genesis/t00_system.go | 29 + .../lotus/chain/gen/genesis/t01_init.go | 74 + .../lotus/chain/gen/genesis/t02_reward.go | 30 + .../lotus/chain/gen/genesis/t03_cron.go | 29 + .../lotus/chain/gen/genesis/t04_power.go | 47 + .../lotus/chain/gen/genesis/t05_market.go | 42 + .../lotus/chain/gen/genesis/t06_vreg.go | 59 + .../lotus/chain/gen/genesis/util.go | 53 + .../lotus/chain/gen/mining.go | 177 + .../lotus/chain/market/fundmgr.go | 82 + .../lotus/chain/messagepool/messagepool.go | 884 ++ .../chain/messagepool/messagepool_test.go | 235 + .../lotus/chain/metrics/consensus.go | 128 + .../lotus/chain/state/statetree.go | 341 + .../lotus/chain/state/statetree_test.go | 278 + .../lotus/chain/stmgr/call.go | 109 + .../lotus/chain/stmgr/forks.go | 25 + .../lotus/chain/stmgr/forks_test.go | 233 + .../lotus/chain/stmgr/stmgr.go | 820 + .../lotus/chain/stmgr/utils.go | 644 + .../filecoin-project/lotus/chain/store/fts.go | 54 + .../lotus/chain/store/index.go | 161 + .../lotus/chain/store/index_test.go | 80 + .../lotus/chain/store/store.go | 1209 ++ .../lotus/chain/store/store_test.go | 114 + .../lotus/chain/store/weight.go | 108 + .../lotus/chain/sub/incoming.go | 400 + .../filecoin-project/lotus/chain/sync.go | 1538 ++ .../lotus/chain/sync_manager.go | 426 + .../lotus/chain/sync_manager_test.go | 150 + .../filecoin-project/lotus/chain/sync_test.go | 547 + .../filecoin-project/lotus/chain/syncstate.go | 105 + .../lotus/chain/types/actor.go | 22 + .../lotus/chain/types/bigint.go | 96 + .../lotus/chain/types/bigint_test.go | 103 + .../lotus/chain/types/blockheader.go | 226 + .../lotus/chain/types/blockheader_test.go | 136 + .../lotus/chain/types/blockmsg.go | 34 + .../lotus/chain/types/cbor_gen.go | 1556 ++ .../lotus/chain/types/execresult.go | 103 + .../filecoin-project/lotus/chain/types/fil.go | 42 + .../lotus/chain/types/fullblock.go | 13 + .../lotus/chain/types/keystore.go | 28 + .../lotus/chain/types/logs.go | 17 + .../lotus/chain/types/message.go | 160 + .../lotus/chain/types/message_fuzz.go | 30 + .../lotus/chain/types/message_receipt.go | 17 + .../lotus/chain/types/mock/chain.go | 91 + .../lotus/chain/types/signature_test.go | 29 + .../lotus/chain/types/signedmessage.go | 86 + .../lotus/chain/types/tipset.go | 222 + .../lotus/chain/types/tipset_key.go | 123 + .../lotus/chain/types/tipset_key_test.go | 83 + .../lotus/chain/types/types_test.go | 41 + .../lotus/chain/types/vmcontext.go | 47 + .../lotus/chain/types/voucher.go | 22 + .../lotus/chain/types_test.go | 36 + .../lotus/chain/validation/applier.go | 192 + .../lotus/chain/validation/config.go | 37 + .../lotus/chain/validation/factories.go | 34 + .../lotus/chain/validation/keymanager.go | 103 + .../lotus/chain/validation/state.go | 217 + .../lotus/chain/vectors/gen/main.go | 202 + .../lotus/chain/vectors/vector_types.go | 25 + .../lotus/chain/vectors/vectors_test.go | 85 + .../filecoin-project/lotus/chain/vm/gas.go | 212 + .../filecoin-project/lotus/chain/vm/gas_v0.go | 197 + .../lotus/chain/vm/invoker.go | 200 + .../lotus/chain/vm/invoker_test.go | 112 + .../lotus/chain/vm/mkactor.go | 102 + .../lotus/chain/vm/runtime.go | 580 + .../lotus/chain/vm/runtime_test.go | 47 + .../lotus/chain/vm/syscalls.go | 276 + .../lotus/chain/vm/validation_test.go | 71 + .../filecoin-project/lotus/chain/vm/vm.go | 732 + .../lotus/chain/wallet/memkeystore.go | 48 + .../lotus/chain/wallet/wallet.go | 307 + .../filecoin-project/lotus/cli/auth.go | 135 + .../filecoin-project/lotus/cli/chain.go | 952 ++ .../filecoin-project/lotus/cli/client.go | 630 + .../filecoin-project/lotus/cli/cmd.go | 243 + .../filecoin-project/lotus/cli/log.go | 101 + .../filecoin-project/lotus/cli/mpool.go | 230 + .../filecoin-project/lotus/cli/multisig.go | 471 + .../filecoin-project/lotus/cli/net.go | 186 + .../filecoin-project/lotus/cli/params.go | 33 + .../filecoin-project/lotus/cli/paych.go | 387 + .../filecoin-project/lotus/cli/send.go | 106 + .../filecoin-project/lotus/cli/state.go | 1504 ++ .../filecoin-project/lotus/cli/sync.go | 201 + .../filecoin-project/lotus/cli/version.go | 32 + .../filecoin-project/lotus/cli/wait.go | 34 + .../filecoin-project/lotus/cli/wallet.go | 408 + .../lotus/cmd/chain-noise/main.go | 94 + .../lotus/cmd/lotus-bench/import.go | 623 + .../lotus/cmd/lotus-bench/main.go | 747 + .../lotus/cmd/lotus-bench/stats_test.go | 47 + .../lotus/cmd/lotus-chainwatch/blockssub.go | 27 + .../lotus/cmd/lotus-chainwatch/dot.go | 87 + .../lotus/cmd/lotus-chainwatch/main.go | 112 + .../lotus/cmd/lotus-chainwatch/mpool.go | 60 + .../cmd/lotus-chainwatch/site/block.html | 61 + .../cmd/lotus-chainwatch/site/blocks.html | 43 + .../cmd/lotus-chainwatch/site/index.html | 37 + .../lotus/cmd/lotus-chainwatch/site/key.html | 40 + .../lotus/cmd/lotus-chainwatch/site/keys.html | 28 + .../lotus/cmd/lotus-chainwatch/site/main.css | 66 + .../lotus/cmd/lotus-chainwatch/storage.go | 1278 ++ .../lotus/cmd/lotus-chainwatch/sync.go | 596 + .../lotus/cmd/lotus-chainwatch/templates.go | 350 + .../lotus/cmd/lotus-fountain/main.go | 454 + .../lotus/cmd/lotus-fountain/rate_limiter.go | 94 + .../cmd/lotus-fountain/rate_limiter_test.go | 38 + .../lotus/cmd/lotus-fountain/site/_miner.html | 51 + .../lotus/cmd/lotus-fountain/site/funds.html | 29 + .../lotus/cmd/lotus-fountain/site/index.html | 27 + .../lotus/cmd/lotus-fountain/site/main.css | 56 + .../lotus/cmd/lotus-fountain/site/wait.html | 69 + .../lotus/cmd/lotus-health/main.go | 265 + .../lotus/cmd/lotus-health/main_test.go | 166 + .../lotus/cmd/lotus-health/notify.go | 31 + .../lotus/cmd/lotus-seal-worker/main.go | 371 + .../lotus/cmd/lotus-seal-worker/rpc.go | 20 + .../lotus/cmd/lotus-seed/genesis.go | 143 + .../lotus/cmd/lotus-seed/main.go | 195 + .../lotus/cmd/lotus-seed/seed/seed.go | 271 + .../lotus/cmd/lotus-shed/base16.go | 52 + .../lotus/cmd/lotus-shed/base32.go | 53 + .../lotus/cmd/lotus-shed/bigint.go | 47 + .../lotus/cmd/lotus-shed/bitfield.go | 245 + .../lotus/cmd/lotus-shed/commp.go | 27 + .../lotus/cmd/lotus-shed/import-car.go | 78 + .../lotus/cmd/lotus-shed/keyinfo.go | 365 + .../lotus/cmd/lotus-shed/main.go | 52 + .../lotus/cmd/lotus-shed/nonce-fix.go | 109 + .../lotus/cmd/lotus-shed/params.go | 35 + .../lotus/cmd/lotus-shed/proofs.go | 108 + .../lotus/cmd/lotus-shed/stateroot-stats.go | 94 + .../lotus/cmd/lotus-shed/verifreg.go | 378 + .../lotus/cmd/lotus-stats/README.md | 39 + .../cmd/lotus-stats/chain.dashboard.json | 2533 +++ .../lotus/cmd/lotus-stats/docker-compose.yml | 26 + .../lotus/cmd/lotus-stats/env.stats | 3 + .../lotus/cmd/lotus-stats/main.go | 72 + .../lotus/cmd/lotus-stats/setup.bash | 29 + .../lotus/cmd/lotus-storage-miner/actor.go | 94 + .../lotus/cmd/lotus-storage-miner/info.go | 250 + .../lotus/cmd/lotus-storage-miner/init.go | 669 + .../lotus/cmd/lotus-storage-miner/main.go | 87 + .../lotus/cmd/lotus-storage-miner/market.go | 449 + .../lotus/cmd/lotus-storage-miner/proving.go | 328 + .../lotus-storage-miner/retrieval-deals.go | 113 + .../lotus/cmd/lotus-storage-miner/rewards.go | 88 + .../lotus/cmd/lotus-storage-miner/run.go | 180 + .../lotus/cmd/lotus-storage-miner/sectors.go | 283 + .../lotus/cmd/lotus-storage-miner/stop.go | 29 + .../lotus/cmd/lotus-storage-miner/storage.go | 382 + .../lotus/cmd/lotus-storage-miner/workers.go | 108 + .../lotus/cmd/lotus-townhall/main.go | 134 + .../cmd/lotus-townhall/townhall/.gitignore | 23 + .../cmd/lotus-townhall/townhall/package.json | 31 + .../lotus-townhall/townhall/public/index.html | 13 + .../lotus-townhall/townhall/public/robots.txt | 2 + .../cmd/lotus-townhall/townhall/src/App.css | 1 + .../cmd/lotus-townhall/townhall/src/App.js | 87 + .../lotus-townhall/townhall/src/App.test.js | 9 + .../cmd/lotus-townhall/townhall/src/index.css | 6 + .../cmd/lotus-townhall/townhall/src/index.js | 6 + .../lotus/cmd/lotus/daemon.go | 360 + .../lotus/cmd/lotus/daemon_nodaemon.go | 24 + .../lotus/cmd/lotus/debug_advance.go | 84 + .../filecoin-project/lotus/cmd/lotus/main.go | 85 + .../filecoin-project/lotus/cmd/lotus/rpc.go | 111 + .../lotus/documentation/en/.glossary.json | 146 + .../lotus/documentation/en/.library.json | 205 + .../documentation/en/api-scripting-support.md | 25 + .../documentation/en/api-troubleshooting.md | 36 + .../lotus/documentation/en/api.md | 85 + .../lotus/documentation/en/architecture.md | 394 + .../documentation/en/block-validation.md | 137 + .../lotus/documentation/en/cli.md | 108 + .../en/dev-tools-jaeger-tracing.md | 26 + .../documentation/en/dev-tools-pond-ui.md | 32 + .../lotus/documentation/en/dev-tools.md | 3 + .../en/dev/WIP-arch-complementary-notes.md | 153 + .../lotus/documentation/en/faqs.md | 138 + .../lotus/documentation/en/getting-started.md | 23 + .../lotus/documentation/en/hardware-mining.md | 54 + .../lotus/documentation/en/hardware.md | 7 + .../documentation/en/install-lotus-arch.md | 44 + .../documentation/en/install-lotus-fedora.md | 41 + .../documentation/en/install-lotus-macos.md | 62 + .../documentation/en/install-lotus-ubuntu.md | 53 + .../en/install-systemd-services.md | 29 + .../lotus/documentation/en/join-testnet.md | 84 + .../lotus/documentation/en/local-dev-net.md | 46 + .../lotus/documentation/en/miner-deals.md | 39 + .../en/mining-lotus-seal-worker.md | 81 + .../en/mining-troubleshooting.md | 66 + .../lotus/documentation/en/mining.md | 101 + .../lotus/documentation/en/retrieving-data.md | 27 + .../lotus/documentation/en/sealing-procs.md | 70 + .../documentation/en/setting-a-static-port.md | 54 + .../documentation/en/setup-troubleshooting.md | 46 + .../en/storing-data-troubleshooting.md | 27 + .../lotus/documentation/en/storing-data.md | 62 + .../en/storing-ipfs-integration.md | 20 + .../lotus/documentation/en/updating-lotus.md | 11 + .../documentation/images/lotus_logo_h.png | Bin 0 -> 5976 bytes .../documentation/images/lotus_logo_h.svg | 1 + .../extern/filecoin-ffi/.circleci/config.yml | 348 + .../lotus/extern/filecoin-ffi/.gitignore | 11 + .../lotus/extern/filecoin-ffi/CHANGELOG.md | 258 + .../lotus/extern/filecoin-ffi/LICENSE-APACHE | 7 + .../lotus/extern/filecoin-ffi/LICENSE-MIT | 23 + .../lotus/extern/filecoin-ffi/Makefile | 40 + .../lotus/extern/filecoin-ffi/README.md | 74 + .../lotus/extern/filecoin-ffi/bls.go | 140 + .../lotus/extern/filecoin-ffi/bls_test.go | 177 + .../lotus/extern/filecoin-ffi/build.sh | 12 + .../filecoin-ffi/cgoleakdetect/runner.go | 63 + .../lotus/extern/filecoin-ffi/filcrypto.yml | 38 + .../filecoin-ffi/generated/cgo_helpers.go | 3517 ++++ .../filecoin-ffi/generated/cgo_helpers.h | 9 + .../extern/filecoin-ffi/generated/const.go | 53 + .../filecoin-ffi/generated/customallocs.go | 54 + .../filecoin-ffi/generated/generated.go | 792 + .../extern/filecoin-ffi/generated/types.go | 319 + .../lotus/extern/filecoin-ffi/go.mod | 12 + .../lotus/extern/filecoin-ffi/go.sum | 147 + .../extern/filecoin-ffi/install-filcrypto | 216 + .../lotus/extern/filecoin-ffi/mkreleaselog | 240 + .../lotus/extern/filecoin-ffi/parameters.json | 152 + .../lotus/extern/filecoin-ffi/proofs.go | 929 ++ .../lotus/extern/filecoin-ffi/proofs_test.go | 162 + .../lotus/extern/filecoin-ffi/run_tests.sh | 3 + .../lotus/extern/filecoin-ffi/rust/Cargo.lock | 3021 ++++ .../lotus/extern/filecoin-ffi/rust/Cargo.toml | 41 + .../lotus/extern/filecoin-ffi/rust/build.rs | 11 + .../extern/filecoin-ffi/rust/cbindgen.toml | 23 + .../filecoin-ffi/rust/filcrypto.pc.template | 4 + .../extern/filecoin-ffi/rust/rust-toolchain | 1 + .../rust/rustc-target-features-optimized.json | 30 + .../rust/scripts/build-release.sh | 56 + .../rust/scripts/package-release.sh | 38 + .../rust/scripts/publish-release.sh | 73 + .../extern/filecoin-ffi/rust/src/bls/api.rs | 437 + .../extern/filecoin-ffi/rust/src/bls/mod.rs | 2 + .../extern/filecoin-ffi/rust/src/bls/types.rs | 67 + .../lotus/extern/filecoin-ffi/rust/src/lib.rs | 6 + .../filecoin-ffi/rust/src/proofs/api.rs | 1689 ++ .../filecoin-ffi/rust/src/proofs/helpers.rs | 134 + .../filecoin-ffi/rust/src/proofs/mod.rs | 4 + .../filecoin-ffi/rust/src/proofs/types.rs | 609 + .../extern/filecoin-ffi/rust/src/util/api.rs | 168 + .../extern/filecoin-ffi/rust/src/util/mod.rs | 2 + .../filecoin-ffi/rust/src/util/types.rs | 55 + .../lotus/extern/filecoin-ffi/types.go | 127 + .../lotus/extern/filecoin-ffi/workflows.go | 388 + .../serialization-vectors/block_headers.json | 274 + .../message_signing.json | 42 + .../unsigned_messages.json | 296 + .../filecoin-project/lotus/gen/main.go | 75 + .../filecoin-project/lotus/genesis/types.go | 70 + .../github.com/filecoin-project/lotus/go.mod | 129 + .../github.com/filecoin-project/lotus/go.sum | 1825 +++ .../lotus/lib/addrutil/parse.go | 89 + .../lotus/lib/bufbstore/buf_bstore.go | 146 + .../lotus/lib/increadtimeout/incrt.go | 73 + .../lotus/lib/ipfsbstore/ipfsbstore.go | 119 + .../lotus/lib/lotuslog/levels.go | 21 + .../lotus/lib/nullreader/reader.go | 10 + .../lotus/lib/parmap/parmap.go | 88 + .../lotus/lib/peermgr/peermgr.go | 169 + .../lotus/lib/sigs/bls/bls_bench_test.go | 38 + .../lotus/lib/sigs/bls/init.go | 54 + .../filecoin-project/lotus/lib/sigs/doc.go | 9 + .../lotus/lib/sigs/secp/init.go | 59 + .../filecoin-project/lotus/lib/sigs/sigs.go | 112 + .../lotus/lib/tracing/setup.go | 34 + .../lotus/lib/ulimit/ulimit.go | 116 + .../lotus/lib/ulimit/ulimit_freebsd.go | 36 + .../lotus/lib/ulimit/ulimit_test.go | 84 + .../lotus/lib/ulimit/ulimit_unix.go | 27 + .../filecoin-project/lotus/lotuspond/api.go | 138 + .../lotus/lotuspond/front/.gitignore | 23 + .../lotus/lotuspond/front/package-lock.json | 13255 ++++++++++++++++ .../lotus/lotuspond/front/package.json | 44 + .../lotus/lotuspond/front/public/index.html | 14 + .../lotuspond/front/public/manifest.json | 15 + .../lotus/lotuspond/front/src/Address.js | 148 + .../lotus/lotuspond/front/src/App.css | 232 + .../lotus/lotuspond/front/src/App.js | 24 + .../lotus/lotuspond/front/src/App.test.js | 9 + .../lotus/lotuspond/front/src/Block.js | 87 + .../lotus/lotuspond/front/src/BlockLink.js | 41 + .../lotuspond/front/src/ChainExplorer.js | 178 + .../lotus/lotuspond/front/src/Client.js | 228 + .../lotus/lotuspond/front/src/ConnMgr.js | 126 + .../lotus/lotuspond/front/src/Consensus.js | 69 + .../lotus/lotuspond/front/src/Fil.js | 22 + .../lotus/lotuspond/front/src/FullNode.js | 173 + .../lotus/lotuspond/front/src/Logs.js | 31 + .../lotus/lotuspond/front/src/NodeIndex.js | 110 + .../lotus/lotuspond/front/src/NodeList.js | 198 + .../lotus/lotuspond/front/src/Pond.js | 57 + .../lotus/lotuspond/front/src/SingleNode.js | 67 + .../lotus/lotuspond/front/src/State.js | 209 + .../lotus/lotuspond/front/src/StorageNode.js | 162 + .../lotuspond/front/src/StorageNodeInit.js | 25 + .../lotus/lotuspond/front/src/Window.js | 15 + .../lotus/lotuspond/front/src/chain/code.json | 13 + .../lotuspond/front/src/chain/methodgen.go | 85 + .../lotuspond/front/src/chain/methods.json | 98 + .../lotus/lotuspond/front/src/chain/send.js | 42 + .../lotus/lotuspond/front/src/index.css | 18 + .../lotus/lotuspond/front/src/index.js | 6 + .../filecoin-project/lotus/lotuspond/main.go | 162 + .../lotus/lotuspond/outmux.go | 127 + .../filecoin-project/lotus/lotuspond/spawn.go | 285 + .../lotus/markets/retrievaladapter/client.go | 101 + .../markets/retrievaladapter/provider.go | 81 + .../lotus/markets/storageadapter/client.go | 437 + .../lotus/markets/storageadapter/provider.go | 348 + .../lotus/markets/utils/converters.go | 38 + .../filecoin-project/lotus/metrics/metrics.go | 102 + .../filecoin-project/lotus/miner/miner.go | 578 + .../lotus/miner/miner_test.go | 104 + .../filecoin-project/lotus/miner/testminer.go | 43 + .../filecoin-project/lotus/node/builder.go | 520 + .../filecoin-project/lotus/node/config/def.go | 161 + .../lotus/node/config/load.go | 57 + .../lotus/node/config/load_test.go | 63 + .../lotus/node/config/storage.go | 51 + .../filecoin-project/lotus/node/fxlog.go | 17 + .../lotus/node/hello/cbor_gen.go | 266 + .../lotus/node/hello/hello.go | 183 + .../lotus/node/impl/client/client.go | 571 + .../lotus/node/impl/common/common.go | 146 + .../filecoin-project/lotus/node/impl/full.go | 29 + .../lotus/node/impl/full/chain.go | 507 + .../lotus/node/impl/full/mpool.go | 124 + .../lotus/node/impl/full/multisig.go | 224 + .../lotus/node/impl/full/state.go | 840 + .../lotus/node/impl/full/sync.go | 102 + .../lotus/node/impl/full/wallet.go | 86 + .../lotus/node/impl/market/market.go | 22 + .../lotus/node/impl/paych/paych.go | 258 + .../lotus/node/impl/remoteworker.go | 54 + .../lotus/node/impl/storminer.go | 292 + .../lotus/node/modules/chain.go | 169 + .../lotus/node/modules/client.go | 136 + .../lotus/node/modules/core.go | 95 + .../lotus/node/modules/dtypes/api.go | 10 + .../lotus/node/modules/dtypes/beacon.go | 6 + .../lotus/node/modules/dtypes/bootstrap.go | 8 + .../lotus/node/modules/dtypes/chain.go | 4 + .../lotus/node/modules/dtypes/miner.go | 52 + .../lotus/node/modules/dtypes/scorekeeper.go | 24 + .../lotus/node/modules/dtypes/shutdown.go | 5 + .../lotus/node/modules/dtypes/storage.go | 50 + .../lotus/node/modules/graphsync.go | 43 + .../lotus/node/modules/helpers/helpers.go | 25 + .../lotus/node/modules/ipfsclient.go | 45 + .../lotus/node/modules/lp2p/addrs.go | 117 + .../lotus/node/modules/lp2p/discovery.go | 35 + .../lotus/node/modules/lp2p/host.go | 113 + .../lotus/node/modules/lp2p/libp2p.go | 110 + .../lotus/node/modules/lp2p/nat.go | 40 + .../lotus/node/modules/lp2p/pubsub.go | 348 + .../lotus/node/modules/lp2p/relay.go | 28 + .../lotus/node/modules/lp2p/routing.go | 70 + .../lotus/node/modules/lp2p/smux.go | 54 + .../lotus/node/modules/lp2p/transport.go | 38 + .../lotus/node/modules/services.go | 128 + .../lotus/node/modules/storage.go | 31 + .../lotus/node/modules/storageminer.go | 558 + .../lotus/node/modules/testing/beacon.go | 12 + .../lotus/node/modules/testing/genesis.go | 106 + .../lotus/node/modules/testing/storage.go | 39 + .../filecoin-project/lotus/node/node_test.go | 532 + .../filecoin-project/lotus/node/options.go | 156 + .../lotus/node/repo/fsrepo.go | 488 + .../lotus/node/repo/fsrepo_ds.go | 74 + .../lotus/node/repo/fsrepo_test.go | 33 + .../lotus/node/repo/interface.go | 59 + .../lotus/node/repo/memrepo.go | 357 + .../lotus/node/repo/memrepo_test.go | 10 + .../lotus/node/repo/repo_test.go | 130 + .../filecoin-project/lotus/node/testopts.go | 20 + .../lotus/paychmgr/cbor_gen.go | 395 + .../filecoin-project/lotus/paychmgr/paych.go | 373 + .../filecoin-project/lotus/paychmgr/simple.go | 146 + .../filecoin-project/lotus/paychmgr/state.go | 80 + .../filecoin-project/lotus/paychmgr/store.go | 202 + .../lotus/scripts/archive-branches.sh | 66 + .../lotus/scripts/bash-completion/lotus | 10 + .../bash-completion/lotus-storage-miner | 10 + .../lotus/scripts/bootstrap.toml | 2 + .../lotus/scripts/build-bundle.sh | 52 + .../lotus/scripts/chainwatch.service | 15 + .../lotus/scripts/deploy-bootstrapper.sh | 34 + .../lotus/scripts/deploy-miner.sh | 18 + .../lotus/scripts/deploy-node.sh | 38 + .../lotus/scripts/dev/drop-local-repos | 5 + .../lotus/scripts/dev/gen-daemon | 11 + .../lotus/scripts/dev/sminer-init | 10 + .../lotus/scripts/devnet.bash | 196 + .../lotus/scripts/filebeat.yml | 76 + .../lotus/scripts/init-network.sh | 117 + .../lotus/scripts/lotus-daemon.service | 19 + .../lotus/scripts/lotus-miner.service | 13 + .../lotus/scripts/make-completions.sh | 9 + .../lotus/scripts/miner-mon.sh | 23 + .../lotus/scripts/publish-release.sh | 94 + .../lotus/scripts/quick-network-join.bash | 180 + .../lotus/scripts/setup-host.sh | 6 + .../lotus/scripts/zsh-completion/lotus | 12 + .../zsh-completion/lotus-storage-miner | 12 + .../lotus/storage/adapter_events.go | 29 + .../lotus/storage/adapter_storage_miner.go | 240 + .../filecoin-project/lotus/storage/miner.go | 193 + .../lotus/storage/mockstorage/preseal.go | 64 + .../filecoin-project/lotus/storage/sealing.go | 45 + .../lotus/storage/sectorblocks/blocks.go | 172 + .../lotus/storage/wdpost_run.go | 528 + .../lotus/storage/wdpost_sched.go | 220 + .../lotus/tools/dockers/README.md | 3 + .../tools/dockers/docker-examples/README.md | 34 + .../api-hosted-debian-nginx/README.md | 10 + .../docker-examples/api-local-arch/README.md | 8 + .../basic-miner-busybox/Dockerfile | 95 + .../basic-miner-busybox/README.md | 4 + .../lotus/tools/stats/.gitignore | 1 + .../lotus/tools/stats/collect.go | 63 + .../lotus/tools/stats/head_buffer.go | 47 + .../lotus/tools/stats/head_buffer_test.go | 43 + .../lotus/tools/stats/metrics.go | 364 + .../filecoin-project/lotus/tools/stats/rpc.go | 224 + .../specs-actors/.circleci/config.yml | 124 + .../specs-actors/.codecov.yml | 31 + .../specs-actors/CONTRIBUTING.md | 3 + .../filecoin-project/specs-actors/COPYRIGHT | 3 + .../specs-actors/LICENSE-APACHE | 13 + .../filecoin-project/specs-actors/LICENSE-MIT | 19 + .../filecoin-project/specs-actors/Makefile | 29 + .../filecoin-project/specs-actors/README.md | 31 + .../specs-actors/actors/abi/big/int.go | 305 + .../specs-actors/actors/abi/big/int_test.go | 157 + .../specs-actors/actors/abi/bitfield.go | 79 + .../specs-actors/actors/abi/bitfield_test.go | 95 + .../specs-actors/actors/abi/cbor_gen.go | 929 ++ .../specs-actors/actors/abi/constants.go | 11 + .../specs-actors/actors/abi/deal.go | 9 + .../specs-actors/actors/abi/invokee.go | 5 + .../specs-actors/actors/abi/piece.go | 50 + .../specs-actors/actors/abi/piece_test.go | 57 + .../specs-actors/actors/abi/primitives.go | 68 + .../specs-actors/actors/abi/sector.go | 265 + .../specs-actors/actors/abi/sector_test.go | 38 + .../actors/builtin/account/account_actor.go | 50 + .../actors/builtin/account/account_test.go | 78 + .../actors/builtin/account/cbor_gen.go | 56 + .../specs-actors/actors/builtin/cbor_gen.go | 147 + .../specs-actors/actors/builtin/codes.go | 99 + .../actors/builtin/cron/cbor_gen.go | 222 + .../actors/builtin/cron/cron_actor.go | 44 + .../actors/builtin/cron/cron_state.go | 35 + .../actors/builtin/cron/cron_test.go | 107 + .../actors/builtin/exported/actors.go | 85 + .../actors/builtin/init/cbor_gen.go | 287 + .../actors/builtin/init/init_actor.go | 101 + .../actors/builtin/init/init_actor_state.go | 91 + .../actors/builtin/init/init_test.go | 232 + .../actors/builtin/market/cbor_gen.go | 1406 ++ .../actors/builtin/market/deal.go | 91 + .../actors/builtin/market/market_actor.go | 750 + .../actors/builtin/market/market_state.go | 479 + .../actors/builtin/market/market_test.go | 1002 ++ .../actors/builtin/market/policy.go | 42 + .../actors/builtin/market/set_multimap.go | 159 + .../actors/builtin/market/types.go | 89 + .../specs-actors/actors/builtin/methods.go | 108 + .../actors/builtin/miner/cbor_gen.go | 2645 +++ .../actors/builtin/miner/deadlines.go | 284 + .../actors/builtin/miner/deadlines_test.go | 613 + .../actors/builtin/miner/expirations.go | 37 + .../actors/builtin/miner/expirations_test.go | 39 + .../actors/builtin/miner/miner_actor.go | 2190 +++ .../builtin/miner/miner_internal_test.go | 164 + .../actors/builtin/miner/miner_state.go | 1164 ++ .../actors/builtin/miner/miner_state_test.go | 1089 ++ .../actors/builtin/miner/miner_test.go | 2091 +++ .../actors/builtin/miner/monies.go | 78 + .../actors/builtin/miner/monies_test.go | 63 + .../actors/builtin/miner/policy.go | 196 + .../actors/builtin/multisig/cbor_gen.go | 1351 ++ .../actors/builtin/multisig/multisig_actor.go | 510 + .../actors/builtin/multisig/multisig_state.go | 111 + .../actors/builtin/multisig/multisig_test.go | 1547 ++ .../specs-actors/actors/builtin/network.go | 30 + .../actors/builtin/paych/cbor_gen.go | 1007 ++ .../actors/builtin/paych/paych_actor.go | 340 + .../actors/builtin/paych/paych_state.go | 54 + .../actors/builtin/paych/paych_test.go | 817 + .../actors/builtin/power/cbor_gen.go | 1159 ++ .../actors/builtin/power/policy.go | 11 + .../actors/builtin/power/power_actor.go | 485 + .../actors/builtin/power/power_state.go | 272 + .../actors/builtin/power/power_test.go | 382 + .../actors/builtin/reward/cbor_gen.go | 298 + .../actors/builtin/reward/reward_actor.go | 114 + .../actors/builtin/reward/reward_state.go | 307 + .../builtin/reward/reward_state_test.go | 67 + .../actors/builtin/reward/reward_test.go | 91 + .../specs-actors/actors/builtin/shared.go | 55 + .../specs-actors/actors/builtin/singletons.go | 40 + .../actors/builtin/system/cbor_gen.go | 42 + .../actors/builtin/system/system_actor.go | 27 + .../actors/builtin/system/system_test.go | 12 + .../actors/builtin/verifreg/cbor_gen.go | 321 + .../verifreg/verified_registry_actor.go | 219 + .../verifreg/verified_registry_state.go | 132 + .../verifreg/verified_registry_test.go | 12 + .../specs-actors/actors/crypto/randomness.go | 14 + .../specs-actors/actors/crypto/signature.go | 119 + .../specs-actors/actors/puppet/cbor_gen.go | 287 + .../specs-actors/actors/puppet/puppet.go | 156 + .../specs-actors/actors/puppet/puppet_test.go | 72 + .../actors/runtime/exitcode/common.go | 21 + .../actors/runtime/exitcode/reserved.go | 119 + .../specs-actors/actors/runtime/runtime.go | 271 + .../specs-actors/actors/util/adt/adt_test.go | 24 + .../specs-actors/actors/util/adt/array.go | 108 + .../actors/util/adt/array_test.go | 22 + .../actors/util/adt/balancetable.go | 144 + .../actors/util/adt/balancetable_test.go | 80 + .../specs-actors/actors/util/adt/empty.go | 38 + .../specs-actors/actors/util/adt/map.go | 118 + .../specs-actors/actors/util/adt/multimap.go | 123 + .../specs-actors/actors/util/adt/set.go | 59 + .../specs-actors/actors/util/adt/store.go | 138 + .../specs-actors/actors/util/assert.go | 25 + .../specs-actors/gen/command-line-arguments | Bin 0 -> 15310924 bytes .../filecoin-project/specs-actors/gen/gen.go | 219 + .../filecoin-project/specs-actors/go.mod | 29 + .../filecoin-project/specs-actors/go.sum | 160 + .../specs-actors/support/ipld/store.go | 39 + .../specs-actors/support/mock/builder.go | 97 + .../specs-actors/support/mock/exports.go | 24 + .../specs-actors/support/mock/mockrt.go | 930 ++ .../specs-actors/support/testing/address.go | 46 + .../specs-actors/support/testing/adt.go | 20 + .../specs-actors/support/testing/cid.go | 17 + 911 files changed, 175590 insertions(+) create mode 100644 vendor/github.com/filecoin-project/go-address/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/go-address/CONTRIBUTING.md create mode 100644 vendor/github.com/filecoin-project/go-address/COPYRIGHT create mode 100644 vendor/github.com/filecoin-project/go-address/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-address/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-address/Makefile create mode 100644 vendor/github.com/filecoin-project/go-address/README.md create mode 100644 vendor/github.com/filecoin-project/go-address/address.go create mode 100644 vendor/github.com/filecoin-project/go-address/address_test.go create mode 100644 vendor/github.com/filecoin-project/go-address/bench_test.go create mode 100644 vendor/github.com/filecoin-project/go-address/constants.go create mode 100644 vendor/github.com/filecoin-project/go-address/go.mod create mode 100644 vendor/github.com/filecoin-project/go-address/go.sum create mode 100644 vendor/github.com/filecoin-project/go-address/testing.go create mode 100644 vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-amt-ipld/v2/README.md create mode 100644 vendor/github.com/filecoin-project/go-amt-ipld/v2/amt.go create mode 100644 vendor/github.com/filecoin-project/go-amt-ipld/v2/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-amt-ipld/v2/go.mod create mode 100644 vendor/github.com/filecoin-project/go-amt-ipld/v2/go.sum create mode 100644 vendor/github.com/filecoin-project/go-bitfield/.github/workflows/go.yml create mode 100644 vendor/github.com/filecoin-project/go-bitfield/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-bitfield/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-bitfield/README.md create mode 100644 vendor/github.com/filecoin-project/go-bitfield/bitfield.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/bitfield_benchmark_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/bitfield_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/go.mod create mode 100644 vendor/github.com/filecoin-project/go-bitfield/go.sum create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/bits.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/bits_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/bitvec.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/bitvec_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/interface.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/joinclose.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/joinclose_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/merge.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/rleplus.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_golden_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_reader.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_test.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_writer.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/runs.go create mode 100644 vendor/github.com/filecoin-project/go-bitfield/rle/runs_test.go create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/CONTRIBUTING.md create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/COPYRIGHT create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/README.md create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/go.mod create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/go.sum create mode 100644 vendor/github.com/filecoin-project/go-cbor-util/rpc.go create mode 100644 vendor/github.com/filecoin-project/go-crypto/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/go-crypto/COPYRIGHT create mode 100644 vendor/github.com/filecoin-project/go-crypto/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-crypto/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-crypto/README.md create mode 100644 vendor/github.com/filecoin-project/go-crypto/crypto.go create mode 100644 vendor/github.com/filecoin-project/go-crypto/crypto_test.go create mode 100644 vendor/github.com/filecoin-project/go-crypto/go.mod create mode 100644 vendor/github.com/filecoin-project/go-crypto/go.sum create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/CONTRIBUTING.md create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/COPYRIGHT create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/Makefile create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/README.md create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/channels/channels.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/channels/channels_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/go.mod create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/go.sum create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/dagservice/dagservice.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/message.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/message_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/network/interface.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/registry/registry.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/registry/registry_test.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/testutil/fakegraphsync.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/testutil/fixtures/lorem.txt create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/testutil/gstestdata.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/testutil/testutil.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/tools.go create mode 100644 vendor/github.com/filecoin-project/go-data-transfer/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/CHANGELOG.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/CONTRIBUTING.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/COPYRIGHT create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/Makefile create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/README.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/codecov.yml create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd.png create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd.svg create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd.png create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd.svg create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd.png create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd.svg create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd.png create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd.svg create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/docsgen/main.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/filestore/README.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/filestore/file.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/filestore/filestore.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/filestore/filestore_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/filestore/mocks/File.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/filestore/mocks/FileStore.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/filestore/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/go.mod create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/go.sum create mode 100755 vendor/github.com/filecoin-project/go-fil-markets/mkreleaselog create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/package-lock.json create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/package.json create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/README.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/cario/cario.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/mocks/CarIO.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/mocks/PieceIO.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/mocks/PreparedCar.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/mocks/ReadStore.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/mocks/SectorCalculator.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/mocks/WriteStore.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/pieceio.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/pieceio_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/tempDir/.gitkeep create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/pieceio/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/piecestore/README.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/piecestore/piecestore.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/piecestore/piecestore_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/piecestore/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/piecestore/types_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/README.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/common.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/discovery/discovery.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/discovery/local.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/discovery/local_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockio/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockio/reader.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockio/reader_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockio/traverser.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockio/traverser_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockio/verify.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockio/verify_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockunsealing/blockunsealing.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/blockunsealing/blockunsealing_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/client.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/client_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/clientstates/client_fsm.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/clientstates/client_states.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/clientstates/client_states_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/clientstates/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/fixtures/lorem.txt create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/fixtures/lorem_under_1_block.txt create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/integration_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/provider.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/provider_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/providerstates/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/providerstates/provider_fsm.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/providerstates/provider_states.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/providerstates/provider_states_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/testnodes/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/testnodes/test_retrieval_client_node.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/testnodes/test_retrieval_provider_node.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/network/deal_stream.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/network/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/network/libp2p_impl.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/network/libp2p_impl_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/network/network.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/network/query_stream.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/storage_retrieval_integration_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/testing/test_provider_deal_environment.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/types_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/retrievalmarket/types_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared/selectors.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared_testutil/generators.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared_testutil/mocknet.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared_testutil/test_filestore.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared_testutil/test_ipld_tree.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared_testutil/test_network_types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared_testutil/test_piecestore.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/shared_testutil/testutil.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/README.md create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/client.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/dealstatus.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/events.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/fixtures/payload.txt create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/blockrecorder/blockrecorder.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/blockrecorder/blockrecorder_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/blockrecorder/blockrecorder_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/client.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/client_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/clientstates/client_fsm.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/clientstates/client_states.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/clientstates/client_states_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/clientstates/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/clientutils/clientutils.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/clientutils/clientutils_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/connmanager/connmanager.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/connmanager/connmanager_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/dtutils/dtutils.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/dtutils/dtutils_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/provider.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/provider_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/providerstates/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/providerstates/provider_fsm.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/providerstates/provider_states.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/providerstates/provider_states_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/providerutils/providerutils.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/providerutils/providerutils_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation/common.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation/request_validation_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation/types_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation/unified_request_validator.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/storedask/storedask.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/impl/storedask/storedask_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/integration_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/ask_stream.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/deal_status_stream.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/deal_stream.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/doc.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/libp2p_impl.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/libp2p_impl_test.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/network.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/network/types_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/nodes.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/provider.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/testnodes/testnodes.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/types.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/storagemarket/types_cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/go-fil-markets/tools/tools.go create mode 100644 vendor/github.com/filecoin-project/go-statestore/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/go-statestore/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/go-statestore/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/go-statestore/Makefile create mode 100644 vendor/github.com/filecoin-project/go-statestore/README.md create mode 100644 vendor/github.com/filecoin-project/go-statestore/go.mod create mode 100644 vendor/github.com/filecoin-project/go-statestore/go.sum create mode 100644 vendor/github.com/filecoin-project/go-statestore/state.go create mode 100644 vendor/github.com/filecoin-project/go-statestore/store.go create mode 100644 vendor/github.com/filecoin-project/go-statestore/store_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/lotus/.codecov.yml create mode 120000 vendor/github.com/filecoin-project/lotus/.dockerignore create mode 100644 vendor/github.com/filecoin-project/lotus/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 vendor/github.com/filecoin-project/lotus/.github/ISSUE_TEMPLATE/sealingfailed.md create mode 100644 vendor/github.com/filecoin-project/lotus/.golangci.yml create mode 100644 vendor/github.com/filecoin-project/lotus/CHANGELOG.md create mode 100644 vendor/github.com/filecoin-project/lotus/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/lotus/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/lotus/Makefile create mode 100644 vendor/github.com/filecoin-project/lotus/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/SECURITY.md create mode 100644 vendor/github.com/filecoin-project/lotus/api/api_common.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/api_full.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/api_storage.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/api_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/api_worker.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/apibstore/apibstore.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/apistruct/permissioned.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/apistruct/struct.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/apistruct/struct_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/client/client.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/docgen/docgen.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/test/deals.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/test/mining.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/test/test.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/test/window_post.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/types.go create mode 100644 vendor/github.com/filecoin-project/lotus/api/utils.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/bootstrap.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/bootstrap/.gitkeep create mode 100644 vendor/github.com/filecoin-project/lotus/build/bootstrap/bootstrappers.pi create mode 100644 vendor/github.com/filecoin-project/lotus/build/flags.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/forks.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/genesis.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/genesis/.gitkeep create mode 100644 vendor/github.com/filecoin-project/lotus/build/genesis/devnet.car create mode 100644 vendor/github.com/filecoin-project/lotus/build/parameters.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/params_2k.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/params_debug.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/params_shared_funcs.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/params_shared_vals.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/params_testground.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/params_testnet.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/proof-params/parameters.json create mode 100644 vendor/github.com/filecoin-project/lotus/build/testing_flags.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/tools.go create mode 100644 vendor/github.com/filecoin-project/lotus/build/version.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/actors/aerrors/error.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/actors/aerrors/error_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/actors/aerrors/wrap.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/actors/params.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/badtscache.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/beacon/beacon.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/beacon/drand/drand.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/beacon/drand/drand_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/beacon/mock.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/block_receipt_tracker.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/blocksync/blocksync.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/blocksync/blocksync_client.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/blocksync/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/blocksync/graphsync_client.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/events.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/events_called.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/events_height.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/events_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/state/predicates.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/state/predicates_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/tscache.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/tscache_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/events/utils.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/gen.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/gen_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/genesis.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/miners.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/t00_system.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/t01_init.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/t02_reward.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/t03_cron.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/t04_power.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/t05_market.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/t06_vreg.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/genesis/util.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/gen/mining.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/market/fundmgr.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/messagepool/messagepool.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/messagepool/messagepool_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/metrics/consensus.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/state/statetree.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/state/statetree_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/stmgr/call.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/stmgr/forks.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/stmgr/forks_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/stmgr/stmgr.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/stmgr/utils.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/store/fts.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/store/index.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/store/index_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/store/store.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/store/store_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/store/weight.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/sub/incoming.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/sync.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/sync_manager.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/sync_manager_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/sync_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/syncstate.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/actor.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/bigint.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/bigint_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/blockheader.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/blockheader_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/blockmsg.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/execresult.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/fil.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/fullblock.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/keystore.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/logs.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/message.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/message_fuzz.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/message_receipt.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/mock/chain.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/signature_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/signedmessage.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/tipset.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/tipset_key.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/tipset_key_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/types_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/vmcontext.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types/voucher.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/types_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/validation/applier.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/validation/config.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/validation/factories.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/validation/keymanager.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/validation/state.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vectors/gen/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vectors/vector_types.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vectors/vectors_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/gas.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/gas_v0.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/invoker.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/invoker_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/mkactor.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/runtime.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/runtime_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/syscalls.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/validation_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/vm/vm.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/wallet/memkeystore.go create mode 100644 vendor/github.com/filecoin-project/lotus/chain/wallet/wallet.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/auth.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/chain.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/client.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/cmd.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/log.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/mpool.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/multisig.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/net.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/params.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/paych.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/send.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/state.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/sync.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/version.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/wait.go create mode 100644 vendor/github.com/filecoin-project/lotus/cli/wallet.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/chain-noise/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/import.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/stats_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/blockssub.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/dot.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/mpool.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/block.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/blocks.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/index.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/key.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/keys.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/main.css create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/storage.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/sync.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/templates.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/_miner.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/funds.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/index.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/main.css create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/wait.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-health/notify.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/rpc.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/genesis.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/seed/seed.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base16.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base32.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bigint.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bitfield.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/commp.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/import-car.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/keyinfo.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/nonce-fix.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/params.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/proofs.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/stateroot-stats.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/verifreg.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/chain.dashboard.json create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/docker-compose.yml create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/env.stats create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/main.go create mode 100755 vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/setup.bash create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/actor.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/info.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/init.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/market.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/proving.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/retrieval-deals.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/rewards.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/run.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/sectors.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/stop.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/storage.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/workers.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/.gitignore create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/package.json create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/index.html create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/robots.txt create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.css create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.js create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.test.js create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.css create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.js create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon_nodaemon.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus/debug_advance.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/cmd/lotus/rpc.go create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/.glossary.json create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/.library.json create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/api-scripting-support.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/api-troubleshooting.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/api.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/architecture.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/block-validation.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/cli.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-jaeger-tracing.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-pond-ui.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/dev/WIP-arch-complementary-notes.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/faqs.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/getting-started.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/hardware-mining.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/hardware.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-arch.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-fedora.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-macos.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-ubuntu.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/install-systemd-services.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/join-testnet.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/local-dev-net.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/miner-deals.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/mining-lotus-seal-worker.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/mining-troubleshooting.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/mining.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/retrieving-data.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/sealing-procs.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/setting-a-static-port.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/setup-troubleshooting.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/storing-data-troubleshooting.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/storing-data.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/storing-ipfs-integration.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/en/updating-lotus.md create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/images/lotus_logo_h.png create mode 100644 vendor/github.com/filecoin-project/lotus/documentation/images/lotus_logo_h.svg create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.gitignore create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/CHANGELOG.md create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/Makefile create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls_test.go create mode 100755 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/build.sh create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/cgoleakdetect/runner.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/filcrypto.yml create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.h create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/const.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/customallocs.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/generated.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/types.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.mod create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.sum create mode 100755 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/install-filcrypto create mode 100755 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/mkreleaselog create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/parameters.json create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/proofs.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/proofs_test.go create mode 100755 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/run_tests.sh create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/Cargo.lock create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/Cargo.toml create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/build.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/cbindgen.toml create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/filcrypto.pc.template create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rust-toolchain create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rustc-target-features-optimized.json create mode 100755 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/build-release.sh create mode 100755 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/package-release.sh create mode 100755 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/publish-release.sh create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/api.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/mod.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/types.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/lib.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/api.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/helpers.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/mod.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/types.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/api.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/mod.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/types.rs create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/types.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/workflows.go create mode 100644 vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/block_headers.json create mode 100644 vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/message_signing.json create mode 100644 vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/unsigned_messages.json create mode 100644 vendor/github.com/filecoin-project/lotus/gen/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/genesis/types.go create mode 100644 vendor/github.com/filecoin-project/lotus/go.mod create mode 100644 vendor/github.com/filecoin-project/lotus/go.sum create mode 100644 vendor/github.com/filecoin-project/lotus/lib/addrutil/parse.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/bufbstore/buf_bstore.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/increadtimeout/incrt.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/ipfsbstore/ipfsbstore.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/lotuslog/levels.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/nullreader/reader.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/parmap/parmap.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/peermgr/peermgr.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/sigs/bls/bls_bench_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/sigs/bls/init.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/sigs/doc.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/sigs/secp/init.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/sigs/sigs.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/tracing/setup.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_freebsd.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_unix.go create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/api.go create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/.gitignore create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/package-lock.json create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/package.json create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/public/index.html create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/public/manifest.json create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Address.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.css create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.test.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Block.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/BlockLink.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ChainExplorer.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Client.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ConnMgr.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Consensus.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Fil.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/FullNode.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Logs.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeIndex.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeList.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Pond.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/SingleNode.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/State.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNode.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNodeInit.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Window.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/code.json create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methodgen.go create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methods.json create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/send.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.css create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.js create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/main.go create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/outmux.go create mode 100644 vendor/github.com/filecoin-project/lotus/lotuspond/spawn.go create mode 100644 vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/client.go create mode 100644 vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/provider.go create mode 100644 vendor/github.com/filecoin-project/lotus/markets/storageadapter/client.go create mode 100644 vendor/github.com/filecoin-project/lotus/markets/storageadapter/provider.go create mode 100644 vendor/github.com/filecoin-project/lotus/markets/utils/converters.go create mode 100644 vendor/github.com/filecoin-project/lotus/metrics/metrics.go create mode 100644 vendor/github.com/filecoin-project/lotus/miner/miner.go create mode 100644 vendor/github.com/filecoin-project/lotus/miner/miner_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/miner/testminer.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/builder.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/config/def.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/config/load.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/config/load_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/config/storage.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/fxlog.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/hello/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/hello/hello.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/client/client.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/common/common.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/full.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/full/chain.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/full/mpool.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/full/multisig.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/full/state.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/full/sync.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/full/wallet.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/market/market.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/paych/paych.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/remoteworker.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/impl/storminer.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/chain.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/client.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/core.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/api.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/beacon.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/bootstrap.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/chain.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/miner.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/scorekeeper.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/shutdown.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/dtypes/storage.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/graphsync.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/helpers/helpers.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/ipfsclient.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/addrs.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/discovery.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/host.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/libp2p.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/nat.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/pubsub.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/relay.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/routing.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/smux.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/lp2p/transport.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/services.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/storage.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/storageminer.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/testing/beacon.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/testing/genesis.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/modules/testing/storage.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/node_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/options.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/repo/fsrepo.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_ds.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/repo/interface.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/repo/memrepo.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/repo/memrepo_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/repo/repo_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/node/testopts.go create mode 100644 vendor/github.com/filecoin-project/lotus/paychmgr/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/lotus/paychmgr/paych.go create mode 100644 vendor/github.com/filecoin-project/lotus/paychmgr/simple.go create mode 100644 vendor/github.com/filecoin-project/lotus/paychmgr/state.go create mode 100644 vendor/github.com/filecoin-project/lotus/paychmgr/store.go create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/archive-branches.sh create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus-storage-miner create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/bootstrap.toml create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/build-bundle.sh create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/chainwatch.service create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/deploy-bootstrapper.sh create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/deploy-miner.sh create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/deploy-node.sh create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/dev/drop-local-repos create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/dev/gen-daemon create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/dev/sminer-init create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/devnet.bash create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/filebeat.yml create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/init-network.sh create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/lotus-daemon.service create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/lotus-miner.service create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/make-completions.sh create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/miner-mon.sh create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/publish-release.sh create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/quick-network-join.bash create mode 100755 vendor/github.com/filecoin-project/lotus/scripts/setup-host.sh create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus create mode 100644 vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus-storage-miner create mode 100644 vendor/github.com/filecoin-project/lotus/storage/adapter_events.go create mode 100644 vendor/github.com/filecoin-project/lotus/storage/adapter_storage_miner.go create mode 100644 vendor/github.com/filecoin-project/lotus/storage/miner.go create mode 100644 vendor/github.com/filecoin-project/lotus/storage/mockstorage/preseal.go create mode 100644 vendor/github.com/filecoin-project/lotus/storage/sealing.go create mode 100644 vendor/github.com/filecoin-project/lotus/storage/sectorblocks/blocks.go create mode 100644 vendor/github.com/filecoin-project/lotus/storage/wdpost_run.go create mode 100644 vendor/github.com/filecoin-project/lotus/storage/wdpost_sched.go create mode 100644 vendor/github.com/filecoin-project/lotus/tools/dockers/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-hosted-debian-nginx/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-local-arch/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/Dockerfile create mode 100644 vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/README.md create mode 100644 vendor/github.com/filecoin-project/lotus/tools/stats/.gitignore create mode 100644 vendor/github.com/filecoin-project/lotus/tools/stats/collect.go create mode 100644 vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer.go create mode 100644 vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer_test.go create mode 100644 vendor/github.com/filecoin-project/lotus/tools/stats/metrics.go create mode 100644 vendor/github.com/filecoin-project/lotus/tools/stats/rpc.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/.circleci/config.yml create mode 100644 vendor/github.com/filecoin-project/specs-actors/.codecov.yml create mode 100644 vendor/github.com/filecoin-project/specs-actors/CONTRIBUTING.md create mode 100644 vendor/github.com/filecoin-project/specs-actors/COPYRIGHT create mode 100644 vendor/github.com/filecoin-project/specs-actors/LICENSE-APACHE create mode 100644 vendor/github.com/filecoin-project/specs-actors/LICENSE-MIT create mode 100644 vendor/github.com/filecoin-project/specs-actors/Makefile create mode 100644 vendor/github.com/filecoin-project/specs-actors/README.md create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/constants.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/deal.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/invokee.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/piece.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/piece_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/primitives.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/sector.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/abi/sector_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/codes.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/exported/actors.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/deal.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/policy.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/set_multimap.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/types.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/methods.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_internal_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/policy.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/network.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/policy.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/shared.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/singletons.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_actor.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_state.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/crypto/randomness.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/crypto/signature.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/puppet/cbor_gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/common.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/reserved.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/runtime/runtime.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/adt_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable_test.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/empty.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/map.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/multimap.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/set.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/adt/store.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/actors/util/assert.go create mode 100755 vendor/github.com/filecoin-project/specs-actors/gen/command-line-arguments create mode 100644 vendor/github.com/filecoin-project/specs-actors/gen/gen.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/go.mod create mode 100644 vendor/github.com/filecoin-project/specs-actors/go.sum create mode 100644 vendor/github.com/filecoin-project/specs-actors/support/ipld/store.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/support/mock/builder.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/support/mock/exports.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/support/mock/mockrt.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/support/testing/address.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/support/testing/adt.go create mode 100644 vendor/github.com/filecoin-project/specs-actors/support/testing/cid.go diff --git a/vendor/github.com/filecoin-project/go-address/.circleci/config.yml b/vendor/github.com/filecoin-project/go-address/.circleci/config.yml new file mode 100644 index 0000000000..4fca8299da --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/.circleci/config.yml @@ -0,0 +1,185 @@ +version: 2.1 +orbs: + go: gotest/tools@0.0.9 + +executors: + golang: + docker: + - image: circleci/golang:1.13 + resource_class: small + +commands: + install-deps: + steps: + - go/install-ssh + - go/install: {package: git} + prepare: + parameters: + linux: + default: true + description: is a linux build environment? + type: boolean + steps: + - checkout + - when: + condition: << parameters.linux >> + steps: + - run: sudo apt-get update + - run: sudo apt-get install ocl-icd-opencl-dev + - run: git submodule sync + - run: git submodule update --init + build-all: + + +jobs: + mod-tidy-check: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - go/mod-tidy-check + + build-all: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - run: sudo apt-get update + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - run: + command: make build + - store_artifacts: + path: go-address + - store_artifacts: + path: go-address + + test: &test + description: | + Run tests with gotestsum. + parameters: + executor: + type: executor + default: golang + go-test-flags: + type: string + default: "-timeout 5m" + description: Flags passed to go test. + packages: + type: string + default: "./..." + description: Import paths of packages to be tested. + test-suite-name: + type: string + default: unit + description: Test suite name to report to CircleCI. + gotestsum-format: + type: string + default: short + description: gotestsum format. https://github.com/gotestyourself/gotestsum#format + coverage: + type: string + default: -coverprofile=coverage.txt + description: Coverage flag. Set to the empty string to disable. + codecov-upload: + type: boolean + default: false + description: | + Upload coverage report to https://codecov.io/. Requires the codecov API token to be + set as an environment variable for private projects. + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/mod-download + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - run: + command: make build + - go/install-gotestsum: + gobin: $HOME/.local/bin + - run: + name: go test + environment: + GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml + GOTESTSUM_FORMAT: << parameters.gotestsum-format >> + command: | + mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> + gotestsum -- \ + << parameters.coverage >> \ + << parameters.go-test-flags >> \ + << parameters.packages >> + no_output_timeout: 30m + - store_test_results: + path: /tmp/test-reports + - when: + condition: << parameters.codecov-upload >> + steps: + - go/install: {package: bash} + - go/install: {package: curl} + - run: + shell: /bin/bash -eo pipefail + command: | + bash <(curl -s https://codecov.io/bash) + - save_cache: + name: save go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + paths: + - "~/go/pkg" + - "~/go/src/github.com" + - "~/go/src/golang.org" + + lint: &lint + description: | + Run golangci-lint. + parameters: + executor: + type: executor + default: golang + golangci-lint-version: + type: string + default: 1.21.0 + concurrency: + type: string + default: '2' + description: | + Concurrency used to run linters. Defaults to 2 because NumCPU is not + aware of container CPU limits. + args: + type: string + default: '' + description: | + Arguments to pass to golangci-lint + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - run: + command: make build + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: << parameters.golangci-lint-version >> + - run: + name: Lint + command: | + $HOME/.local/bin/golangci-lint run -v \ + --concurrency << parameters.concurrency >> << parameters.args >> + lint-changes: + <<: *lint + + lint-all: + <<: *lint + +workflows: + version: 2.1 + ci: + jobs: + - lint-changes: + args: "--new-from-rev origin/master" + - test + - mod-tidy-check + - build-all diff --git a/vendor/github.com/filecoin-project/go-address/CONTRIBUTING.md b/vendor/github.com/filecoin-project/go-address/CONTRIBUTING.md new file mode 100644 index 0000000000..5118774981 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/CONTRIBUTING.md @@ -0,0 +1,77 @@ +# Contributing to this repo + +First, thank you for your interest in contributing to this project! Before you pick up your first issue and start +changing code, please: + +1. Review all documentation for the module you're interested in. +1. Look through the [issues for this repo](https://github.com/filecoin-project/go-address/issues) for relevant discussions. +1. If you have questions about an issue, post a comment in the issue. +1. If you want to submit changes that aren't covered by an issue, file a new one with your proposal, outlining what problem you found/feature you want to implement, and how you intend to implement a solution. + +For best results, before submitting a PR, make sure: +1. It has met all acceptance criteria for the issue. +1. It addresses only the one issue and does not make other, irrelevant changes. +1. Your code conforms to our coding style guide. +1. You have adequate test coverage (this should be indicated by CI results anyway). +1. If you like, check out [current PRs](https://github.com/filecoin-project/go-address/pulls) to see how others do it. + +Special Note: +If editing README.md, please conform to the [standard readme specification](https://github.com/RichardLitt/standard-readme/blob/master/spec.md). + +Before a PR can be merged to `master`, it must: +1. Pass continuous integration. +1. Be approved by at least two maintainers + +### Testing + +- All new code should be accompanied by unit tests. Prefer focused unit tests to integration tests for thorough validation of behaviour. Existing code is not necessarily a good model, here. +- Integration tests should test integration, not comprehensive functionality +- Tests should be placed in a separate package named `$PACKAGE_test`. For example, a test of the `chain` package should live in a package named `chain_test`. In limited situations, exceptions may be made for some "white box" tests placed in the same package as the code it tests. + +### Conventions and Style + +#### Imports +We use the following import ordering. +``` +import ( + [stdlib packages, alpha-sorted] + + [external packages] + + [go-address packages] +) +``` + +Where a package name does not match its directory name, an explicit alias is expected (`goimports` will add this for you). + +Example: + +```go +package address_test + +import ( + "bytes" + "encoding/base32" + "fmt" + "math" + "math/rand" + "strconv" + "testing" + "time" + + ffi "github.com/filecoin-project/filecoin-ffi" + "github.com/multiformats/go-varint" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/filecoin-project/go-crypto" + + "github.com/filecoin-project/go-address" +) +``` + +#### Comments +Comments are a communication to other developers (including your future self) to help them understand and maintain code. Good comments describe the _intent_ of the code, without repeating the procedures directly. + +- A `TODO:` comment describes a change that is desired but could not be immediately implemented. It must include a reference to a GitHub issue outlining whatever prevents the thing being done now (which could just be a matter of priority). +- A `NOTE:` comment indicates an aside, some background info, or ideas for future improvement, rather than the intent of the current code. It's often fine to document such ideas alongside the code rather than an issue (at the loss of a space for discussion). +- `FIXME`, `HACK`, `XXX` and similar tags indicating that some code is to be avoided in favour of `TODO`, `NOTE` or some straight prose. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-address/COPYRIGHT b/vendor/github.com/filecoin-project/go-address/COPYRIGHT new file mode 100644 index 0000000000..771e6f7cd7 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/COPYRIGHT @@ -0,0 +1,3 @@ +Copyright 2019. Protocol Labs, Inc. + +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/vendor/github.com/filecoin-project/go-address/LICENSE-APACHE b/vendor/github.com/filecoin-project/go-address/LICENSE-APACHE new file mode 100644 index 0000000000..546514363d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2019. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/filecoin-project/go-address/LICENSE-MIT b/vendor/github.com/filecoin-project/go-address/LICENSE-MIT new file mode 100644 index 0000000000..ea532a8305 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2019. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/filecoin-project/go-address/Makefile b/vendor/github.com/filecoin-project/go-address/Makefile new file mode 100644 index 0000000000..6e8b72d9b5 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/Makefile @@ -0,0 +1,7 @@ +all: build +.PHONY: all + + +build: + go build +.PHONY: build diff --git a/vendor/github.com/filecoin-project/go-address/README.md b/vendor/github.com/filecoin-project/go-address/README.md new file mode 100644 index 0000000000..5a7400d18d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/README.md @@ -0,0 +1,43 @@ +# go-address +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![CircleCI](https://circleci.com/gh/filecoin-project/go-address.svg?style=svg)](https://circleci.com/gh/filecoin-project/go-address) +[![codecov](https://codecov.io/gh/filecoin-project/go-address/branch/master/graph/badge.svg)](https://codecov.io/gh/filecoin-project/go-address) + +The filecoin address type, used for identifying actors on the filecoin network, in various formats. + +## Install + +Install this library with `go mod` + +## Usage + +Addresses support various types of encoding formats and have constructors +for each format + +```golang +// address from ID +idAddress := NewIDAddress(id) +// address from a secp pub key +secp256k1Address := NewSecp256k1Address(pubkey) +// address from data for actor protocol +actorAddress := NewActorAddress(data) +// address from the BLS pubkey +blsAddress := NewBLSAddress(pubkey) +``` + +Serialization + +```golang +var outBuf io.writer +err := address.MarshalCBOR(outbuf) +var inBuf io.reader +err := address.UnmarshalCBOR(inbuf) +``` + +## Project-level documentation +The filecoin-project has a [community repo](https://github.com/filecoin-project/community) that documents in more detail our policies and guidelines, such as discussion forums and chat rooms and [Code of Conduct](https://github.com/filecoin-project/community/blob/master/CODE_OF_CONDUCT.md). + +## License +This repository is dual-licensed under Apache 2.0 and MIT terms. + +Copyright 2019. Protocol Labs, Inc. diff --git a/vendor/github.com/filecoin-project/go-address/address.go b/vendor/github.com/filecoin-project/go-address/address.go new file mode 100644 index 0000000000..d97fa79bb0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/address.go @@ -0,0 +1,410 @@ +package address + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "strconv" + + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/minio/blake2b-simd" + "github.com/multiformats/go-varint" + "github.com/polydawn/refmt/obj/atlas" + "golang.org/x/xerrors" + + cbg "github.com/whyrusleeping/cbor-gen" +) + +func init() { + cbor.RegisterCborType(addressAtlasEntry) +} + +var addressAtlasEntry = atlas.BuildEntry(Address{}).Transform(). + TransformMarshal(atlas.MakeMarshalTransformFunc( + func(a Address) (string, error) { + return string(a.Bytes()), nil + })). + TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( + func(x string) (Address, error) { + return NewFromBytes([]byte(x)) + })). + Complete() + +// Address is the go type that represents an address in the filecoin network. +type Address struct{ str string } + +// Undef is the type that represents an undefined address. +var Undef = Address{} + +// Network represents which network an address belongs to. +type Network = byte + +const ( + // Mainnet is the main network. + Mainnet Network = iota + // Testnet is the test network. + Testnet +) + +// MainnetPrefix is the main network prefix. +const MainnetPrefix = "f" + +// TestnetPrefix is the main network prefix. +const TestnetPrefix = "t" + +// Protocol represents which protocol an address uses. +type Protocol = byte + +const ( + // ID represents the address ID protocol. + ID Protocol = iota + // SECP256K1 represents the address SECP256K1 protocol. + SECP256K1 + // Actor represents the address Actor protocol. + Actor + // BLS represents the address BLS protocol. + BLS + + Unknown = Protocol(255) +) + +// Protocol returns the protocol used by the address. +func (a Address) Protocol() Protocol { + if len(a.str) == 0 { + return Unknown + } + return a.str[0] +} + +// Payload returns the payload of the address. +func (a Address) Payload() []byte { + return []byte(a.str[1:]) +} + +// Bytes returns the address as bytes. +func (a Address) Bytes() []byte { + return []byte(a.str) +} + +// String returns an address encoded as a string. +func (a Address) String() string { + str, err := encode(Testnet, a) + if err != nil { + panic(err) // I don't know if this one is okay + } + return str +} + +// Empty returns true if the address is empty, false otherwise. +func (a Address) Empty() bool { + return a == Undef +} + +// Unmarshal unmarshals the cbor bytes into the address. +func (a Address) Unmarshal(b []byte) error { + return cbor.DecodeInto(b, &a) +} + +// Marshal marshals the address to cbor. +func (a Address) Marshal() ([]byte, error) { + return cbor.DumpObject(a) +} + +// UnmarshalJSON implements the json unmarshal interface. +func (a *Address) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + addr, err := decode(s) + if err != nil { + return err + } + *a = addr + return nil +} + +// MarshalJSON implements the json marshal interface. +func (a Address) MarshalJSON() ([]byte, error) { + return []byte(`"` + a.String() + `"`), nil +} + +func (a *Address) Scan(value interface{}) error { + switch value := value.(type) { + case string: + a1, err := decode(value) + if err != nil { + return err + } + + *a = a1 + + return nil + default: + return xerrors.New("non-string types unsupported") + } +} + +// NewIDAddress returns an address using the ID protocol. +func NewIDAddress(id uint64) (Address, error) { + return newAddress(ID, varint.ToUvarint(id)) +} + +// NewSecp256k1Address returns an address using the SECP256K1 protocol. +func NewSecp256k1Address(pubkey []byte) (Address, error) { + return newAddress(SECP256K1, addressHash(pubkey)) +} + +// NewActorAddress returns an address using the Actor protocol. +func NewActorAddress(data []byte) (Address, error) { + return newAddress(Actor, addressHash(data)) +} + +// NewBLSAddress returns an address using the BLS protocol. +func NewBLSAddress(pubkey []byte) (Address, error) { + return newAddress(BLS, pubkey) +} + +// NewFromString returns the address represented by the string `addr`. +func NewFromString(addr string) (Address, error) { + return decode(addr) +} + +// NewFromBytes return the address represented by the bytes `addr`. +func NewFromBytes(addr []byte) (Address, error) { + if len(addr) == 0 { + return Undef, nil + } + if len(addr) == 1 { + return Undef, ErrInvalidLength + } + return newAddress(addr[0], addr[1:]) +} + +// Checksum returns the checksum of `ingest`. +func Checksum(ingest []byte) []byte { + return hash(ingest, checksumHashConfig) +} + +// ValidateChecksum returns true if the checksum of `ingest` is equal to `expected`> +func ValidateChecksum(ingest, expect []byte) bool { + digest := Checksum(ingest) + return bytes.Equal(digest, expect) +} + +func addressHash(ingest []byte) []byte { + return hash(ingest, payloadHashConfig) +} + +func newAddress(protocol Protocol, payload []byte) (Address, error) { + switch protocol { + case ID: + _, n, err := varint.FromUvarint(payload) + if err != nil { + return Undef, xerrors.Errorf("could not decode: %v: %w", err, ErrInvalidPayload) + } + if n != len(payload) { + return Undef, xerrors.Errorf("different varint length (v:%d != p:%d): %w", + n, len(payload), ErrInvalidPayload) + } + case SECP256K1, Actor: + if len(payload) != PayloadHashLength { + return Undef, ErrInvalidPayload + } + case BLS: + if len(payload) != BlsPublicKeyBytes { + return Undef, ErrInvalidPayload + } + default: + return Undef, ErrUnknownProtocol + } + explen := 1 + len(payload) + buf := make([]byte, explen) + + buf[0] = protocol + copy(buf[1:], payload) + + return Address{string(buf)}, nil +} + +func encode(network Network, addr Address) (string, error) { + if addr == Undef { + return UndefAddressString, nil + } + var ntwk string + switch network { + case Mainnet: + ntwk = MainnetPrefix + case Testnet: + ntwk = TestnetPrefix + default: + return UndefAddressString, ErrUnknownNetwork + } + + var strAddr string + switch addr.Protocol() { + case SECP256K1, Actor, BLS: + cksm := Checksum(append([]byte{addr.Protocol()}, addr.Payload()...)) + strAddr = ntwk + fmt.Sprintf("%d", addr.Protocol()) + AddressEncoding.WithPadding(-1).EncodeToString(append(addr.Payload(), cksm[:]...)) + case ID: + i, n, err := varint.FromUvarint(addr.Payload()) + if err != nil { + return UndefAddressString, xerrors.Errorf("could not decode varint: %w", err) + } + if n != len(addr.Payload()) { + return UndefAddressString, xerrors.Errorf("payload contains additional bytes") + } + strAddr = fmt.Sprintf("%s%d%d", ntwk, addr.Protocol(), i) + default: + return UndefAddressString, ErrUnknownProtocol + } + return strAddr, nil +} + +func decode(a string) (Address, error) { + if len(a) == 0 { + return Undef, nil + } + if a == UndefAddressString { + return Undef, nil + } + if len(a) > MaxAddressStringLength || len(a) < 3 { + return Undef, ErrInvalidLength + } + + if string(a[0]) != MainnetPrefix && string(a[0]) != TestnetPrefix { + return Undef, ErrUnknownNetwork + } + + var protocol Protocol + switch a[1] { + case '0': + protocol = ID + case '1': + protocol = SECP256K1 + case '2': + protocol = Actor + case '3': + protocol = BLS + default: + return Undef, ErrUnknownProtocol + } + + raw := a[2:] + if protocol == ID { + // 20 is length of math.MaxUint64 as a string + if len(raw) > 20 { + return Undef, ErrInvalidLength + } + id, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + return Undef, ErrInvalidPayload + } + return newAddress(protocol, varint.ToUvarint(id)) + } + + payloadcksm, err := AddressEncoding.WithPadding(-1).DecodeString(raw) + if err != nil { + return Undef, err + } + payload := payloadcksm[:len(payloadcksm)-ChecksumHashLength] + cksm := payloadcksm[len(payloadcksm)-ChecksumHashLength:] + + if protocol == SECP256K1 || protocol == Actor { + if len(payload) != 20 { + return Undef, ErrInvalidPayload + } + } + + if !ValidateChecksum(append([]byte{protocol}, payload...), cksm) { + return Undef, ErrInvalidChecksum + } + + return newAddress(protocol, payload) +} + +func hash(ingest []byte, cfg *blake2b.Config) []byte { + hasher, err := blake2b.New(cfg) + if err != nil { + // If this happens sth is very wrong. + panic(fmt.Sprintf("invalid address hash configuration: %v", err)) // ok + } + if _, err := hasher.Write(ingest); err != nil { + // blake2bs Write implementation never returns an error in its current + // setup. So if this happens sth went very wrong. + panic(fmt.Sprintf("blake2b is unable to process hashes: %v", err)) // ok + } + return hasher.Sum(nil) +} + +func (a Address) MarshalBinary() ([]byte, error) { + return a.Bytes(), nil +} + +func (a *Address) UnmarshalBinary(b []byte) error { + newAddr, err := NewFromBytes(b) + if err != nil { + return err + } + *a = newAddr + return nil +} + +func (a Address) MarshalCBOR(w io.Writer) error { + if a == Undef { + return fmt.Errorf("cannot marshal undefined address") + } + + if err := cbg.WriteMajorTypeHeader(w, cbg.MajByteString, uint64(len(a.str))); err != nil { + return err + } + + if _, err := io.WriteString(w, a.str); err != nil { + return err + } + + return nil +} + +func (a *Address) UnmarshalCBOR(br io.Reader) error { + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + + if maj != cbg.MajByteString { + return fmt.Errorf("cbor type for address unmarshal was not byte string") + } + + if extra > 64 { + return fmt.Errorf("too many bytes to unmarshal for an address") + } + + buf := make([]byte, int(extra)) + if _, err := io.ReadFull(br, buf); err != nil { + return err + } + + addr, err := NewFromBytes(buf) + if err != nil { + return err + } + if addr == Undef { + return fmt.Errorf("cbor input should not contain empty addresses") + } + + *a = addr + + return nil +} + +func IDFromAddress(addr Address) (uint64, error) { + if addr.Protocol() != ID { + return 0, xerrors.Errorf("cannot get id from non id address") + } + + i, _, err := varint.FromUvarint(addr.Payload()) + return i, err +} diff --git a/vendor/github.com/filecoin-project/go-address/address_test.go b/vendor/github.com/filecoin-project/go-address/address_test.go new file mode 100644 index 0000000000..ac33fca74c --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/address_test.go @@ -0,0 +1,506 @@ +package address + +import ( + "bytes" + "encoding/base32" + "fmt" + "math" + "math/rand" + "strconv" + "testing" + "time" + + "github.com/multiformats/go-varint" + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/go-crypto" +) + +func init() { + rand.Seed(time.Now().Unix()) +} + +func TestRandomIDAddress(t *testing.T) { + assert := assert.New(t) + + addr, err := NewIDAddress(uint64(rand.Int())) + assert.NoError(err) + assert.Equal(ID, addr.Protocol()) + + str, err := encode(Testnet, addr) + assert.NoError(err) + + maybe, err := decode(str) + assert.NoError(err) + assert.Equal(addr, maybe) + +} + +var allTestAddresses = []string{ + "t00", + "t01", + "t010", + "t0150", + "t0499", + "t01024", + "t01729", + "t0999999", + "t15ihq5ibzwki2b4ep2f46avlkrqzhpqgtga7pdrq", + "t12fiakbhe2gwd5cnmrenekasyn6v5tnaxaqizq6a", + "t1wbxhu3ypkuo6eyp6hjx6davuelxaxrvwb2kuwva", + "t1xtwapqc6nh4si2hcwpr3656iotzmlwumogqbuaa", + "t1xcbgdhkgkwht3hrrnui3jdopeejsoatkzmoltqy", + "t17uoq6tp427uzv7fztkbsnn64iwotfrristwpryy", + "t24vg6ut43yw2h2jqydgbg2xq7x6f4kub3bg6as6i", + "t25nml2cfbljvn4goqtclhifepvfnicv6g7mfmmvq", + "t2nuqrg7vuysaue2pistjjnt3fadsdzvyuatqtfei", + "t24dd4ox4c2vpf5vk5wkadgyyn6qtuvgcpxxon64a", + "t2gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr23y", + "t3vvmn62lofvhjd2ugzca6sof2j2ubwok6cj4xxbfzz4yuxfkgobpihhd2thlanmsh3w2ptld2gqkn2jvlss4a", + "t3wmuu6crofhqmm3v4enos73okk2l366ck6yc4owxwbdtkmpk42ohkqxfitcpa57pjdcftql4tojda2poeruwa", + "t3s2q2hzhkpiknjgmf4zq3ejab2rh62qbndueslmsdzervrhapxr7dftie4kpnpdiv2n6tvkr743ndhrsw6d3a", + "t3q22fijmmlckhl56rn5nkyamkph3mcfu5ed6dheq53c244hfmnq2i7efdma3cj5voxenwiummf2ajlsbxc65a", + "t3u5zgwa4ael3vuocgc5mfgygo4yuqocrntuuhcklf4xzg5tcaqwbyfabxetwtj4tsam3pbhnwghyhijr5mixa", +} + +func TestVectorsIDAddress(t *testing.T) { + testCases := []struct { + input uint64 + expected string + }{ + {uint64(0), "t00"}, + {uint64(1), "t01"}, + {uint64(10), "t010"}, + {uint64(150), "t0150"}, + {uint64(499), "t0499"}, + {uint64(1024), "t01024"}, + {uint64(1729), "t01729"}, + {uint64(999999), "t0999999"}, + {math.MaxUint64, fmt.Sprintf("t0%s", strconv.FormatUint(math.MaxUint64, 10))}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing actorID address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewIDAddress(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(ID, maybeAddr.Protocol()) + id, _, err := varint.FromUvarint(maybeAddr.Payload()) + assert.NoError(err) + assert.Equal(tc.input, id) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } + +} + +func TestSecp256k1Address(t *testing.T) { + assert := assert.New(t) + + sk, err := crypto.GenerateKey() + assert.NoError(err) + + addr, err := NewSecp256k1Address(crypto.PublicKey(sk)) + assert.NoError(err) + assert.Equal(SECP256K1, addr.Protocol()) + + str, err := encode(Mainnet, addr) + assert.NoError(err) + + maybe, err := decode(str) + assert.NoError(err) + assert.Equal(addr, maybe) + +} + +func TestVectorSecp256k1Address(t *testing.T) { + testCases := []struct { + input []byte + expected string + }{ + {[]byte{4, 148, 2, 250, 195, 126, 100, 50, 164, 22, 163, 160, 202, 84, + 38, 181, 24, 90, 179, 178, 79, 97, 52, 239, 162, 92, 228, 135, 200, + 45, 46, 78, 19, 191, 69, 37, 17, 224, 210, 36, 84, 33, 248, 97, 59, + 193, 13, 114, 250, 33, 102, 102, 169, 108, 59, 193, 57, 32, 211, + 255, 35, 63, 208, 188, 5}, + "t15ihq5ibzwki2b4ep2f46avlkrqzhpqgtga7pdrq"}, + + {[]byte{4, 118, 135, 185, 16, 55, 155, 242, 140, 190, 58, 234, 103, 75, + 18, 0, 12, 107, 125, 186, 70, 255, 192, 95, 108, 148, 254, 42, 34, + 187, 204, 38, 2, 255, 127, 92, 118, 242, 28, 165, 93, 54, 149, 145, + 82, 176, 225, 232, 135, 145, 124, 57, 53, 118, 238, 240, 147, 246, + 30, 189, 58, 208, 111, 127, 218}, + "t12fiakbhe2gwd5cnmrenekasyn6v5tnaxaqizq6a"}, + {[]byte{4, 222, 253, 208, 16, 1, 239, 184, 110, 1, 222, 213, 206, 52, + 248, 71, 167, 58, 20, 129, 158, 230, 65, 188, 182, 11, 185, 41, 147, + 89, 111, 5, 220, 45, 96, 95, 41, 133, 248, 209, 37, 129, 45, 172, + 65, 99, 163, 150, 52, 155, 35, 193, 28, 194, 255, 53, 157, 229, 75, + 226, 135, 234, 98, 49, 155}, + "t1wbxhu3ypkuo6eyp6hjx6davuelxaxrvwb2kuwva"}, + {[]byte{4, 3, 237, 18, 200, 20, 182, 177, 13, 46, 224, 157, 149, 180, + 104, 141, 178, 209, 128, 208, 169, 163, 122, 107, 106, 125, 182, 61, + 41, 129, 30, 233, 115, 4, 121, 216, 239, 145, 57, 233, 18, 73, 202, + 189, 57, 50, 145, 207, 229, 210, 119, 186, 118, 222, 69, 227, 224, + 133, 163, 118, 129, 191, 54, 69, 210}, + "t1xtwapqc6nh4si2hcwpr3656iotzmlwumogqbuaa"}, + {[]byte{4, 247, 150, 129, 154, 142, 39, 22, 49, 175, 124, 24, 151, 151, + 181, 69, 214, 2, 37, 147, 97, 71, 230, 1, 14, 101, 98, 179, 206, 158, + 254, 139, 16, 20, 65, 97, 169, 30, 208, 180, 236, 137, 8, 0, 37, 63, + 166, 252, 32, 172, 144, 251, 241, 251, 242, 113, 48, 164, 236, 195, + 228, 3, 183, 5, 118}, + "t1xcbgdhkgkwht3hrrnui3jdopeejsoatkzmoltqy"}, + {[]byte{4, 66, 131, 43, 248, 124, 206, 158, 163, 69, 185, 3, 80, 222, + 125, 52, 149, 133, 156, 164, 73, 5, 156, 94, 136, 221, 231, 66, 133, + 223, 251, 158, 192, 30, 186, 188, 95, 200, 98, 104, 207, 234, 235, + 167, 174, 5, 191, 184, 214, 142, 183, 90, 82, 104, 120, 44, 248, 111, + 200, 112, 43, 239, 138, 31, 224}, + "t17uoq6tp427uzv7fztkbsnn64iwotfrristwpryy"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing secp256k1 address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewSecp256k1Address(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(SECP256K1, maybeAddr.Protocol()) + assert.Equal(addressHash(tc.input), maybeAddr.Payload()) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } +} + +func TestRandomActorAddress(t *testing.T) { + assert := assert.New(t) + + actorMsg := make([]byte, 20) + rand.Read(actorMsg) + + addr, err := NewActorAddress(actorMsg) + assert.NoError(err) + assert.Equal(Actor, addr.Protocol()) + + str, err := encode(Mainnet, addr) + assert.NoError(err) + + maybe, err := decode(str) + assert.NoError(err) + assert.Equal(addr, maybe) + +} + +func TestVectorActorAddress(t *testing.T) { + testCases := []struct { + input []byte + expected string + }{ + {[]byte{118, 18, 129, 144, 205, 240, 104, 209, 65, 128, 68, 172, 192, + 62, 11, 103, 129, 151, 13, 96}, + "t24vg6ut43yw2h2jqydgbg2xq7x6f4kub3bg6as6i"}, + {[]byte{44, 175, 184, 226, 224, 107, 186, 152, 234, 101, 124, 92, 245, + 244, 32, 35, 170, 35, 232, 142}, + "t25nml2cfbljvn4goqtclhifepvfnicv6g7mfmmvq"}, + {[]byte{2, 44, 158, 14, 162, 157, 143, 64, 197, 106, 190, 195, 92, 141, + 88, 125, 160, 166, 76, 24}, + "t2nuqrg7vuysaue2pistjjnt3fadsdzvyuatqtfei"}, + {[]byte{223, 236, 3, 14, 32, 79, 15, 89, 216, 15, 29, 94, 233, 29, 253, + 6, 109, 127, 99, 189}, + "t24dd4ox4c2vpf5vk5wkadgyyn6qtuvgcpxxon64a"}, + {[]byte{61, 58, 137, 232, 221, 171, 84, 120, 50, 113, 108, 109, 70, 140, + 53, 96, 201, 244, 127, 216}, + "t2gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr23y"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing Actor address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewActorAddress(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(Actor, maybeAddr.Protocol()) + assert.Equal(addressHash(tc.input), maybeAddr.Payload()) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } +} + +func TestVectorBLSAddress(t *testing.T) { + testCases := []struct { + input []byte + expected string + }{ + {[]byte{173, 88, 223, 105, 110, 45, 78, 145, 234, 134, 200, 129, 233, 56, + 186, 78, 168, 27, 57, 94, 18, 121, 123, 132, 185, 207, 49, 75, 149, 70, + 112, 94, 131, 156, 122, 153, 214, 6, 178, 71, 221, 180, 249, 172, 122, + 52, 20, 221}, + "t3vvmn62lofvhjd2ugzca6sof2j2ubwok6cj4xxbfzz4yuxfkgobpihhd2thlanmsh3w2ptld2gqkn2jvlss4a"}, + {[]byte{179, 41, 79, 10, 46, 41, 224, 198, 110, 188, 35, 93, 47, 237, + 202, 86, 151, 191, 120, 74, 246, 5, 199, 90, 246, 8, 230, 166, 61, 92, + 211, 142, 168, 92, 168, 152, 158, 14, 253, 233, 24, 139, 56, 47, + 147, 114, 70, 13}, + "t3wmuu6crofhqmm3v4enos73okk2l366ck6yc4owxwbdtkmpk42ohkqxfitcpa57pjdcftql4tojda2poeruwa"}, + {[]byte{150, 161, 163, 228, 234, 122, 20, 212, 153, 133, 230, 97, 178, + 36, 1, 212, 79, 237, 64, 45, 29, 9, 37, 178, 67, 201, 35, 88, 156, + 15, 188, 126, 50, 205, 4, 226, 158, 215, 141, 21, 211, 125, 58, 170, + 63, 230, 218, 51}, + "t3s2q2hzhkpiknjgmf4zq3ejab2rh62qbndueslmsdzervrhapxr7dftie4kpnpdiv2n6tvkr743ndhrsw6d3a"}, + {[]byte{134, 180, 84, 37, 140, 88, 148, 117, 247, 209, 111, 90, 172, 1, + 138, 121, 246, 193, 22, 157, 32, 252, 51, 146, 29, 216, 181, 206, 28, + 172, 108, 52, 143, 144, 163, 96, 54, 36, 246, 174, 185, 27, 100, 81, + 140, 46, 128, 149}, + "t3q22fijmmlckhl56rn5nkyamkph3mcfu5ed6dheq53c244hfmnq2i7efdma3cj5voxenwiummf2ajlsbxc65a"}, + {[]byte{167, 114, 107, 3, 128, 34, 247, 90, 56, 70, 23, 88, 83, 96, 206, + 230, 41, 7, 10, 45, 157, 40, 113, 41, 101, 229, 242, 110, 204, 64, + 133, 131, 130, 128, 55, 36, 237, 52, 242, 114, 3, 54, 240, 157, 182, + 49, 240, 116}, + "t3u5zgwa4ael3vuocgc5mfgygo4yuqocrntuuhcklf4xzg5tcaqwbyfabxetwtj4tsam3pbhnwghyhijr5mixa"}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing bls address: %s", tc.expected), func(t *testing.T) { + assert := assert.New(t) + + // Round trip encoding and decoding from string + addr, err := NewBLSAddress(tc.input) + assert.NoError(err) + assert.Equal(tc.expected, addr.String()) + + maybeAddr, err := NewFromString(tc.expected) + assert.NoError(err) + assert.Equal(BLS, maybeAddr.Protocol()) + assert.Equal(tc.input, maybeAddr.Payload()) + + // Round trip to and from bytes + maybeAddrBytes, err := NewFromBytes(maybeAddr.Bytes()) + assert.NoError(err) + assert.Equal(maybeAddr, maybeAddrBytes) + + // Round trip encoding and decoding json + b, err := addr.MarshalJSON() + assert.NoError(err) + + var newAddr Address + err = newAddr.UnmarshalJSON(b) + assert.NoError(err) + assert.Equal(addr, newAddr) + }) + } +} + +func TestInvalidStringAddresses(t *testing.T) { + testCases := []struct { + input string + expetErr error + }{ + {"Q2gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr23y", ErrUnknownNetwork}, + {"t4gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr23y", ErrUnknownProtocol}, + {"t2gfvuyh7v2sx3patm5k23wdzmhyhtmqctasbr24y", ErrInvalidChecksum}, + {"t0banananananannnnnnnnn", ErrInvalidLength}, + {"t0banananananannnnnnnn", ErrInvalidPayload}, + {"t2gfvuyh7v2sx3patm1k23wdzmhyhtmqctasbr24y", base32.CorruptInputError(16)}, // '1' is not in base32 alphabet + {"t2gfvuyh7v2sx3paTm1k23wdzmhyhtmqctasbr24y", base32.CorruptInputError(14)}, // 'T' is not in base32 alphabet + {"t2", ErrInvalidLength}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing string address: %s", tc.expetErr), func(t *testing.T) { + assert := assert.New(t) + + _, err := NewFromString(tc.input) + assert.Equal(tc.expetErr, err) + }) + } + +} + +func TestInvalidByteAddresses(t *testing.T) { + testCases := []struct { + input []byte + expetErr error + }{ + // Unknown Protocol + {[]byte{4, 4, 4}, ErrUnknownProtocol}, + + // ID protocol + {[]byte{0}, ErrInvalidLength}, + + // SECP256K1 Protocol + {append([]byte{1}, make([]byte, PayloadHashLength-1)...), ErrInvalidPayload}, + {append([]byte{1}, make([]byte, PayloadHashLength+1)...), ErrInvalidPayload}, + // Actor Protocol + {append([]byte{2}, make([]byte, PayloadHashLength-1)...), ErrInvalidPayload}, + {append([]byte{2}, make([]byte, PayloadHashLength+1)...), ErrInvalidPayload}, + + // BLS Protocol + {append([]byte{3}, make([]byte, BlsPublicKeyBytes-1)...), ErrInvalidPayload}, + {append([]byte{3}, make([]byte, BlsPrivateKeyBytes+1)...), ErrInvalidPayload}, + } + + for _, tc := range testCases { + tc := tc + t.Run(fmt.Sprintf("testing byte address: %s", tc.expetErr), func(t *testing.T) { + assert := assert.New(t) + + _, err := NewFromBytes(tc.input) + assert.Equal(tc.expetErr, err) + }) + } + +} + +func TestChecksum(t *testing.T) { + assert := assert.New(t) + + data := []byte("helloworld") + bata := []byte("kittinmittins") + + cksm := Checksum(data) + assert.Len(cksm, ChecksumHashLength) + + assert.True(ValidateChecksum(data, cksm)) + assert.False(ValidateChecksum(bata, cksm)) + +} + +func TestCborMarshal(t *testing.T) { + for _, a := range allTestAddresses { + addr, err := NewFromString(a) + if err != nil { + t.Fatal(err) + } + + buf := new(bytes.Buffer) + if err := addr.MarshalCBOR(buf); err != nil { + t.Fatal(err) + } + + /* + // Note: this is commented out because we're currently serializing addresses as cbor "text strings", not "byte strings". + // This is to get around the restriction that refmt only allows string keys in maps. + // if you change it to serialize to byte strings and uncomment this, the tests pass fine + oldbytes, err := cbor.DumpObject(addr) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(oldbytes, buf.Bytes()) { + t.Fatalf("serialization doesnt match old serialization: %s", a) + } + */ + + var out Address + if err := out.UnmarshalCBOR(buf); err != nil { + t.Fatal(err) + } + + if out != addr { + t.Fatalf("failed to round trip %s", a) + } + } +} + +func BenchmarkCborMarshal(b *testing.B) { + addr, err := NewFromString("t15ihq5ibzwki2b4ep2f46avlkrqzhpqgtga7pdrq") + if err != nil { + b.Fatal(err) + } + + b.ReportAllocs() + b.ResetTimer() + + buf := new(bytes.Buffer) + for i := 0; i < b.N; i++ { + buf.Reset() + if err := addr.MarshalCBOR(buf); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkCborUnmarshal(b *testing.B) { + addr, err := NewFromString("t15ihq5ibzwki2b4ep2f46avlkrqzhpqgtga7pdrq") + if err != nil { + b.Fatal(err) + } + + buf := new(bytes.Buffer) + if err := addr.MarshalCBOR(buf); err != nil { + b.Fatal(err) + } + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + var a Address + if err := a.UnmarshalCBOR(bytes.NewReader(buf.Bytes())); err != nil { + b.Fatal(err) + } + } +} + +func TestIDEdgeCase(t *testing.T) { + a, err := NewFromBytes([]byte{0, 0x80}) + _ = a.String() + assert.Error(t, err) +} diff --git a/vendor/github.com/filecoin-project/go-address/bench_test.go b/vendor/github.com/filecoin-project/go-address/bench_test.go new file mode 100644 index 0000000000..2c21d549e9 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/bench_test.go @@ -0,0 +1,94 @@ +package address + +import ( + "fmt" + "math/rand" + + "testing" +) + +func blsaddr(n int64) Address { + buf := make([]byte, 48) + r := rand.New(rand.NewSource(n)) + r.Read(buf) + + addr, err := NewBLSAddress(buf) + if err != nil { + panic(err) // ok + } + + return addr +} + +func makeActorAddresses(n int) [][]byte { + var addrs [][]byte + for i := 0; i < n; i++ { + a, err := NewActorAddress([]byte(fmt.Sprintf("ACTOR ADDRESS %d", i))) + if err != nil { + panic(err) // ok + } + addrs = append(addrs, a.Bytes()) + } + + return addrs +} + +func makeBlsAddresses(n int64) [][]byte { + var addrs [][]byte + for i := int64(0); i < n; i++ { + addrs = append(addrs, blsaddr(n).Bytes()) + } + return addrs +} + +func makeSecpAddresses(n int) [][]byte { + var addrs [][]byte + for i := 0; i < n; i++ { + r := rand.New(rand.NewSource(int64(i))) + buf := make([]byte, 32) + r.Read(buf) + + a, err := NewSecp256k1Address(buf) + if err != nil { + panic(err) // ok + } + + addrs = append(addrs, a.Bytes()) + } + return addrs +} + +func makeIDAddresses(n int) [][]byte { + var addrs [][]byte + for i := 0; i < n; i++ { + + a, err := NewIDAddress(uint64(i)) + if err != nil { + panic(err) // ok + } + + addrs = append(addrs, a.Bytes()) + } + return addrs +} + +func BenchmarkParseActorAddress(b *testing.B) { + benchTestWithAddrs := func(a [][]byte) func(b *testing.B) { + return func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, err := NewFromBytes(a[i%len(a)]) + if err != nil { + b.Fatal(err) + } + } + } + } + + b.Run("actor", benchTestWithAddrs(makeActorAddresses(20))) + b.Run("bls", benchTestWithAddrs(makeBlsAddresses(20))) + b.Run("secp256k1", benchTestWithAddrs(makeSecpAddresses(20))) + b.Run("id", benchTestWithAddrs(makeIDAddresses(20))) +} diff --git a/vendor/github.com/filecoin-project/go-address/constants.go b/vendor/github.com/filecoin-project/go-address/constants.go new file mode 100644 index 0000000000..e3266df740 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/constants.go @@ -0,0 +1,71 @@ +package address + +import ( + "encoding/base32" + "errors" + + "github.com/minio/blake2b-simd" +) + +func init() { + + var err error + + TestAddress, err = NewActorAddress([]byte("satoshi")) + if err != nil { + panic(err) + } + + TestAddress2, err = NewActorAddress([]byte("nakamoto")) + if err != nil { + panic(err) + } +} + +var ( + // TestAddress is an account with some initial funds in it. + TestAddress Address + // TestAddress2 is an account with some initial funds in it. + TestAddress2 Address +) + +var ( + // ErrUnknownNetwork is returned when encountering an unknown network in an address. + ErrUnknownNetwork = errors.New("unknown address network") + + // ErrUnknownProtocol is returned when encountering an unknown protocol in an address. + ErrUnknownProtocol = errors.New("unknown address protocol") + // ErrInvalidPayload is returned when encountering an invalid address payload. + ErrInvalidPayload = errors.New("invalid address payload") + // ErrInvalidLength is returned when encountering an address of invalid length. + ErrInvalidLength = errors.New("invalid address length") + // ErrInvalidChecksum is returned when encountering an invalid address checksum. + ErrInvalidChecksum = errors.New("invalid address checksum") +) + +// UndefAddressString is the string used to represent an empty address when encoded to a string. +var UndefAddressString = "" + +// PayloadHashLength defines the hash length taken over addresses using the Actor and SECP256K1 protocols. +const PayloadHashLength = 20 + +// ChecksumHashLength defines the hash length used for calculating address checksums. +const ChecksumHashLength = 4 + +// MaxAddressStringLength is the max length of an address encoded as a string +// it include the network prefx, protocol, and bls publickey +const MaxAddressStringLength = 2 + 84 + +// BlsPublicKeyBytes is the length of a BLS public key +const BlsPublicKeyBytes = 48 + +// BlsPrivateKeyBytes is the length of a BLS private key +const BlsPrivateKeyBytes = 32 + +var payloadHashConfig = &blake2b.Config{Size: PayloadHashLength} +var checksumHashConfig = &blake2b.Config{Size: ChecksumHashLength} + +const encodeStd = "abcdefghijklmnopqrstuvwxyz234567" + +// AddressEncoding defines the base32 config used for address encoding and decoding. +var AddressEncoding = base32.NewEncoding(encodeStd) diff --git a/vendor/github.com/filecoin-project/go-address/go.mod b/vendor/github.com/filecoin-project/go-address/go.mod new file mode 100644 index 0000000000..133139973a --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/go.mod @@ -0,0 +1,14 @@ +module github.com/filecoin-project/go-address + +go 1.13 + +require ( + github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 + github.com/ipfs/go-ipld-cbor v0.0.3 + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/multiformats/go-varint v0.0.5 + github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 + github.com/stretchr/testify v1.4.0 + github.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +) diff --git a/vendor/github.com/filecoin-project/go-address/go.sum b/vendor/github.com/filecoin-project/go-address/go.sum new file mode 100644 index 0000000000..c09220bdfc --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/go.sum @@ -0,0 +1,98 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 h1:QN88Q0kT2QiDaLxpR/SDsqOBtNIEF/F3n96gSDUimkA= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.3 h1:ENsxvybwkmke7Z/QJOmeJfoguj6GH3Y0YOaGrfy9Q0I= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.2 h1:6sUvyh2YHpJCb8RZ6eYzj6iJQ4+chWYmyIHxszqlPTA= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 h1:CskT+S6Ay54OwxBGB0R3Rsx4Muto6UnEYTyKJbyRIAI= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0 h1:efb/4CnrubzNGqQOeHErxyQ6rIsJb7GcgeSDF7fqWeI= +github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756 h1:SSUF3WR9bHjHZBalytHBOAoOxJ9vdvTWUS6ztyRk3Qc= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/filecoin-project/go-address/testing.go b/vendor/github.com/filecoin-project/go-address/testing.go new file mode 100644 index 0000000000..9bc41376dc --- /dev/null +++ b/vendor/github.com/filecoin-project/go-address/testing.go @@ -0,0 +1,20 @@ +package address + +import ( + "fmt" +) + +// NewForTestGetter returns a closure that returns an address unique to that invocation. +// The address is unique wrt the closure returned, not globally. +func NewForTestGetter() func() Address { + i := 0 + return func() Address { + s := fmt.Sprintf("address%d", i) + i++ + newAddr, err := NewActorAddress([]byte(s)) + if err != nil { + panic(err) + } + return newAddr + } +} diff --git a/vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-APACHE b/vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-APACHE new file mode 100644 index 0000000000..14478a3b60 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-APACHE @@ -0,0 +1,5 @@ +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-MIT b/vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-MIT new file mode 100644 index 0000000000..72dc60d84b --- /dev/null +++ b/vendor/github.com/filecoin-project/go-amt-ipld/v2/LICENSE-MIT @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/filecoin-project/go-amt-ipld/v2/README.md b/vendor/github.com/filecoin-project/go-amt-ipld/v2/README.md new file mode 100644 index 0000000000..8472b00909 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-amt-ipld/v2/README.md @@ -0,0 +1,8 @@ +# go-amt-ipld + +> Array Mapped Trie (Persistent Vector) implementation using go-ipld + + +## License + +Dual MIT and Apache 2 diff --git a/vendor/github.com/filecoin-project/go-amt-ipld/v2/amt.go b/vendor/github.com/filecoin-project/go-amt-ipld/v2/amt.go new file mode 100644 index 0000000000..9cea1cb25e --- /dev/null +++ b/vendor/github.com/filecoin-project/go-amt-ipld/v2/amt.go @@ -0,0 +1,556 @@ +package amt + +import ( + "bytes" + "context" + "fmt" + "math/bits" + + cid "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + logging "github.com/ipfs/go-log" + cbg "github.com/whyrusleeping/cbor-gen" +) + +var log = logging.Logger("amt") + +const ( + // Width must be a power of 2. We set this to 8. + maxIndexBits = 63 + widthBits = 3 + width = 1 << widthBits // 8 + bitfieldSize = 1 // ((width - 1) >> 3) + 1 + maxHeight = maxIndexBits/widthBits - 1 // 20 (because the root is at height 0). +) + +// MaxIndex is the maximum index for elements in the AMT. This is currently 1^63 +// (max int) because the width is 8. That means every "level" consumes 3 bits +// from the index, and 63/3 is a nice even 21 +const MaxIndex = uint64(1< maxHeight { + return nil, fmt.Errorf("failed to load AMT: height out of bounds: %d > %d", r.Height, maxHeight) + } + + r.store = bs + + return &r, nil +} + +func (r *Root) Set(ctx context.Context, i uint64, val interface{}) error { + if i > MaxIndex { + return fmt.Errorf("index %d is out of range for the amt", i) + } + + var b []byte + if m, ok := val.(cbg.CBORMarshaler); ok { + buf := new(bytes.Buffer) + if err := m.MarshalCBOR(buf); err != nil { + return err + } + b = buf.Bytes() + } else { + var err error + b, err = cbor.DumpObject(val) + if err != nil { + return err + } + } + + for i >= nodesForHeight(int(r.Height)+1) { + if !r.Node.empty() { + if err := r.Node.Flush(ctx, r.store, int(r.Height)); err != nil { + return err + } + + c, err := r.store.Put(ctx, &r.Node) + if err != nil { + return err + } + + r.Node = Node{ + Bmap: [...]byte{0x01}, + Links: []cid.Cid{c}, + } + } + r.Height++ + } + + addVal, err := r.Node.set(ctx, r.store, int(r.Height), i, &cbg.Deferred{Raw: b}) + if err != nil { + return err + } + + if addVal { + r.Count++ + } + + return nil +} + +func FromArray(ctx context.Context, bs cbor.IpldStore, vals []cbg.CBORMarshaler) (cid.Cid, error) { + r := NewAMT(bs) + if err := r.BatchSet(ctx, vals); err != nil { + return cid.Undef, err + } + + return r.Flush(ctx) +} + +func (r *Root) BatchSet(ctx context.Context, vals []cbg.CBORMarshaler) error { + // TODO: there are more optimized ways of doing this method + for i, v := range vals { + if err := r.Set(ctx, uint64(i), v); err != nil { + return err + } + } + return nil +} + +func (r *Root) Get(ctx context.Context, i uint64, out interface{}) error { + if i > MaxIndex { + return fmt.Errorf("index %d is out of range for the amt", i) + } + + if i >= nodesForHeight(int(r.Height+1)) { + return &ErrNotFound{Index: i} + } + return r.Node.get(ctx, r.store, int(r.Height), i, out) +} + +func (n *Node) get(ctx context.Context, bs cbor.IpldStore, height int, i uint64, out interface{}) error { + subi := i / nodesForHeight(height) + set, _ := n.getBit(subi) + if !set { + return &ErrNotFound{i} + } + if height == 0 { + n.expandValues() + + d := n.expVals[i] + + if um, ok := out.(cbg.CBORUnmarshaler); ok { + return um.UnmarshalCBOR(bytes.NewReader(d.Raw)) + } else { + return cbor.DecodeInto(d.Raw, out) + } + } + + subn, err := n.loadNode(ctx, bs, subi, false) + if err != nil { + return err + } + + return subn.get(ctx, bs, height-1, i%nodesForHeight(height), out) +} + +func (r *Root) BatchDelete(ctx context.Context, indices []uint64) error { + // TODO: theres a faster way of doing this, but this works for now + for _, i := range indices { + if err := r.Delete(ctx, i); err != nil { + return err + } + } + + return nil +} + +func (r *Root) Delete(ctx context.Context, i uint64) error { + if i > MaxIndex { + return fmt.Errorf("index %d is out of range for the amt", i) + } + //fmt.Printf("i: %d, h: %d, nfh: %d\n", i, r.Height, nodesForHeight(int(r.Height))) + if i >= nodesForHeight(int(r.Height+1)) { + return &ErrNotFound{i} + } + + if err := r.Node.delete(ctx, r.store, int(r.Height), i); err != nil { + return err + } + r.Count-- + + for r.Node.Bmap[0] == 1 && r.Height > 0 { + sub, err := r.Node.loadNode(ctx, r.store, 0, false) + if err != nil { + return err + } + + r.Node = *sub + r.Height-- + } + + return nil +} + +func (n *Node) delete(ctx context.Context, bs cbor.IpldStore, height int, i uint64) error { + subi := i / nodesForHeight(height) + set, _ := n.getBit(subi) + if !set { + return &ErrNotFound{i} + } + if height == 0 { + n.expandValues() + + n.expVals[i] = nil + n.clearBit(i) + + return nil + } + + subn, err := n.loadNode(ctx, bs, subi, false) + if err != nil { + return err + } + + if err := subn.delete(ctx, bs, height-1, i%nodesForHeight(height)); err != nil { + return err + } + + if subn.empty() { + n.clearBit(subi) + n.cache[subi] = nil + n.expLinks[subi] = cid.Undef + } + + return nil +} + +// Subtract removes all elements of 'or' from 'r' +func (r *Root) Subtract(ctx context.Context, or *Root) error { + // TODO: as with other methods, there should be an optimized way of doing this + return or.ForEach(ctx, func(i uint64, _ *cbg.Deferred) error { + return r.Delete(ctx, i) + }) +} + +func (r *Root) ForEach(ctx context.Context, cb func(uint64, *cbg.Deferred) error) error { + return r.Node.forEachAt(ctx, r.store, int(r.Height), 0, 0, cb) +} + +func (r *Root) ForEachAt(ctx context.Context, start uint64, cb func(uint64, *cbg.Deferred) error) error { + return r.Node.forEachAt(ctx, r.store, int(r.Height), start, 0, cb) +} + +func (n *Node) forEachAt(ctx context.Context, bs cbor.IpldStore, height int, start, offset uint64, cb func(uint64, *cbg.Deferred) error) error { + if height == 0 { + n.expandValues() + + for i, v := range n.expVals { + if v != nil { + ix := offset + uint64(i) + if ix < start { + continue + } + + if err := cb(offset+uint64(i), v); err != nil { + return err + } + } + } + + return nil + } + + if n.cache == nil { + n.expandLinks() + } + + subCount := nodesForHeight(height) + for i, v := range n.expLinks { + var sub Node + if n.cache[i] != nil { + sub = *n.cache[i] + } else if v != cid.Undef { + if err := bs.Get(ctx, v, &sub); err != nil { + return err + } + } else { + continue + } + + offs := offset + (uint64(i) * subCount) + nextOffs := offs + subCount + if start >= nextOffs { + continue + } + + if err := sub.forEachAt(ctx, bs, height-1, start, offs, cb); err != nil { + return err + } + } + return nil + +} + +func (r *Root) FirstSetIndex(ctx context.Context) (uint64, error) { + return r.Node.firstSetIndex(ctx, r.store, int(r.Height)) +} + +var errNoVals = fmt.Errorf("no values") + +func (n *Node) firstSetIndex(ctx context.Context, bs cbor.IpldStore, height int) (uint64, error) { + if height == 0 { + n.expandValues() + for i, v := range n.expVals { + if v != nil { + return uint64(i), nil + } + } + // Would be really weird if we ever actually hit this + return 0, errNoVals + } + + if n.cache == nil { + n.expandLinks() + } + + for i := 0; i < width; i++ { + ok, _ := n.getBit(uint64(i)) + if ok { + subn, err := n.loadNode(ctx, bs, uint64(i), false) + if err != nil { + return 0, err + } + + ix, err := subn.firstSetIndex(ctx, bs, height-1) + if err != nil { + return 0, err + } + + subCount := nodesForHeight(height) + return ix + (uint64(i) * subCount), nil + } + } + + return 0, errNoVals +} + +func (n *Node) expandValues() { + if len(n.expVals) == 0 { + n.expVals = make([]*cbg.Deferred, width) + for x := uint64(0); x < width; x++ { + set, ix := n.getBit(x) + if set { + n.expVals[x] = n.Values[ix] + } + } + } +} + +func (n *Node) set(ctx context.Context, bs cbor.IpldStore, height int, i uint64, val *cbg.Deferred) (bool, error) { + //nfh := nodesForHeight(height) + //fmt.Printf("[set] h: %d, i: %d, subi: %d\n", height, i, i/nfh) + if height == 0 { + n.expandValues() + alreadySet, _ := n.getBit(i) + n.expVals[i] = val + n.setBit(i) + + return !alreadySet, nil + } + + nfh := nodesForHeight(height) + + subn, err := n.loadNode(ctx, bs, i/nfh, true) + if err != nil { + return false, err + } + + return subn.set(ctx, bs, height-1, i%nfh, val) +} + +func (n *Node) getBit(i uint64) (bool, int) { + if i > 7 { + panic("cant deal with wider arrays yet") + } + + if len(n.Bmap) == 0 { + return false, 0 + } + + if n.Bmap[0]&byte(1< 7 { + panic("cant deal with wider arrays yet") + } + + if len(n.Bmap) == 0 { + n.Bmap = [...]byte{0} + } + + n.Bmap[0] = n.Bmap[0] | byte(1< 7 { + panic("cant deal with wider arrays yet") + } + + if len(n.Bmap) == 0 { + panic("invariant violated: called clear bit on empty node") + } + + mask := byte(0xff - (1 << i)) + + n.Bmap[0] = n.Bmap[0] & mask +} + +func (n *Node) expandLinks() { + n.cache = make([]*Node, width) + n.expLinks = make([]cid.Cid, width) + for x := uint64(0); x < width; x++ { + set, ix := n.getBit(x) + if set { + n.expLinks[x] = n.Links[ix] + } + } +} + +func (n *Node) loadNode(ctx context.Context, bs cbor.IpldStore, i uint64, create bool) (*Node, error) { + if n.cache == nil { + n.expandLinks() + } else { + if n := n.cache[i]; n != nil { + return n, nil + } + } + + set, _ := n.getBit(i) + + var subn *Node + if set { + var sn Node + if err := bs.Get(ctx, n.expLinks[i], &sn); err != nil { + return nil, err + } + + subn = &sn + } else { + if create { + subn = &Node{} + n.setBit(i) + } else { + return nil, fmt.Errorf("no node found at (sub)index %d", i) + } + } + n.cache[i] = subn + + return subn, nil +} + +func nodesForHeight(height int) uint64 { + heightLogTwo := uint64(widthBits * height) + if heightLogTwo >= 64 { + // Should never happen. Max height is checked at all entry points. + panic("height overflow") + } + return 1 << heightLogTwo +} + +func (r *Root) Flush(ctx context.Context) (cid.Cid, error) { + if err := r.Node.Flush(ctx, r.store, int(r.Height)); err != nil { + return cid.Undef, err + } + + return r.store.Put(ctx, r) +} + +func (n *Node) empty() bool { + return len(n.Bmap) == 0 || n.Bmap[0] == 0 +} + +func (n *Node) Flush(ctx context.Context, bs cbor.IpldStore, depth int) error { + if depth == 0 { + if len(n.expVals) == 0 { + return nil + } + n.Values = nil + for i := uint64(0); i < width; i++ { + v := n.expVals[i] + if v != nil { + n.Values = append(n.Values, v) + n.setBit(i) + } + } + return nil + } + + if len(n.expLinks) == 0 { + // nothing to do! + return nil + } + + n.Bmap = [...]byte{0} + n.Links = nil + + for i := uint64(0); i < width; i++ { + subn := n.cache[i] + if subn != nil { + if err := subn.Flush(ctx, bs, depth-1); err != nil { + return err + } + + c, err := bs.Put(ctx, subn) + if err != nil { + return err + } + n.expLinks[i] = c + } + + l := n.expLinks[i] + if l != cid.Undef { + n.Links = append(n.Links, l) + n.setBit(i) + } + } + + return nil +} + +type ErrNotFound struct { + Index uint64 +} + +func (e ErrNotFound) Error() string { + return fmt.Sprintf("Index %d not found in AMT", e.Index) +} + +func (e ErrNotFound) NotFound() bool { + return true +} diff --git a/vendor/github.com/filecoin-project/go-amt-ipld/v2/cbor_gen.go b/vendor/github.com/filecoin-project/go-amt-ipld/v2/cbor_gen.go new file mode 100644 index 0000000000..f316beedbe --- /dev/null +++ b/vendor/github.com/filecoin-project/go-amt-ipld/v2/cbor_gen.go @@ -0,0 +1,261 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package amt + +import ( + "fmt" + "io" + + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +var lengthBufRoot = []byte{131} + +func (t *Root) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufRoot); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Height (uint64) (uint64) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Height)); err != nil { + return err + } + + // t.Count (uint64) (uint64) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Count)); err != nil { + return err + } + + // t.Node (amt.Node) (struct) + if err := t.Node.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *Root) UnmarshalCBOR(r io.Reader) error { + *t = Root{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Height (uint64) (uint64) + + { + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Height = uint64(extra) + + } + // t.Count (uint64) (uint64) + + { + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Count = uint64(extra) + + } + // t.Node (amt.Node) (struct) + + { + + if err := t.Node.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Node: %w", err) + } + + } + return nil +} + +var lengthBufNode = []byte{131} + +func (t *Node) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufNode); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Bmap ([1]uint8) (array) + if len(t.Bmap) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Bmap was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Bmap))); err != nil { + return err + } + + if _, err := w.Write(t.Bmap[:]); err != nil { + return err + } + + // t.Links ([]cid.Cid) (slice) + if len(t.Links) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Links was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Links))); err != nil { + return err + } + for _, v := range t.Links { + if err := cbg.WriteCidBuf(scratch, w, v); err != nil { + return xerrors.Errorf("failed writing cid field t.Links: %w", err) + } + } + + // t.Values ([]*typegen.Deferred) (slice) + if len(t.Values) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Values was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Values))); err != nil { + return err + } + for _, v := range t.Values { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *Node) UnmarshalCBOR(r io.Reader) error { + *t = Node{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Bmap ([1]uint8) (array) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Bmap: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra != 1 { + return fmt.Errorf("expected array to have 1 elements") + } + + t.Bmap = [1]uint8{} + + if _, err := io.ReadFull(br, t.Bmap[:]); err != nil { + return err + } + // t.Links ([]cid.Cid) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Links: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Links = make([]cid.Cid, extra) + } + + for i := 0; i < int(extra); i++ { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("reading cid field t.Links failed: %w", err) + } + t.Links[i] = c + } + + // t.Values ([]*typegen.Deferred) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Values: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Values = make([]*cbg.Deferred, extra) + } + + for i := 0; i < int(extra); i++ { + + var v cbg.Deferred + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Values[i] = &v + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/go-amt-ipld/v2/go.mod b/vendor/github.com/filecoin-project/go-amt-ipld/v2/go.mod new file mode 100644 index 0000000000..2b36bc7959 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-amt-ipld/v2/go.mod @@ -0,0 +1,13 @@ +module github.com/filecoin-project/go-amt-ipld/v2 + +go 1.12 + +require ( + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-cid v0.0.6 + github.com/ipfs/go-ipld-cbor v0.0.4 + github.com/ipfs/go-log v1.0.4 + github.com/stretchr/testify v1.6.1 + github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +) diff --git a/vendor/github.com/filecoin-project/go-amt-ipld/v2/go.sum b/vendor/github.com/filecoin-project/go-amt-ipld/v2/go.sum new file mode 100644 index 0000000000..ebb6eabab7 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-amt-ipld/v2/go.sum @@ -0,0 +1,143 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.6 h1:go0y+GcDOGeJIV01FeBsta4FHngoA4Wz7KMeLkXAhMs= +github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.4 h1:Aw3KPOKXjvrm6VjwJvFf1F1ekR/BH3jdof3Bk7OTiSA= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= +github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log/v2 v2.0.5 h1:fL4YI+1g5V/b1Yxr1qAiXTMg1H8z9vx/VmJxBuQMHvU= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= +github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= +github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377 h1:LHFlP/ktDvOnCap7PsT87cs7Gwd0p+qv6Qm5g2ZPR+I= +github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/filecoin-project/go-bitfield/.github/workflows/go.yml b/vendor/github.com/filecoin-project/go-bitfield/.github/workflows/go.yml new file mode 100644 index 0000000000..2208ea2a52 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/.github/workflows/go.yml @@ -0,0 +1,35 @@ +name: Go + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + + build: + name: Build + runs-on: ubuntu-latest + steps: + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.14 + id: go + - uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Build + run: go build -v . + + - name: Test + run: go test -v . diff --git a/vendor/github.com/filecoin-project/go-bitfield/LICENSE-APACHE b/vendor/github.com/filecoin-project/go-bitfield/LICENSE-APACHE new file mode 100644 index 0000000000..14478a3b60 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/LICENSE-APACHE @@ -0,0 +1,5 @@ +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/vendor/github.com/filecoin-project/go-bitfield/LICENSE-MIT b/vendor/github.com/filecoin-project/go-bitfield/LICENSE-MIT new file mode 100644 index 0000000000..72dc60d84b --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/LICENSE-MIT @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/filecoin-project/go-bitfield/README.md b/vendor/github.com/filecoin-project/go-bitfield/README.md new file mode 100644 index 0000000000..8c23252b2e --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/README.md @@ -0,0 +1,14 @@ +# go-bitfield + +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![CircleCI](https://circleci.com/gh/filecoin-project/go-bitfield.svg?style=svg)](https://circleci.com/gh/filecoin-project/go-bitfield) +[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) + +> Advanced RLE+ implementation + +## License + +The Filecoin Project is dual-licensed under Apache 2.0 and MIT terms: + +- Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/filecoin-project/go-bitfield/blob/master/LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](https://github.com/filecoin-project/go-bitfield/blob/master/LICENSE-MIT) or http://opensource.org/licenses/MIT) diff --git a/vendor/github.com/filecoin-project/go-bitfield/bitfield.go b/vendor/github.com/filecoin-project/go-bitfield/bitfield.go new file mode 100644 index 0000000000..7d1ca9b5a0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/bitfield.go @@ -0,0 +1,668 @@ +package bitfield + +import ( + "errors" + "fmt" + "io" + + rlepluslazy "github.com/filecoin-project/go-bitfield/rle" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" +) + +var ( + ErrBitFieldTooMany = errors.New("to many items in RLE") + ErrNoBitsSet = errors.New("bitfield has no set bits") +) + +type BitField struct { + rle rlepluslazy.RLE + + set map[uint64]struct{} + unset map[uint64]struct{} +} + +// New constructs a new BitField. +func New() BitField { + bf, err := NewFromBytes([]byte{}) + if err != nil { + panic(fmt.Sprintf("creating empty rle: %+v", err)) + } + return bf +} + +// NewFromBytes deserializes the encoded bitfield. +func NewFromBytes(rle []byte) (BitField, error) { + bf := BitField{} + rlep, err := rlepluslazy.FromBuf(rle) + if err != nil { + return BitField{}, xerrors.Errorf("could not decode rle+: %w", err) + } + bf.rle = rlep + bf.set = make(map[uint64]struct{}) + bf.unset = make(map[uint64]struct{}) + return bf, nil + +} + +func newWithRle(rle rlepluslazy.RLE) *BitField { + return &BitField{ + set: make(map[uint64]struct{}), + unset: make(map[uint64]struct{}), + rle: rle, + } +} + +// NewFromSet constructs a bitfield from the given set. +func NewFromSet(setBits []uint64) *BitField { + res := &BitField{ + set: make(map[uint64]struct{}, len(setBits)), + unset: make(map[uint64]struct{}), + } + for _, b := range setBits { + res.set[b] = struct{}{} + } + return res +} + +// NewFromIter constructs a BitField from the RunIterator. +func NewFromIter(r rlepluslazy.RunIterator) (*BitField, error) { + buf, err := rlepluslazy.EncodeRuns(r, nil) + if err != nil { + return nil, err + } + + rle, err := rlepluslazy.FromBuf(buf) + if err != nil { + return nil, err + } + + return newWithRle(rle), nil +} + +// MergeBitFields returns the union of the two BitFields. +// +// For example, given two BitFields: +// +// 0 1 1 0 1 +// 1 1 0 1 0 +// +// MergeBitFields would return +// +// 1 1 1 1 1 +// +// This operation's runtime is O(number of runs). +func MergeBitFields(a, b *BitField) (*BitField, error) { + ra, err := a.RunIterator() + if err != nil { + return nil, err + } + + rb, err := b.RunIterator() + if err != nil { + return nil, err + } + + merge, err := rlepluslazy.Or(ra, rb) + if err != nil { + return nil, err + } + + mergebytes, err := rlepluslazy.EncodeRuns(merge, nil) + if err != nil { + return nil, err + } + + rle, err := rlepluslazy.FromBuf(mergebytes) + if err != nil { + return nil, err + } + + return newWithRle(rle), nil +} + +// MultiMerge returns the unions of all the passed BitFields. +// +// Calling MultiMerge is identical to calling MergeBitFields repeatedly, just +// more efficient when merging more than two BitFields. +// +// This operation's runtime is O(number of runs * number of bitfields). +func MultiMerge(bfs ...*BitField) (*BitField, error) { + if len(bfs) == 0 { + return NewFromSet(nil), nil + } + + iters := make([]rlepluslazy.RunIterator, 0, len(bfs)) + for _, bf := range bfs { + iter, err := bf.RunIterator() + if err != nil { + return nil, err + } + iters = append(iters, iter) + } + + iter, err := rlepluslazy.Union(iters...) + if err != nil { + return nil, err + } + return NewFromIter(iter) +} + +func (bf *BitField) RunIterator() (rlepluslazy.RunIterator, error) { + iter, err := bf.rle.RunIterator() + if err != nil { + return nil, err + } + if len(bf.set) > 0 { + slc := make([]uint64, 0, len(bf.set)) + for b := range bf.set { + slc = append(slc, b) + } + set, err := rlepluslazy.RunsFromSlice(slc) + if err != nil { + return nil, err + } + newIter, err := rlepluslazy.Or(iter, set) + if err != nil { + return nil, err + } + iter = newIter + } + if len(bf.unset) > 0 { + slc := make([]uint64, 0, len(bf.unset)) + for b := range bf.unset { + slc = append(slc, b) + } + + unset, err := rlepluslazy.RunsFromSlice(slc) + if err != nil { + return nil, err + } + newIter, err := rlepluslazy.Subtract(iter, unset) + if err != nil { + return nil, err + } + iter = newIter + } + return iter, nil +} + +// Set sets the given bit in the BitField +// +// This operation's runtime is O(1) up-front. However, it adds an O(bits +// explicitly set) cost to all other operations. +func (bf *BitField) Set(bit uint64) { + delete(bf.unset, bit) + bf.set[bit] = struct{}{} +} + +// Unset unsets given bit in the BitField +// +// This operation's runtime is O(1). However, it adds an O(bits +// explicitly unset) cost to all other operations. +func (bf *BitField) Unset(bit uint64) { + delete(bf.set, bit) + bf.unset[bit] = struct{}{} +} + +// Count counts the non-zero bits in the bitfield. +// +// For example, given: +// +// 1 0 1 1 +// +// Count() will return 3. +// +// This operation's runtime is O(number of runs). +func (bf *BitField) Count() (uint64, error) { + s, err := bf.RunIterator() + if err != nil { + return 0, err + } + return rlepluslazy.Count(s) +} + +// All returns a slice of set bits in sorted order. +// +// For example, given: +// +// 1 0 0 1 +// +// All will return: +// +// []uint64{0, 3} +// +// This operation's runtime is O(number of bits). +func (bf *BitField) All(max uint64) ([]uint64, error) { + c, err := bf.Count() + if err != nil { + return nil, xerrors.Errorf("count errror: %w", err) + } + if c > max { + return nil, xerrors.Errorf("expected %d, got %d: %w", max, c, ErrBitFieldTooMany) + } + + runs, err := bf.RunIterator() + if err != nil { + return nil, err + } + + res, err := rlepluslazy.SliceFromRuns(runs) + if err != nil { + return nil, err + } + + return res, nil +} + +// AllMap returns a map of all set bits. +// +// For example, given: +// +// 1 0 0 1 +// +// All will return: +// +// map[uint64]bool{0: true, 3: true} +// +// This operation's runtime is O(number of bits). +func (bf *BitField) AllMap(max uint64) (map[uint64]bool, error) { + c, err := bf.Count() + if err != nil { + return nil, xerrors.Errorf("count errror: %w", err) + } + if c > max { + return nil, xerrors.Errorf("expected %d, got %d: %w", max, c, ErrBitFieldTooMany) + } + + runs, err := bf.RunIterator() + if err != nil { + return nil, err + } + + res, err := rlepluslazy.SliceFromRuns(runs) + if err != nil { + return nil, err + } + + out := make(map[uint64]bool, len(res)) + for _, i := range res { + out[i] = true + } + return out, nil +} + +func (bf *BitField) MarshalCBOR(w io.Writer) error { + if bf == nil { + _, err := w.Write(cbg.CborNull) + return err + } + s, err := bf.RunIterator() + if err != nil { + return err + } + + rle, err := rlepluslazy.EncodeRuns(s, []byte{}) + if err != nil { + return err + } + + if len(rle) > 8192 { + return xerrors.Errorf("encoded bitfield was too large (%d)", len(rle)) + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(rle)))); err != nil { + return err + } + if _, err = w.Write(rle); err != nil { + return xerrors.Errorf("writing rle: %w", err) + } + return nil +} + +func (bf *BitField) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("array too large") + } + + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + buf := make([]byte, extra) + if _, err := io.ReadFull(br, buf); err != nil { + return err + } + + rle, err := rlepluslazy.FromBuf(buf) + if err != nil { + return xerrors.Errorf("could not decode rle+: %w", err) + } + bf.rle = rle + bf.set = make(map[uint64]struct{}) + bf.unset = make(map[uint64]struct{}) + + return nil +} + +func (bf *BitField) MarshalJSON() ([]byte, error) { + + c, err := bf.Copy() + if err != nil { + return nil, err + } + + return c.rle.MarshalJSON() +} + +func (bf *BitField) UnmarshalJSON(b []byte) error { + + err := bf.rle.UnmarshalJSON(b) + if err != nil { + return err + } + bf.set = make(map[uint64]struct{}) + bf.unset = make(map[uint64]struct{}) + return nil +} + +// ForEach iterates over each set bit. +// +// This operation's runtime is O(bits set). +func (bf *BitField) ForEach(f func(uint64) error) error { + iter, err := bf.RunIterator() + if err != nil { + return err + } + + var i uint64 + for iter.HasNext() { + r, err := iter.NextRun() + if err != nil { + return err + } + + if r.Val { + for j := uint64(0); j < r.Len; j++ { + if err := f(i); err != nil { + return err + } + i++ + } + } else { + i += r.Len + } + } + return nil +} + +// IsSet returns true if the given bit is set. +// +// This operation's runtime is O(number of runs). +func (bf *BitField) IsSet(x uint64) (bool, error) { + if _, ok := bf.set[x]; ok { + return true, nil + } + + if _, ok := bf.unset[x]; ok { + return false, nil + } + + iter, err := bf.rle.RunIterator() + if err != nil { + return false, err + } + + return rlepluslazy.IsSet(iter, x) +} + +// First returns the index of the first set bit. This function returns +// ErrNoBitsSet when no bits have been set. +// +// This operation's runtime is O(1). +func (bf *BitField) First() (uint64, error) { + iter, err := bf.RunIterator() + if err != nil { + return 0, err + } + + var i uint64 + for iter.HasNext() { + r, err := iter.NextRun() + if err != nil { + return 0, err + } + + if r.Val { + return i, nil + } else { + i += r.Len + } + } + return 0, ErrNoBitsSet +} + +// IsEmpty returns true if the bitset is empty. +// +// This operation's runtime is O(1). +func (bf *BitField) IsEmpty() (bool, error) { + _, err := bf.First() + switch err { + case ErrNoBitsSet: + return true, nil + case nil: + return false, nil + default: + return false, err + } +} + +// Slice treats the BitField as an ordered set of set bits, then slices this set. +// +// That is, it skips start set bits, then returns the next count set bits. +// +// For example, given: +// +// 1 0 1 1 0 1 1 +// +// bf.Slice(2, 2) would return: +// +// 0 0 0 1 0 1 0 +// +// This operation's runtime is O(number of runs). +func (bf *BitField) Slice(start, count uint64) (*BitField, error) { + iter, err := bf.RunIterator() + if err != nil { + return nil, err + } + + valsUntilStart := start + + var sliceRuns []rlepluslazy.Run + var i, outcount uint64 + for iter.HasNext() && valsUntilStart > 0 { + r, err := iter.NextRun() + if err != nil { + return nil, err + } + + if r.Val { + if r.Len <= valsUntilStart { + valsUntilStart -= r.Len + i += r.Len + } else { + i += valsUntilStart + + rem := r.Len - valsUntilStart + if rem > count { + rem = count + } + + sliceRuns = append(sliceRuns, + rlepluslazy.Run{Val: false, Len: i}, + rlepluslazy.Run{Val: true, Len: rem}, + ) + outcount += rem + valsUntilStart = 0 + } + } else { + i += r.Len + } + } + + for iter.HasNext() && outcount < count { + r, err := iter.NextRun() + if err != nil { + return nil, err + } + + if r.Val { + if r.Len <= count-outcount { + sliceRuns = append(sliceRuns, r) + outcount += r.Len + } else { + sliceRuns = append(sliceRuns, rlepluslazy.Run{Val: true, Len: count - outcount}) + outcount = count + } + } else { + if len(sliceRuns) == 0 { + r.Len += i + } + sliceRuns = append(sliceRuns, r) + } + } + if outcount < count { + return nil, fmt.Errorf("not enough bits set in field to satisfy slice count") + } + + buf, err := rlepluslazy.EncodeRuns(&rlepluslazy.RunSliceIterator{Runs: sliceRuns}, nil) + if err != nil { + return nil, err + } + + rle, err := rlepluslazy.FromBuf(buf) + if err != nil { + return nil, err + } + + return &BitField{rle: rle}, nil +} + +// IntersectBitField returns the intersection of the two BitFields. +// +// For example, given two BitFields: +// +// 0 1 1 0 1 +// 1 1 0 1 0 +// +// IntersectBitField would return +// +// 0 1 0 0 0 +// +// This operation's runtime is O(number of runs). +func IntersectBitField(a, b *BitField) (*BitField, error) { + ar, err := a.RunIterator() + if err != nil { + return nil, err + } + + br, err := b.RunIterator() + if err != nil { + return nil, err + } + + andIter, err := rlepluslazy.And(ar, br) + if err != nil { + return nil, err + } + + buf, err := rlepluslazy.EncodeRuns(andIter, nil) + if err != nil { + return nil, err + } + + rle, err := rlepluslazy.FromBuf(buf) + if err != nil { + return nil, err + } + + return newWithRle(rle), nil +} + +// SubtractBitField returns the difference between the two BitFields. That is, +// it returns a bitfield of all bits set in a but not set in b. +// +// For example, given two BitFields: +// +// 0 1 1 0 1 // a +// 1 1 0 1 0 // b +// +// SubtractBitFields would return +// +// 0 0 1 0 1 +// +// This operation's runtime is O(number of runs). +func SubtractBitField(a, b *BitField) (*BitField, error) { + ar, err := a.RunIterator() + if err != nil { + return nil, err + } + + br, err := b.RunIterator() + if err != nil { + return nil, err + } + + andIter, err := rlepluslazy.Subtract(ar, br) + if err != nil { + return nil, err + } + + buf, err := rlepluslazy.EncodeRuns(andIter, nil) + if err != nil { + return nil, err + } + + rle, err := rlepluslazy.FromBuf(buf) + if err != nil { + return nil, err + } + + return newWithRle(rle), nil +} + +// Copy flushes the bitfield and returns a copy that can be mutated +// without changing the original values +func (bf *BitField) Copy() (*BitField, error) { + r, err := bf.RunIterator() + if err != nil { + return nil, err + } + + buf, err := rlepluslazy.EncodeRuns(r, nil) + if err != nil { + return nil, err + } + + rle, err := rlepluslazy.FromBuf(buf) + if err != nil { + return nil, err + } + + return newWithRle(rle), nil +} + +// BitIterator iterates over the bits in the bitmap +func (bf *BitField) BitIterator() (rlepluslazy.BitIterator, error) { + r, err := bf.RunIterator() + if err != nil { + return nil, err + } + return rlepluslazy.BitsFromRuns(r) +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/bitfield_benchmark_test.go b/vendor/github.com/filecoin-project/go-bitfield/bitfield_benchmark_test.go new file mode 100644 index 0000000000..0e29230394 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/bitfield_benchmark_test.go @@ -0,0 +1,66 @@ +package bitfield + +import ( + "fmt" + "testing" +) + +func benchmark(b *testing.B, cb func(b *testing.B, bf *BitField)) { + for _, size := range []int{ + 0, + 1, + 10, + 1000, + 1000000, + } { + benchmarkSize(b, size, cb) + } +} + +func benchmarkSize(b *testing.B, size int, cb func(b *testing.B, bf *BitField)) { + b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { + vals := getRandIndexSet(size) + bf := NewFromSet(vals) + b.Run("basic", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cb(b, bf) + } + }) + + if size < 1 { + return + } + + // Set and unset some bits + i := uint64(size / 10) + bf.Set(i) + bf.Set(i + 1) + bf.Set(i * 2) + bf.Unset(i / 2) + bf.Unset(uint64(size) - 1) + + b.Run("modified", func(b *testing.B) { + for i := 0; i < b.N; i++ { + cb(b, bf) + } + }) + }) +} + +func BenchmarkCount(b *testing.B) { + benchmark(b, func(b *testing.B, bf *BitField) { + _, err := bf.Count() + if err != nil { + b.Fatal(err) + } + }) +} + +func BenchmarkIsEmpty(b *testing.B) { + benchmark(b, func(b *testing.B, bf *BitField) { + _, err := bf.IsEmpty() + if err != nil { + b.Fatal(err) + } + }) +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/bitfield_test.go b/vendor/github.com/filecoin-project/go-bitfield/bitfield_test.go new file mode 100644 index 0000000000..63eb044093 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/bitfield_test.go @@ -0,0 +1,522 @@ +package bitfield + +import ( + "encoding/json" + "fmt" + "math/rand" + "sort" + "testing" + + rlepluslazy "github.com/filecoin-project/go-bitfield/rle" +) + +func slicesEqual(a, b []uint64) bool { + if len(a) != len(b) { + return false + } + + for i, v := range a { + if b[i] != v { + return false + } + } + return true +} + +func getRandIndexSet(n int) []uint64 { + return getRandIndexSetSeed(n, 55) +} + +func getRandIndexSetSeed(n int, seed int64) []uint64 { + r := rand.New(rand.NewSource(seed)) + + var items []uint64 + for i := 0; i < n; i++ { + if r.Intn(3) != 0 { + items = append(items, uint64(i)) + } + } + return items +} + +func TestBitfieldSlice(t *testing.T) { + vals := getRandIndexSet(10000) + + bf := NewFromSet(vals) + + sl, err := bf.Slice(600, 500) + if err != nil { + t.Fatal(err) + } + + expslice := vals[600:1100] + + outvals, err := sl.All(10000) + if err != nil { + t.Fatal(err) + } + + if !slicesEqual(expslice, outvals) { + fmt.Println(expslice) + fmt.Println(outvals) + t.Fatal("output slice was not correct") + } +} + +func TestBitfieldSliceSmall(t *testing.T) { + vals := []uint64{1, 5, 6, 7, 10, 11, 12, 15} + + testPerm := func(start, count uint64) func(*testing.T) { + return func(t *testing.T) { + + bf := NewFromSet(vals) + + sl, err := bf.Slice(start, count) + if err != nil { + t.Fatal(err) + } + + expslice := vals[start : start+count] + + outvals, err := sl.All(10000) + if err != nil { + t.Fatal(err) + } + + if !slicesEqual(expslice, outvals) { + fmt.Println(expslice) + fmt.Println(outvals) + t.Fatal("output slice was not correct") + } + } + } + + /* + t.Run("all", testPerm(0, 8)) + t.Run("not first", testPerm(1, 7)) + t.Run("last item", testPerm(7, 1)) + t.Run("start during gap", testPerm(1, 4)) + t.Run("start during run", testPerm(3, 4)) + t.Run("end during run", testPerm(1, 1)) + */ + + for i := 0; i < len(vals); i++ { + for j := 0; j < len(vals)-i; j++ { + t.Run(fmt.Sprintf("comb-%d-%d", i, j), testPerm(uint64(i), uint64(j))) + } + } +} + +func unionArrs(a, b []uint64) []uint64 { + m := make(map[uint64]bool) + for _, v := range a { + m[v] = true + } + for _, v := range b { + m[v] = true + } + + out := make([]uint64, 0, len(m)) + for v := range m { + out = append(out, v) + } + + sort.Slice(out, func(i, j int) bool { + return out[i] < out[j] + }) + + return out +} + +func TestBitfieldUnion(t *testing.T) { + a := getRandIndexSetSeed(100, 1) + b := getRandIndexSetSeed(100, 2) + + bfa := NewFromSet(a) + bfb := NewFromSet(b) + + bfu, err := MergeBitFields(bfa, bfb) + if err != nil { + t.Fatal(err) + } + + out, err := bfu.All(100000) + if err != nil { + t.Fatal(err) + } + + exp := unionArrs(a, b) + + if !slicesEqual(out, exp) { + fmt.Println(out) + fmt.Println(exp) + t.Fatal("union was wrong") + } +} + +func multiUnionArrs(arrs [][]uint64) []uint64 { + base := arrs[0] + for i := 1; i < len(arrs); i++ { + base = unionArrs(base, arrs[i]) + } + return base +} + +func TestBitfieldMultiUnion(t *testing.T) { + var sets [][]uint64 + var bfs []*BitField + for i := 0; i < 15; i++ { + s := getRandIndexSetSeed(10000, 1) + sets = append(sets, s) + bfs = append(bfs, NewFromSet(s)) + } + + bfu, err := MultiMerge(bfs...) + if err != nil { + t.Fatal(err) + } + + out, err := bfu.All(100000) + if err != nil { + t.Fatal(err) + } + + exp := multiUnionArrs(sets) + + if !slicesEqual(out, exp) { + fmt.Println(out) + fmt.Println(exp) + t.Fatal("union was wrong") + } +} + +func TestBitfieldJson(t *testing.T) { + vals := []uint64{1, 5, 6, 7, 10, 11, 12, 15} + + bf := NewFromSet(vals) + + b, err := bf.MarshalJSON() + if err != nil { + t.Fatal(err) + } + + var buf []uint64 + if err := json.Unmarshal(b, &buf); err != nil { + t.Fatal(err) + } + + // (0) (1) (2, 3, 4), (5, 6, 7), (8, 9), (10, 11, 12), (13, 14), 15 + runs := []uint64{1, 1, 3, 3, 2, 3, 2, 1} + if !slicesEqual(runs, buf) { + t.Fatal("runs not encoded correctly") + } +} + +func TestEmptyBitfieldJson(t *testing.T) { + type ct struct { + B *BitField + } + + ebf := New() + s := &ct{ + B: &ebf, + } + + b, err := json.Marshal(s) + if err != nil { + t.Fatal(err) + } + + var u ct + if err := json.Unmarshal(b, &u); err != nil { + t.Fatal(err) + } + + if u.B == nil { + t.Fatal("u.B is nil", string(b)) + } + + set, err := u.B.Count() + if err != nil { + t.Fatal(err) + } + + if set > 0 { + t.Errorf("expected 0 bits to be set") + } +} + +func TestBitfieldJsonRoundTrip(t *testing.T) { + vals := getRandIndexSet(100000) + + bf := NewFromSet(vals) + + b, err := bf.MarshalJSON() + if err != nil { + t.Fatal(err) + } + + var out BitField + if err := out.UnmarshalJSON(b); err != nil { + t.Fatal(err) + } + + outv, err := out.All(100000) + if err != nil { + t.Fatal(err) + } + + if !slicesEqual(vals, outv) { + t.Fatal("round trip failed") + } +} + +func setIntersect(a, b []uint64) []uint64 { + m := make(map[uint64]bool) + for _, v := range a { + m[v] = true + } + + var out []uint64 + for _, v := range b { + if m[v] { + out = append(out, v) + } + } + return out +} + +func TestBitfieldIntersect(t *testing.T) { + a := getRandIndexSetSeed(100, 1) + b := getRandIndexSetSeed(100, 2) + + bfa := NewFromSet(a) + bfb := NewFromSet(b) + + inter, err := IntersectBitField(bfa, bfb) + if err != nil { + t.Fatal(err) + } + + out, err := inter.All(10000) + if err != nil { + t.Fatal(err) + } + + exp := setIntersect(a, b) + + if !slicesEqual(out, exp) { + fmt.Println(a) + fmt.Println(b) + fmt.Println(out) + fmt.Println(exp) + t.Fatal("intersection is wrong") + } +} + +func setSubtract(a, b []uint64) []uint64 { + m := make(map[uint64]bool) + for _, v := range a { + m[v] = true + } + for _, v := range b { + delete(m, v) + } + + out := make([]uint64, 0, len(m)) + for v := range m { + out = append(out, v) + } + + sort.Slice(out, func(i, j int) bool { + return out[i] < out[j] + }) + + return out +} + +func TestBitfieldOrDifferentLenZeroSuffix(t *testing.T) { + ra := &rlepluslazy.RunSliceIterator{ + Runs: []rlepluslazy.Run{ + {Val: false, Len: 5}, + }, + } + + rb := &rlepluslazy.RunSliceIterator{ + Runs: []rlepluslazy.Run{ + {Val: false, Len: 8}, + }, + } + + merge, err := rlepluslazy.Or(ra, rb) + if err != nil { + t.Fatal(err) + } + + mergebytes, err := rlepluslazy.EncodeRuns(merge, nil) + if err != nil { + t.Fatal(err) + } + + b, err := NewFromBytes(mergebytes) + if err != nil { + t.Fatal(err) + } + + c, err := b.Count() + if err != nil { + t.Fatal(err) + } + + if c != 0 { + t.Error("expected 0 set bits", c) + } +} + +func TestBitfieldSubDifferentLenZeroSuffix(t *testing.T) { + ra := &rlepluslazy.RunSliceIterator{ + Runs: []rlepluslazy.Run{ + {Val: true, Len: 5}, + {Val: false, Len: 5}, + }, + } + + rb := &rlepluslazy.RunSliceIterator{ + Runs: []rlepluslazy.Run{ + {Val: true, Len: 5}, + {Val: false, Len: 8}, + }, + } + + merge, err := rlepluslazy.Subtract(ra, rb) + if err != nil { + t.Fatal(err) + } + + mergebytes, err := rlepluslazy.EncodeRuns(merge, nil) + if err != nil { + t.Fatal(err) + } + + b, err := NewFromBytes(mergebytes) + if err != nil { + t.Fatal(err) + } + + c, err := b.Count() + if err != nil { + t.Fatal(err) + } + + if c != 0 { + t.Error("expected 0 set bits", c) + } +} + +func TestBitfieldSubtract(t *testing.T) { + a := getRandIndexSetSeed(100, 1) + b := getRandIndexSetSeed(100, 2) + + bfa := NewFromSet(a) + bfb := NewFromSet(b) + + inter, err := SubtractBitField(bfa, bfb) + if err != nil { + t.Fatal(err) + } + + out, err := inter.All(10000) + if err != nil { + t.Fatal(err) + } + + exp := setSubtract(a, b) + + if !slicesEqual(out, exp) { + fmt.Println(a) + fmt.Println(b) + fmt.Println(out) + fmt.Println(exp) + t.Fatal("subtraction is wrong") + } +} + +// +func BitFieldUnion(bfs ...*BitField) (*BitField, error) { + // TODO: optimize me + for len(bfs) > 1 { + var next []*BitField + for i := 0; i < len(bfs); i += 2 { + if i+1 >= len(bfs) { + next = append(next, bfs[i]) + break + } + merged, err := MergeBitFields(bfs[i], bfs[i+1]) + if err != nil { + return nil, err + } + + next = append(next, merged) + } + bfs = next + } + return bfs[0], nil +} + +// +func TestBitfieldSubtractMore(t *testing.T) { + have := NewFromSet([]uint64{5, 6, 8, 10, 11, 13, 14, 17}) + s1, err := SubtractBitField(NewFromSet([]uint64{5, 6}), have) + if err != nil { + t.Fatal(err) + } + s2, err := SubtractBitField(NewFromSet([]uint64{8, 10}), have) + if err != nil { + t.Fatal(err) + } + s3, err := SubtractBitField(NewFromSet([]uint64{11, 13}), have) + if err != nil { + t.Fatal(err) + } + s4, err := SubtractBitField(NewFromSet([]uint64{14, 17}), have) + if err != nil { + t.Fatal(err) + } + + u, err := BitFieldUnion(s1, s2, s3, s4) + if err != nil { + t.Fatal(err) + } + + c, err := u.Count() + if err != nil { + t.Fatal(err) + } + if c != 0 { + ua, err := u.All(500) + fmt.Printf("%s %+v", err, ua) + t.Error("expected 0", c) + } +} + +func TestBitfieldCopy(t *testing.T) { + start := []uint64{5, 6, 8, 10, 11, 13, 14, 17} + + orig := NewFromSet(start) + + cp, err := orig.Copy() + if err != nil { + t.Fatal(err) + } + + cp.Unset(10) + + s, err := orig.IsSet(10) + if err != nil { + t.Fatal(err) + } + if !s { + t.Fatal("mutation affected original bitfield") + } + +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/go.mod b/vendor/github.com/filecoin-project/go-bitfield/go.mod new file mode 100644 index 0000000000..e09e76c703 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/go.mod @@ -0,0 +1,11 @@ +module github.com/filecoin-project/go-bitfield + +go 1.13 + +require ( + github.com/ipfs/go-cid v0.0.5 // indirect + github.com/multiformats/go-varint v0.0.5 + github.com/stretchr/testify v1.4.0 + github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +) diff --git a/vendor/github.com/filecoin-project/go-bitfield/go.sum b/vendor/github.com/filecoin-project/go-bitfield/go.sum new file mode 100644 index 0000000000..2eba620503 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/go.sum @@ -0,0 +1,75 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e h1:JY8o/ebUUrCYetWmjRCNghxC59cOEaili83rxPRQCLw= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/bits.go b/vendor/github.com/filecoin-project/go-bitfield/rle/bits.go new file mode 100644 index 0000000000..8e1534d200 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/bits.go @@ -0,0 +1,195 @@ +package rlepluslazy + +import ( + "errors" + "sort" +) + +var ErrEndOfIterator = errors.New("end of iterator") + +type it2b struct { + source RunIterator + curIdx uint64 + + run Run +} + +func (it *it2b) HasNext() bool { + return it.run.Valid() +} + +func (it *it2b) Next() (uint64, error) { + it.run.Len-- + res := it.curIdx + it.curIdx++ + return res, it.prep() +} + +func (it *it2b) Nth(n uint64) (uint64, error) { + skip := n + 1 + for it.run.Len < skip { + if !it.HasNext() { + return 0, ErrEndOfIterator + } + skip -= it.run.Len + it.curIdx += it.run.Len + it.run.Len = 0 + if err := it.prep(); err != nil { + return 0, err + } + } + it.run.Len -= skip + it.curIdx += skip + res := it.curIdx - 1 + return res, it.prep() +} + +func (it *it2b) prep() error { + for !it.run.Valid() && it.source.HasNext() { + var err error + it.run, err = it.source.NextRun() + if err != nil { + return err + } + + if !it.run.Val { + it.curIdx += it.run.Len + it.run.Len = 0 + } + } + return nil +} + +func BitsFromRuns(source RunIterator) (BitIterator, error) { + it := &it2b{source: source} + if err := it.prep(); err != nil { + return nil, err + } + return it, nil +} + +type sliceIt struct { + s []uint64 +} + +func (it sliceIt) HasNext() bool { + return len(it.s) != 0 +} + +func (it *sliceIt) Next() (uint64, error) { + if len(it.s) == 0 { + return 0, ErrEndOfIterator + } + res := it.s[0] + it.s = it.s[1:] + return res, nil +} + +func (it *sliceIt) Nth(n uint64) (uint64, error) { + if uint64(len(it.s)) <= n { + it.s = nil + return 0, ErrEndOfIterator + } + res := it.s[n] + it.s = it.s[n+1:] + return res, nil +} + +func BitsFromSlice(slice []uint64) BitIterator { + sort.Slice(slice, func(i, j int) bool { return slice[i] < slice[j] }) + return &sliceIt{slice} +} + +type it2r struct { + source BitIterator + + runIdx uint64 + run [2]Run +} + +func (it *it2r) HasNext() bool { + return it.run[0].Valid() +} + +func (it *it2r) NextRun() (Run, error) { + res := it.run[0] + it.runIdx = it.runIdx + res.Len + it.run[0], it.run[1] = it.run[1], Run{} + return res, it.prep() +} + +func (it *it2r) prep() error { + if !it.HasNext() { + return nil + } + if it.run[0].Val == false { + it.run[1].Val = true + it.run[1].Len = 1 + return nil + } + + for it.source.HasNext() && !it.run[1].Valid() { + nB, err := it.source.Next() + if err != nil { + return err + } + + //fmt.Printf("runIdx: %d, run[0].Len: %d, nB: %d\n", it.runIdx, it.run[0].Len, nB) + if it.runIdx+it.run[0].Len == nB { + it.run[0].Len++ + } else { + it.run[1].Len = nB - it.runIdx - it.run[0].Len + it.run[1].Val = false + } + } + return nil +} + +func (it *it2r) init() error { + if it.source.HasNext() { + nB, err := it.source.Next() + if err != nil { + return err + } + it.run[0].Len = nB + it.run[0].Val = false + it.run[1].Len = 1 + it.run[1].Val = true + } + + if !it.run[0].Valid() { + it.run[0], it.run[1] = it.run[1], Run{} + return it.prep() + } + return nil +} + +func SliceFromRuns(source RunIterator) ([]uint64, error) { + rit, err := BitsFromRuns(source) + if err != nil { + return nil, err + } + + res := make([]uint64, 0) + for rit.HasNext() { + bit, err := rit.Next() + if err != nil { + return nil, err + } + res = append(res, bit) + } + return res, nil +} + +func RunsFromBits(source BitIterator) (RunIterator, error) { + it := &it2r{source: source} + + if err := it.init(); err != nil { + return nil, err + } + return it, nil +} + +func RunsFromSlice(slice []uint64) (RunIterator, error) { + return RunsFromBits(BitsFromSlice(slice)) +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/bits_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/bits_test.go new file mode 100644 index 0000000000..31e62f4577 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/bits_test.go @@ -0,0 +1,86 @@ +package rlepluslazy + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRunsFromBits(t *testing.T) { + expected := []Run{{Val: false, Len: 0x1}, + {Val: true, Len: 0x3}, + {Val: false, Len: 0x2}, + {Val: true, Len: 0x3}, + } + rit, err := RunsFromBits(BitsFromSlice([]uint64{1, 2, 3, 6, 7, 8})) + assert.NoError(t, err) + i := 10 + output := make([]Run, 0, 4) + for rit.HasNext() && i > 0 { + run, err := rit.NextRun() + assert.NoError(t, err) + i-- + output = append(output, run) + } + assert.NotEqual(t, 0, i, "too many iterations") + assert.Equal(t, expected, output) +} + +func TestNthSlice(t *testing.T) { + testIter(t, func(t *testing.T, bits []uint64) BitIterator { + iter := BitsFromSlice(bits) + return iter + }) +} + +func TestNthRuns(t *testing.T) { + testIter(t, func(t *testing.T, bits []uint64) BitIterator { + riter, err := RunsFromSlice(bits) + assert.NoError(t, err) + biter, err := BitsFromRuns(riter) + assert.NoError(t, err) + return biter + }) +} + +func testIter(t *testing.T, ctor func(t *testing.T, bits []uint64) BitIterator) { + for i := 0; i < 10; i++ { + bits := randomBits(1000, 1500) + iter := ctor(t, bits) + + n, err := iter.Nth(10) + assert.NoError(t, err) + assert.Equal(t, bits[10], n) + + n, err = iter.Nth(0) + assert.NoError(t, err) + assert.Equal(t, bits[11], n) + + n, err = iter.Nth(1) + assert.NoError(t, err) + assert.Equal(t, bits[13], n) + + n, err = iter.Next() + assert.NoError(t, err) + assert.Equal(t, bits[14], n) + + runs, err := RunsFromBits(iter) + assert.NoError(t, err) + + remainingBits, err := SliceFromRuns(runs) + assert.NoError(t, err) + + assert.Equal(t, bits[15:], remainingBits) + } + for i := 0; i < 10; i++ { + bits := randomBits(1000, 1500) + iter := ctor(t, bits) + + last, err := iter.Nth(uint64(len(bits) - 1)) + assert.NoError(t, err) + assert.Equal(t, bits[len(bits)-1], last) + assert.False(t, iter.HasNext()) + _, err = iter.Nth(0) + assert.Equal(t, ErrEndOfIterator, err) + } +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/bitvec.go b/vendor/github.com/filecoin-project/go-bitfield/rle/bitvec.go new file mode 100644 index 0000000000..0aca2578f1 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/bitvec.go @@ -0,0 +1,114 @@ +package rlepluslazy + +type rbitvec struct { + index int + + bits uint16 + bitCap byte + + vec []byte +} + +func readBitvec(vec []byte) *rbitvec { + bv := &rbitvec{ + vec: vec, + index: 1, + bitCap: 8, + } + if len(vec) > 0 { + bv.bits = uint16(bv.vec[0]) + } + return bv +} + +// bitMasks is a mask for selecting N first bits out of a byte +var bitMasks = [9]byte{ + 0x0, + 0x1, + 0x3, + 0x7, + 0xF, + 0x1F, + 0x3F, + 0x7F, + 0xFF, +} + +func (bv *rbitvec) Get(count byte) byte { + res := byte(bv.bits) & bitMasks[count] // select count bits + bv.bits = bv.bits >> count // remove those bits from storage + bv.bitCap = bv.bitCap - count // decrease nuber of stored bits + + if bv.index < len(bv.vec) { // if vector allows + // add bits onto the end of temporary storage + bv.bits = bv.bits | uint16(bv.vec[bv.index])<> 7 // inc == 1 iff bitcap<8 (+10% perf) + bv.index = bv.index + int(inc) // increase index if we need more bits + bv.bitCap = bv.bitCap + inc*8 // increase bitCap by 8 + + return res +} + +func writeBitvec(buf []byte) *wbitvec { + // reslice to 0 length for consistent input but to keep capacity + return &wbitvec{buf: buf[:0]} +} + +type wbitvec struct { + buf []byte // buffer we will be saving to + index int // index of at which the next byte will be saved + + bits uint16 // temporary storage for bits + bitCap byte // number of bits stored in temporary storage +} + +func (bv *wbitvec) Out() []byte { + if bv.bitCap != 0 { + // if there are some bits in temporary storage we need to save them + bv.buf = append(bv.buf, 0)[:bv.index+1] + bv.buf[bv.index] = byte(bv.bits) + } + if bv.bitCap > 8 { + // if we store some needed bits in second byte, save them also + bv.buf = append(bv.buf, byte(bv.bits>>8)) + bv.index++ + bv.bits = bv.bits - 8 + } + return bv.buf +} + +func (bv *wbitvec) Put(val byte, count byte) { + // put val into its place in bv.bits + bv.bits = bv.bits | uint16(val)< cap(bv.buf) { + bv.buf = append(bv.buf, 0) + } + bv.buf = bv.buf[:bv.index+1] + // save the bits + bv.buf[bv.index] = byte(bv.bits) + + // Warning, dragons again + // if bitCap is greater than 7 it underflows, same thing as in Put + inc := (7 - bv.bitCap) >> 7 // inc == 1 iff bitcap>=8 + bv.index = bv.index + int(inc) // increase index for the next save + bv.bitCap = bv.bitCap - inc*8 // we store less bits now in temporary buffer + bv.bits = bv.bits >> (inc * 8) // we can discard those bits as they were saved +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/bitvec_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/bitvec_test.go new file mode 100644 index 0000000000..6938bd7932 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/bitvec_test.go @@ -0,0 +1,21 @@ +package rlepluslazy + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestReadBitVec(t *testing.T) { + buf := []byte{0x0, 0xff} + bv := readBitvec(buf) + + o := bv.Get(1) + assert.EqualValues(t, 0, o) + + o = bv.Get(8) + assert.EqualValues(t, 0x80, o) + + o = bv.Get(7) + assert.EqualValues(t, 0x7f, o) +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/interface.go b/vendor/github.com/filecoin-project/go-bitfield/rle/interface.go new file mode 100644 index 0000000000..f76de1d189 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/interface.go @@ -0,0 +1,25 @@ +package rlepluslazy + +type Run struct { + Val bool + Len uint64 +} + +func (r Run) Valid() bool { + return r.Len != 0 +} + +type RunIterator interface { + NextRun() (Run, error) + HasNext() bool +} + +type RunIterable interface { + RunIterator() (RunIterator, error) +} + +type BitIterator interface { + Next() (uint64, error) + Nth(n uint64) (uint64, error) + HasNext() bool +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector.go b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector.go new file mode 100644 index 0000000000..e5094e3e7e --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector.go @@ -0,0 +1,154 @@ +package rleplus + +import ( + "errors" + "log" +) + +var ( + // ErrOutOfRange - the index passed is out of range for the BitVector + ErrOutOfRange = errors.New("index out of range") +) + +// BitNumbering indicates the ordering of bits, either +// least-significant bit in position 0, or most-significant bit +// in position 0. +// +// It it used in 3 ways with BitVector: +// 1. Ordering of bits within the Buf []byte structure +// 2. What order to add bits when using Extend() +// 3. What order to read bits when using Take() +// +// https://en.wikipedia.org/wiki/Bit_numbering +type BitNumbering int + +const ( + // LSB0 - bit ordering starts with the low-order bit + LSB0 BitNumbering = iota + + // MSB0 - bit ordering starts with the high-order bit + MSB0 +) + +// BitVector is used to manipulate ordered collections of bits +type BitVector struct { + Buf []byte + + // BytePacking is the bit ordering within bytes + BytePacking BitNumbering + + // Len is the logical number of bits in the vector. + // The last byte in Buf may have undefined bits if Len is not a multiple of 8 + Len uint +} + +// NewBitVector constructs a new BitVector from a slice of bytes. +// +// The bytePacking parameter is required to know how to interpret the bit ordering within the bytes. +func NewBitVector(buf []byte, bytePacking BitNumbering) *BitVector { + return &BitVector{ + BytePacking: bytePacking, + Buf: buf, + Len: uint(len(buf) * 8), + } +} + +// Push adds a single bit to the BitVector. +// +// Although it takes a byte, only the low-order bit is used, so just use 0 or 1. +func (v *BitVector) Push(val byte) { + if v.Len%8 == 0 { + v.Buf = append(v.Buf, 0) + } + lastIdx := v.Len / 8 + + switch v.BytePacking { + case LSB0: + v.Buf[lastIdx] |= (val & 1) << (v.Len % 8) + default: + v.Buf[lastIdx] |= (val & 1) << (7 - (v.Len % 8)) + } + + v.Len++ +} + +// Get returns a single bit as a byte -- either 0 or 1 +func (v *BitVector) Get(idx uint) (byte, error) { + if idx >= v.Len { + return 0, ErrOutOfRange + } + blockIdx := idx / 8 + + switch v.BytePacking { + case LSB0: + return v.Buf[blockIdx] >> (idx % 8) & 1, nil + default: + return v.Buf[blockIdx] >> (7 - idx%8) & 1, nil + } +} + +// Extend adds up to 8 bits to the receiver +// +// Given a byte b == 0b11010101 +// v.Extend(b, 4, LSB0) would add < 1, 0, 1, 0 > +// v.Extend(b, 4, MSB0) would add < 1, 1, 0, 1 > +// +// Panics if count is out of range +func (v *BitVector) Extend(val byte, count uint, order BitNumbering) { + if count > 8 { + log.Panicf("invalid count") + } + + for i := uint(0); i < count; i++ { + switch order { + case LSB0: + v.Push((val >> i) & 1) + default: + v.Push((val >> (7 - i)) & 1) + } + } +} + +// Take reads up to 8 bits at the given index. +// +// Given a BitVector < 1, 1, 0, 1, 0, 1, 0, 1 > +// v.Take(0, 4, LSB0) would return 0b00001011 +// v.Take(0, 4, MSB0) would return 0b11010000 +// +// Panics if count is out of range +func (v *BitVector) Take(index uint, count uint, order BitNumbering) (out byte) { + if count > 8 { + log.Panicf("invalid count") + } + + for i := uint(0); i < count; i++ { + val, _ := v.Get(index + i) + + switch order { + case LSB0: + out |= val << i + default: + out |= val << (7 - i) + } + } + return +} + +// Iterator returns a function, which when invoked, returns the number +// of bits requested, and increments an internal cursor. +// +// When the end of the BitVector is reached, it returns zeroes indefinitely +// +// Panics if count is out of range +func (v *BitVector) Iterator(order BitNumbering) func(uint) byte { + cursor := uint(0) + return func(count uint) (out byte) { + if count > 8 { + log.Panicf("invalid count") + } + + out = v.Take(cursor, count, order) + cursor += count + return + } +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector_test.go new file mode 100644 index 0000000000..eb3c8db0de --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/bitvector_test.go @@ -0,0 +1,134 @@ +package rleplus + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBitVector(t *testing.T) { + t.Run("zero value", func(t *testing.T) { + var v BitVector + + assert.Equal(t, LSB0, v.BytePacking) + }) + + t.Run("Push", func(t *testing.T) { + // MSB0 bit numbering + v := BitVector{BytePacking: MSB0} + v.Push(1) + v.Push(0) + v.Push(1) + v.Push(1) + + assert.Equal(t, byte(176), v.Buf[0]) + + // LSB0 bit numbering + v = BitVector{BytePacking: LSB0} + v.Push(1) + v.Push(0) + v.Push(1) + v.Push(1) + + assert.Equal(t, byte(13), v.Buf[0]) + }) + + t.Run("Get", func(t *testing.T) { + bits := []byte{1, 0, 1, 1, 0, 0, 1, 0} + + for _, numbering := range []BitNumbering{MSB0, LSB0} { + v := BitVector{BytePacking: numbering} + + for _, bit := range bits { + v.Push(bit) + } + + for idx, expected := range bits { + actual, _ := v.Get(uint(idx)) + assert.Equal(t, expected, actual) + } + } + }) + + t.Run("Extend", func(t *testing.T) { + val := byte(171) // 0b10101011 + + var v BitVector + + // MSB0 bit numbering + v = BitVector{} + v.Extend(val, 4, MSB0) + assertBitVector(t, []byte{1, 0, 1, 0}, v) + v.Extend(val, 5, MSB0) + assertBitVector(t, []byte{1, 0, 1, 0, 1, 0, 1, 0, 1}, v) + + // LSB0 bit numbering + v = BitVector{} + v.Extend(val, 4, LSB0) + assertBitVector(t, []byte{1, 1, 0, 1}, v) + v.Extend(val, 5, LSB0) + assertBitVector(t, []byte{1, 1, 0, 1, 1, 1, 0, 1, 0}, v) + }) + + t.Run("invalid counts to Take/Extend/Iterator cause panics", func(t *testing.T) { + v := BitVector{BytePacking: LSB0} + + assert.Panics(t, func() { v.Extend(0xff, 9, LSB0) }) + + assert.Panics(t, func() { v.Take(0, 9, LSB0) }) + + next := v.Iterator(LSB0) + assert.Panics(t, func() { next(9) }) + }) + + t.Run("Take", func(t *testing.T) { + var v BitVector + + bits := []byte{1, 0, 1, 0, 1, 0, 1, 1} + for _, bit := range bits { + v.Push(bit) + } + + assert.Equal(t, byte(176), v.Take(4, 4, MSB0)) + assert.Equal(t, byte(13), v.Take(4, 4, LSB0)) + }) + + t.Run("Iterator", func(t *testing.T) { + var buf []byte + + // make a bitvector of 256 sample bits + for i := 0; i < 32; i++ { + buf = append(buf, 128+32) + } + + v := NewBitVector(buf, LSB0) + + next := v.Iterator(LSB0) + + // compare to Get() + for i := uint(0); i < v.Len; i++ { + expected, _ := v.Get(i) + assert.Equal(t, expected, next(1)) + } + + // out of range should return zero + assert.Equal(t, byte(0), next(1)) + assert.Equal(t, byte(0), next(8)) + + // compare to Take() + next = v.Iterator(LSB0) + assert.Equal(t, next(5), v.Take(0, 5, LSB0)) + assert.Equal(t, next(8), v.Take(5, 8, LSB0)) + }) +} + +// Note: When using this helper assertion, expectedBits should *only* be 0s and 1s. +func assertBitVector(t *testing.T, expectedBits []byte, actual BitVector) { + assert.Equal(t, uint(len(expectedBits)), actual.Len) + + for idx, bit := range expectedBits { + actualBit, err := actual.Get(uint(idx)) + assert.NoError(t, err) + assert.Equal(t, bit, actualBit) + } +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus.go b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus.go new file mode 100644 index 0000000000..1c48ebcec0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus.go @@ -0,0 +1,202 @@ +package rleplus + +import ( + "encoding/binary" + "errors" + "fmt" + "sort" +) + +// Version is the 2 lowest bits of this constant +const Version = 0 + +var ( + // ErrRunLengthTooLarge - data implies a run-length which isn't supported + ErrRunLengthTooLarge = fmt.Errorf("run length too large for RLE+ version %d", Version) + + // ErrDecode - invalid encoding for this version + ErrDecode = fmt.Errorf("invalid encoding for RLE+ version %d", Version) + + // ErrWrongVersion - wrong version of RLE+ + ErrWrongVersion = errors.New("invalid RLE+ version") +) + +// Encode returns the RLE+ representation of the provided integers. +// Also returned is the number of bits required by this encoding, +// which is not necessarily on a byte boundary. +// +// The RLE+ spec is here: https://github.com/filecoin-project/specs/blob/master/data-structures.md#rle-bitset-encoding +// and is described by the BNF Grammar: +// +// ::=
+//
::= +// ::= "00" +// ::= | "" +// ::= | | +// ::= "1" +// ::= "01" +// ::= "00" +// ::= "0" | "1" +// +// Filecoin specific: +// The encoding is returned as a []byte, each byte packed starting with the low-order bit (LSB0) +func Encode(ints []uint64) ([]byte, uint, error) { + v := BitVector{BytePacking: LSB0} + firstBit, runs := RunLengths(ints) + + // Add version header + v.Extend(Version, 2, LSB0) + + v.Push(firstBit) + + for _, run := range runs { + switch { + case run == 1: + v.Push(1) + case run < 16: + v.Push(0) + v.Push(1) + v.Extend(byte(run), 4, LSB0) + case run >= 16: + v.Push(0) + v.Push(0) + // 10 bytes needed to encode MaxUint64 + buf := make([]byte, 10) + numBytes := binary.PutUvarint(buf, run) + for i := 0; i < numBytes; i++ { + v.Extend(buf[i], 8, LSB0) + } + default: + return nil, 0, ErrRunLengthTooLarge + } + } + + return v.Buf, v.Len, nil +} + +// Decode returns integers represented by the given RLE+ encoding +// +// The length of the encoding is not specified. It is inferred by +// reading zeroes from the (possibly depleted) BitVector, by virtue +// of the behavior of BitVector.Take() returning 0 when the end of +// the BitVector has been reached. This has the downside of not +// being able to detect corrupt encodings. +// +// The passed []byte should be packed in LSB0 bit numbering +func Decode(buf []byte) (ints []uint64, err error) { + if len(buf) == 0 { + return + } + + v := NewBitVector(buf, LSB0) + take := v.Iterator(LSB0) + + // Read version and check + // Version check + ver := take(2) + if ver != Version { + return nil, ErrWrongVersion + } + + curIdx := uint64(0) + curBit := take(1) + var runLength int + done := false + + for done == false { + y := take(1) + switch y { + case 1: + runLength = 1 + case 0: + val := take(1) + + if val == 1 { + // short block + runLength = int(take(4)) + } else { + // long block + var buf []byte + for { + b := take(8) + buf = append(buf, b) + + if b&0x80 == 0 { + break + } + + // 10 bytes is required to store math.MaxUint64 in a uvarint + if len(buf) > 10 { + return nil, ErrDecode + } + } + x, _ := binary.Uvarint(buf) + + if x == 0 { + done = true + } + runLength = int(x) + } + } + + if curBit == 1 { + for j := 0; j < runLength; j++ { + ints = append(ints, curIdx+uint64(j)) + } + } + curIdx += uint64(runLength) + curBit = 1 - curBit + } + + return +} + +// RunLengths transforms integers into its bit-set-run-length representation. +// +// A set of unsigned integers { 0, 2, 4, 5, 6 } can be thought of as +// indices into a bitset { 1, 0, 1, 0, 1, 1, 1 } where bitset[index] == 1. +// +// The bit set run lengths of this set would then be { 1, 1, 1, 1, 3 }, +// representing lengths of runs alternating between 1 and 0, starting +// with a first bit of 1. +// +// Duplicated numbers are ignored. +// +// This is a helper function for Encode() +func RunLengths(ints []uint64) (firstBit byte, runs []uint64) { + if len(ints) == 0 { + return + } + + // Sort our incoming numbers + sort.Slice(ints, func(i, j int) bool { return ints[i] < ints[j] }) + + prev := ints[0] + + // Initialize our return value + if prev == 0 { + firstBit = 1 + } + + if firstBit == 0 { + // first run of zeroes + runs = append(runs, prev) + } + runs = append(runs, 1) + + for _, cur := range ints[1:] { + delta := cur - prev + switch { + case delta == 1: + runs[len(runs)-1]++ + case delta > 1: + // add run of zeroes if there is a gap + runs = append(runs, delta-1) + runs = append(runs, 1) + default: + // repeated number? + } + prev = cur + } + return +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus_test.go new file mode 100644 index 0000000000..0147b6fbe5 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/internal/rleplus/rleplus_test.go @@ -0,0 +1,211 @@ +package rleplus + +import ( + "fmt" + "math" + "sort" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRleplus(t *testing.T) { + + t.Run("Encode", func(t *testing.T) { + // Encode an intset + ints := []uint64{ + // run of 1 + 0, + // gap of 1 + // run of 1 + 2, + // gap of 1 + // run of 3 + 4, 5, 6, + // gap of 4 + // run of 17 + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + } + + expectedBits := []byte{ + 0, 0, // version + 1, // first bit + 1, // run of 1 + 1, // gap of 1 + 1, // run of 1 + 1, // gap of 1 + 0, 1, 1, 1, 0, 0, // run of 3 + 0, 1, 0, 0, 1, 0, // gap of 4 + + // run of 17 < 0 0 (varint) > + 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + } + + v := BitVector{} + for _, bit := range expectedBits { + v.Push(bit) + } + actualBytes, _, err := Encode(ints) + assert.NoError(t, err) + + assert.Equal(t, len(v.Buf), len(actualBytes)) + for idx, expected := range v.Buf { + assert.Equal( + t, + fmt.Sprintf("%08b", expected), + fmt.Sprintf("%08b", actualBytes[idx]), + ) + } + }) + + t.Run("Encode allows all runs sizes possible uint64", func(t *testing.T) { + // create a run of math.MaxUint64 + ints := []uint64{math.MaxUint64} + + // There would be 64 bits(1) for the UvarInt, totally 9 bytes. + expected := []byte{0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x20} + encodeBytes, _, err := Encode(ints) + assert.NoError(t, err) + for idx, v := range encodeBytes { + assert.Equal( + t, + fmt.Sprintf("%8b", v), + fmt.Sprintf("%8b", expected[idx]), + ) + } + }) + + t.Run("Encode for some big numbers", func(t *testing.T) { + // create a run of math.MaxUint64 + ints := make([]uint64, 1024) + + // ints {2^63 .. 2^63+1023} + for i := uint64(0); i < 1024; i++ { + ints[i] = uint64(1)<<63 + i + } + + expected := []byte{0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0x00, 0x40, 0x04} + encodeBytes, _, err := Encode(ints) + assert.NoError(t, err) + for idx, v := range encodeBytes { + // fmt.Println(v, expected[idx]) + assert.Equal( + t, + fmt.Sprintf("%8b", v), + fmt.Sprintf("%8b", expected[idx]), + ) + } + }) + + t.Run("Decode", func(t *testing.T) { + testCases := [][]uint64{ + {}, + {1}, + {0}, + {0, 1, 2, 3}, + { + // run of 1 + 0, + // gap of 1 + // run of 1 + 2, + // gap of 1 + // run of 3 + 4, 5, 6, + // gap of 4 + // run of 17 + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + }, + } + + for _, tc := range testCases { + encoded, _, err := Encode(tc) + assert.NoError(t, err) + + result, err := Decode(encoded) + assert.NoError(t, err) + + sort.Slice(tc, func(i, j int) bool { return tc[i] < tc[j] }) + sort.Slice(result, func(i, j int) bool { return result[i] < result[j] }) + + assert.Equal(t, len(tc), len(result)) + + for idx, expected := range tc { + assert.Equal(t, expected, result[idx]) + } + } + }) + + t.Run("Decode version check", func(t *testing.T) { + _, err := Decode([]byte{0xff}) + assert.Error(t, err, "invalid RLE+ version") + }) + + t.Run("Decode returns an error with a bad encoding", func(t *testing.T) { + // create an encoding with a buffer with a run which is too long + _, err := Decode([]byte{0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) + assert.Error(t, err, "invalid encoding for RLE+ version 0") + }) + + t.Run("outputs same as reference implementation", func(t *testing.T) { + // Encoding bitvec![LittleEndian; 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + // in the Rust reference implementation gives an encoding of [223, 145, 136, 0] (without version field) + // The bit vector is equivalent to the integer set { 0, 2, 4, 5, 6, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 } + + // This is the above reference output with a version header "00" manually added + referenceEncoding := []byte{124, 71, 34, 2} + + expectedNumbers := []uint64{0, 2, 4, 5, 6, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27} + + encoded, _, err := Encode(expectedNumbers) + assert.NoError(t, err) + + // Our encoded bytes are the same as the ref bytes + assert.Equal(t, len(referenceEncoding), len(encoded)) + for idx, expected := range referenceEncoding { + assert.Equal(t, expected, encoded[idx]) + } + + decoded, err := Decode(referenceEncoding) + assert.NoError(t, err) + + // Our decoded integers are the same as expected + sort.Slice(decoded, func(i, j int) bool { return decoded[i] < decoded[j] }) + assert.Equal(t, len(expectedNumbers), len(decoded)) + for idx, expected := range expectedNumbers { + assert.Equal(t, expected, decoded[idx]) + } + }) + + t.Run("RunLengths", func(t *testing.T) { + testCases := []struct { + ints []uint64 + first byte + runs []uint64 + }{ + // empty + {}, + + // leading with ones + {[]uint64{0}, 1, []uint64{1}}, + {[]uint64{0, 1}, 1, []uint64{2}}, + {[]uint64{0, 0xffffffff, 0xffffffff + 1}, 1, []uint64{1, 0xffffffff - 1, 2}}, + + // leading with zeroes + {[]uint64{1}, 0, []uint64{1, 1}}, + {[]uint64{2}, 0, []uint64{2, 1}}, + {[]uint64{10, 11, 13, 20}, 0, []uint64{10, 2, 1, 1, 6, 1}}, + {[]uint64{10, 11, 11, 13, 20, 10, 11, 13, 20}, 0, []uint64{10, 2, 1, 1, 6, 1}}, + } + + for _, testCase := range testCases { + first, runs := RunLengths(testCase.ints) + assert.Equal(t, testCase.first, first) + assert.Equal(t, len(testCase.runs), len(runs)) + for idx, runLength := range testCase.runs { + assert.Equal(t, runLength, runs[idx]) + } + } + }) +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/joinclose.go b/vendor/github.com/filecoin-project/go-bitfield/rle/joinclose.go new file mode 100644 index 0000000000..1fd85bb362 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/joinclose.go @@ -0,0 +1,65 @@ +package rlepluslazy + +func JoinClose(it RunIterator, closeness uint64) (RunIterator, error) { + jc := &jcIt{ + it: &peekIter{it: it}, + closeness: closeness, + } + if err := jc.prep(); err != nil { + return nil, err + } + return jc, nil +} + +type jcIt struct { + it *peekIter + run Run + + closeness uint64 +} + +func (jc *jcIt) prep() error { + if !jc.it.HasNext() { + jc.run = Run{} + return nil + } + + var err error + jc.run, err = jc.it.NextRun() + if err != nil { + return err + } + + if jc.run.Val { + for { + if jc.it.HasNext() { + run, err := jc.it.NextRun() + if err != nil { + return err + } + if run.Len <= jc.closeness || run.Val { + jc.run.Len += run.Len + continue + } else { + jc.it.put(run, err) + break + } + } + break + } + } + return nil +} + +func (jc *jcIt) HasNext() bool { + return jc.run.Valid() +} + +func (jc *jcIt) NextRun() (Run, error) { + out := jc.run + if err := jc.prep(); err != nil { + return Run{}, err + } + return out, nil + +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/joinclose_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/joinclose_test.go new file mode 100644 index 0000000000..7e43e01911 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/joinclose_test.go @@ -0,0 +1,34 @@ +package rlepluslazy + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestJoinClose(t *testing.T) { + inBits := []uint64{0, 1, 4, 5, 9, 14} + var tests = []struct { + name string + given []uint64 + expected []uint64 + closeness uint64 + }{ + {"closeness 0", inBits, []uint64{0, 1, 4, 5, 9, 14}, 0}, + {"closeness 2", inBits, []uint64{0, 1, 2, 3, 4, 5, 9, 14}, 2}, + {"closeness 3", inBits, []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14}, 3}, + {"closeness 4", inBits, []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 4}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + a, err := RunsFromSlice(tt.given) + assert.NoError(t, err) + jc, err := JoinClose(a, tt.closeness) + assert.NoError(t, err) + bits, err := SliceFromRuns(jc) + assert.Equal(t, tt.expected, bits) + }) + } + +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/merge.go b/vendor/github.com/filecoin-project/go-bitfield/rle/merge.go new file mode 100644 index 0000000000..9c18f4bfcc --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/merge.go @@ -0,0 +1,31 @@ +package rlepluslazy + +// Union returns the union of the passed iterators. Internally, this calls Or on +// the passed iterators, combining them with a binary tree of Ors. +func Union(iters ...RunIterator) (RunIterator, error) { + if len(iters) == 0 { + return RunsFromSlice(nil) + } + + for len(iters) > 1 { + var next []RunIterator + + for i := 0; i < len(iters); i += 2 { + if i+1 >= len(iters) { + next = append(next, iters[i]) + continue + } + + orit, err := Or(iters[i], iters[i+1]) + if err != nil { + return nil, err + } + + next = append(next, orit) + } + + iters = next + } + + return iters[0], nil +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus.go b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus.go new file mode 100644 index 0000000000..791a48e14d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus.go @@ -0,0 +1,125 @@ +package rlepluslazy + +import ( + "encoding/json" + "errors" + "fmt" + "math" + + "golang.org/x/xerrors" +) + +const Version = 0 + +var ( + ErrWrongVersion = errors.New("invalid RLE+ version") + ErrDecode = fmt.Errorf("invalid encoding for RLE+ version %d", Version) +) + +type RLE struct { + buf []byte + runs []Run +} + +func FromBuf(buf []byte) (RLE, error) { + rle := RLE{buf: buf} + + if len(buf) > 0 && buf[0]&3 != Version { + return RLE{}, xerrors.Errorf("could not create RLE+ for a buffer: %w", ErrWrongVersion) + } + + return rle, nil +} + +func (rle *RLE) RunIterator() (RunIterator, error) { + if rle.runs == nil { + source, err := DecodeRLE(rle.buf) + if err != nil { + return nil, xerrors.Errorf("decoding RLE: %w", err) + } + var length uint64 + var runs []Run + for source.HasNext() { + r, err := source.NextRun() + if err != nil { + return nil, xerrors.Errorf("reading run: %w", err) + } + if math.MaxUint64-r.Len < length { + return nil, xerrors.New("RLE+ overflows") + } + length += r.Len + runs = append(runs, r) + } + rle.runs = runs + } + + return &RunSliceIterator{Runs: rle.runs}, nil +} + +func (rle *RLE) Count() (uint64, error) { + it, err := rle.RunIterator() + if err != nil { + return 0, err + } + return Count(it) +} + +// Encoded as an array of run-lengths, always starting with zeroes (absent values) +// E.g.: The set {0, 1, 2, 8, 9} is the bitfield 1110000011, and would be marshalled as [0, 3, 5, 2] +func (rle *RLE) MarshalJSON() ([]byte, error) { + r, err := rle.RunIterator() + if err != nil { + return nil, err + } + + var ret []uint64 + if r.HasNext() { + first, err := r.NextRun() + if err != nil { + return nil, err + } + if first.Val { + ret = append(ret, 0) + } + ret = append(ret, first.Len) + + for r.HasNext() { + next, err := r.NextRun() + if err != nil { + return nil, err + } + + ret = append(ret, next.Len) + } + } else { + ret = []uint64{0} + } + + return json.Marshal(ret) +} + +func (rle *RLE) UnmarshalJSON(b []byte) error { + var buf []uint64 + + if err := json.Unmarshal(b, &buf); err != nil { + return err + } + + rle.runs = []Run{} + val := false + for i, v := range buf { + if v == 0 { + if i != 0 { + return xerrors.New("Cannot have a zero-length run except at start") + } + } else { + rle.runs = append(rle.runs, Run{ + Val: val, + Len: v, + }) + } + val = !val + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_golden_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_golden_test.go new file mode 100644 index 0000000000..091d9826c4 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_golden_test.go @@ -0,0 +1,3 @@ +package rlepluslazy + +var goldenRLE = []byte{0x20, 0xfc, 0x40, 0xc2, 0xcc, 0xe5, 0xd8, 0xc1, 0xe1, 0x1e, 0x23, 0xd3, 0x2, 0x2e, 0xcd, 0x3, 0x3e, 0x83, 0x16, 0x26, 0x3a, 0x5c, 0x30, 0x8e, 0x0, 0x5, 0xcc, 0x24, 0xe, 0x96, 0x15, 0x48, 0xa0, 0x2a, 0x40, 0x4, 0x92, 0xe, 0x94, 0xc0, 0x48, 0x91, 0xee, 0x5, 0x28, 0x98, 0x55, 0x90, 0xa0, 0xa4, 0x50, 0x98, 0x14, 0x40, 0x4, 0x59, 0xa, 0x22, 0x0, 0x74, 0xb0, 0x40, 0x66, 0x30, 0xf9, 0x66, 0x90, 0x51, 0xc7, 0x70, 0x74, 0x40, 0x48, 0x7f, 0xf0, 0x80, 0x24, 0x20, 0x85, 0x58, 0x6, 0x7, 0x66, 0x4, 0x87, 0xe5, 0x5, 0x28, 0x0, 0xa4, 0xf0, 0x61, 0x2e, 0x90, 0x8, 0x44, 0x70, 0x38, 0x34, 0xf0, 0x8, 0x4f, 0x70, 0x68, 0xad, 0xd0, 0x90, 0x1e, 0x90, 0x38, 0xc1, 0x85, 0x76, 0x4, 0x15, 0x7c, 0x4, 0x28, 0x28, 0x17, 0x70, 0xe0, 0x15, 0x0, 0x82, 0xfb, 0x11, 0xb, 0x76, 0x9, 0x22, 0xb8, 0x2f, 0x90, 0x20, 0x5f, 0x80, 0x84, 0xc9, 0x10, 0x85, 0x66, 0x9, 0x5, 0xc9, 0x3, 0x2d, 0x19, 0xa4, 0x5a, 0x70, 0x45, 0xa5, 0x40, 0xc2, 0x5, 0x6c, 0x4a, 0xf, 0x64, 0xf4, 0x19, 0xb0, 0x40, 0x28, 0x8b, 0x2, 0x6c, 0x20, 0x3e, 0x90, 0x40, 0x1, 0x19, 0xea, 0x9, 0x20, 0x60, 0x2f, 0x50, 0x60, 0x15, 0x0, 0x4, 0x69, 0x6, 0xb1, 0x8c, 0xa9, 0x85, 0xc6, 0x1f, 0x13, 0x54, 0x3e, 0x58, 0x40, 0x17, 0x60, 0x41, 0x2e, 0x8a, 0x42, 0x3c, 0x8b, 0xb, 0x3f, 0x8, 0x10, 0x5c, 0x32, 0x38, 0xd4, 0x1e, 0x68, 0x18, 0x5b, 0x70, 0xc1, 0x2c, 0x6, 0x17, 0x6c, 0x17, 0xf8, 0x74, 0x36, 0x28, 0x9c, 0xe, 0x20, 0x2, 0xa1, 0x84, 0xf, 0xa2, 0x82, 0xe, 0xbf, 0x82, 0x45, 0x29, 0x84, 0x7, 0x16, 0x25, 0x10, 0x12, 0x38, 0x8c, 0x13, 0x50, 0x41, 0xff, 0x3, 0x13, 0x70, 0x16, 0x80, 0x81, 0x63, 0x85, 0x8f, 0xa0, 0x81, 0xa, 0xe1, 0x80, 0x84, 0xa3, 0x81, 0x89, 0xff, 0x84, 0xc7, 0x3c, 0x87, 0x49, 0xbb, 0x81, 0x4b, 0x21, 0x82, 0x3, 0x2f, 0x83, 0x84, 0x29, 0x83, 0x8c, 0xe0, 0x0, 0x40, 0x8c, 0xda, 0x20, 0x42, 0x6, 0x13, 0x64, 0x7, 0x24, 0x85, 0xc, 0xa6, 0x21, 0x24, 0x6c, 0x7, 0x74, 0x20, 0x13, 0x3c, 0x2, 0x13, 0x54, 0xba, 0x1d, 0x14, 0x9e, 0xb, 0xe0, 0x0, 0x39, 0x82, 0xa, 0x72, 0xb, 0x80, 0x60, 0x53, 0x20, 0xd5, 0xe, 0x32, 0xd5, 0xe, 0x12, 0xb9, 0x1, 0x44, 0x90, 0x27, 0x51, 0x59, 0xe0, 0x12, 0xc3, 0x4, 0xe8, 0x1, 0x78, 0x40, 0xd8, 0xe0, 0x3, 0x7b, 0x60, 0x93, 0x6b, 0x20, 0x72, 0xf8, 0x20, 0xf1, 0xe1, 0xe0, 0x4d, 0x90, 0xdf, 0x2, 0x1f, 0x69, 0x3, 0x36, 0x30, 0x8d, 0x20, 0x82, 0x58, 0xa, 0x8f, 0xec, 0x2, 0x8d, 0xe8, 0x0, 0x11, 0x55, 0x81, 0x58, 0x17, 0xa0, 0x82, 0xa5, 0x81, 0x88, 0xb6, 0x83, 0x88, 0xed, 0x86, 0x88, 0xe0, 0x86, 0x4b, 0x6e, 0x82, 0x45, 0xe1, 0x89, 0xc8, 0x2c, 0x41, 0x78, 0x9, 0x12, 0xbd, 0x91, 0x50, 0x1, 0x42, 0x90, 0x85, 0x70, 0x69, 0xb5, 0x20, 0x83, 0x5e, 0x2, 0x8d, 0xfb, 0x2, 0xf, 0xfb, 0xa, 0x9, 0xcc, 0x4, 0x8b, 0xe4, 0x5, 0x87, 0xc9, 0x2, 0xf, 0xfc, 0x1, 0x5c, 0x8, 0xf, 0xd0, 0x1, 0x4e, 0xd0, 0x60, 0x4d, 0x50, 0xa1, 0x3c, 0xf0, 0x20, 0x6c, 0x88, 0xe1, 0x41, 0x5c, 0x11, 0x1c, 0xc8, 0x25, 0x4c, 0xc0, 0x1d, 0x1c, 0x4e, 0x61, 0x54, 0x2a, 0x5, 0x14, 0xf6, 0x54, 0x3c, 0xb, 0x44, 0xe4, 0x5, 0x64, 0x42, 0x1f, 0x64, 0x32, 0x23, 0xa0, 0x20, 0xf9, 0x1, 0xc, 0x40, 0x27, 0xf8, 0x40, 0x3c, 0xc0, 0x82, 0x72, 0x1, 0xd, 0xd1, 0x43, 0x11, 0x1, 0xd, 0xaa, 0x35, 0xc8, 0xe0, 0x1e, 0x42, 0x41, 0x5b, 0x20, 0x8b, 0x4, 0xe, 0xc9, 0x3, 0xa, 0xea, 0x1, 0x3e, 0x5f, 0x12, 0xab, 0x7, 0x40, 0xf0, 0xad, 0x60, 0x42, 0x6f, 0xa1, 0xd2, 0x39, 0x60, 0x91, 0x64, 0xf1, 0xe4, 0x10, 0x3f, 0x60, 0xc2, 0x5c, 0x94, 0x62, 0x7, 0x1f, 0x67, 0x5, 0x87, 0xcc, 0x7, 0x9f, 0xee, 0xe, 0x13, 0xd8, 0x2, 0x38, 0xa0, 0xb5, 0x20, 0x2, 0x4e, 0x1, 0x85, 0x7c, 0xc, 0x4e, 0xb0, 0xde, 0x90, 0x80, 0x2c, 0x50, 0xd8, 0x77, 0x88, 0xf6, 0x80, 0x4, 0x22, 0x85, 0xce, 0xf2, 0x82, 0xcb, 0xb4, 0x5, 0x14, 0x68, 0xa9, 0x70, 0x77, 0xb8, 0x34, 0x1b, 0xf0, 0x1, 0xec, 0x1, 0x13, 0x58, 0x1a, 0x78, 0x88, 0xb, 0x58, 0x80, 0x27, 0x98, 0x20, 0x4b, 0x50, 0x41, 0x69, 0x84, 0xc9, 0x63, 0x81, 0x8, 0x7b, 0x6, 0x10, 0xd8, 0x1e, 0x38, 0x1c, 0x17, 0x68, 0x0, 0x2e, 0xa8, 0xe4, 0x23, 0x78, 0xdc, 0xa, 0x28, 0x38, 0xb, 0x28, 0xcc, 0x1f, 0x40, 0x1, 0x6f, 0x83, 0x88, 0x75, 0x82, 0xc7, 0x8c, 0x4, 0xec, 0x8, 0x28, 0xcc, 0x7b, 0xe4, 0xb8, 0x0, 0xe, 0x46, 0x35, 0x2c, 0xc2, 0x2d, 0xb8, 0xe0, 0xb5, 0x42, 0xa2, 0x75, 0x40, 0x2, 0xfc, 0xc4, 0x43, 0x98, 0x41, 0xa1, 0x56, 0x40, 0xc4, 0x5a, 0x1, 0x13, 0xda, 0x33, 0x5c, 0xf2, 0x7, 0x44, 0x74, 0x3f, 0x5c, 0x5a, 0x49, 0x24, 0x64, 0x3, 0x2c, 0xd8, 0x23, 0x34, 0x78, 0x19, 0xb8, 0x61, 0x15, 0x42, 0xa3, 0xc6, 0x46, 0x73, 0x80, 0xa, 0x52, 0x17, 0x0, 0xa1, 0x7d, 0x40, 0x26, 0x19, 0xc1, 0x6, 0xf0, 0x40, 0x45, 0x90, 0xc2, 0x81, 0xf6, 0xc0, 0x22, 0xf3, 0x80, 0x15, 0x2, 0x7, 0x2c, 0x9a, 0x3, 0xd8, 0xc0, 0x95, 0x21, 0xbb, 0x4, 0x80, 0x0, 0x99, 0xe0, 0x90, 0x19, 0x21, 0x93, 0xfe, 0x21, 0x43, 0x1a, 0x90, 0x64, 0x2, 0x2e, 0x20, 0x65, 0xc8, 0x79, 0x86, 0xc4, 0x78, 0x4, 0x2a, 0x38, 0x9e, 0x50, 0x82, 0xaf, 0x5, 0x17, 0x50, 0x33, 0xa0, 0x42, 0x21, 0x5, 0x24, 0xc0, 0xf, 0x64, 0xb0, 0x40, 0xe5, 0x3a, 0x42, 0xc1, 0xfd, 0x2, 0x3c, 0x10, 0x9, 0x88, 0x40, 0x5a, 0x40, 0x84, 0x11, 0x41, 0x83, 0x7f, 0x42, 0x82, 0x10, 0x3, 0x8, 0x8a, 0x1b, 0xc8, 0xc0, 0xb2, 0x81, 0x16, 0x6e, 0x68, 0x21, 0x1a, 0x2, 0x11, 0x30, 0x0, 0x42, 0x71, 0xc1, 0xe7, 0x89, 0x18, 0x60, 0x5, 0x3c, 0x70, 0x3c, 0xa2, 0x35, 0x14, 0xe6, 0x25, 0x98, 0x20, 0x97, 0x20, 0xa8, 0x2, 0x26, 0x8e, 0x12, 0x6c, 0x30, 0x2a, 0xa0, 0x22, 0x5e, 0xc2, 0x5, 0x8f, 0x8, 0xa, 0xea, 0x4, 0xa, 0x9b, 0x4, 0x3e, 0xf4, 0x3, 0x2e, 0x92, 0x5, 0x26, 0x65, 0xe0, 0x28, 0xe, 0x38, 0x50, 0xb0, 0x2f, 0x61, 0xe1, 0x6a, 0xa0, 0xf3, 0x2c, 0x12, 0x49, 0x6, 0x26, 0x20, 0x84, 0x30, 0x51, 0x5d, 0x90, 0xb0, 0x57, 0x70, 0x11, 0x3d, 0x70, 0x10, 0x53, 0x1c, 0x98, 0xf8, 0x54, 0x0, 0x2, 0xc3, 0x10, 0x58, 0xb0, 0x4d, 0xb0, 0x20, 0xd, 0x71, 0x40, 0x4d, 0x20, 0x4, 0x79, 0x5, 0x1f, 0x7b, 0x1, 0x89, 0x69, 0x2, 0x28, 0xc8, 0x17, 0x30, 0x81, 0x15, 0xd0, 0xc0, 0x5f, 0x50, 0x19, 0x1e, 0x72, 0x4d, 0x8d, 0xc1, 0x1, 0x91, 0x7e, 0x5, 0x34, 0x30, 0xe, 0x91, 0xc9, 0x74, 0x20, 0x84, 0xd5, 0x13, 0xb, 0x61, 0xd, 0x8f, 0xd8, 0x0, 0x32, 0x88, 0x4e, 0x20, 0x4, 0xd7, 0x84, 0xbc, 0x6, 0x38, 0x6c, 0x1f, 0xc8, 0xe0, 0x12, 0x68, 0xb4, 0x16, 0xa0, 0x41, 0x3a, 0x7, 0x27, 0x90, 0x1a, 0x88, 0x18, 0xa, 0xa5, 0x71, 0x25, 0xf1, 0x9, 0xa8, 0x50, 0x9d, 0xe1, 0x82, 0xbc, 0x81, 0x4, 0xc9, 0x9, 0x7c, 0x10, 0x3e, 0x40, 0x5, 0xe9, 0x2, 0x3a, 0xce, 0xd, 0x5c, 0x70, 0xfa, 0x60, 0x91, 0x41, 0x9, 0xc7, 0x8, 0xa, 0x93, 0x3, 0x7c, 0xa0, 0x3f, 0xe0, 0x53, 0x4b, 0x40, 0x6, 0xea, 0xd, 0xa, 0xcd, 0x18, 0xa, 0x83, 0x5, 0x2a, 0x29, 0xe, 0xc3, 0x1, 0x54, 0xb0, 0x7c, 0x41, 0x4, 0xaf, 0x2, 0x54, 0x40, 0xbe, 0x20, 0x41, 0xa7, 0x21, 0x29, 0xe1, 0x62, 0x6a, 0x81, 0x8, 0xb8, 0x4, 0x64, 0xb0, 0x29, 0xa0, 0xb0, 0x7f, 0xe0, 0x0, 0x3a, 0xc0, 0x5, 0xcb, 0x2, 0xb8, 0xe0, 0x6e, 0xc0, 0x8, 0xda, 0x13, 0x78, 0xe0, 0x1a, 0x0, 0x4, 0xe2, 0x8, 0xa, 0x1b, 0x16, 0x9d, 0x35, 0x88, 0x0, 0xa, 0x61, 0xe3, 0x1d, 0x61, 0xa1, 0x8f, 0xe0, 0xe3, 0x7d, 0x0, 0x8, 0x56, 0x16, 0xb9, 0x5, 0x7c, 0x50, 0x5a, 0xe2, 0xd1, 0xc9, 0x40, 0x8, 0x93, 0xa, 0x36, 0xc4, 0x2, 0xe, 0xf7, 0x15, 0xa, 0xae, 0x1b, 0xa, 0x83, 0xd, 0x36, 0xe8, 0xa, 0x16, 0xde, 0x11, 0x3e, 0x89, 0xb, 0x50, 0x70, 0xd9, 0x10, 0xca, 0x0, 0x38, 0xc0, 0x8f, 0xc1, 0x83, 0x77, 0x86, 0xc, 0x1b, 0xe8, 0x0, 0x9e, 0x78, 0x8, 0xb, 0xa0, 0xc3, 0xb7, 0x84, 0x82, 0x18, 0x4b, 0x54, 0x3b, 0x70, 0x81, 0xbe, 0x41, 0xcc, 0xd, 0x8, 0x61, 0x8e, 0x17, 0x0, 0xd, 0xd8, 0x40, 0x34, 0x20, 0xbd, 0x12, 0xe, 0x83, 0x16, 0x3a, 0x8a, 0x16, 0x48, 0xd0, 0x59, 0xe0, 0x21, 0x4c, 0x60, 0x42, 0xaa, 0xa0, 0x60, 0x69, 0x0, 0x5, 0xb9, 0x2, 0x12, 0x94, 0xf, 0x48, 0x60, 0xfe, 0x90, 0x66, 0x3, 0x4e, 0xf8, 0x4c, 0x50, 0xd8, 0x5f, 0x70, 0x99, 0x1f, 0xd0, 0xf0, 0x55, 0x88, 0x74, 0x81, 0xd, 0x6b, 0x80, 0x84, 0xb9, 0x8d, 0xc7, 0x34, 0x81, 0x4e, 0xa4, 0x8a, 0x82, 0xa1, 0x2, 0x15, 0x40, 0x7, 0x70, 0x81, 0x7f, 0x8d, 0x3, 0x61, 0x2, 0x11, 0x1c, 0x1e, 0x78, 0xb8, 0x1a, 0x80, 0x2, 0xa3, 0x80, 0x2, 0x69, 0x80, 0xc7, 0xf3, 0x1, 0x2c, 0xdc, 0x13, 0x90, 0x81, 0xad, 0x81, 0x88, 0xb8, 0x81, 0x82, 0x78, 0x84, 0x4e, 0xb6, 0x83, 0x45, 0xb3, 0x6, 0x37, 0x90, 0x5e, 0x68, 0x48, 0x82, 0x28, 0x0, 0xc1, 0x1, 0xe5, 0x80, 0x86, 0xf2, 0x81, 0xcc, 0xb9, 0x81, 0x88, 0xeb, 0x80, 0x3, 0xb7, 0x87, 0x8d, 0x69, 0x83, 0x45, 0x74, 0x5, 0x22, 0x84, 0x43, 0x48, 0x48, 0x9f, 0xa4, 0xf3, 0x40, 0xa4, 0x78, 0x80, 0xb, 0xec, 0xb, 0x2c, 0x8, 0x7, 0x74, 0x88, 0x15, 0x34, 0xc2, 0xa2, 0xa1, 0x33, 0xd, 0xc1, 0x8, 0x91, 0x18, 0xf0, 0x60, 0x38, 0x40, 0x7, 0x83, 0x1, 0x8c, 0x10, 0x19, 0x40, 0x4, 0xbb, 0x1a, 0x68, 0x30, 0x2b, 0x60, 0x92, 0xaa, 0x80, 0x8, 0xef, 0x2, 0x54, 0x50, 0x7f, 0x80, 0xa, 0x89, 0x2, 0x32, 0x94, 0x17, 0x1a, 0xe1, 0x4, 0xe, 0xa6, 0x1, 0xa, 0x97, 0xb, 0x16, 0xe4, 0xa, 0x91, 0x3c, 0x90, 0xf9, 0x1e, 0x10, 0xf1, 0x25, 0x70, 0x29, 0x1d, 0xa0, 0x82, 0xf0, 0x4, 0x40, 0xe8, 0x56, 0x40, 0x5, 0x54, 0xf, 0x1b, 0xc6, 0x1, 0x2a, 0x98, 0x35, 0xf0, 0x30, 0xbd, 0x80, 0x7, 0xd9, 0x6, 0x20, 0x90, 0x5e, 0x9, 0xf9, 0xb, 0x1c, 0xac, 0x22, 0x20, 0xc1, 0x96, 0x4f, 0x70, 0x80, 0x4b, 0xae, 0x81, 0x47, 0xb9, 0x8d, 0x8d, 0x3d, 0x82, 0x45, 0x65, 0x80, 0xca, 0xb9, 0x5, 0x18, 0x6c, 0x26, 0xa4, 0x53, 0x40, 0xc7, 0xb2, 0xc2, 0x6, 0xdf, 0x80, 0xa, 0xa0, 0x29, 0x30, 0x23, 0x32, 0x81, 0x8, 0x7c, 0x3c, 0x3e, 0x37, 0xb8, 0x20, 0xd7, 0x80, 0xb, 0xfc, 0x25, 0x24, 0xe8, 0x1d, 0x2c, 0x50, 0xd, 0x3c, 0xe0, 0x88, 0x60, 0x3a, 0x83, 0xc, 0xa6, 0x11, 0xb2, 0x5c, 0xc1, 0x7, 0xf2, 0x1, 0x2a, 0xce, 0x1, 0x12, 0xd7, 0x64, 0xe, 0xb2, 0x7, 0xa9, 0x6e, 0xd0, 0x71, 0x1d, 0x70, 0x80, 0xe5, 0x8, 0x6d, 0x83, 0x84, 0x6a, 0x0, 0x19, 0x78, 0xe, 0x48, 0xc4, 0x7, 0x80, 0x81, 0xae, 0x80, 0x44, 0x3f, 0x1, 0x13, 0x4c, 0x1f, 0x58, 0xe0, 0x4a, 0x48, 0x8c, 0x2e, 0x4, 0x78, 0x81, 0x16, 0x7a, 0x5, 0x90, 0xa0, 0xdd, 0xc3, 0xa7, 0xd8, 0xc2, 0x44, 0xfc, 0x40, 0x2, 0xda, 0x0, 0xc, 0x54, 0x11, 0xe0, 0xc0, 0xba, 0x80, 0x9, 0x7a, 0x9, 0xa0, 0x0, 0x52, 0x40, 0x61, 0x51, 0x44, 0x67, 0x12, 0x3, 0xc, 0x0, 0xf, 0x70, 0xe1, 0x31, 0xc0, 0xe1, 0xb6, 0xc2, 0xa1, 0xb9, 0xc1, 0x46, 0x50, 0x40, 0x1, 0x9b, 0x1, 0x1a, 0xc2, 0x11, 0x72, 0x4c, 0xa1, 0x2, 0x5b, 0x20, 0xb1, 0x28, 0xc0, 0x4, 0xc7, 0x12, 0x40, 0x0, 0xee, 0x0, 0x8, 0xd1, 0x2a, 0x32, 0xd0, 0x11, 0x81, 0x7f, 0xa0, 0x84, 0x77, 0xa, 0x93, 0xc8, 0x0, 0x97, 0xe7, 0x1, 0x9, 0x50, 0x1, 0x5, 0xf5, 0x0, 0x85, 0xee, 0x3, 0x93, 0x59, 0x82, 0x3c, 0x59, 0x14, 0x52, 0x28, 0xa4, 0xb, 0x28, 0x30, 0xa, 0x84, 0x4d, 0x81, 0x7f, 0x43, 0xa7, 0x56, 0x80, 0xb, 0x92, 0xf, 0x3c, 0x98, 0x47, 0xa8, 0x0, 0x35, 0x20, 0xde, 0x3, 0x2a, 0x8b, 0x2, 0x2e, 0x8f, 0x6, 0x58, 0x40, 0x58, 0xe0, 0x33, 0x4d, 0xc1, 0xa, 0xc0, 0x6, 0xc0, 0xc0, 0x4, 0x5, 0xf5, 0x4, 0x16, 0xfa, 0x26, 0x60, 0x60, 0x9c, 0xa0, 0x63, 0x2f, 0x20, 0x13, 0xbe, 0x81, 0xc, 0x97, 0xd, 0x32, 0xd0, 0x1, 0x22, 0x3e, 0x80, 0x20, 0x49, 0xe0, 0x50, 0x18, 0x21, 0x2, 0x19, 0xe0, 0x20, 0xbd, 0x10, 0xc8, 0x4, 0x9b, 0x40, 0xd, 0x24, 0xe0, 0xcd, 0x90, 0xe9, 0x3, 0x82, 0x16, 0x11, 0x28, 0x2a, 0xd0, 0xb5, 0x0, 0x83, 0x73, 0xb, 0x19, 0xd6, 0x7, 0x1b, 0x71, 0x5, 0x26, 0x28, 0x6d, 0x0, 0x82, 0x7f, 0x5, 0x2a, 0xb8, 0x56, 0x80, 0x84, 0x79, 0x4, 0x86, 0xa0, 0x7e, 0x50, 0x20, 0xe3, 0x3, 0x20, 0x36, 0x88, 0xaf, 0x90, 0x91, 0xd5, 0x60, 0x82, 0xe4, 0x1, 0x93, 0xf4, 0x8, 0x95, 0xc0, 0x5, 0x1b, 0x61, 0x6, 0x87, 0xc3, 0x1, 0x47, 0xb5, 0x41, 0x51, 0xc9, 0x26, 0x0, 0x3, 0xc1, 0x0, 0x87, 0x46, 0x5, 0x8f, 0x5a, 0x1, 0x95, 0xef, 0x9, 0x89, 0xca, 0x0, 0x8b, 0xf7, 0x2, 0x19, 0x5b, 0xb, 0x32, 0x8, 0x82, 0x2, 0xec, 0x0, 0x13, 0x23, 0x11, 0x40, 0x4, 0x20, 0xe0, 0x26, 0x51, 0x89, 0x85, 0x40, 0x84, 0xc2, 0x1, 0xf, 0x51, 0x1, 0xd, 0x8, 0x6e, 0xf8, 0x6e, 0x0, 0x82, 0x6a, 0x1, 0xf, 0x72, 0x4, 0x2c, 0x40, 0x4d, 0x50, 0x41, 0x16, 0x8, 0x67, 0x46, 0x4a, 0xd, 0x90, 0xc0, 0xfe, 0xc1, 0x42, 0x30, 0x1, 0x9, 0x50, 0xd, 0x5c, 0x16, 0x9, 0xc0, 0x0, 0xf6, 0x41, 0x27, 0x92, 0xc0, 0x63, 0x7a, 0xc2, 0xa1, 0x9c, 0x40, 0x21, 0x27, 0xec, 0x25, 0x4c, 0x80, 0x1b, 0x20, 0x81, 0x2b, 0xa0, 0x0, 0x18, 0xe0, 0xe1, 0x6a, 0x21, 0x2, 0xa3, 0xd2, 0xaf, 0xe0, 0x3, 0x7a, 0x0, 0x4, 0x99, 0x26, 0x50, 0x70, 0xcf, 0xa0, 0xe1, 0x58, 0xa1, 0xd3, 0x38, 0xa0, 0x30, 0x79, 0x20, 0xd2, 0x3a, 0x20, 0xb3, 0x5e, 0x60, 0xa1, 0xeb, 0x80, 0x5, 0xc8, 0x1, 0x4c, 0xc0, 0x5b, 0xa0, 0x60, 0xc8, 0x41, 0x4, 0x6d, 0xc8, 0x20, 0xab, 0x10, 0xe3, 0x7, 0x1f, 0x4b, 0x7, 0x28, 0x70, 0x17, 0x80, 0x84, 0xf9, 0x6, 0x46, 0x90, 0x44, 0xf0, 0x40, 0xf6, 0x60, 0x5, 0xca, 0x7, 0x1b, 0xcf, 0x2, 0xb, 0x61, 0x12, 0x15} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_reader.go b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_reader.go new file mode 100644 index 0000000000..0b3a77da00 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_reader.go @@ -0,0 +1,77 @@ +package rlepluslazy + +import ( + "github.com/multiformats/go-varint" + "golang.org/x/xerrors" +) + +func DecodeRLE(buf []byte) (RunIterator, error) { + bv := readBitvec(buf) + + ver := bv.Get(2) // Read version + if ver != Version { + return nil, ErrWrongVersion + } + + it := &rleIterator{bv: bv} + + // next run is previous in relation to prep + // so we invert the value + it.nextRun.Val = bv.Get(1) != 1 + if err := it.prep(); err != nil { + return nil, err + } + return it, nil +} + +type rleIterator struct { + bv *rbitvec + + nextRun Run +} + +func (it *rleIterator) HasNext() bool { + return it.nextRun.Valid() +} + +func (it *rleIterator) NextRun() (Run, error) { + ret := it.nextRun + return ret, it.prep() +} + +func (it *rleIterator) prep() error { + x := it.bv.Get(1) + + switch x { + case 1: + it.nextRun.Len = 1 + + case 0: + y := it.bv.Get(1) + switch y { + case 1: + it.nextRun.Len = uint64(it.bv.Get(4)) + case 0: + var buf = make([]byte, 0, 10) + for { + b := it.bv.Get(8) + buf = append(buf, b) + if b&0x80 == 0 { + break + } + if len(buf) > 10 { + return xerrors.Errorf("run too long: %w", ErrDecode) + } + } + var err error + it.nextRun.Len, _, err = varint.FromUvarint(buf) + if err != nil { + return err + } + + } + } + + it.nextRun.Val = !it.nextRun.Val + return nil +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_test.go new file mode 100644 index 0000000000..0731d0aef8 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_test.go @@ -0,0 +1,184 @@ +package rlepluslazy + +import ( + "math/rand" + "testing" + + "github.com/filecoin-project/go-bitfield/rle/internal/rleplus" + "github.com/stretchr/testify/assert" +) + +func TestDecode(t *testing.T) { + // Encoding bitvec![LittleEndian; 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + // in the Rust reference implementation gives an encoding of [223, 145, 136, 0] (without version field) + // The bit vector is equivalent to the integer set { 0, 2, 4, 5, 6, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 } + + // This is the above reference output with a version header "00" manually added + referenceEncoding := []byte{124, 71, 34, 2} + + expectedNumbers := []uint64{0, 2, 4, 5, 6, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27} + + runs, err := RunsFromBits(BitsFromSlice(expectedNumbers)) + assert.NoError(t, err) + encoded, err := EncodeRuns(runs, []byte{}) + assert.NoError(t, err) + + // Our encoded bytes are the same as the ref bytes + assert.Equal(t, len(referenceEncoding), len(encoded)) + assert.Equal(t, referenceEncoding, encoded) + + rle, err := FromBuf(encoded) + assert.NoError(t, err) + decoded := make([]uint64, 0, len(expectedNumbers)) + + rit, err := rle.RunIterator() + assert.NoError(t, err) + + it, err := BitsFromRuns(rit) + assert.NoError(t, err) + for it.HasNext() { + bit, err := it.Next() + assert.NoError(t, err) + decoded = append(decoded, bit) + } + + // Our decoded integers are the same as expected + assert.Equal(t, expectedNumbers, decoded) +} + +func TestGoldenGen(t *testing.T) { + t.SkipNow() + N := 10000 + mod := uint32(1) << 20 + runExProp := float32(0.93) + + bits := make([]uint64, N) + + for i := 0; i < N; i++ { + x := rand.Uint32() % mod + bits[i] = uint64(x) + for rand.Float32() < runExProp && i+1 < N { + i++ + x = (x + 1) % mod + bits[i] = uint64(x) + } + } + + out, _, err := rleplus.Encode(bits) + assert.NoError(t, err) + t.Logf("%#v", out) + _, runs := rleplus.RunLengths(bits) + t.Logf("runs: %v", runs) + t.Logf("len: %d", len(out)) +} + +func TestGolden(t *testing.T) { + expected, _ := rleplus.Decode(goldenRLE) + res := make([]uint64, 0, len(expected)) + + rle, err := FromBuf(goldenRLE) + assert.NoError(t, err) + rit, err := rle.RunIterator() + assert.NoError(t, err) + it, err := BitsFromRuns(rit) + assert.NoError(t, err) + for it.HasNext() { + bit, err := it.Next() + assert.NoError(t, err) + res = append(res, bit) + } + assert.Equal(t, expected, res) +} + +func TestGoldenLoop(t *testing.T) { + rle, err := FromBuf(goldenRLE) + assert.NoError(t, err) + + rit, err := rle.RunIterator() + assert.NoError(t, err) + + buf, err := EncodeRuns(rit, nil) + assert.NoError(t, err) + + assert.Equal(t, goldenRLE, buf) +} + +func TestEncodeConsecutiveFails(t *testing.T) { + ra := &RunSliceIterator{ + Runs: []Run{ + {Val: true, Len: 5}, + {Val: true, Len: 8}, + }, + } + + _, err := EncodeRuns(ra, nil) + if err != ErrSameValRuns { + t.Fatal("expected ErrSameValRuns") + } +} + +var Res uint64 = 0 + +func BenchmarkRunIterator(b *testing.B) { + b.ReportAllocs() + var r uint64 + for i := 0; i < b.N; i++ { + rle, _ := FromBuf(goldenRLE) + rit, _ := rle.RunIterator() + for rit.HasNext() { + run, _ := rit.NextRun() + if run.Val { + r = r + run.Len + } + } + } + Res = Res + r +} + +func BenchmarkRunsToBits(b *testing.B) { + b.ReportAllocs() + var r uint64 + for i := 0; i < b.N; i++ { + rle, _ := FromBuf(goldenRLE) + rit, _ := rle.RunIterator() + it, _ := BitsFromRuns(rit) + for it.HasNext() { + bit, _ := it.Next() + if bit < 1<<63 { + r++ + } + } + } + Res = Res + r +} + +func BenchmarkOldRLE(b *testing.B) { + b.ReportAllocs() + var r uint64 + for i := 0; i < b.N; i++ { + rle, _ := rleplus.Decode(goldenRLE) + r = r + uint64(len(rle)) + } + Res = Res + r +} + +func BenchmarkDecodeEncode(b *testing.B) { + b.ReportAllocs() + var r uint64 + out := make([]byte, 0, len(goldenRLE)) + for i := 0; i < b.N; i++ { + rle, _ := FromBuf(goldenRLE) + rit, _ := rle.RunIterator() + out, _ = EncodeRuns(rit, out) + r = r + uint64(len(out)) + } + + /* + for i := 0; i < b.N; i++ { + rle, _ := rleplus.Decode(goldenRLE) + out, _, _ := rleplus.Encode(rle) + r = r + uint64(len(out)) + } + */ + Res = Res + r +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_writer.go b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_writer.go new file mode 100644 index 0000000000..4e1b7661aa --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/rleplus_writer.go @@ -0,0 +1,63 @@ +package rlepluslazy + +import ( + "encoding/binary" + "errors" +) + +var ErrSameValRuns = errors.New("2 consecutive runs with the same value") + +func EncodeRuns(rit RunIterator, buf []byte) ([]byte, error) { + rit = newNormIter(rit) + + bv := writeBitvec(buf) + bv.Put(0, 2) + + first := true + varBuf := make([]byte, binary.MaxVarintLen64) + prev := false + + for rit.HasNext() { + run, err := rit.NextRun() + if err != nil { + return nil, err + } + + if first { + if run.Val { + bv.Put(1, 1) + } else { + bv.Put(0, 1) + } + prev = run.Val + first = false + } else { + if prev == run.Val { + return nil, ErrSameValRuns + } + prev = run.Val + } + + switch { + case run.Len == 1: + bv.Put(1, 1) + case run.Len < 16: + bv.Put(2, 2) + bv.Put(byte(run.Len), 4) + case run.Len >= 16: + bv.Put(0, 2) + numBytes := binary.PutUvarint(varBuf, run.Len) + for i := 0; i < numBytes; i++ { + bv.Put(varBuf[i], 8) + } + } + + } + + if first { + bv.Put(0, 1) + } + + return bv.Out(), nil + +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/runs.go b/vendor/github.com/filecoin-project/go-bitfield/rle/runs.go new file mode 100644 index 0000000000..e991b34c4b --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/runs.go @@ -0,0 +1,393 @@ +package rlepluslazy + +import ( + "fmt" + "math" + + "golang.org/x/xerrors" +) + +func Or(a, b RunIterator) (RunIterator, error) { + it := addIt{a: a, b: b} + return &it, it.prep() +} + +type addIt struct { + a RunIterator + b RunIterator + + next Run + + arun Run + brun Run +} + +func (it *addIt) prep() error { + var err error + + fetch := func() error { + if !it.arun.Valid() && it.a.HasNext() { + it.arun, err = it.a.NextRun() + if err != nil { + return err + } + } + + if !it.brun.Valid() && it.b.HasNext() { + it.brun, err = it.b.NextRun() + if err != nil { + return err + } + } + return nil + } + + if err := fetch(); err != nil { + return err + } + + // one is not valid + if !it.arun.Valid() { + it.next = it.brun + it.brun.Len = 0 + return nil + } + + if !it.brun.Valid() { + it.next = it.arun + it.arun.Len = 0 + return nil + } + + if !it.arun.Val && !it.brun.Val { + min := it.arun.Len + if it.brun.Len < min { + min = it.brun.Len + } + it.next = Run{Val: it.arun.Val, Len: min} + it.arun.Len -= it.next.Len + it.brun.Len -= it.next.Len + + if err := fetch(); err != nil { + return err + } + trailingRun := func(r1, r2 Run) bool { + return !r1.Valid() && r2.Val == it.next.Val + } + if trailingRun(it.arun, it.brun) || trailingRun(it.brun, it.arun) { + it.next.Len += it.arun.Len + it.next.Len += it.brun.Len + it.arun.Len = 0 + it.brun.Len = 0 + } + + return nil + } + + it.next = Run{Val: true} + // different vals, 'true' wins + for (it.arun.Val && it.arun.Valid()) || (it.brun.Val && it.brun.Valid()) { + min := it.arun.Len + if it.brun.Len < min && it.brun.Valid() || !it.arun.Valid() { + min = it.brun.Len + } + it.next.Len += min + if it.arun.Valid() { + it.arun.Len -= min + } + if it.brun.Valid() { + it.brun.Len -= min + } + if err := fetch(); err != nil { + return err + } + } + + return nil +} + +func (it *addIt) HasNext() bool { + return it.next.Valid() +} + +func (it *addIt) NextRun() (Run, error) { + next := it.next + return next, it.prep() +} + +func Count(ri RunIterator) (uint64, error) { + var length uint64 + var count uint64 + + for ri.HasNext() { + r, err := ri.NextRun() + if err != nil { + return 0, err + } + + if math.MaxUint64-r.Len < length { + return 0, xerrors.New("RLE+ overflows") + } + length += r.Len + + if r.Val { + count += r.Len + } + } + return count, nil +} + +func IsSet(ri RunIterator, x uint64) (bool, error) { + var i uint64 + for ri.HasNext() { + r, err := ri.NextRun() + if err != nil { + return false, err + } + + if i+r.Len > x { + return r.Val, nil + } + + i += r.Len + } + return false, nil +} + +func min(a, b uint64) uint64 { + if a < b { + return a + } + return b +} + +type andIter struct { + a, b RunIterator + ar, br Run +} + +func (ai *andIter) HasNext() bool { + return (ai.ar.Valid() || ai.a.HasNext()) && (ai.br.Valid() || ai.b.HasNext()) +} + +func (ai *andIter) NextRun() (run Run, err error) { + for { + // Ensure we have two valid runs. + if !ai.ar.Valid() { + if !ai.a.HasNext() { + break + } + ai.ar, err = ai.a.NextRun() + if err != nil { + return Run{}, err + } + } + + if !ai.br.Valid() { + if !ai.b.HasNext() { + break + } + ai.br, err = ai.b.NextRun() + if err != nil { + return Run{}, err + } + } + + // && + newVal := ai.ar.Val && ai.br.Val + + // Check to see if we have an ongoing run and if we've changed + // value. + if run.Len > 0 && run.Val != newVal { + return run, nil + } + + newLen := min(ai.ar.Len, ai.br.Len) + + run.Val = newVal + run.Len += newLen + ai.ar.Len -= newLen + ai.br.Len -= newLen + } + + if run.Valid() { + return run, nil + } + + return Run{}, fmt.Errorf("end of runs") +} + +func And(a, b RunIterator) (RunIterator, error) { + return &andIter{a: a, b: b}, nil +} + +type RunSliceIterator struct { + Runs []Run + i int +} + +func (ri *RunSliceIterator) HasNext() bool { + return ri.i < len(ri.Runs) +} + +func (ri *RunSliceIterator) NextRun() (Run, error) { + if ri.i >= len(ri.Runs) { + return Run{}, fmt.Errorf("end of runs") + } + + out := ri.Runs[ri.i] + ri.i++ + return out, nil +} + +type notIter struct { + it RunIterator +} + +func (ni *notIter) HasNext() bool { + return true +} + +func (ni *notIter) NextRun() (Run, error) { + if !ni.it.HasNext() { + return Run{ + Val: true, + Len: 40_000_000_000_000, // close enough to infinity + }, nil + } + + nr, err := ni.it.NextRun() + if err != nil { + return Run{}, err + } + + nr.Val = !nr.Val + return nr, nil +} + +func Subtract(a, b RunIterator) (RunIterator, error) { + return And(a, ¬Iter{it: b}) +} + +type nextRun struct { + set bool + run Run + err error +} + +type peekIter struct { + it RunIterator + stash nextRun +} + +func (it *peekIter) HasNext() bool { + if it.stash.set { + return true + } + return it.it.HasNext() +} + +func (it *peekIter) NextRun() (Run, error) { + if it.stash.set { + run := it.stash.run + err := it.stash.err + it.stash = nextRun{} + return run, err + } + + return it.it.NextRun() +} + +func (it *peekIter) peek() (Run, error) { + run, err := it.NextRun() + it.put(run, err) + return run, err +} + +func (it *peekIter) put(run Run, err error) { + it.stash = nextRun{ + set: true, + run: run, + err: err, + } +} + +// normIter trims the last run of 0s +type normIter struct { + it *peekIter +} + +func newNormIter(it RunIterator) *normIter { + if nit, ok := it.(*normIter); ok { + return nit + } + return &normIter{ + it: &peekIter{ + it: it, + }, + } +} + +func (it *normIter) HasNext() bool { + if !it.it.HasNext() { + return false + } + + // check if this is the last run + cur, err := it.it.NextRun() + if err != nil { + it.it.put(cur, err) + return true + } + + notLast := it.it.HasNext() + it.it.put(cur, err) + if notLast { + return true + } + + return cur.Val +} + +func (it *normIter) NextRun() (Run, error) { + return it.it.NextRun() +} + +func LastIndex(iter RunIterator, val bool) (uint64, error) { + var at uint64 + var max uint64 + for iter.HasNext() { + r, err := iter.NextRun() + if err != nil { + return 0, err + } + + at += r.Len + + if r.Val == val { + max = at + } + } + + return max, nil +} + +// Returns iterator with all bits up to the last bit set: +// in: 11100000111010001110000 +// out: 1111111111111111111 +func Fill(i RunIterator) (RunIterator, error) { + max, err := LastIndex(i, true) + if err != nil { + return nil, err + } + + var runs []Run + if max > 0 { + runs = append(runs, Run{ + Val: true, + Len: max, + }) + } + + return &RunSliceIterator{Runs: runs}, nil +} diff --git a/vendor/github.com/filecoin-project/go-bitfield/rle/runs_test.go b/vendor/github.com/filecoin-project/go-bitfield/rle/runs_test.go new file mode 100644 index 0000000000..c8a71400ba --- /dev/null +++ b/vendor/github.com/filecoin-project/go-bitfield/rle/runs_test.go @@ -0,0 +1,177 @@ +package rlepluslazy + +import ( + "math" + "math/rand" + "sort" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestOrRuns(t *testing.T) { + { + a, err := RunsFromSlice([]uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14}) + assert.NoError(t, err) + b, err := RunsFromSlice([]uint64{0, 1, 2, 3, 9, 10, 16, 17, 18, 50, 51, 70}) + assert.NoError(t, err) + + s, err := Or(a, b) + assert.NoError(t, err) + bis, err := SliceFromRuns(s) + assert.Equal(t, []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 50, 51, 70}, bis) + assert.NoError(t, err) + } + + { + a, err := RunsFromSlice([]uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14}) + assert.NoError(t, err) + b, err := RunsFromSlice([]uint64{0, 1, 2, 3, 9, 10, 16, 17, 18, 50, 51, 70}) + assert.NoError(t, err) + + s, err := Or(b, a) + assert.NoError(t, err) + bis, err := SliceFromRuns(s) + assert.Equal(t, []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 50, 51, 70}, bis) + assert.NoError(t, err) + } +} + +func randomBits(N int, max uint64) []uint64 { + all := make(map[uint64]struct{}) + for len(all) <= N { + x := rand.Uint64() % max + if _, has := all[x]; has { + continue + } + all[x] = struct{}{} + } + + res := make([]uint64, 0, N) + for x := range all { + res = append(res, x) + } + sort.Slice(res, func(i, j int) bool { return res[i] < res[j] }) + + return res +} + +func sum(a, b []uint64) []uint64 { + all := make(map[uint64]struct{}) + for _, x := range a { + all[x] = struct{}{} + } + for _, x := range b { + all[x] = struct{}{} + } + res := make([]uint64, 0, len(all)) + for x := range all { + res = append(res, x) + } + sort.Slice(res, func(i, j int) bool { return res[i] < res[j] }) + + return res +} + +func and(a, b []uint64) []uint64 { + amap := make(map[uint64]struct{}) + for _, x := range a { + amap[x] = struct{}{} + } + + res := make([]uint64, 0) + for _, x := range b { + if _, ok := amap[x]; ok { + res = append(res, x) + } + + } + sort.Slice(res, func(i, j int) bool { return res[i] < res[j] }) + + return res +} + +func TestOrRandom(t *testing.T) { + N := 100 + for i := 0; i < N; i++ { + abits := randomBits(1000, 1500) + bbits := randomBits(1000, 1500) + sumbits := sum(abits, bbits) + + a, err := RunsFromSlice(abits) + assert.NoError(t, err) + b, err := RunsFromSlice(bbits) + assert.NoError(t, err) + + s, err := Or(b, a) + assert.NoError(t, err) + bis, err := SliceFromRuns(s) + assert.NoError(t, err) + assert.Equal(t, sumbits, bis) + } +} + +func TestIsSet(t *testing.T) { + set := []uint64{0, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14} + setMap := make(map[uint64]struct{}) + for _, v := range set { + setMap[v] = struct{}{} + } + + for i := uint64(0); i < 30; i++ { + a, err := RunsFromSlice(set) + assert.NoError(t, err) + res, err := IsSet(a, i) + assert.NoError(t, err) + _, should := setMap[i] + assert.Equal(t, should, res, "IsSet result missmatch at: %d", i) + + } +} + +func TestCount(t *testing.T) { + tests := []struct { + name string + runs []Run + count uint64 + shouldFail bool + }{ + { + name: "count-20", + runs: []Run{{false, 4}, {true, 7}, {false, 10}, {true, 3}, {false, 13}, {true, 10}}, + count: 20, + }, + { + name: "count-2024", + runs: []Run{{false, 4}, {true, 1000}, {false, 10}, {true, 1000}, + {false, 13}, {true, 24}, {false, 4}}, + count: 2024, + }, + { + name: "fail-set-over-max", + runs: []Run{{false, 4}, {true, math.MaxUint64 / 2}, {false, 10}, {true, math.MaxUint64 / 2}, + {false, 13}, {true, 24}, {false, 4}}, + shouldFail: true, + }, + { + name: "length-over-max", + runs: []Run{{false, math.MaxUint64 / 2}, {true, 4}, {false, 10}, {true, math.MaxUint64 / 2}, + {false, 13}, {true, 24}, {false, 4}}, + shouldFail: true, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + runs := &RunSliceIterator{Runs: test.runs} + c, err := Count(runs) + if test.shouldFail { + assert.Error(t, err, "test indicated it should fail") + } else { + assert.NoError(t, err) + assert.EqualValues(t, test.count, c) + } + }) + } +} diff --git a/vendor/github.com/filecoin-project/go-cbor-util/.circleci/config.yml b/vendor/github.com/filecoin-project/go-cbor-util/.circleci/config.yml new file mode 100644 index 0000000000..521d7fb390 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/.circleci/config.yml @@ -0,0 +1,161 @@ +version: 2.1 +orbs: + go: gotest/tools@0.0.9 + +executors: + golang: + docker: + - image: circleci/golang:1.13 + resource_class: small + +commands: + install-deps: + steps: + - go/install-ssh + - go/install: {package: git} + prepare: + parameters: + linux: + default: true + description: is a linux build environment? + type: boolean + steps: + - checkout + - when: + condition: << parameters.linux >> + steps: + - run: sudo apt-get update + - run: sudo apt-get install ocl-icd-opencl-dev + build-all: + + +jobs: + mod-tidy-check: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - go/mod-tidy-check + + test: &test + description: | + Run tests with gotestsum. + parameters: + executor: + type: executor + default: golang + go-test-flags: + type: string + default: "-timeout 5m" + description: Flags passed to go test. + packages: + type: string + default: "./..." + description: Import paths of packages to be tested. + test-suite-name: + type: string + default: unit + description: Test suite name to report to CircleCI. + gotestsum-format: + type: string + default: short + description: gotestsum format. https://github.com/gotestyourself/gotestsum#format + coverage: + type: string + default: -coverprofile=coverage.txt + description: Coverage flag. Set to the empty string to disable. + codecov-upload: + type: boolean + default: false + description: | + Upload coverage report to https://codecov.io/. Requires the codecov API token to be + set as an environment variable for private projects. + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/mod-download + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - go/install-gotestsum: + gobin: $HOME/.local/bin + - run: + name: go test + environment: + GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml + GOTESTSUM_FORMAT: << parameters.gotestsum-format >> + command: | + mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> + gotestsum -- \ + << parameters.coverage >> \ + << parameters.go-test-flags >> \ + << parameters.packages >> + no_output_timeout: 30m + - store_test_results: + path: /tmp/test-reports + - when: + condition: << parameters.codecov-upload >> + steps: + - go/install: {package: bash} + - go/install: {package: curl} + - run: + shell: /bin/bash -eo pipefail + command: | + bash <(curl -s https://codecov.io/bash) + - save_cache: + name: save go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + paths: + - "~/go/pkg" + - "~/go/src/github.com" + - "~/go/src/golang.org" + + lint: &lint + description: | + Run golangci-lint. + parameters: + executor: + type: executor + default: golang + golangci-lint-version: + type: string + default: 1.21.0 + concurrency: + type: string + default: '2' + description: | + Concurrency used to run linters. Defaults to 2 because NumCPU is not + aware of container CPU limits. + args: + type: string + default: '' + description: | + Arguments to pass to golangci-lint + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: << parameters.golangci-lint-version >> + - run: + name: Lint + command: | + $HOME/.local/bin/golangci-lint run -v \ + --concurrency << parameters.concurrency >> << parameters.args >> + lint-changes: + <<: *lint + + lint-all: + <<: *lint + +workflows: + version: 2.1 + ci: + jobs: + - lint-changes: + args: "--new-from-rev origin/master" + - test + - mod-tidy-check diff --git a/vendor/github.com/filecoin-project/go-cbor-util/CONTRIBUTING.md b/vendor/github.com/filecoin-project/go-cbor-util/CONTRIBUTING.md new file mode 100644 index 0000000000..cd329d7929 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/CONTRIBUTING.md @@ -0,0 +1,52 @@ +# Contributing to this repo + +First, thank you for your interest in contributing to this project! Before you pick up your first issue and start +changing code, please: + +1. Review all documentation for the module you're interested in. +1. Look through the [issues for this repo](https://github.com/filecoin-project/go-cbor-util/issues) for relevant discussions. +1. If you have questions about an issue, post a comment in the issue. +1. If you want to submit changes that aren't covered by an issue, file a new one with your proposal, outlining what problem you found/feature you want to implement, and how you intend to implement a solution. + +For best results, before submitting a PR, make sure: +1. It has met all acceptance criteria for the issue. +1. It addresses only the one issue and does not make other, irrelevant changes. +1. Your code conforms to our coding style guide. +1. You have adequate test coverage (this should be indicated by CI results anyway). +1. If you like, check out [current PRs](https://github.com/filecoin-project/go-cbor-util/pulls) to see how others do it. + +Special Note: +If editing README.md, please conform to the [standard readme specification](https://github.com/RichardLitt/standard-readme/blob/master/spec.md). + +Before a PR can be merged to `master`, it must: +1. Pass continuous integration. +1. Be approved by at least two maintainers + +### Testing + +- All new code should be accompanied by unit tests. Prefer focused unit tests to integration tests for thorough validation of behaviour. Existing code is not necessarily a good model, here. +- Integration tests should test integration, not comprehensive functionality +- Tests should be placed in a separate package named `$PACKAGE_test`. For example, a test of the `chain` package should live in a package named `chain_test`. In limited situations, exceptions may be made for some "white box" tests placed in the same package as the code it tests. + +### Conventions and Style + +#### Imports +We use the following import ordering. +``` +import ( + [stdlib packages, alpha-sorted] + + [external packages] + + [go-cbor-util packages] +) +``` + +Where a package name does not match its directory name, an explicit alias is expected (`goimports` will add this for you). + +#### Comments +Comments are a communication to other developers (including your future self) to help them understand and maintain code. Good comments describe the _intent_ of the code, without repeating the procedures directly. + +- A `TODO:` comment describes a change that is desired but could not be immediately implemented. It must include a reference to a GitHub issue outlining whatever prevents the thing being done now (which could just be a matter of priority). +- A `NOTE:` comment indicates an aside, some background info, or ideas for future improvement, rather than the intent of the current code. It's often fine to document such ideas alongside the code rather than an issue (at the loss of a space for discussion). +- `FIXME`, `HACK`, `XXX` and similar tags indicating that some code is to be avoided in favour of `TODO`, `NOTE` or some straight prose. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-cbor-util/COPYRIGHT b/vendor/github.com/filecoin-project/go-cbor-util/COPYRIGHT new file mode 100644 index 0000000000..771e6f7cd7 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/COPYRIGHT @@ -0,0 +1,3 @@ +Copyright 2019. Protocol Labs, Inc. + +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/vendor/github.com/filecoin-project/go-cbor-util/LICENSE-APACHE b/vendor/github.com/filecoin-project/go-cbor-util/LICENSE-APACHE new file mode 100644 index 0000000000..546514363d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2019. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/filecoin-project/go-cbor-util/LICENSE-MIT b/vendor/github.com/filecoin-project/go-cbor-util/LICENSE-MIT new file mode 100644 index 0000000000..ea532a8305 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2019. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/filecoin-project/go-cbor-util/README.md b/vendor/github.com/filecoin-project/go-cbor-util/README.md new file mode 100644 index 0000000000..b0fc8d5373 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/README.md @@ -0,0 +1,56 @@ +# go-cbor-util +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![CircleCI](https://circleci.com/gh/filecoin-project/go-cbor-util.svg?style=svg)](https://circleci.com/gh/filecoin-project/go-cbor-util) +[![codecov](https://codecov.io/gh/filecoin-project/go-cbor-util/branch/master/graph/badge.svg)](https://codecov.io/gh/filecoin-project/go-cbor-util) + +CBOR utilities for reading and writing objects to CBOR representation, optimizing for fast path serialization/deserialization generated by cbor-gen + +## Install + +Install this library with `go mod` + +## Usage + +Write an object to a stream in cbor + +```golang +import ( + cborutil "github.com/filecoin-project/go-cbor-util" + cbg "github.com/whyrusleeping/cbor-gen" +) + +var w io.Writer +// some object type with cbg fastpath marshalling +var out cbg.CBORMarshaler +err := cborutil.WriteCborRPC(w, obj) + +var slow interface{} +// will work but will be slower if slow does not support fast path marshalling +err := cborutil.WriteCborRPC(w, slow) +``` + +Read an object form a stream in cbor + +```golang +import ( + cborutil "github.com/filecoin-project/go-cbor-util" + cbg "github.com/whyrusleeping/cbor-gen" +) + +var r io.Reader +// some object type with cbg fastpath marshalling +var out cbg.CBORUnmarshaler +err := cborutil.ReadCborRPC(r, obj) + +var slow interface{} +// will work but will be slower if slow does not support fast path unmarshalling +err := cborutil.ReadCborRPC(r, slow) +``` + +## Project-level documentation +The filecoin-project has a [community repo](https://github.com/filecoin-project/community) that documents in more detail our policies and guidelines, such as discussion forums and chat rooms and [Code of Conduct](https://github.com/filecoin-project/community/blob/master/CODE_OF_CONDUCT.md). + +## License +This repository is dual-licensed under Apache 2.0 and MIT terms. + +Copyright 2019. Protocol Labs, Inc. diff --git a/vendor/github.com/filecoin-project/go-cbor-util/go.mod b/vendor/github.com/filecoin-project/go-cbor-util/go.mod new file mode 100644 index 0000000000..9ef44cfdc0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/go.mod @@ -0,0 +1,10 @@ +module github.com/filecoin-project/go-cbor-util + +go 1.13 + +require ( + github.com/ipfs/go-ipld-cbor v0.0.3 + github.com/ipfs/go-ipld-format v0.0.2 + github.com/ipfs/go-log v1.0.0 + github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0 +) diff --git a/vendor/github.com/filecoin-project/go-cbor-util/go.sum b/vendor/github.com/filecoin-project/go-cbor-util/go.sum new file mode 100644 index 0000000000..be803b6f0c --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/go.sum @@ -0,0 +1,77 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.3 h1:ENsxvybwkmke7Z/QJOmeJfoguj6GH3Y0YOaGrfy9Q0I= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-log v1.0.0 h1:BW3LQIiZzpNyolt84yvKNCd3FU+AK4VDw1hnHR+1aiI= +github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0 h1:efb/4CnrubzNGqQOeHErxyQ6rIsJb7GcgeSDF7fqWeI= +github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j1yYgiuvjbjRzDj/KH0= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/filecoin-project/go-cbor-util/rpc.go b/vendor/github.com/filecoin-project/go-cbor-util/rpc.go new file mode 100644 index 0000000000..d2c4e214eb --- /dev/null +++ b/vendor/github.com/filecoin-project/go-cbor-util/rpc.go @@ -0,0 +1,88 @@ +package cborutil + +import ( + "bytes" + "encoding/hex" + "io" + "math" + + cbor "github.com/ipfs/go-ipld-cbor" + ipld "github.com/ipfs/go-ipld-format" + logging "github.com/ipfs/go-log" + cbg "github.com/whyrusleeping/cbor-gen" +) + +var log = logging.Logger("cborrrpc") + +// Debug will produce more debugging messages +const Debug = false + +func init() { + if Debug { + log.Warn("CBOR-RPC Debugging enabled") + } +} + +// WriteCborRPC with encode an object to cbor, opting for fast path if possible +// and then write it into the given io.Writer +func WriteCborRPC(w io.Writer, obj interface{}) error { + if m, ok := obj.(cbg.CBORMarshaler); ok { + // TODO: impl debug + return m.MarshalCBOR(w) + } + data, err := cbor.DumpObject(obj) + if err != nil { + return err + } + + if Debug { + log.Infof("> %s", hex.EncodeToString(data)) + } + + _, err = w.Write(data) + return err +} + +// ReadCborRPC will read an object from the given io.Reader +// opting for fast path if possible +func ReadCborRPC(r io.Reader, out interface{}) error { + if um, ok := out.(cbg.CBORUnmarshaler); ok { + return um.UnmarshalCBOR(r) + } + return cbor.DecodeReader(r, out) +} + +// Dump returns the cbor bytes representation of an object +func Dump(obj interface{}) ([]byte, error) { + var out bytes.Buffer + if err := WriteCborRPC(&out, obj); err != nil { + return nil, err + } + return out.Bytes(), nil +} + +// AsIpld converts an object to an ipld.Node interface +// TODO: this is a bit ugly, and this package is not exactly the best place +func AsIpld(obj interface{}) (ipld.Node, error) { + if m, ok := obj.(cbg.CBORMarshaler); ok { + b, err := Dump(m) + if err != nil { + return nil, err + } + return cbor.Decode(b, math.MaxUint64, -1) + } + return cbor.WrapObject(obj, math.MaxUint64, -1) +} + +// Equals is true if two objects have the same cbor representation +func Equals(a cbg.CBORMarshaler, b cbg.CBORMarshaler) (bool, error) { + ab, err := Dump(a) + if err != nil { + return false, err + } + bb, err := Dump(b) + if err != nil { + return false, err + } + return bytes.Equal(ab, bb), nil +} diff --git a/vendor/github.com/filecoin-project/go-crypto/.circleci/config.yml b/vendor/github.com/filecoin-project/go-crypto/.circleci/config.yml new file mode 100644 index 0000000000..521d7fb390 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/.circleci/config.yml @@ -0,0 +1,161 @@ +version: 2.1 +orbs: + go: gotest/tools@0.0.9 + +executors: + golang: + docker: + - image: circleci/golang:1.13 + resource_class: small + +commands: + install-deps: + steps: + - go/install-ssh + - go/install: {package: git} + prepare: + parameters: + linux: + default: true + description: is a linux build environment? + type: boolean + steps: + - checkout + - when: + condition: << parameters.linux >> + steps: + - run: sudo apt-get update + - run: sudo apt-get install ocl-icd-opencl-dev + build-all: + + +jobs: + mod-tidy-check: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - go/mod-tidy-check + + test: &test + description: | + Run tests with gotestsum. + parameters: + executor: + type: executor + default: golang + go-test-flags: + type: string + default: "-timeout 5m" + description: Flags passed to go test. + packages: + type: string + default: "./..." + description: Import paths of packages to be tested. + test-suite-name: + type: string + default: unit + description: Test suite name to report to CircleCI. + gotestsum-format: + type: string + default: short + description: gotestsum format. https://github.com/gotestyourself/gotestsum#format + coverage: + type: string + default: -coverprofile=coverage.txt + description: Coverage flag. Set to the empty string to disable. + codecov-upload: + type: boolean + default: false + description: | + Upload coverage report to https://codecov.io/. Requires the codecov API token to be + set as an environment variable for private projects. + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/mod-download + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - go/install-gotestsum: + gobin: $HOME/.local/bin + - run: + name: go test + environment: + GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml + GOTESTSUM_FORMAT: << parameters.gotestsum-format >> + command: | + mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> + gotestsum -- \ + << parameters.coverage >> \ + << parameters.go-test-flags >> \ + << parameters.packages >> + no_output_timeout: 30m + - store_test_results: + path: /tmp/test-reports + - when: + condition: << parameters.codecov-upload >> + steps: + - go/install: {package: bash} + - go/install: {package: curl} + - run: + shell: /bin/bash -eo pipefail + command: | + bash <(curl -s https://codecov.io/bash) + - save_cache: + name: save go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + paths: + - "~/go/pkg" + - "~/go/src/github.com" + - "~/go/src/golang.org" + + lint: &lint + description: | + Run golangci-lint. + parameters: + executor: + type: executor + default: golang + golangci-lint-version: + type: string + default: 1.21.0 + concurrency: + type: string + default: '2' + description: | + Concurrency used to run linters. Defaults to 2 because NumCPU is not + aware of container CPU limits. + args: + type: string + default: '' + description: | + Arguments to pass to golangci-lint + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: << parameters.golangci-lint-version >> + - run: + name: Lint + command: | + $HOME/.local/bin/golangci-lint run -v \ + --concurrency << parameters.concurrency >> << parameters.args >> + lint-changes: + <<: *lint + + lint-all: + <<: *lint + +workflows: + version: 2.1 + ci: + jobs: + - lint-changes: + args: "--new-from-rev origin/master" + - test + - mod-tidy-check diff --git a/vendor/github.com/filecoin-project/go-crypto/COPYRIGHT b/vendor/github.com/filecoin-project/go-crypto/COPYRIGHT new file mode 100644 index 0000000000..771e6f7cd7 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/COPYRIGHT @@ -0,0 +1,3 @@ +Copyright 2019. Protocol Labs, Inc. + +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/vendor/github.com/filecoin-project/go-crypto/LICENSE-APACHE b/vendor/github.com/filecoin-project/go-crypto/LICENSE-APACHE new file mode 100644 index 0000000000..546514363d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2019. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/filecoin-project/go-crypto/LICENSE-MIT b/vendor/github.com/filecoin-project/go-crypto/LICENSE-MIT new file mode 100644 index 0000000000..ea532a8305 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2019. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/filecoin-project/go-crypto/README.md b/vendor/github.com/filecoin-project/go-crypto/README.md new file mode 100644 index 0000000000..8050daead9 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/README.md @@ -0,0 +1,8 @@ +# go-crypto + +Crypto utility functions used in filecoin + +## License +This repository is dual-licensed under Apache 2.0 and MIT terms. + +Copyright 2019. Protocol Labs, Inc. diff --git a/vendor/github.com/filecoin-project/go-crypto/crypto.go b/vendor/github.com/filecoin-project/go-crypto/crypto.go new file mode 100644 index 0000000000..7ef5d6718a --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/crypto.go @@ -0,0 +1,70 @@ +package crypto + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "io" + + secp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1" +) + +// PrivateKeyBytes is the size of a serialized private key. +const PrivateKeyBytes = 32 + +// PublicKeyBytes is the size of a serialized public key. +const PublicKeyBytes = 65 + +// PublicKey returns the public key for this private key. +func PublicKey(sk []byte) []byte { + x, y := secp256k1.S256().ScalarBaseMult(sk) + return elliptic.Marshal(secp256k1.S256(), x, y) +} + +// Sign signs the given message, which must be 32 bytes long. +func Sign(sk, msg []byte) ([]byte, error) { + return secp256k1.Sign(msg, sk) +} + +// Equals compares two private key for equality and returns true if they are the same. +func Equals(sk, other []byte) bool { + return bytes.Equal(sk, other) +} + +// Verify checks the given signature and returns true if it is valid. +func Verify(pk, msg, signature []byte) bool { + if len(signature) == 65 { + // Drop the V (1byte) in [R | S | V] style signatures. + // The V (1byte) is the recovery bit and is not apart of the signature verification. + return secp256k1.VerifySignature(pk[:], msg, signature[:len(signature)-1]) + } + + return secp256k1.VerifySignature(pk[:], msg, signature) +} + +// GenerateKeyFromSeed generates a new key from the given reader. +func GenerateKeyFromSeed(seed io.Reader) ([]byte, error) { + key, err := ecdsa.GenerateKey(secp256k1.S256(), seed) + if err != nil { + return nil, err + } + + privkey := make([]byte, PrivateKeyBytes) + blob := key.D.Bytes() + + // the length is guaranteed to be fixed, given the serialization rules for secp2561k curve points. + copy(privkey[PrivateKeyBytes-len(blob):], blob) + + return privkey, nil +} + +// GenerateKey creates a new key using secure randomness from crypto.rand. +func GenerateKey() ([]byte, error) { + return GenerateKeyFromSeed(rand.Reader) +} + +// EcRecover recovers the public key from a message, signature pair. +func EcRecover(msg, signature []byte) ([]byte, error) { + return secp256k1.RecoverPubkey(msg, signature) +} diff --git a/vendor/github.com/filecoin-project/go-crypto/crypto_test.go b/vendor/github.com/filecoin-project/go-crypto/crypto_test.go new file mode 100644 index 0000000000..6e20493ed0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/crypto_test.go @@ -0,0 +1,61 @@ +package crypto_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/go-crypto" +) + +func TestGenerateKey(t *testing.T) { + rand.Seed(time.Now().UnixNano()) + + sk, err := crypto.GenerateKey() + assert.NoError(t, err) + + assert.Equal(t, len(sk), 32) + + msg := make([]byte, 32) + for i := 0; i < len(msg); i++ { + msg[i] = byte(i) + } + + digest, err := crypto.Sign(sk, msg) + assert.NoError(t, err) + assert.Equal(t, len(digest), 65) + pk := crypto.PublicKey(sk) + + // valid signature + assert.True(t, crypto.Verify(pk, msg, digest)) + + // invalid signature - different message (too short) + assert.False(t, crypto.Verify(pk, msg[3:], digest)) + + // invalid signature - different message + msg2 := make([]byte, 32) + copy(msg2, msg) + rand.Shuffle(len(msg2), func(i, j int) { msg2[i], msg2[j] = msg2[j], msg2[i] }) + assert.False(t, crypto.Verify(pk, msg2, digest)) + + // invalid signature - different digest + digest2 := make([]byte, 65) + copy(digest2, digest) + rand.Shuffle(len(digest2), func(i, j int) { digest2[i], digest2[j] = digest2[j], digest2[i] }) + assert.False(t, crypto.Verify(pk, msg, digest2)) + + // invalid signature - digest too short + assert.False(t, crypto.Verify(pk, msg, digest[3:])) + assert.False(t, crypto.Verify(pk, msg, digest[:29])) + + // invalid signature - digest too long + digest3 := make([]byte, 70) + copy(digest3, digest) + assert.False(t, crypto.Verify(pk, msg, digest3)) + + recovered, err := crypto.EcRecover(msg, digest) + assert.NoError(t, err) + assert.Equal(t, recovered, crypto.PublicKey(sk)) +} diff --git a/vendor/github.com/filecoin-project/go-crypto/go.mod b/vendor/github.com/filecoin-project/go-crypto/go.mod new file mode 100644 index 0000000000..0a580200b5 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/go.mod @@ -0,0 +1,12 @@ +module github.com/filecoin-project/go-crypto + +go 1.13 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 + github.com/kr/pretty v0.1.0 // indirect + github.com/stretchr/testify v1.4.0 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + gopkg.in/yaml.v2 v2.2.4 // indirect +) diff --git a/vendor/github.com/filecoin-project/go-crypto/go.sum b/vendor/github.com/filecoin-project/go-crypto/go.sum new file mode 100644 index 0000000000..bb23197e92 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-crypto/go.sum @@ -0,0 +1,21 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/filecoin-project/go-data-transfer/.circleci/config.yml b/vendor/github.com/filecoin-project/go-data-transfer/.circleci/config.yml new file mode 100644 index 0000000000..521d7fb390 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/.circleci/config.yml @@ -0,0 +1,161 @@ +version: 2.1 +orbs: + go: gotest/tools@0.0.9 + +executors: + golang: + docker: + - image: circleci/golang:1.13 + resource_class: small + +commands: + install-deps: + steps: + - go/install-ssh + - go/install: {package: git} + prepare: + parameters: + linux: + default: true + description: is a linux build environment? + type: boolean + steps: + - checkout + - when: + condition: << parameters.linux >> + steps: + - run: sudo apt-get update + - run: sudo apt-get install ocl-icd-opencl-dev + build-all: + + +jobs: + mod-tidy-check: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - go/mod-tidy-check + + test: &test + description: | + Run tests with gotestsum. + parameters: + executor: + type: executor + default: golang + go-test-flags: + type: string + default: "-timeout 5m" + description: Flags passed to go test. + packages: + type: string + default: "./..." + description: Import paths of packages to be tested. + test-suite-name: + type: string + default: unit + description: Test suite name to report to CircleCI. + gotestsum-format: + type: string + default: short + description: gotestsum format. https://github.com/gotestyourself/gotestsum#format + coverage: + type: string + default: -coverprofile=coverage.txt + description: Coverage flag. Set to the empty string to disable. + codecov-upload: + type: boolean + default: false + description: | + Upload coverage report to https://codecov.io/. Requires the codecov API token to be + set as an environment variable for private projects. + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/mod-download + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - go/install-gotestsum: + gobin: $HOME/.local/bin + - run: + name: go test + environment: + GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml + GOTESTSUM_FORMAT: << parameters.gotestsum-format >> + command: | + mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> + gotestsum -- \ + << parameters.coverage >> \ + << parameters.go-test-flags >> \ + << parameters.packages >> + no_output_timeout: 30m + - store_test_results: + path: /tmp/test-reports + - when: + condition: << parameters.codecov-upload >> + steps: + - go/install: {package: bash} + - go/install: {package: curl} + - run: + shell: /bin/bash -eo pipefail + command: | + bash <(curl -s https://codecov.io/bash) + - save_cache: + name: save go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + paths: + - "~/go/pkg" + - "~/go/src/github.com" + - "~/go/src/golang.org" + + lint: &lint + description: | + Run golangci-lint. + parameters: + executor: + type: executor + default: golang + golangci-lint-version: + type: string + default: 1.21.0 + concurrency: + type: string + default: '2' + description: | + Concurrency used to run linters. Defaults to 2 because NumCPU is not + aware of container CPU limits. + args: + type: string + default: '' + description: | + Arguments to pass to golangci-lint + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: << parameters.golangci-lint-version >> + - run: + name: Lint + command: | + $HOME/.local/bin/golangci-lint run -v \ + --concurrency << parameters.concurrency >> << parameters.args >> + lint-changes: + <<: *lint + + lint-all: + <<: *lint + +workflows: + version: 2.1 + ci: + jobs: + - lint-changes: + args: "--new-from-rev origin/master" + - test + - mod-tidy-check diff --git a/vendor/github.com/filecoin-project/go-data-transfer/CONTRIBUTING.md b/vendor/github.com/filecoin-project/go-data-transfer/CONTRIBUTING.md new file mode 100644 index 0000000000..dbc47e6ce7 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# Contributing to this repo + +First, thank you for your interest in contributing to this project! Before you pick up your first issue and start +changing code, please: + +1. Review all documentation for the module you're interested in. +1. Look through the [issues for this repo](https://github.com/filecoin-project/go-data-transfer/issues) for relevant discussions. +1. If you have questions about an issue, post a comment in the issue. +1. If you want to submit changes that aren't covered by an issue, file a new one with your proposal, outlining what problem you found/feature you want to implement, and how you intend to implement a solution. + +For best results, before submitting a PR, make sure: +1. It has met all acceptance criteria for the issue. +1. It addresses only the one issue and does not make other, irrelevant changes. +1. Your code conforms to our coding style guide. +1. You have adequate test coverage (this should be indicated by CI results anyway). +1. If you like, check out [current PRs](https://github.com/filecoin-project/go-data-transfer/pulls) to see how others do it. + +Special Note: +If editing README.md, please conform to the [standard readme specification](https://github.com/RichardLitt/standard-readme/blob/master/spec.md). + +Before a PR can be merged to `master`, it must: +1. Pass continuous integration. +1. Be approved by at least two maintainers + +### Testing + +- All new code should be accompanied by unit tests. Prefer focused unit tests to integration tests for thorough validation of behaviour. Existing code is not necessarily a good model, here. +- Integration tests should test integration, not comprehensive functionality +- Tests should be placed in a separate package named `$PACKAGE_test`. For example, a test of the `chain` package should live in a package named `chain_test`. In limited situations, exceptions may be made for some "white box" tests placed in the same package as the code it tests. + +### Conventions and Style + +#### Imports +We use the following import ordering. +``` +import ( + [stdlib packages, alpha-sorted] + + [external packages] + + [go-data-transfer packages] +) +``` + +Where a package name does not match its directory name, an explicit alias is expected (`goimports` will add this for you). + +Example: + +```go +package message + +import ( + "io" + + "github.com/ipfs/go-cid" + cborgen "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/go-data-transfer" +) +``` + +#### Comments +Comments are a communication to other developers (including your future self) to help them understand and maintain code. Good comments describe the _intent_ of the code, without repeating the procedures directly. + +- A `TODO:` comment describes a change that is desired but could not be immediately implemented. It must include a reference to a GitHub issue outlining whatever prevents the thing being done now (which could just be a matter of priority). +- A `NOTE:` comment indicates an aside, some background info, or ideas for future improvement, rather than the intent of the current code. It's often fine to document such ideas alongside the code rather than an issue (at the loss of a space for discussion). +- `FIXME`, `HACK`, `XXX` and similar tags indicating that some code is to be avoided in favour of `TODO`, `NOTE` or some straight prose. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-data-transfer/COPYRIGHT b/vendor/github.com/filecoin-project/go-data-transfer/COPYRIGHT new file mode 100644 index 0000000000..771e6f7cd7 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/COPYRIGHT @@ -0,0 +1,3 @@ +Copyright 2019. Protocol Labs, Inc. + +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/vendor/github.com/filecoin-project/go-data-transfer/LICENSE-APACHE b/vendor/github.com/filecoin-project/go-data-transfer/LICENSE-APACHE new file mode 100644 index 0000000000..546514363d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2019. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/filecoin-project/go-data-transfer/LICENSE-MIT b/vendor/github.com/filecoin-project/go-data-transfer/LICENSE-MIT new file mode 100644 index 0000000000..ea532a8305 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2019. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/filecoin-project/go-data-transfer/Makefile b/vendor/github.com/filecoin-project/go-data-transfer/Makefile new file mode 100644 index 0000000000..1f6e2060ed --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/Makefile @@ -0,0 +1,17 @@ +all: build +.PHONY: all + +GOVERSION:=$(shell go version | cut -d' ' -f 3 | cut -d. -f 2) +ifeq ($(shell expr $(GOVERSION) \< 13), 1) +$(warning Your Golang version is go 1.$(GOVERSION)) +$(error Update Golang to version $(shell grep '^go' go.mod)) +endif + +build: + go build ./... + +test: + go test ./... + +type-gen: build + go run ./cbor-gen/main.go diff --git a/vendor/github.com/filecoin-project/go-data-transfer/README.md b/vendor/github.com/filecoin-project/go-data-transfer/README.md new file mode 100644 index 0000000000..f1dfbbd2dd --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/README.md @@ -0,0 +1,180 @@ +# go-data-transfer +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![CircleCI](https://circleci.com/gh/filecoin-project/go-data-transfer.svg?style=svg)](https://circleci.com/gh/filecoin-project/go-data-transfer) +[![codecov](https://codecov.io/gh/filecoin-project/go-data-transfer/branch/master/graph/badge.svg)](https://codecov.io/gh/filecoin-project/go-data-transfer) + +A go module to perform data transfers over [ipfs/go-graphsync](https://github.com/ipfs/go-graphsync) + +## Description +This module encapsulates protocols for exchanging piece data between storage clients and miners, both when consummating a storage deal and when retrieving the piece later. + +## Table of Contents +* [Background](https://github.com/filecoin-project/go-data-transfer/tree/master#background) +* [Usage](https://github.com/filecoin-project/go-data-transfer/tree/master#usage) + * [Initialize a data transfer module](https://github.com/filecoin-project/go-data-transfer/tree/master#initialize-a-data-transfer-module) + * [Register a validator](https://github.com/filecoin-project/go-data-transfer/tree/master#register-a-validator) + * [Open a Push or Pull Request](https://github.com/filecoin-project/go-data-transfer/tree/master#open-a-push-or-pull-request) + * [Subscribe to Events](https://github.com/filecoin-project/go-data-transfer/tree/master#subscribe-to-events) +* [Contribute](https://github.com/filecoin-project/go-data-transfer/tree/master#contribute) + +## Background + +Please see the [design documentation](https://github.com/filecoin-project/go-data-transfer/tree/master/docs/DESIGNDOC) +for this module for a high-level overview and and explanation of the terms and concepts. + +## Usage + +**Requires go 1.13** + +Install the module in your package or app with `go get "github.com/filecoin-project/go-data-transfer/datatransfer"` + + +### Initialize a data transfer module +1. Set up imports. You need, minimally, the following imports: + ```go + package mypackage + + import ( + gsimpl "github.com/ipfs/go-graphsync/impl" + "github.com/filecoin-project/go-data-transfer/datatransfer" + "github.com/libp2p/go-libp2p-core/host" + ) + + ``` +1. Provide or create a [libp2p host.Host](https://github.com/libp2p/go-libp2p-examples/tree/master/libp2p-host) +1. Provide or create a [go-graphsync GraphExchange](https://github.com/ipfs/go-graphsync#initializing-a-graphsync-exchange) +1. Create a new instance of GraphsyncDataTransfer + ```go + func NewGraphsyncDatatransfer(h host.Host, gs graphsync.GraphExchange) { + dt := datatransfer.NewGraphSyncDataTransfer(h, gs) + } + ``` + +1. If needed, build out your voucher struct and its validator. + + A push or pull request must include a voucher. The voucher's type must have been registered with + the node receiving the request before it's sent, otherwise the request will be rejected. + + [datatransfer.Voucher](https://github.com/filecoin-project/go-data-transfer/blob/21dd66ba370176224114b13030ee68cb785fadb2/datatransfer/types.go#L17) + and [datatransfer.Validator](https://github.com/filecoin-project/go-data-transfer/blob/21dd66ba370176224114b13030ee68cb785fadb2/datatransfer/types.go#L153) + are the interfaces used for validation of graphsync datatransfer messages. Voucher types plus a Validator for them must be registered + with the peer to whom requests will be sent. + +#### Example Toy Voucher and Validator +```go +type myVoucher struct { + data string +} + +func (v *myVoucher) ToBytes() ([]byte, error) { + return []byte(v.data), nil +} + +func (v *myVoucher) FromBytes(data []byte) error { + v.data = string(data) + return nil +} + +func (v *myVoucher) Type() string { + return "FakeDTType" +} + +type myValidator struct { + ctx context.Context + validationsReceived chan receivedValidation +} + +func (vl *myValidator) ValidatePush( + sender peer.ID, + voucher datatransfer.Voucher, + baseCid cid.Cid, + selector ipld.Node) error { + + v := voucher.(*myVoucher) + if v.data == "" || v.data != "validpush" { + return errors.New("invalid") + } + + return nil +} + +func (vl *myValidator) ValidatePull( + receiver peer.ID, + voucher datatransfer.Voucher, + baseCid cid.Cid, + selector ipld.Node) error { + + v := voucher.(*myVoucher) + if v.data == "" || v.data != "validpull" { + return errors.New("invalid") + } + + return nil +} + +``` + + +Please see +[go-data-transfer/blob/master/types.go](https://github.com/filecoin-project/go-data-transfer/blob/master/types.go) +for more detail. + + +### Register a validator +Before sending push or pull requests, you must register a `datatransfer.Voucher` +by its `reflect.Type` and `dataTransfer.RequestValidator` for vouchers that +must be sent with the request. Using the trivial examples above: +```go + func NewGraphsyncDatatransfer(h host.Host, gs graphsync.GraphExchange) { + dt := datatransfer.NewGraphSyncDataTransfer(h, gs) + + vouch := &myVoucher{} + mv := &myValidator{} + dt.RegisterVoucherType(reflect.TypeOf(vouch), mv) + } +``` + +For more detail, please see the [unit tests](https://github.com/filecoin-project/go-data-transfer/blob/master/impl/graphsync/graphsync_impl_test.go). + +### Open a Push or Pull Request +For a push or pull request, provide a context, a `datatransfer.Voucher`, a host recipient `peer.ID`, a baseCID `cid.CID` and a selector `ipld.Node`. These +calls return a `datatransfer.ChannelID` and any error: +```go + channelID, err := dtm.OpenPullDataChannel(ctx, recipient, voucher, baseCid, selector) + // OR + channelID, err := dtm.OpenPushDataChannel(ctx, recipient, voucher, baseCid, selector) + +``` + +### Subscribe to Events + +The module allows the consumer to be notified when a graphsync Request is sent or a datatransfer push or pull request response is received: + +```go + func ToySubscriberFunc (event Event, channelState ChannelState) { + if event.Code == datatransfer.Error { + // log error, flail about helplessly + return + } + // + if channelState.Recipient() == our.PeerID && channelState.Received() > 0 { + // log some stuff, update some state somewhere, send data to a channel, etc. + } + } + + dtm := SetupDataTransferManager(ctx, h, gs, baseCid, snode) + unsubFunc := dtm.SubscribeToEvents(ToySubscriberFunc) + + // . . . later, when you don't need to know about events any more: + unsubFunc() +``` + +## Contributing +PRs are welcome! Please first read the design docs and look over the current code. PRs against +master require approval of at least two maintainers. For the rest, please see our +[CONTRIBUTING](https://github.com/filecoin-project/go-data-transfer/CONTRIBUTING.md) guide. + +## License +This repository is dual-licensed under Apache 2.0 and MIT terms. + +Copyright 2019. Protocol Labs, Inc. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-data-transfer/channels/channels.go b/vendor/github.com/filecoin-project/go-data-transfer/channels/channels.go new file mode 100644 index 0000000000..84506160c9 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/channels/channels.go @@ -0,0 +1,171 @@ +package channels + +import ( + "errors" + "sync" + "sync/atomic" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/ipfs/go-cid" + "github.com/ipld/go-ipld-prime" + peer "github.com/libp2p/go-libp2p-core/peer" +) + +// channel represents all the parameters for a single data transfer +type channel struct { + // an identifier for this channel shared by request and responder, set by requester through protocol + transferID datatransfer.TransferID + // base CID for the piece being transferred + baseCid cid.Cid + // portion of Piece to return, specified by an IPLD selector + selector ipld.Node + // used to verify this channel + voucher datatransfer.Voucher + // the party that is sending the data (not who initiated the request) + sender peer.ID + // the party that is receiving the data (not who initiated the request) + recipient peer.ID + // expected amount of data to be transferred + totalSize uint64 +} + +// NewChannel makes a new channel +func NewChannel(transferID datatransfer.TransferID, baseCid cid.Cid, + selector ipld.Node, + voucher datatransfer.Voucher, + sender peer.ID, + recipient peer.ID, + totalSize uint64) datatransfer.Channel { + return channel{transferID, baseCid, selector, voucher, sender, recipient, totalSize} +} + +// TransferID returns the transfer id for this channel +func (c channel) TransferID() datatransfer.TransferID { return c.transferID } + +// BaseCID returns the CID that is at the root of this data transfer +func (c channel) BaseCID() cid.Cid { return c.baseCid } + +// Selector returns the IPLD selector for this data transfer (represented as +// an IPLD node) +func (c channel) Selector() ipld.Node { return c.selector } + +// Voucher returns the voucher for this data transfer +func (c channel) Voucher() datatransfer.Voucher { return c.voucher } + +// Sender returns the peer id for the node that is sending data +func (c channel) Sender() peer.ID { return c.sender } + +// Recipient returns the peer id for the node that is receiving data +func (c channel) Recipient() peer.ID { return c.recipient } + +// TotalSize returns the total size for the data being transferred +func (c channel) TotalSize() uint64 { return c.totalSize } + +// ChannelState is immutable channel data plus mutable state +type ChannelState struct { + datatransfer.Channel + // total bytes sent from this node (0 if receiver) + sent uint64 + // total bytes received by this node (0 if sender) + received uint64 +} + +// EmptyChannelState is the zero value for channel state, meaning not present +var EmptyChannelState = ChannelState{} + +// Sent returns the number of bytes sent +func (c ChannelState) Sent() uint64 { return c.sent } + +// Received returns the number of bytes received +func (c ChannelState) Received() uint64 { return c.received } + +type internalChannel struct { + datatransfer.Channel + sent *uint64 + received *uint64 +} + +// ErrNotFound is returned when a channel cannot be found with a given channel ID +var ErrNotFound = errors.New("No channel for this channel ID") + +// ErrWrongType is returned when a caller attempts to change the type of implementation data after setting it +var ErrWrongType = errors.New("Cannot change type of implementation specific data after setting it") + +// Channels is a thread safe list of channels +type Channels struct { + channelsLk sync.RWMutex + channels map[datatransfer.ChannelID]internalChannel +} + +// New returns a new thread safe list of channels +func New() *Channels { + return &Channels{ + sync.RWMutex{}, + make(map[datatransfer.ChannelID]internalChannel), + } +} + +// CreateNew creates a new channel id and channel state and saves to channels. +// returns error if the channel exists already. +func (c *Channels) CreateNew(tid datatransfer.TransferID, baseCid cid.Cid, selector ipld.Node, voucher datatransfer.Voucher, initiator, dataSender, dataReceiver peer.ID) (datatransfer.ChannelID, error) { + chid := datatransfer.ChannelID{Initiator: initiator, ID: tid} + c.channelsLk.Lock() + defer c.channelsLk.Unlock() + _, ok := c.channels[chid] + if ok { + return chid, errors.New("tried to create channel but it already exists") + } + c.channels[chid] = internalChannel{Channel: NewChannel(0, baseCid, selector, voucher, dataSender, dataReceiver, 0), sent: new(uint64), received: new(uint64)} + return chid, nil +} + +// InProgress returns a list of in progress channels +func (c *Channels) InProgress() map[datatransfer.ChannelID]datatransfer.ChannelState { + c.channelsLk.RLock() + defer c.channelsLk.RUnlock() + channelsCopy := make(map[datatransfer.ChannelID]datatransfer.ChannelState, len(c.channels)) + for channelID, internalChannel := range c.channels { + channelsCopy[channelID] = ChannelState{ + internalChannel.Channel, atomic.LoadUint64(internalChannel.sent), atomic.LoadUint64(internalChannel.received), + } + } + return channelsCopy +} + +// GetByID searches for a channel in the slice of channels with id `chid`. +// Returns datatransfer.EmptyChannelState if there is no channel with that id +func (c *Channels) GetByID(chid datatransfer.ChannelID) (datatransfer.ChannelState, error) { + c.channelsLk.RLock() + internalChannel, ok := c.channels[chid] + c.channelsLk.RUnlock() + if !ok { + return EmptyChannelState, ErrNotFound + } + return ChannelState{ + internalChannel.Channel, atomic.LoadUint64(internalChannel.sent), atomic.LoadUint64(internalChannel.received), + }, nil +} + +// IncrementSent increments the total sent on the given channel by the given amount (returning +// the new total) +func (c *Channels) IncrementSent(chid datatransfer.ChannelID, delta uint64) (uint64, error) { + c.channelsLk.RLock() + channel, ok := c.channels[chid] + c.channelsLk.RUnlock() + if !ok { + return 0, ErrNotFound + } + return atomic.AddUint64(channel.sent, delta), nil +} + +// IncrementReceived increments the total received on the given channel by the given amount (returning +// the new total) +func (c *Channels) IncrementReceived(chid datatransfer.ChannelID, delta uint64) (uint64, error) { + c.channelsLk.RLock() + channel, ok := c.channels[chid] + c.channelsLk.RUnlock() + if !ok { + return 0, ErrNotFound + } + return atomic.AddUint64(channel.received, delta), nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/channels/channels_test.go b/vendor/github.com/filecoin-project/go-data-transfer/channels/channels_test.go new file mode 100644 index 0000000000..e6b21e951a --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/channels/channels_test.go @@ -0,0 +1,102 @@ +package channels_test + +import ( + "testing" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/channels" + "github.com/filecoin-project/go-data-transfer/testutil" + basicnode "github.com/ipld/go-ipld-prime/node/basic" + "github.com/ipld/go-ipld-prime/traversal/selector/builder" + "github.com/stretchr/testify/require" +) + +func TestChannels(t *testing.T) { + channelList := channels.New() + + tid1 := datatransfer.TransferID(0) + tid2 := datatransfer.TransferID(1) + fv1 := &testutil.FakeDTType{} + fv2 := &testutil.FakeDTType{} + cids := testutil.GenerateCids(2) + selector := builder.NewSelectorSpecBuilder(basicnode.Style.Any).Matcher().Node() + peers := testutil.GeneratePeers(4) + + t.Run("adding channels", func(t *testing.T) { + chid, err := channelList.CreateNew(tid1, cids[0], selector, fv1, peers[0], peers[0], peers[1]) + require.NoError(t, err) + require.Equal(t, peers[0], chid.Initiator) + require.Equal(t, tid1, chid.ID) + + // cannot add twice for same channel id + _, err = channelList.CreateNew(tid1, cids[1], selector, fv2, peers[0], peers[1], peers[0]) + require.Error(t, err) + + // can add for different id + chid, err = channelList.CreateNew(tid2, cids[1], selector, fv2, peers[3], peers[2], peers[3]) + require.NoError(t, err) + require.Equal(t, peers[3], chid.Initiator) + require.Equal(t, tid2, chid.ID) + }) + + t.Run("in progress channels", func(t *testing.T) { + inProgress := channelList.InProgress() + require.Len(t, inProgress, 2) + require.Contains(t, inProgress, datatransfer.ChannelID{Initiator: peers[0], ID: tid1}) + require.Contains(t, inProgress, datatransfer.ChannelID{Initiator: peers[3], ID: tid2}) + }) + + t.Run("get by id and sender", func(t *testing.T) { + state, err := channelList.GetByID(datatransfer.ChannelID{Initiator: peers[0], ID: tid1}) + require.NoError(t, err) + require.NotEqual(t, channels.EmptyChannelState, state) + require.Equal(t, cids[0], state.BaseCID()) + require.Equal(t, selector, state.Selector()) + require.Equal(t, fv1, state.Voucher()) + require.Equal(t, peers[0], state.Sender()) + require.Equal(t, peers[1], state.Recipient()) + + // empty if channel does not exist + state, err = channelList.GetByID(datatransfer.ChannelID{Initiator: peers[1], ID: tid1}) + require.Equal(t, channels.EmptyChannelState, state) + require.EqualError(t, err, channels.ErrNotFound.Error()) + + // works for other channel as well + state, err = channelList.GetByID(datatransfer.ChannelID{Initiator: peers[3], ID: tid2}) + require.NotEqual(t, channels.EmptyChannelState, state) + require.NoError(t, err) + }) + + t.Run("updating send/receive values", func(t *testing.T) { + state, err := channelList.GetByID(datatransfer.ChannelID{Initiator: peers[0], ID: tid1}) + require.NoError(t, err) + require.NotEqual(t, channels.EmptyChannelState, state) + require.Equal(t, uint64(0), state.Received()) + require.Equal(t, uint64(0), state.Sent()) + + received, err := channelList.IncrementReceived(datatransfer.ChannelID{Initiator: peers[0], ID: tid1}, 50) + require.Equal(t, uint64(50), received) + require.NoError(t, err) + sent, err := channelList.IncrementSent(datatransfer.ChannelID{Initiator: peers[0], ID: tid1}, 100) + require.Equal(t, uint64(100), sent) + require.NoError(t, err) + + state, err = channelList.GetByID(datatransfer.ChannelID{Initiator: peers[0], ID: tid1}) + require.NoError(t, err) + require.Equal(t, uint64(50), state.Received()) + require.Equal(t, uint64(100), state.Sent()) + + // errors if channel does not exist + _, err = channelList.IncrementReceived(datatransfer.ChannelID{Initiator: peers[1], ID: tid1}, 200) + require.EqualError(t, err, channels.ErrNotFound.Error()) + _, err = channelList.IncrementSent(datatransfer.ChannelID{Initiator: peers[1], ID: tid1}, 200) + require.EqualError(t, err, channels.ErrNotFound.Error()) + + received, err = channelList.IncrementReceived(datatransfer.ChannelID{Initiator: peers[0], ID: tid1}, 50) + require.Equal(t, uint64(100), received) + require.NoError(t, err) + sent, err = channelList.IncrementSent(datatransfer.ChannelID{Initiator: peers[0], ID: tid1}, 25) + require.Equal(t, uint64(125), sent) + require.NoError(t, err) + }) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding.go b/vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding.go new file mode 100644 index 0000000000..7cca7d73c0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding.go @@ -0,0 +1,122 @@ +package encoding + +import ( + "bytes" + "reflect" + + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/codec/dagcbor" + cborgen "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" +) + +// Encodable is an object that can be written to CBOR and decoded back +type Encodable interface{} + +// Encode encodes an encodable to CBOR, using the best available path for +// writing to CBOR +func Encode(value Encodable) ([]byte, error) { + if cbgEncodable, ok := value.(cborgen.CBORMarshaler); ok { + buf := new(bytes.Buffer) + err := cbgEncodable.MarshalCBOR(buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil + } + if ipldEncodable, ok := value.(ipld.Node); ok { + buf := new(bytes.Buffer) + err := dagcbor.Encoder(ipldEncodable, buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil + } + return cbor.DumpObject(value) +} + +// Decoder is CBOR decoder for a given encodable type +type Decoder interface { + DecodeFromCbor([]byte) (Encodable, error) +} + +// NewDecoder creates a new Decoder that will decode into new instances of the given +// object type. It will use the decoding that is optimal for that type +// It returns error if it's not possible to setup a decoder for this type +func NewDecoder(decodeType Encodable) (Decoder, error) { + // check if type is ipld.Node, if so, just use style + if ipldDecodable, ok := decodeType.(ipld.Node); ok { + return &ipldDecoder{ipldDecodable.Style()}, nil + } + // check if type is a pointer, as we need that to make new copies + // for cborgen types & regular IPLD types + decodeReflectType := reflect.TypeOf(decodeType) + if decodeReflectType.Kind() != reflect.Ptr { + return nil, xerrors.New("type must be a pointer") + } + // check if type is a cbor-gen type + if _, ok := decodeType.(cborgen.CBORUnmarshaler); ok { + return &cbgDecoder{decodeReflectType}, nil + } + // type does is neither ipld-prime nor cbor-gen, so we need to see if it + // can rountrip with oldschool ipld-format + encoded, err := cbor.DumpObject(decodeType) + if err != nil { + return nil, xerrors.New("Object type did not encode") + } + newDecodable := reflect.New(decodeReflectType.Elem()).Interface() + if err := cbor.DecodeInto(encoded, newDecodable); err != nil { + return nil, xerrors.New("Object type did not decode") + } + return &defaultDecoder{decodeReflectType}, nil +} + +type ipldDecoder struct { + style ipld.NodeStyle +} + +func (decoder *ipldDecoder) DecodeFromCbor(encoded []byte) (Encodable, error) { + builder := decoder.style.NewBuilder() + buf := bytes.NewReader(encoded) + err := dagcbor.Decoder(builder, buf) + if err != nil { + return nil, err + } + return builder.Build(), nil +} + +type cbgDecoder struct { + cbgType reflect.Type +} + +func (decoder *cbgDecoder) DecodeFromCbor(encoded []byte) (Encodable, error) { + decodedValue := reflect.New(decoder.cbgType.Elem()) + decoded, ok := decodedValue.Interface().(cborgen.CBORUnmarshaler) + if !ok || reflect.ValueOf(decoded).IsNil() { + return nil, xerrors.New("problem instantiating decoded value") + } + buf := bytes.NewReader(encoded) + err := decoded.UnmarshalCBOR(buf) + if err != nil { + return nil, err + } + return decoded, nil +} + +type defaultDecoder struct { + ptrType reflect.Type +} + +func (decoder *defaultDecoder) DecodeFromCbor(encoded []byte) (Encodable, error) { + decodedValue := reflect.New(decoder.ptrType.Elem()) + decoded, ok := decodedValue.Interface().(Encodable) + if !ok || reflect.ValueOf(decoded).IsNil() { + return nil, xerrors.New("problem instantiating decoded value") + } + err := cbor.DecodeInto(encoded, decoded) + if err != nil { + return nil, err + } + return decoded, nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding_test.go b/vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding_test.go new file mode 100644 index 0000000000..43a66f5d89 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/encoding/encoding_test.go @@ -0,0 +1,37 @@ +package encoding_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-data-transfer/encoding" + "github.com/filecoin-project/go-data-transfer/encoding/testdata" +) + +func TestRoundTrip(t *testing.T) { + testCases := map[string]struct { + val encoding.Encodable + }{ + "can encode/decode IPLD prime types": { + val: testdata.Prime, + }, + "can encode/decode cbor-gen types": { + val: testdata.Cbg, + }, + "can encode/decode old ipld format types": { + val: testdata.Standard, + }, + } + for testCase, data := range testCases { + t.Run(testCase, func(t *testing.T) { + encoded, err := encoding.Encode(data.val) + require.NoError(t, err) + decoder, err := encoding.NewDecoder(data.val) + require.NoError(t, err) + decoded, err := decoder.DecodeFromCbor(encoded) + require.NoError(t, err) + require.Equal(t, data.val, decoded) + }) + } +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata.go b/vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata.go new file mode 100644 index 0000000000..c76abc247c --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata.go @@ -0,0 +1,37 @@ +package testdata + +import ( + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/ipld/go-ipld-prime/fluent" + basicnode "github.com/ipld/go-ipld-prime/node/basic" +) + +// Prime = an instance of an ipld prime piece of data +var Prime = fluent.MustBuildMap(basicnode.Style.Map, 2, func(na fluent.MapAssembler) { + nva := na.AssembleEntry("X") + nva.AssignInt(100) + nva = na.AssembleEntry("Y") + nva.AssignString("appleSauce") +}) + +type standardType struct { + X int + Y string +} + +func init() { + cbor.RegisterCborType(standardType{}) +} + +// Standard = an instance that is neither ipld prime nor cbor +var Standard *standardType = &standardType{X: 100, Y: "appleSauce"} + +//go:generate cbor-gen-for cbgType + +type cbgType struct { + X uint64 + Y string +} + +// Cbg = an instance of a cbor-gen type +var Cbg *cbgType = &cbgType{X: 100, Y: "appleSauce"} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata_cbor_gen.go b/vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata_cbor_gen.go new file mode 100644 index 0000000000..67c6c68878 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/encoding/testdata/testdata_cbor_gen.go @@ -0,0 +1,84 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package testdata + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *cbgType) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.X (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.X))); err != nil { + return err + } + + // t.Y (string) (string) + if len(t.Y) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Y was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Y)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.Y)); err != nil { + return err + } + return nil +} + +func (t *cbgType) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.X (uint64) (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.X = uint64(extra) + + } + // t.Y (string) (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.Y = string(sval) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/go.mod b/vendor/github.com/filecoin-project/go-data-transfer/go.mod new file mode 100644 index 0000000000..f3b7036ada --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/go.mod @@ -0,0 +1,32 @@ +module github.com/filecoin-project/go-data-transfer + +go 1.13 + +require ( + github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b + github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099 + github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-blockservice v0.1.3 + github.com/ipfs/go-cid v0.0.5 + github.com/ipfs/go-datastore v0.4.4 + github.com/ipfs/go-graphsync v0.0.6-0.20200527235412-ea9535659648 + github.com/ipfs/go-ipfs-blockstore v0.1.4 + github.com/ipfs/go-ipfs-blocksutil v0.0.1 + github.com/ipfs/go-ipfs-chunker v0.0.5 + github.com/ipfs/go-ipfs-exchange-offline v0.0.1 + github.com/ipfs/go-ipfs-files v0.0.8 + github.com/ipfs/go-ipld-cbor v0.0.4 + github.com/ipfs/go-ipld-format v0.2.0 + github.com/ipfs/go-log v1.0.2 + github.com/ipfs/go-merkledag v0.3.1 + github.com/ipfs/go-unixfs v0.2.4 + github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e + github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c + github.com/libp2p/go-libp2p v0.6.0 + github.com/libp2p/go-libp2p-core v0.5.0 + github.com/prometheus/common v0.10.0 + github.com/stretchr/testify v1.5.1 + github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +) diff --git a/vendor/github.com/filecoin-project/go-data-transfer/go.sum b/vendor/github.com/filecoin-project/go-data-transfer/go.sum new file mode 100644 index 0000000000..2285a1dbbf --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/go.sum @@ -0,0 +1,700 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= +github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 h1:A/EVblehb75cUgXA5njHPn0kLAsykn6mJGz7rnmW5W0= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= +github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 h1:6xT9KW8zLC5IlbaIF5Q7JNieBoACT7iW0YTxQHR0in0= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= +github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099 h1:vQqOW42RRM5LoM/1K5dK940VipLqpH8lEVGrMz+mNjU= +github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099/go.mod h1:WVPCl0HO/0RAL5+vBH2GMxBomlxBF70MAS78+Lu1//k= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= +github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= +github.com/ipfs/go-bitswap v0.1.8 h1:38X1mKXkiU6Nzw4TOSWD8eTVY5eX3slQunv3QEWfXKg= +github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= +github.com/ipfs/go-blockservice v0.1.3 h1:9XgsPMwwWJSC9uVr2pMDsW2qFTBSkxpGMhmna8mIjPM= +github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= +github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-graphsync v0.0.6-0.20200527235412-ea9535659648 h1:OEyYvBH/4gUd4Hskef1CRBqQ4fpnlwQW3pj8taPt8ko= +github.com/ipfs/go-graphsync v0.0.6-0.20200527235412-ea9535659648/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= +github.com/ipfs/go-ipfs-blockstore v0.1.4 h1:2SGI6U1B44aODevza8Rde3+dY30Pb+lbcObe1LETxOQ= +github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-chunker v0.0.1 h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE27SEw= +github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= +github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= +github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1 h1:QBg+Ts2zgeemK/dB0saiF/ykzRGgfoFMT90Rzo0OnVU= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-ds-help v0.1.1 h1:IW/bXGeaAZV2VH0Kuok+Ohva/zHkHmeLFBxC1k7mNPc= +github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= +github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= +github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= +github.com/ipfs/go-ipfs-pq v0.0.1 h1:zgUotX8dcAB/w/HidJh1zzc1yFq6Vm8J7T2F4itj/RU= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= +github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.3 h1:ENsxvybwkmke7Z/QJOmeJfoguj6GH3Y0YOaGrfy9Q0I= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.4 h1:Aw3KPOKXjvrm6VjwJvFf1F1ekR/BH3jdof3Bk7OTiSA= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= +github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.2 h1:s19ZwJxH8rPWzypjcDpqPLIyV7BnbLqvpli3iZoqYK0= +github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= +github.com/ipfs/go-log/v2 v2.0.2 h1:xguurydRdfKMJjKyxNXNU8lYP0VZH1NUwJRwUorjuEw= +github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= +github.com/ipfs/go-merkledag v0.3.1 h1:3UqWINBEr3/N+r6OwgFXAddDP/8zpQX/8J7IGVOCqRQ= +github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.1.1 h1:+gPjbI+V3NktXZOqJA1kzbms2pYmhjgQQal0MzZrOAY= +github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN1EJOjc= +github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= +github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo= +github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e h1:ZISbJlM0urTANR9KRfRaqlBmyOj5uUtxs2r4Up9IXsA= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1 h1:K1Ysr7kgIlo7YQkPqdkA6H7BVdIugvuAz7OQUTJxLdE= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= +github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c h1:uUx61FiAa1GI6ZmVd2wf2vULeQZIKG66eybjNXKYCz4= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security-multistream v0.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ= +github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= +github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= +github.com/libp2p/go-libp2p v0.6.0 h1:EFArryT9N7AVA70LCcOh8zxsW+FeDnxwcpWQx9k7+GM= +github.com/libp2p/go-libp2p v0.6.0/go.mod h1:mfKWI7Soz3ABX+XEBR61lGbg+ewyMtJHVt043oWeqwg= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-autonat v0.1.1 h1:WLBZcIRsjZlWdAZj9CiBSvU2wQXoUOiS1Zk1tM7DTJI= +github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-blankhost v0.1.4 h1:I96SWjR4rK9irDHcHq3XHN6hawCRTPUADzkJacgZLvk= +github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-circuit v0.1.4 h1:Phzbmrg3BkVzbqd4ZZ149JxCuUWu2wZcXf/Kr6hZJj8= +github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= +github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= +github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= +github.com/libp2p/go-libp2p-core v0.2.4 h1:Et6ykkTwI6PU44tr8qUF9k43vP0aduMNniShAbUJJw8= +github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= +github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.0 h1:FBQ1fpq2Fo/ClyjojVJ5AKXlKhvNc/B6U0O+7AN1ffE= +github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-discovery v0.2.0 h1:1p3YSOq7VsgaL+xVHPi8XAmtGyas6D2J6rWBEfz/aiY= +github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-mplex v0.2.2 h1:+Ld7YDAfVERQ0E+qqjE7o6fHwKuM0SqTzYiwN1lVVSA= +github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= +github.com/libp2p/go-libp2p-nat v0.0.4 h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-nat v0.0.5 h1:/mH8pXFVKleflDL1YwqMg27W9GD8kjEx7NY0P6eGc98= +github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-peerstore v0.1.3 h1:wMgajt1uM2tMiqf4M+4qWKVyyFc8SfA+84VV9glZq1M= +github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= +github.com/libp2p/go-libp2p-peerstore v0.2.0 h1:XcgJhI8WyUOCbHyRLNEX5542YNj8hnLSJ2G1InRjDhk= +github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= +github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= +github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-record v0.1.1 h1:ZJK2bHXYUBqObHX+rHLSNrM3M8fmJUlUHrodDPPATmY= +github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-secio v0.2.0 h1:ywzZBsWEEz2KNTn5RtzauEDq5RFEefPsttXYwAWqHng= +github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= +github.com/libp2p/go-libp2p-secio v0.2.1 h1:eNWbJTdyPA7NxhP7J3c5lT97DC5d+u+IldkgCYFTPVA= +github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-swarm v0.2.2 h1:T4hUpgEs2r371PweU3DuH7EOmBIdTBCwWs+FLcgx3bQ= +github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.1.0 h1:WaFRj/t3HdMZGNZqnU2pS7pDRBmMeoDx7/HDNpeyT9U= +github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU= +github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0 h1:5EhPgQhXZNyfL22ERZTUoVp9UVVbNowWNVtELQaKCHk= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1 h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-libp2p-yamux v0.2.2 h1:eGvbqWqWY9S5lrpe2gA0UCOLCdzCgYSAR3vo/xCsNQg= +github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg= +github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-mplex v0.1.1 h1:huPH/GGRJzmsHR9IZJJsrSwIM5YE2gL4ssgl1YWb/ps= +github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.3 h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= +github.com/libp2p/go-nat v0.0.4 h1:KbizNnq8YIf7+Hn7+VFL/xE0eDrkPru2zIO9NMwL8UQ= +github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= +github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= +github.com/libp2p/go-openssl v0.0.3 h1:wjlG7HvQkt4Fq4cfH33Ivpwp0omaElYEi9z26qaIkIk= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-tcp-transport v0.1.1 h1:yGlqURmqgNA2fvzjSgZNlHcsd/IulAnKM8Ncu+vlqnw= +github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= +github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-ws-transport v0.2.0 h1:MJCw2OrPA9+76YNRvdo1wMnSOxb9Bivj6sVFY1Xrj6w= +github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.0 h1:FsYzT16Wq2XqUGJsBbOxoz9g+dFklvNi7jN6YFPfl7U= +github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.1 h1:rVAztJYMhCQ7vEFr8FvxW3mS+HF2eY/oPbOMeS0ZDnE= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.2.1 h1:SgG/cw5vqyB5QQe5FPe2TqggU9WtrA9X4nZw7LlVqOI= +github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= +github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multiaddr-net v0.1.0 h1:ZepO8Ezwovd+7b5XPPDhQhayk1yt0AJpzQBpq9fejx4= +github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.2 h1:P7zcBH9FRETdPkDrylcXVjQLQ2t1JQtNItZULWNWgeg= +github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI= +github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli/v2 v2.0.0 h1:+HU9SCbu8GnEUFtIBfuUNXN39ofWViIEJIp6SURMpCg= +github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a h1:xc8sbWMwBsvi8OrxFZR8zxw/fdCneHBLFDJJaV14eaE= +github.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105 h1:Sh6UG5dW5xW8Ek2CtRGq4ipdEvvx9hOyBJjEGyTYDl0= +github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361 h1:RIIXAeV6GvDBuADKumTODatUqANFZ+5BPMnzsy4hulY= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/dagservice/dagservice.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/dagservice/dagservice.go new file mode 100644 index 0000000000..7f228cc9e4 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/dagservice/dagservice.go @@ -0,0 +1,87 @@ +package datatransfer + +import ( + "context" + "time" + + "github.com/ipfs/go-cid" + ipldformat "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-merkledag" + "github.com/ipld/go-ipld-prime" + "github.com/libp2p/go-libp2p-core/peer" + "golang.org/x/xerrors" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/channels" +) + +// This file implements a VERY simple, incomplete version of the data transfer +// module that allows us to make the necessary insertions of data transfer +// functionality into the storage market +// It does not: +// -- actually validate requests +// -- support Push requests +// -- support multiple subscribers +// -- do any actual network coordination or use Graphsync + +type dagserviceImpl struct { + dag ipldformat.DAGService + subscriber datatransfer.Subscriber +} + +// NewDAGServiceDataTransfer returns a data transfer manager based on +// an IPLD DAGService +func NewDAGServiceDataTransfer(dag ipldformat.DAGService) datatransfer.Manager { + return &dagserviceImpl{dag, nil} +} + +// RegisterVoucherType registers a validator for the given voucher type +// will error if voucher type does not implement voucher +// or if there is a voucher type registered with an identical identifier +func (impl *dagserviceImpl) RegisterVoucherType(voucherType datatransfer.Voucher, validator datatransfer.RequestValidator) error { + return nil +} + +// open a data transfer that will send data to the recipient peer and +// transfer parts of the piece that match the selector +func (impl *dagserviceImpl) OpenPushDataChannel(ctx context.Context, to peer.ID, voucher datatransfer.Voucher, baseCid cid.Cid, Selector ipld.Node) (datatransfer.ChannelID, error) { + return datatransfer.ChannelID{}, xerrors.Errorf("not implemented") +} + +// open a data transfer that will request data from the sending peer and +// transfer parts of the piece that match the selector +func (impl *dagserviceImpl) OpenPullDataChannel(ctx context.Context, to peer.ID, voucher datatransfer.Voucher, baseCid cid.Cid, Selector ipld.Node) (datatransfer.ChannelID, error) { + ctx, cancel := context.WithCancel(ctx) + go func() { + defer cancel() + err := merkledag.FetchGraph(ctx, baseCid, impl.dag) + event := datatransfer.Event{Timestamp: time.Now()} + if err != nil { + event.Code = datatransfer.Error + event.Message = err.Error() + } else { + event.Code = datatransfer.Complete + } + impl.subscriber(event, channels.ChannelState{Channel: channels.NewChannel(0, baseCid, Selector, voucher, to, "", 0)}) + }() + return datatransfer.ChannelID{}, nil +} + +// close an open channel (effectively a cancel) +func (impl *dagserviceImpl) CloseDataTransferChannel(x datatransfer.ChannelID) {} + +// get status of a transfer +func (impl *dagserviceImpl) TransferChannelStatus(x datatransfer.ChannelID) datatransfer.Status { + return datatransfer.ChannelNotFoundError +} + +// get notified when certain types of events happen +func (impl *dagserviceImpl) SubscribeToEvents(subscriber datatransfer.Subscriber) datatransfer.Unsubscribe { + impl.subscriber = subscriber + return func() {} +} + +// get all in progress transfers +func (impl *dagserviceImpl) InProgressChannels() map[datatransfer.ChannelID]datatransfer.ChannelState { + return nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension.go new file mode 100644 index 0000000000..658096e8cf --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension.go @@ -0,0 +1,62 @@ +package extension + +import ( + "bytes" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/ipfs/go-graphsync" + "github.com/libp2p/go-libp2p-core/peer" +) + +const ( + // ExtensionDataTransfer is the identifier for the data transfer extension to graphsync + ExtensionDataTransfer = graphsync.ExtensionName("fil/data-transfer") +) + +//go:generate cbor-gen-for TransferData + +// TransferData is the extension data for +// the graphsync extension. +type TransferData struct { + TransferID uint64 + Initiator peer.ID + IsPull bool +} + +// GetChannelID gets the channelID for this extension, given the peers on either side +func (e TransferData) GetChannelID() datatransfer.ChannelID { + return datatransfer.ChannelID{Initiator: e.Initiator, ID: datatransfer.TransferID(e.TransferID)} +} + +// NewTransferData returns transfer data to encode in a graphsync request +func NewTransferData(transferID datatransfer.TransferID, initiator peer.ID, isPull bool) TransferData { + return TransferData{ + TransferID: uint64(transferID), + Initiator: initiator, + IsPull: isPull, + } +} + +// GsExtended is a small interface used by getExtensionData +type GsExtended interface { + Extension(name graphsync.ExtensionName) ([]byte, bool) +} + +// GetTransferData unmarshals extension data. +// Returns: +// * nil + nil if the extension is not found +// * nil + error if the extendedData fails to unmarshal +// * unmarshaled ExtensionDataTransferData + nil if all goes well +func GetTransferData(extendedData GsExtended) (*TransferData, error) { + data, ok := extendedData.Extension(ExtensionDataTransfer) + if !ok { + return nil, nil + } + var extStruct TransferData + + reader := bytes.NewReader(data) + if err := extStruct.UnmarshalCBOR(reader); err != nil { + return nil, err + } + return &extStruct, nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension_cbor_gen.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension_cbor_gen.go new file mode 100644 index 0000000000..8d7aeb1b18 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/extension/gsextension_cbor_gen.go @@ -0,0 +1,107 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package extension + +import ( + "fmt" + "io" + + "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *TransferData) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.TransferID (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.TransferID))); err != nil { + return err + } + + // t.Initiator (peer.ID) (string) + if len(t.Initiator) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Initiator was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Initiator)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.Initiator)); err != nil { + return err + } + + // t.IsPull (bool) (bool) + if err := cbg.WriteBool(w, t.IsPull); err != nil { + return err + } + return nil +} + +func (t *TransferData) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.TransferID (uint64) (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.TransferID = uint64(extra) + + } + // t.Initiator (peer.ID) (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.Initiator = peer.ID(sval) + } + // t.IsPull (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.IsPull = false + case 21: + t.IsPull = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl.go new file mode 100644 index 0000000000..26980852ef --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl.go @@ -0,0 +1,307 @@ +package graphsyncimpl + +import ( + "bytes" + "context" + "errors" + "fmt" + "time" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-graphsync" + logging "github.com/ipfs/go-log" + "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "golang.org/x/xerrors" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/channels" + "github.com/filecoin-project/go-data-transfer/impl/graphsync/extension" + "github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks" + "github.com/filecoin-project/go-data-transfer/message" + "github.com/filecoin-project/go-data-transfer/network" + "github.com/filecoin-project/go-data-transfer/registry" + "github.com/filecoin-project/go-storedcounter" + "github.com/hannahhoward/go-pubsub" +) + +var log = logging.Logger("graphsync-impl") + +type graphsyncImpl struct { + dataTransferNetwork network.DataTransferNetwork + validatedTypes *registry.Registry + pubSub *pubsub.PubSub + channels *channels.Channels + gs graphsync.GraphExchange + peerID peer.ID + storedCounter *storedcounter.StoredCounter +} + +type internalEvent struct { + evt datatransfer.Event + state datatransfer.ChannelState +} + +func dispatcher(evt pubsub.Event, subscriberFn pubsub.SubscriberFn) error { + ie, ok := evt.(internalEvent) + if !ok { + return errors.New("wrong type of event") + } + cb, ok := subscriberFn.(datatransfer.Subscriber) + if !ok { + return errors.New("wrong type of event") + } + cb(ie.evt, ie.state) + return nil +} + +// NewGraphSyncDataTransfer initializes a new graphsync based data transfer manager +func NewGraphSyncDataTransfer(host host.Host, gs graphsync.GraphExchange, storedCounter *storedcounter.StoredCounter) datatransfer.Manager { + dataTransferNetwork := network.NewFromLibp2pHost(host) + impl := &graphsyncImpl{ + dataTransferNetwork: dataTransferNetwork, + validatedTypes: registry.NewRegistry(), + pubSub: pubsub.New(dispatcher), + channels: channels.New(), + gs: gs, + peerID: host.ID(), + storedCounter: storedCounter, + } + + dtReceiver := &graphsyncReceiver{impl} + dataTransferNetwork.SetDelegate(dtReceiver) + + hooksManager := hooks.NewManager(host.ID(), impl) + hooksManager.RegisterHooks(gs) + return impl +} + +func (impl *graphsyncImpl) OnRequestSent(chid datatransfer.ChannelID) error { + _, err := impl.channels.GetByID(chid) + return err +} + +func (impl *graphsyncImpl) OnDataReceived(chid datatransfer.ChannelID, link ipld.Link, size uint64) error { + _, err := impl.channels.IncrementReceived(chid, size) + if err != nil { + return err + } + chst, err := impl.channels.GetByID(chid) + if err != nil { + return err + } + evt := datatransfer.Event{ + Code: datatransfer.Progress, + Message: fmt.Sprintf("Received %d more bytes", size), + Timestamp: time.Now(), + } + err = impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } + return nil +} + +func (impl *graphsyncImpl) OnDataSent(chid datatransfer.ChannelID, link ipld.Link, size uint64) error { + _, err := impl.channels.IncrementSent(chid, size) + if err != nil { + return err + } + chst, err := impl.channels.GetByID(chid) + if err != nil { + return err + } + evt := datatransfer.Event{ + Code: datatransfer.Progress, + Message: fmt.Sprintf("Sent %d more bytes", size), + Timestamp: time.Now(), + } + err = impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } + return nil +} + +func (impl *graphsyncImpl) OnRequestReceived(chid datatransfer.ChannelID) error { + _, err := impl.channels.GetByID(chid) + return err +} + +func (impl *graphsyncImpl) OnResponseCompleted(chid datatransfer.ChannelID, success bool) error { + chst, err := impl.channels.GetByID(chid) + if err != nil { + return err + } + + evt := datatransfer.Event{ + Code: datatransfer.Error, + Timestamp: time.Now(), + } + if success { + evt.Code = datatransfer.Complete + } + err = impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } + return nil +} + +// RegisterVoucherType registers a validator for the given voucher type +// returns error if: +// * voucher type does not implement voucher +// * there is a voucher type registered with an identical identifier +// * voucherType's Kind is not reflect.Ptr +func (impl *graphsyncImpl) RegisterVoucherType(voucherType datatransfer.Voucher, validator datatransfer.RequestValidator) error { + err := impl.validatedTypes.Register(voucherType, validator) + if err != nil { + return xerrors.Errorf("error registering voucher type: %w", err) + } + return nil +} + +// OpenPushDataChannel opens a data transfer that will send data to the recipient peer and +// transfer parts of the piece that match the selector +func (impl *graphsyncImpl) OpenPushDataChannel(ctx context.Context, requestTo peer.ID, voucher datatransfer.Voucher, baseCid cid.Cid, selector ipld.Node) (datatransfer.ChannelID, error) { + tid, err := impl.sendDtRequest(ctx, selector, false, voucher, baseCid, requestTo) + if err != nil { + return datatransfer.ChannelID{}, err + } + + chid, err := impl.channels.CreateNew(tid, baseCid, selector, voucher, + impl.peerID, impl.peerID, requestTo) // initiator = us, sender = us, receiver = them + if err != nil { + return chid, err + } + evt := datatransfer.Event{ + Code: datatransfer.Open, + Message: "New Request Initiated", + Timestamp: time.Now(), + } + chst, err := impl.channels.GetByID(chid) + if err != nil { + return chid, err + } + err = impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } + return chid, nil +} + +// OpenPullDataChannel opens a data transfer that will request data from the sending peer and +// transfer parts of the piece that match the selector +func (impl *graphsyncImpl) OpenPullDataChannel(ctx context.Context, requestTo peer.ID, voucher datatransfer.Voucher, baseCid cid.Cid, selector ipld.Node) (datatransfer.ChannelID, error) { + + tid, err := impl.sendDtRequest(ctx, selector, true, voucher, baseCid, requestTo) + if err != nil { + return datatransfer.ChannelID{}, err + } + // initiator = us, sender = them, receiver = us + chid, err := impl.channels.CreateNew(tid, baseCid, selector, voucher, + impl.peerID, requestTo, impl.peerID) + if err != nil { + return chid, err + } + evt := datatransfer.Event{ + Code: datatransfer.Open, + Message: "New Request Initiated", + Timestamp: time.Now(), + } + chst, err := impl.channels.GetByID(chid) + if err != nil { + return chid, err + } + err = impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } + return chid, nil +} + +// sendDtRequest encapsulates message creation and posting to the data transfer network with the provided parameters +func (impl *graphsyncImpl) sendDtRequest(ctx context.Context, selector ipld.Node, isPull bool, voucher datatransfer.Voucher, baseCid cid.Cid, to peer.ID) (datatransfer.TransferID, error) { + next, err := impl.storedCounter.Next() + if err != nil { + return 0, err + } + tid := datatransfer.TransferID(next) + req, err := message.NewRequest(tid, isPull, voucher.Type(), voucher, baseCid, selector) + if err != nil { + return 0, err + } + if err := impl.dataTransferNetwork.SendMessage(ctx, to, req); err != nil { + return 0, err + } + return tid, nil +} + +func (impl *graphsyncImpl) sendResponse(ctx context.Context, isAccepted bool, to peer.ID, tid datatransfer.TransferID) { + resp := message.NewResponse(tid, isAccepted) + if err := impl.dataTransferNetwork.SendMessage(ctx, to, resp); err != nil { + log.Error(err) + } +} + +// close an open channel (effectively a cancel) +func (impl *graphsyncImpl) CloseDataTransferChannel(x datatransfer.ChannelID) {} + +// get status of a transfer +func (impl *graphsyncImpl) TransferChannelStatus(x datatransfer.ChannelID) datatransfer.Status { + return datatransfer.ChannelNotFoundError +} + +// get notified when certain types of events happen +func (impl *graphsyncImpl) SubscribeToEvents(subscriber datatransfer.Subscriber) datatransfer.Unsubscribe { + return datatransfer.Unsubscribe(impl.pubSub.Subscribe(subscriber)) +} + +// get all in progress transfers +func (impl *graphsyncImpl) InProgressChannels() map[datatransfer.ChannelID]datatransfer.ChannelState { + return impl.channels.InProgress() +} + +// sendGsRequest assembles a graphsync request and determines if the transfer was completed/successful. +// notifies subscribers of final request status. +func (impl *graphsyncImpl) sendGsRequest(ctx context.Context, initiator peer.ID, transferID datatransfer.TransferID, isPull bool, dataSender peer.ID, root cidlink.Link, stor ipld.Node) { + extDtData := extension.NewTransferData(transferID, initiator, isPull) + var buf bytes.Buffer + if err := extDtData.MarshalCBOR(&buf); err != nil { + log.Error(err) + } + extData := buf.Bytes() + _, errChan := impl.gs.Request(ctx, dataSender, root, stor, + graphsync.ExtensionData{ + Name: extension.ExtensionDataTransfer, + Data: extData, + }) + go func() { + var lastError error + for err := range errChan { + lastError = err + } + evt := datatransfer.Event{ + Code: datatransfer.Error, + Timestamp: time.Now(), + } + chid := datatransfer.ChannelID{Initiator: initiator, ID: transferID} + chst, err := impl.channels.GetByID(chid) + if err != nil { + msg := "cannot find a matching channel for this request" + evt.Message = msg + } else { + if lastError == nil { + evt.Code = datatransfer.Complete + } else { + evt.Message = lastError.Error() + } + } + err = impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } + }() +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl_test.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl_test.go new file mode 100644 index 0000000000..c3143908b1 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_impl_test.go @@ -0,0 +1,1066 @@ +package graphsyncimpl_test + +import ( + "bytes" + "context" + "errors" + "math/rand" + "testing" + "time" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-graphsync" + gsmsg "github.com/ipfs/go-graphsync/message" + "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + basicnode "github.com/ipld/go-ipld-prime/node/basic" + "github.com/ipld/go-ipld-prime/traversal/selector" + "github.com/ipld/go-ipld-prime/traversal/selector/builder" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + datatransfer "github.com/filecoin-project/go-data-transfer" + . "github.com/filecoin-project/go-data-transfer/impl/graphsync" + "github.com/filecoin-project/go-data-transfer/impl/graphsync/extension" + "github.com/filecoin-project/go-data-transfer/message" + "github.com/filecoin-project/go-data-transfer/network" + "github.com/filecoin-project/go-data-transfer/testutil" +) + +type receivedMessage struct { + message message.DataTransferMessage + sender peer.ID +} + +// Receiver is an interface for receiving messages from the GraphSyncNetwork. +type receiver struct { + messageReceived chan receivedMessage +} + +func (r *receiver) ReceiveRequest( + ctx context.Context, + sender peer.ID, + incoming message.DataTransferRequest) { + + select { + case <-ctx.Done(): + case r.messageReceived <- receivedMessage{incoming, sender}: + } +} + +func (r *receiver) ReceiveResponse( + ctx context.Context, + sender peer.ID, + incoming message.DataTransferResponse) { + + select { + case <-ctx.Done(): + case r.messageReceived <- receivedMessage{incoming, sender}: + } +} + +func (r *receiver) ReceiveError(err error) { +} + +func TestDataTransferOneWay(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 + host2 := gsData.Host2 + // setup receiving peer to just record message coming in + dtnet2 := network.NewFromLibp2pHost(host2) + r := &receiver{ + messageReceived: make(chan receivedMessage), + } + dtnet2.SetDelegate(r) + + gs := gsData.SetupGraphsyncHost1() + dt := NewGraphSyncDataTransfer(host1, gs, gsData.StoredCounter1) + + t.Run("OpenPushDataTransfer", func(t *testing.T) { + ssb := builder.NewSelectorSpecBuilder(basicnode.Style.Any) + + // this is the selector for "get the whole DAG" + // TODO: support storage deals with custom payload selectors + stor := ssb.ExploreRecursive(selector.RecursionLimitNone(), + ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node() + + voucher := testutil.NewFakeDTType() + baseCid := testutil.GenerateCids(1)[0] + channelID, err := dt.OpenPushDataChannel(ctx, host2.ID(), voucher, baseCid, stor) + require.NoError(t, err) + require.NotNil(t, channelID) + require.Equal(t, channelID.Initiator, host1.ID()) + require.NoError(t, err) + + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + + sender := messageReceived.sender + require.Equal(t, sender, host1.ID()) + + received := messageReceived.message + require.True(t, received.IsRequest()) + receivedRequest, ok := received.(message.DataTransferRequest) + require.True(t, ok) + + require.Equal(t, receivedRequest.TransferID(), channelID.ID) + require.Equal(t, receivedRequest.BaseCid(), baseCid) + require.False(t, receivedRequest.IsCancel()) + require.False(t, receivedRequest.IsPull()) + receivedSelector, err := receivedRequest.Selector() + require.NoError(t, err) + require.Equal(t, receivedSelector, stor) + testutil.AssertFakeDTVoucher(t, receivedRequest, voucher) + }) + + t.Run("OpenPullDataTransfer", func(t *testing.T) { + ssb := builder.NewSelectorSpecBuilder(basicnode.Style.Any) + + stor := ssb.ExploreRecursive(selector.RecursionLimitNone(), + ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node() + + voucher := testutil.NewFakeDTType() + baseCid := testutil.GenerateCids(1)[0] + channelID, err := dt.OpenPullDataChannel(ctx, host2.ID(), voucher, baseCid, stor) + require.NoError(t, err) + require.NotNil(t, channelID) + require.Equal(t, channelID.Initiator, host1.ID()) + require.NoError(t, err) + + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + + sender := messageReceived.sender + require.Equal(t, sender, host1.ID()) + + received := messageReceived.message + require.True(t, received.IsRequest()) + receivedRequest, ok := received.(message.DataTransferRequest) + require.True(t, ok) + + require.Equal(t, receivedRequest.TransferID(), channelID.ID) + require.Equal(t, receivedRequest.BaseCid(), baseCid) + require.False(t, receivedRequest.IsCancel()) + require.True(t, receivedRequest.IsPull()) + receivedSelector, err := receivedRequest.Selector() + require.NoError(t, err) + require.Equal(t, receivedSelector, stor) + testutil.AssertFakeDTVoucher(t, receivedRequest, voucher) + }) +} + +type receivedValidation struct { + isPull bool + other peer.ID + voucher datatransfer.Voucher + baseCid cid.Cid + selector ipld.Node +} + +type fakeValidator struct { + ctx context.Context + validationsReceived chan receivedValidation +} + +func (fv *fakeValidator) ValidatePush( + sender peer.ID, + voucher datatransfer.Voucher, + baseCid cid.Cid, + selector ipld.Node) error { + + select { + case <-fv.ctx.Done(): + case fv.validationsReceived <- receivedValidation{false, sender, voucher, baseCid, selector}: + } + return nil +} + +func (fv *fakeValidator) ValidatePull( + receiver peer.ID, + voucher datatransfer.Voucher, + baseCid cid.Cid, + selector ipld.Node) error { + + select { + case <-fv.ctx.Done(): + case fv.validationsReceived <- receivedValidation{true, receiver, voucher, baseCid, selector}: + } + return nil +} + +func TestDataTransferValidation(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 + host2 := gsData.Host2 + dtnet1 := network.NewFromLibp2pHost(host1) + r := &receiver{ + messageReceived: make(chan receivedMessage), + } + dtnet1.SetDelegate(r) + + gs2 := testutil.NewFakeGraphSync() + + fv := &fakeValidator{ctx, make(chan receivedValidation)} + + id := datatransfer.TransferID(rand.Int31()) + + t.Run("ValidatePush", func(t *testing.T) { + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + err := dt2.RegisterVoucherType(&testutil.FakeDTType{}, fv) + require.NoError(t, err) + // create push request + voucher, baseCid, request := createDTRequest(t, false, id, gsData.AllSelector) + + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + + var validation receivedValidation + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case validation = <-fv.validationsReceived: + assert.False(t, validation.isPull) + } + + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case _ = <-r.messageReceived: + } + + assert.False(t, validation.isPull) + assert.Equal(t, host1.ID(), validation.other) + assert.Equal(t, &voucher, validation.voucher) + assert.Equal(t, baseCid, validation.baseCid) + assert.Equal(t, gsData.AllSelector, validation.selector) + }) + + t.Run("ValidatePull", func(t *testing.T) { + // create pull request + voucher, baseCid, request := createDTRequest(t, true, id, gsData.AllSelector) + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + + var validation receivedValidation + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case validation = <-fv.validationsReceived: + } + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case _ = <-r.messageReceived: + } + + assert.True(t, validation.isPull) + assert.Equal(t, validation.other, host1.ID()) + assert.Equal(t, &voucher, validation.voucher) + assert.Equal(t, baseCid, validation.baseCid) + assert.Equal(t, gsData.AllSelector, validation.selector) + }) +} + +func createDTRequest(t *testing.T, isPull bool, id datatransfer.TransferID, selector ipld.Node) (testutil.FakeDTType, cid.Cid, message.DataTransferRequest) { + voucher := &testutil.FakeDTType{Data: "applesauce"} + baseCid := testutil.GenerateCids(1)[0] + request, err := message.NewRequest(id, isPull, voucher.Type(), voucher, baseCid, selector) + require.NoError(t, err) + return *voucher, baseCid, request +} + +type stubbedValidator struct { + didPush bool + didPull bool + expectPush bool + expectPull bool + pushError error + pullError error +} + +func newSV() *stubbedValidator { + return &stubbedValidator{false, false, false, false, nil, nil} +} + +func (sv *stubbedValidator) ValidatePush( + sender peer.ID, + voucher datatransfer.Voucher, + baseCid cid.Cid, + selector ipld.Node) error { + sv.didPush = true + return sv.pushError +} + +func (sv *stubbedValidator) ValidatePull( + receiver peer.ID, + voucher datatransfer.Voucher, + baseCid cid.Cid, + selector ipld.Node) error { + sv.didPull = true + return sv.pullError +} + +func (sv *stubbedValidator) stubErrorPush() { + sv.pushError = errors.New("something went wrong") +} + +func (sv *stubbedValidator) stubSuccessPush() { + sv.pullError = nil +} + +func (sv *stubbedValidator) expectSuccessPush() { + sv.expectPush = true + sv.stubSuccessPush() +} + +func (sv *stubbedValidator) expectErrorPush() { + sv.expectPush = true + sv.stubErrorPush() +} + +func (sv *stubbedValidator) stubErrorPull() { + sv.pullError = errors.New("something went wrong") +} + +func (sv *stubbedValidator) stubSuccessPull() { + sv.pullError = nil +} + +func (sv *stubbedValidator) expectSuccessPull() { + sv.expectPull = true + sv.stubSuccessPull() +} + +func (sv *stubbedValidator) expectErrorPull() { + sv.expectPull = true + sv.stubErrorPull() +} + +func (sv *stubbedValidator) verifyExpectations(t *testing.T) { + if sv.expectPush { + require.True(t, sv.didPush) + } + if sv.expectPull { + require.True(t, sv.didPull) + } +} + +func TestGraphsyncImpl_RegisterVoucherType(t *testing.T) { + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 + + gs1 := testutil.NewFakeGraphSync() + dt := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + fv := &fakeValidator{ctx, make(chan receivedValidation)} + + // a voucher type can be registered + assert.NoError(t, dt.RegisterVoucherType(&testutil.FakeDTType{}, fv)) + + // it cannot be re-registered + assert.EqualError(t, dt.RegisterVoucherType(&testutil.FakeDTType{}, fv), "error registering voucher type: identifier already registered: FakeDTType") + + // it must be registered as a pointer + assert.EqualError(t, dt.RegisterVoucherType(testutil.FakeDTType{}, fv), + "error registering voucher type: registering entry type FakeDTType: type must be a pointer") +} + +func TestDataTransferSubscribing(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 + host2 := gsData.Host2 + + gs1 := testutil.NewFakeGraphSync() + gs2 := testutil.NewFakeGraphSync() + sv := newSV() + sv.stubErrorPull() + sv.stubErrorPush() + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + require.NoError(t, dt2.RegisterVoucherType(&testutil.FakeDTType{}, sv)) + voucher := testutil.FakeDTType{Data: "applesauce"} + baseCid := testutil.GenerateCids(1)[0] + + dt1 := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + + subscribe1Calls := make(chan struct{}, 1) + subscribe1 := func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Error { + subscribe1Calls <- struct{}{} + } + } + subscribe2Calls := make(chan struct{}, 1) + subscribe2 := func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Error { + subscribe2Calls <- struct{}{} + } + } + unsub1 := dt1.SubscribeToEvents(subscribe1) + unsub2 := dt1.SubscribeToEvents(subscribe2) + _, err := dt1.OpenPushDataChannel(ctx, host2.ID(), &voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + select { + case <-ctx.Done(): + t.Fatal("subscribed events not received") + case <-subscribe1Calls: + } + select { + case <-ctx.Done(): + t.Fatal("subscribed events not received") + case <-subscribe2Calls: + } + unsub1() + unsub2() + + subscribe3Calls := make(chan struct{}, 1) + subscribe3 := func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Error { + subscribe3Calls <- struct{}{} + } + } + subscribe4Calls := make(chan struct{}, 1) + subscribe4 := func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Error { + subscribe4Calls <- struct{}{} + } + } + unsub3 := dt1.SubscribeToEvents(subscribe3) + unsub4 := dt1.SubscribeToEvents(subscribe4) + _, err = dt1.OpenPullDataChannel(ctx, host2.ID(), &voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + select { + case <-ctx.Done(): + t.Fatal("subscribed events not received") + case <-subscribe1Calls: + t.Fatal("received channel that should have been unsubscribed") + case <-subscribe2Calls: + t.Fatal("received channel that should have been unsubscribed") + case <-subscribe3Calls: + } + select { + case <-ctx.Done(): + t.Fatal("subscribed events not received") + case <-subscribe1Calls: + t.Fatal("received channel that should have been unsubscribed") + case <-subscribe2Calls: + t.Fatal("received channel that should have been unsubscribed") + case <-subscribe4Calls: + } + unsub3() + unsub4() +} + +func TestDataTransferInitiatingPushGraphsyncRequests(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 + host2 := gsData.Host2 + + gs2 := testutil.NewFakeGraphSync() + + // setup receiving peer to just record message coming in + dtnet1 := network.NewFromLibp2pHost(host1) + r := &receiver{ + messageReceived: make(chan receivedMessage), + } + dtnet1.SetDelegate(r) + + id := datatransfer.TransferID(rand.Int31()) + + _, baseCid, request := createDTRequest(t, false, id, gsData.AllSelector) + + t.Run("with successful validation", func(t *testing.T) { + sv := newSV() + sv.expectSuccessPush() + + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + require.NoError(t, dt2.RegisterVoucherType(&testutil.FakeDTType{}, sv)) + + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case <-r.messageReceived: + } + sv.verifyExpectations(t) + + requestReceived := gs2.AssertRequestReceived(ctx, t) + + sv.verifyExpectations(t) + + receiver := requestReceived.P + require.Equal(t, receiver, host1.ID()) + + cl, ok := requestReceived.Root.(cidlink.Link) + require.True(t, ok) + require.Equal(t, baseCid, cl.Cid) + + require.Equal(t, gsData.AllSelector, requestReceived.Selector) + + }) + + t.Run("with error validation", func(t *testing.T) { + sv := newSV() + sv.expectErrorPush() + + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + require.NoError(t, dt2.RegisterVoucherType(&testutil.FakeDTType{}, sv)) + + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case <-r.messageReceived: + } + sv.verifyExpectations(t) + + // no graphsync request should be scheduled + gs2.AssertNoRequestReceived(t) + + }) + +} + +func TestDataTransferInitiatingPullGraphsyncRequests(t *testing.T) { + ctx := context.Background() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 // initiates the pull request + host2 := gsData.Host2 // sends the data + + voucher := testutil.FakeDTType{Data: "applesauce"} + baseCid := testutil.GenerateCids(1)[0] + + t.Run("with successful validation", func(t *testing.T) { + gs1Init := testutil.NewFakeGraphSync() + gs2Sender := testutil.NewFakeGraphSync() + + sv := newSV() + sv.expectSuccessPull() + + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + dtInit := NewGraphSyncDataTransfer(host1, gs1Init, gsData.StoredCounter1) + dtSender := NewGraphSyncDataTransfer(host2, gs2Sender, gsData.StoredCounter2) + err := dtSender.RegisterVoucherType(&testutil.FakeDTType{}, sv) + require.NoError(t, err) + + _, err = dtInit.OpenPullDataChannel(ctx, host2.ID(), &voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + + requestReceived := gs1Init.AssertRequestReceived(ctx, t) + sv.verifyExpectations(t) + + receiver := requestReceived.P + require.Equal(t, receiver, host2.ID()) + + cl, ok := requestReceived.Root.(cidlink.Link) + require.True(t, ok) + require.Equal(t, baseCid.String(), cl.Cid.String()) + + require.Equal(t, gsData.AllSelector, requestReceived.Selector) + }) + + t.Run("with error validation", func(t *testing.T) { + gs1 := testutil.NewFakeGraphSync() + gs2 := testutil.NewFakeGraphSync() + + dt1 := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + sv := newSV() + sv.expectErrorPull() + + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + err := dt2.RegisterVoucherType(&testutil.FakeDTType{}, sv) + require.NoError(t, err) + + subscribeCalls := make(chan struct{}, 1) + subscribe := func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Error { + subscribeCalls <- struct{}{} + } + } + unsub := dt1.SubscribeToEvents(subscribe) + _, err = dt1.OpenPullDataChannel(ctx, host2.ID(), &voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + + select { + case <-ctx.Done(): + t.Fatal("subscribed events not received") + case <-subscribeCalls: + } + + sv.verifyExpectations(t) + + // no graphsync request should be scheduled + gs1.AssertNoRequestReceived(t) + unsub() + }) + + t.Run("does not schedule graphsync request if is push request", func(t *testing.T) { + gs1 := testutil.NewFakeGraphSync() + gs2 := testutil.NewFakeGraphSync() + + sv := newSV() + sv.expectSuccessPush() + + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + dt1 := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + err := dt2.RegisterVoucherType(&testutil.FakeDTType{}, sv) + require.NoError(t, err) + + subscribeCalls := make(chan struct{}, 1) + subscribe := func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Progress { + subscribeCalls <- struct{}{} + } + } + unsub := dt1.SubscribeToEvents(subscribe) + _, err = dt1.OpenPushDataChannel(ctx, host2.ID(), &voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + + select { + case <-ctx.Done(): + t.Fatal("subscribed events not received") + case <-subscribeCalls: + } + sv.verifyExpectations(t) + + // no graphsync request should be scheduled + gs1.AssertNoRequestReceived(t) + unsub() + }) +} + +type receivedGraphSyncMessage struct { + message gsmsg.GraphSyncMessage + p peer.ID +} + +type fakeGraphSyncReceiver struct { + receivedMessages chan receivedGraphSyncMessage +} + +func (fgsr *fakeGraphSyncReceiver) ReceiveMessage(ctx context.Context, sender peer.ID, incoming gsmsg.GraphSyncMessage) { + select { + case <-ctx.Done(): + case fgsr.receivedMessages <- receivedGraphSyncMessage{incoming, sender}: + } +} + +func (fgsr *fakeGraphSyncReceiver) ReceiveError(_ error) { +} +func (fgsr *fakeGraphSyncReceiver) Connected(p peer.ID) { +} +func (fgsr *fakeGraphSyncReceiver) Disconnected(p peer.ID) { +} + +func (fgsr *fakeGraphSyncReceiver) consumeResponses(ctx context.Context, t *testing.T) graphsync.ResponseStatusCode { + var gsMessageReceived receivedGraphSyncMessage + for { + select { + case <-ctx.Done(): + t.Fail() + case gsMessageReceived = <-fgsr.receivedMessages: + responses := gsMessageReceived.message.Responses() + if (len(responses) > 0) && gsmsg.IsTerminalResponseCode(responses[0].Status()) { + return responses[0].Status() + } + } + } +} + +func TestRespondingToPushGraphsyncRequests(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 // initiator and data sender + host2 := gsData.Host2 // data recipient, makes graphsync request for data + voucher := testutil.FakeDTType{Data: "applesauce"} + link := gsData.LoadUnixFSFile(t, false) + + // setup receiving peer to just record message coming in + dtnet2 := network.NewFromLibp2pHost(host2) + r := &receiver{ + messageReceived: make(chan receivedMessage), + } + dtnet2.SetDelegate(r) + + gsr := &fakeGraphSyncReceiver{ + receivedMessages: make(chan receivedGraphSyncMessage), + } + gsData.GsNet2.SetDelegate(gsr) + + gs1 := gsData.SetupGraphsyncHost1() + dt1 := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + + t.Run("when request is initiated", func(t *testing.T) { + _, err := dt1.OpenPushDataChannel(ctx, host2.ID(), &voucher, link.(cidlink.Link).Cid, gsData.AllSelector) + require.NoError(t, err) + + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + requestReceived := messageReceived.message.(message.DataTransferRequest) + + var buf bytes.Buffer + extStruct := &extension.TransferData{TransferID: uint64(requestReceived.TransferID()), Initiator: host1.ID()} + err = extStruct.MarshalCBOR(&buf) + require.NoError(t, err) + extData := buf.Bytes() + + request := gsmsg.NewRequest(graphsync.RequestID(rand.Int31()), link.(cidlink.Link).Cid, gsData.AllSelector, graphsync.Priority(rand.Int31()), graphsync.ExtensionData{ + Name: extension.ExtensionDataTransfer, + Data: extData, + }) + gsmessage := gsmsg.New() + gsmessage.AddRequest(request) + require.NoError(t, gsData.GsNet2.SendMessage(ctx, host1.ID(), gsmessage)) + + status := gsr.consumeResponses(ctx, t) + require.False(t, gsmsg.IsTerminalFailureCode(status)) + }) + + t.Run("when no request is initiated", func(t *testing.T) { + var buf bytes.Buffer + extStruct := &extension.TransferData{TransferID: rand.Uint64(), Initiator: host1.ID()} + err := extStruct.MarshalCBOR(&buf) + require.NoError(t, err) + extData := buf.Bytes() + + request := gsmsg.NewRequest(graphsync.RequestID(rand.Int31()), link.(cidlink.Link).Cid, gsData.AllSelector, graphsync.Priority(rand.Int31()), graphsync.ExtensionData{ + Name: extension.ExtensionDataTransfer, + Data: extData, + }) + gsmessage := gsmsg.New() + gsmessage.AddRequest(request) + require.NoError(t, gsData.GsNet2.SendMessage(ctx, host1.ID(), gsmessage)) + + status := gsr.consumeResponses(ctx, t) + require.True(t, gsmsg.IsTerminalFailureCode(status)) + }) +} + +func TestResponseHookWhenExtensionNotFound(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 // initiator and data sender + host2 := gsData.Host2 // data recipient, makes graphsync request for data + voucher := testutil.FakeDTType{Data: "applesauce"} + link := gsData.LoadUnixFSFile(t, false) + + // setup receiving peer to just record message coming in + dtnet2 := network.NewFromLibp2pHost(host2) + r := &receiver{ + messageReceived: make(chan receivedMessage), + } + dtnet2.SetDelegate(r) + + gsr := &fakeGraphSyncReceiver{ + receivedMessages: make(chan receivedGraphSyncMessage), + } + gsData.GsNet2.SetDelegate(gsr) + + gs1 := gsData.SetupGraphsyncHost1() + dt1 := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + + t.Run("when it's not our extension, does not error and does not validate", func(t *testing.T) { + //register a hook that validates the request so we don't fail in gs because the request + //never gets processed + validateHook := func(p peer.ID, req graphsync.RequestData, ha graphsync.IncomingRequestHookActions) { + ha.ValidateRequest() + } + gs1.RegisterIncomingRequestHook(validateHook) + + _, err := dt1.OpenPushDataChannel(ctx, host2.ID(), &voucher, link.(cidlink.Link).Cid, gsData.AllSelector) + require.NoError(t, err) + + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case <-r.messageReceived: + } + + request := gsmsg.NewRequest(graphsync.RequestID(rand.Int31()), link.(cidlink.Link).Cid, gsData.AllSelector, graphsync.Priority(rand.Int31())) + gsmessage := gsmsg.New() + gsmessage.AddRequest(request) + require.NoError(t, gsData.GsNet2.SendMessage(ctx, host1.ID(), gsmessage)) + + status := gsr.consumeResponses(ctx, t) + assert.False(t, gsmsg.IsTerminalFailureCode(status)) + }) +} + +func TestRespondingToPullGraphsyncRequests(t *testing.T) { + //create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 // initiator, and recipient, makes graphync request + host2 := gsData.Host2 // data sender + + // setup receiving peer to just record message coming in + dtnet1 := network.NewFromLibp2pHost(host1) + r := &receiver{ + messageReceived: make(chan receivedMessage), + } + dtnet1.SetDelegate(r) + + gsr := &fakeGraphSyncReceiver{ + receivedMessages: make(chan receivedGraphSyncMessage), + } + gsData.GsNet1.SetDelegate(gsr) + + gs2 := gsData.SetupGraphsyncHost2() + + link := gsData.LoadUnixFSFile(t, true) + + id := datatransfer.TransferID(rand.Int31()) + + t.Run("When a pull request is initiated and validated", func(t *testing.T) { + sv := newSV() + sv.expectSuccessPull() + + dt1 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + require.NoError(t, dt1.RegisterVoucherType(&testutil.FakeDTType{}, sv)) + + _, _, request := createDTRequest(t, true, id, gsData.AllSelector) + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + sv.verifyExpectations(t) + receivedResponse, ok := messageReceived.message.(message.DataTransferResponse) + require.True(t, ok) + require.True(t, receivedResponse.Accepted()) + extStruct := &extension.TransferData{ + TransferID: uint64(receivedResponse.TransferID()), + Initiator: host1.ID(), + IsPull: true, + } + + var buf2 = bytes.Buffer{} + err := extStruct.MarshalCBOR(&buf2) + require.NoError(t, err) + extData := buf2.Bytes() + + gsRequest := gsmsg.NewRequest(graphsync.RequestID(rand.Int31()), link.(cidlink.Link).Cid, gsData.AllSelector, graphsync.Priority(rand.Int31()), graphsync.ExtensionData{ + Name: extension.ExtensionDataTransfer, + Data: extData, + }) + + // initiator requests data over graphsync network + gsmessage := gsmsg.New() + gsmessage.AddRequest(gsRequest) + require.NoError(t, gsData.GsNet1.SendMessage(ctx, host2.ID(), gsmessage)) + status := gsr.consumeResponses(ctx, t) + require.False(t, gsmsg.IsTerminalFailureCode(status)) + }) + + t.Run("When request is not initiated, graphsync response is error", func(t *testing.T) { + _ = NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + extStruct := &extension.TransferData{TransferID: rand.Uint64(), Initiator: host1.ID()} + + var buf2 bytes.Buffer + err := extStruct.MarshalCBOR(&buf2) + require.NoError(t, err) + extData := buf2.Bytes() + request := gsmsg.NewRequest(graphsync.RequestID(rand.Int31()), link.(cidlink.Link).Cid, gsData.AllSelector, graphsync.Priority(rand.Int31()), graphsync.ExtensionData{ + Name: extension.ExtensionDataTransfer, + Data: extData, + }) + gsmessage := gsmsg.New() + gsmessage.AddRequest(request) + + // non-initiator requests data over graphsync network, but should not get it + // because there was no previous request + require.NoError(t, gsData.GsNet1.SendMessage(ctx, host2.ID(), gsmessage)) + status := gsr.consumeResponses(ctx, t) + require.True(t, gsmsg.IsTerminalFailureCode(status)) + }) +} + +func TestDataTransferPushRoundTrip(t *testing.T) { + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 // initiator, data sender + host2 := gsData.Host2 // data recipient + + root := gsData.LoadUnixFSFile(t, false) + rootCid := root.(cidlink.Link).Cid + gs1 := gsData.SetupGraphsyncHost1() + gs2 := gsData.SetupGraphsyncHost2() + + dt1 := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + + finished := make(chan struct{}, 2) + errChan := make(chan struct{}, 2) + opened := make(chan struct{}, 2) + sent := make(chan uint64, 21) + received := make(chan uint64, 21) + var subscriber datatransfer.Subscriber = func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Progress { + if channelState.Received() > 0 { + received <- channelState.Received() + } else if channelState.Sent() > 0 { + sent <- channelState.Sent() + } + } + if event.Code == datatransfer.Complete { + finished <- struct{}{} + } + if event.Code == datatransfer.Error { + errChan <- struct{}{} + } + if event.Code == datatransfer.Open { + opened <- struct{}{} + } + } + dt1.SubscribeToEvents(subscriber) + dt2.SubscribeToEvents(subscriber) + voucher := testutil.FakeDTType{Data: "applesauce"} + sv := newSV() + sv.expectSuccessPull() + require.NoError(t, dt2.RegisterVoucherType(&testutil.FakeDTType{}, sv)) + + chid, err := dt1.OpenPushDataChannel(ctx, host2.ID(), &voucher, rootCid, gsData.AllSelector) + require.NoError(t, err) + opens := 0 + completes := 0 + sentIncrements := make([]uint64, 0, 21) + receivedIncrements := make([]uint64, 0, 21) + for opens < 2 || completes < 2 || len(sentIncrements) < 21 || len(receivedIncrements) < 21 { + select { + case <-ctx.Done(): + t.Fatal("Did not complete succcessful data transfer") + case <-finished: + completes++ + case <-opened: + opens++ + case sentIncrement := <-sent: + sentIncrements = append(sentIncrements, sentIncrement) + case receivedIncrement := <-received: + receivedIncrements = append(receivedIncrements, receivedIncrement) + case <-errChan: + t.Fatal("received error on data transfer") + } + } + require.Equal(t, sentIncrements, receivedIncrements) + gsData.VerifyFileTransferred(t, root, true) + assert.Equal(t, chid.Initiator, host1.ID()) +} + +func TestDataTransferPullRoundTrip(t *testing.T) { + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 + host2 := gsData.Host2 + + root := gsData.LoadUnixFSFile(t, false) + rootCid := root.(cidlink.Link).Cid + gs1 := gsData.SetupGraphsyncHost1() + gs2 := gsData.SetupGraphsyncHost2() + + dt1 := NewGraphSyncDataTransfer(host1, gs1, gsData.StoredCounter1) + dt2 := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + + finished := make(chan struct{}, 2) + errChan := make(chan struct{}, 2) + opened := make(chan struct{}, 2) + sent := make(chan uint64, 21) + received := make(chan uint64, 21) + var subscriber datatransfer.Subscriber = func(event datatransfer.Event, channelState datatransfer.ChannelState) { + if event.Code == datatransfer.Progress { + if channelState.Received() > 0 { + received <- channelState.Received() + } else if channelState.Sent() > 0 { + sent <- channelState.Sent() + } + } + if event.Code == datatransfer.Complete { + finished <- struct{}{} + } + if event.Code == datatransfer.Error { + errChan <- struct{}{} + } + if event.Code == datatransfer.Open { + opened <- struct{}{} + } + } + dt1.SubscribeToEvents(subscriber) + dt2.SubscribeToEvents(subscriber) + voucher := testutil.FakeDTType{Data: "applesauce"} + sv := newSV() + sv.expectSuccessPull() + require.NoError(t, dt1.RegisterVoucherType(&testutil.FakeDTType{}, sv)) + + _, err := dt2.OpenPullDataChannel(ctx, host1.ID(), &voucher, rootCid, gsData.AllSelector) + require.NoError(t, err) + opens := 0 + completes := 0 + sentIncrements := make([]uint64, 0, 21) + receivedIncrements := make([]uint64, 0, 21) + for opens < 2 || completes < 2 || len(sentIncrements) < 21 || len(receivedIncrements) < 21 { + select { + case <-ctx.Done(): + t.Fatal("Did not complete succcessful data transfer") + case <-finished: + completes++ + case <-opened: + opens++ + case sentIncrement := <-sent: + sentIncrements = append(sentIncrements, sentIncrement) + case receivedIncrement := <-received: + receivedIncrements = append(receivedIncrements, receivedIncrement) + case <-errChan: + t.Fatal("received error on data transfer") + } + } + require.Equal(t, sentIncrements, receivedIncrements) + gsData.VerifyFileTransferred(t, root, true) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver.go new file mode 100644 index 0000000000..66b5947330 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver.go @@ -0,0 +1,153 @@ +package graphsyncimpl + +import ( + "context" + "time" + + "github.com/ipfs/go-cid" + "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + "github.com/libp2p/go-libp2p-core/peer" + xerrors "golang.org/x/xerrors" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/message" +) + +type graphsyncReceiver struct { + impl *graphsyncImpl +} + +// ReceiveRequest takes an incoming data transfer request, validates the voucher and +// processes the message. +func (receiver *graphsyncReceiver) ReceiveRequest( + ctx context.Context, + initiator peer.ID, + incoming message.DataTransferRequest) { + err := receiver.receiveRequest(initiator, incoming) + if err != nil { + log.Error(err) + } + if err == nil && !incoming.IsPull() { + stor, _ := incoming.Selector() + receiver.impl.sendGsRequest(ctx, initiator, incoming.TransferID(), incoming.IsPull(), initiator, cidlink.Link{Cid: incoming.BaseCid()}, stor) + } + receiver.impl.sendResponse(ctx, err == nil, initiator, incoming.TransferID()) +} + +func (receiver *graphsyncReceiver) receiveRequest( + initiator peer.ID, + incoming message.DataTransferRequest) error { + + voucher, err := receiver.validateVoucher(initiator, incoming) + if err != nil { + return err + } + stor, _ := incoming.Selector() + + var dataSender, dataReceiver peer.ID + if incoming.IsPull() { + dataSender = receiver.impl.peerID + dataReceiver = initiator + } else { + dataSender = initiator + dataReceiver = receiver.impl.peerID + } + + chid, err := receiver.impl.channels.CreateNew(incoming.TransferID(), incoming.BaseCid(), stor, voucher, initiator, dataSender, dataReceiver) + if err != nil { + return err + } + evt := datatransfer.Event{ + Code: datatransfer.Open, + Message: "Incoming request accepted", + Timestamp: time.Now(), + } + chst, err := receiver.impl.channels.GetByID(chid) + if err != nil { + return err + } + err = receiver.impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } + return nil +} + +// validateVoucher converts a voucher in an incoming message to its appropriate +// voucher struct, then runs the validator and returns the results. +// returns error if: +// * reading voucher fails +// * deserialization of selector fails +// * validation fails +func (receiver *graphsyncReceiver) validateVoucher(sender peer.ID, incoming message.DataTransferRequest) (datatransfer.Voucher, error) { + + vtypStr := datatransfer.TypeIdentifier(incoming.VoucherType()) + decoder, has := receiver.impl.validatedTypes.Decoder(vtypStr) + if !has { + return nil, xerrors.Errorf("unknown voucher type: %s", vtypStr) + } + encodable, err := incoming.Voucher(decoder) + if err != nil { + return nil, err + } + vouch := encodable.(datatransfer.Registerable) + + var validatorFunc func(peer.ID, datatransfer.Voucher, cid.Cid, ipld.Node) error + processor, _ := receiver.impl.validatedTypes.Processor(vtypStr) + validator := processor.(datatransfer.RequestValidator) + if incoming.IsPull() { + validatorFunc = validator.ValidatePull + } else { + validatorFunc = validator.ValidatePush + } + + stor, err := incoming.Selector() + if err != nil { + return vouch, err + } + + if err = validatorFunc(sender, vouch, incoming.BaseCid(), stor); err != nil { + return nil, err + } + + return vouch, nil +} + +// ReceiveResponse handles responses to our Push or Pull data transfer request. +// It schedules a graphsync transfer only if our Pull Request is accepted. +func (receiver *graphsyncReceiver) ReceiveResponse( + ctx context.Context, + sender peer.ID, + incoming message.DataTransferResponse) { + evt := datatransfer.Event{ + Code: datatransfer.Error, + Message: "", + Timestamp: time.Now(), + } + chid := datatransfer.ChannelID{Initiator: receiver.impl.peerID, ID: incoming.TransferID()} + chst, err := receiver.impl.channels.GetByID(chid) + if err != nil { + log.Warnf("received response from unknown peer %s, transfer ID %d", sender, incoming.TransferID) + return + } + + if incoming.Accepted() { + evt.Code = datatransfer.Progress + // if we are handling a response to a pull request then they are sending data and the + // initiator is us + if chst.Sender() == sender { + baseCid := chst.BaseCID() + root := cidlink.Link{Cid: baseCid} + receiver.impl.sendGsRequest(ctx, receiver.impl.peerID, incoming.TransferID(), true, sender, root, chst.Selector()) + } + } + err = receiver.impl.pubSub.Publish(internalEvent{evt, chst}) + if err != nil { + log.Warnf("err publishing DT event: %s", err.Error()) + } +} + +func (receiver *graphsyncReceiver) ReceiveError(err error) { + log.Errorf("received error message on data transfer: %s", err.Error()) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver_test.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver_test.go new file mode 100644 index 0000000000..58d726354b --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/graphsync_receiver_test.go @@ -0,0 +1,182 @@ +package graphsyncimpl_test + +import ( + "context" + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + datatransfer "github.com/filecoin-project/go-data-transfer" + . "github.com/filecoin-project/go-data-transfer/impl/graphsync" + "github.com/filecoin-project/go-data-transfer/message" + "github.com/filecoin-project/go-data-transfer/network" + "github.com/filecoin-project/go-data-transfer/testutil" +) + +func TestSendResponseToIncomingRequest(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + gsData := testutil.NewGraphsyncTestingData(ctx, t) + host1 := gsData.Host1 + host2 := gsData.Host2 + + // setup receiving peer to just record message coming in + dtnet1 := network.NewFromLibp2pHost(host1) + r := &receiver{ + messageReceived: make(chan receivedMessage), + } + dtnet1.SetDelegate(r) + + gs2 := testutil.NewFakeGraphSync() + + voucher := testutil.NewFakeDTType() + baseCid := testutil.GenerateCids(1)[0] + + t.Run("Response to push with successful validation", func(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + sv := newSV() + sv.expectSuccessPush() + + dt := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + require.NoError(t, dt.RegisterVoucherType(&testutil.FakeDTType{}, sv)) + + isPull := false + _, err := message.NewRequest(id, isPull, voucher.Type(), voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + request, err := message.NewRequest(id, isPull, voucher.Type(), voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + + sv.verifyExpectations(t) + + sender := messageReceived.sender + require.Equal(t, sender, host2.ID()) + + received := messageReceived.message + require.False(t, received.IsRequest()) + receivedResponse, ok := received.(message.DataTransferResponse) + require.True(t, ok) + + assert.Equal(t, receivedResponse.TransferID(), id) + require.True(t, receivedResponse.Accepted()) + + }) + + t.Run("Response to push with error validation", func(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + sv := newSV() + sv.expectErrorPush() + dt := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + err := dt.RegisterVoucherType(&testutil.FakeDTType{}, sv) + require.NoError(t, err) + + isPull := false + + request, err := message.NewRequest(id, isPull, voucher.Type(), voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + + sv.verifyExpectations(t) + + sender := messageReceived.sender + require.Equal(t, sender, host2.ID()) + + received := messageReceived.message + require.False(t, received.IsRequest()) + receivedResponse, ok := received.(message.DataTransferResponse) + require.True(t, ok) + + require.Equal(t, receivedResponse.TransferID(), id) + require.False(t, receivedResponse.Accepted()) + }) + + t.Run("Response to pull with successful validation", func(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + sv := newSV() + sv.expectSuccessPull() + + dt := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + err := dt.RegisterVoucherType(&testutil.FakeDTType{}, sv) + require.NoError(t, err) + + isPull := true + + request, err := message.NewRequest(id, isPull, voucher.Type(), voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + + sv.verifyExpectations(t) + + sender := messageReceived.sender + require.Equal(t, sender, host2.ID()) + + received := messageReceived.message + require.False(t, received.IsRequest()) + receivedResponse, ok := received.(message.DataTransferResponse) + require.True(t, ok) + + require.Equal(t, receivedResponse.TransferID(), id) + require.True(t, receivedResponse.Accepted()) + }) + + t.Run("Response to push with error validation", func(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + sv := newSV() + sv.expectErrorPull() + + dt := NewGraphSyncDataTransfer(host2, gs2, gsData.StoredCounter2) + err := dt.RegisterVoucherType(&testutil.FakeDTType{}, sv) + require.NoError(t, err) + + isPull := true + + request, err := message.NewRequest(id, isPull, voucher.Type(), voucher, baseCid, gsData.AllSelector) + require.NoError(t, err) + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + + var messageReceived receivedMessage + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case messageReceived = <-r.messageReceived: + } + + sv.verifyExpectations(t) + + sender := messageReceived.sender + require.Equal(t, sender, host2.ID()) + + received := messageReceived.message + require.False(t, received.IsRequest()) + receivedResponse, ok := received.(message.DataTransferResponse) + require.True(t, ok) + + require.Equal(t, receivedResponse.TransferID(), id) + require.False(t, receivedResponse.Accepted()) + }) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks.go new file mode 100644 index 0000000000..6febc4ca96 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks.go @@ -0,0 +1,174 @@ +package hooks + +import ( + "sync" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/impl/graphsync/extension" + "github.com/ipfs/go-graphsync" + ipld "github.com/ipld/go-ipld-prime" + peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/prometheus/common/log" +) + +// Events are semantic data transfer events that happen as a result of graphsync hooks +type Events interface { + // OnRequestSent is called when we ask the other peer to send us data on the + // given channel ID + // return values are: + // - nil = this request is recognized + // - error = ignore incoming data for this request + OnRequestSent(chid datatransfer.ChannelID) error + // OnDataReceive is called when we receive data for the given channel ID + // return values are: + // - nil = continue receiving data + // - error = cancel this request + OnDataReceived(chid datatransfer.ChannelID, link ipld.Link, size uint64) error + // OnDataSent is called when we send data for the given channel ID + // return values are: + // - nil = continue sending data + // - error = cancel this request + OnDataSent(chid datatransfer.ChannelID, link ipld.Link, size uint64) error + // OnRequestReceived is called when we receive a new request to send data + // for the given channel ID + // return values are: + // - nil = proceed with sending data + // - error = cancel this request + OnRequestReceived(chid datatransfer.ChannelID) error + // OnResponseCompleted is called when we finish sending data for the given channel ID + // Error returns are logged but otherwise have not effect + OnResponseCompleted(chid datatransfer.ChannelID, success bool) error +} + +type graphsyncKey struct { + requestID graphsync.RequestID + p peer.ID +} + +// Manager manages graphsync hooks for data transfer, translating from +// graphsync hooks to semantic data transfer events +type Manager struct { + events Events + peerID peer.ID + graphsyncRequestMapLk sync.RWMutex + graphsyncRequestMap map[graphsyncKey]datatransfer.ChannelID +} + +// NewManager makes a new hooks manager with the given hook events interface +func NewManager(peerID peer.ID, hookEvents Events) *Manager { + return &Manager{ + events: hookEvents, + peerID: peerID, + graphsyncRequestMap: make(map[graphsyncKey]datatransfer.ChannelID), + } +} + +// RegisterHooks registers graphsync hooks for the hooks manager +func (hm *Manager) RegisterHooks(gs graphsync.GraphExchange) { + gs.RegisterIncomingRequestHook(hm.gsReqRecdHook) + gs.RegisterCompletedResponseListener(hm.gsCompletedResponseListener) + gs.RegisterIncomingBlockHook(hm.gsIncomingBlockHook) + gs.RegisterOutgoingBlockHook(hm.gsOutgoingBlockHook) + gs.RegisterOutgoingRequestHook(hm.gsOutgoingRequestHook) +} + +func (hm *Manager) gsOutgoingRequestHook(p peer.ID, request graphsync.RequestData, hookActions graphsync.OutgoingRequestHookActions) { + transferData, _ := extension.GetTransferData(request) + + // extension not found; probably not our request. + if transferData == nil { + return + } + + chid := transferData.GetChannelID() + err := hm.events.OnRequestSent(chid) + if err != nil { + return + } + // record the outgoing graphsync request to map it to channel ID going forward + hm.graphsyncRequestMapLk.Lock() + hm.graphsyncRequestMap[graphsyncKey{request.ID(), hm.peerID}] = chid + hm.graphsyncRequestMapLk.Unlock() +} + +func (hm *Manager) gsIncomingBlockHook(p peer.ID, response graphsync.ResponseData, block graphsync.BlockData, hookActions graphsync.IncomingBlockHookActions) { + hm.graphsyncRequestMapLk.RLock() + chid, ok := hm.graphsyncRequestMap[graphsyncKey{response.RequestID(), hm.peerID}] + hm.graphsyncRequestMapLk.RUnlock() + + if !ok { + return + } + + err := hm.events.OnDataReceived(chid, block.Link(), block.BlockSize()) + if err != nil { + hookActions.TerminateWithError(err) + } +} + +func (hm *Manager) gsOutgoingBlockHook(p peer.ID, request graphsync.RequestData, block graphsync.BlockData, hookActions graphsync.OutgoingBlockHookActions) { + hm.graphsyncRequestMapLk.RLock() + chid, ok := hm.graphsyncRequestMap[graphsyncKey{request.ID(), p}] + hm.graphsyncRequestMapLk.RUnlock() + + if !ok { + return + } + + err := hm.events.OnDataSent(chid, block.Link(), block.BlockSize()) + if err != nil { + hookActions.TerminateWithError(err) + } +} + +// gsReqRecdHook is a graphsync.OnRequestReceivedHook hook +// if an incoming request does not match a previous push request, it returns an error. +func (hm *Manager) gsReqRecdHook(p peer.ID, request graphsync.RequestData, hookActions graphsync.IncomingRequestHookActions) { + + // if this is a push request the sender is us. + transferData, err := extension.GetTransferData(request) + if err != nil { + hookActions.TerminateWithError(err) + return + } + + // extension not found; probably not our request. + if transferData == nil { + return + } + + chid := transferData.GetChannelID() + + err = hm.events.OnRequestReceived(chid) + if err != nil { + hookActions.TerminateWithError(err) + return + } + + hm.graphsyncRequestMapLk.Lock() + hm.graphsyncRequestMap[graphsyncKey{request.ID(), p}] = chid + hm.graphsyncRequestMapLk.Unlock() + + raw, _ := request.Extension(extension.ExtensionDataTransfer) + respData := graphsync.ExtensionData{Name: extension.ExtensionDataTransfer, Data: raw} + hookActions.ValidateRequest() + hookActions.SendExtensionData(respData) +} + +// gsCompletedResponseListener is a graphsync.OnCompletedResponseListener. We use it learn when the data transfer is complete +// for the side that is responding to a graphsync request +func (hm *Manager) gsCompletedResponseListener(p peer.ID, request graphsync.RequestData, status graphsync.ResponseStatusCode) { + hm.graphsyncRequestMapLk.RLock() + chid, ok := hm.graphsyncRequestMap[graphsyncKey{request.ID(), p}] + hm.graphsyncRequestMapLk.RUnlock() + + if !ok { + return + } + + success := status == graphsync.RequestCompletedFull + err := hm.events.OnResponseCompleted(chid, success) + if err != nil { + log.Error(err) + } +} \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks_test.go b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks_test.go new file mode 100644 index 0000000000..8dfc1f4d14 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks/hooks_test.go @@ -0,0 +1,377 @@ +package hooks_test + +import ( + "bytes" + "errors" + "math/rand" + "testing" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/impl/graphsync/extension" + "github.com/filecoin-project/go-data-transfer/impl/graphsync/hooks" + "github.com/filecoin-project/go-data-transfer/testutil" + "github.com/ipfs/go-graphsync" + ipld "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/traversal" + peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/stretchr/testify/require" +) + +func TestManager(t *testing.T) { + testCases := map[string]struct { + makeRequest func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.RequestData + makeResponse func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.ResponseData + events fakeEvents + action func(gsData *graphsyncTestData) + check func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) + }{ + "recognized outgoing request will record incoming blocks": { + action: func(gsData *graphsyncTestData) { + gsData.outgoingRequestHook() + gsData.incomingBlockHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestSentCalled) + require.True(t, events.OnDataReceivedCalled) + require.NoError(t, gsData.incomingBlockHookActions.TerminationError) + }, + }, + "non-data-transfer outgoing request will not record incoming blocks": { + makeRequest: func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.RequestData { + return testutil.NewFakeRequest(id, map[graphsync.ExtensionName][]byte{}) + }, + action: func(gsData *graphsyncTestData) { + gsData.outgoingRequestHook() + gsData.incomingBlockHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.False(t, events.OnRequestSentCalled) + require.False(t, events.OnDataReceivedCalled) + require.NoError(t, gsData.incomingBlockHookActions.TerminationError) + }, + }, + "unrecognized outgoing request will not record incoming blocks": { + events: fakeEvents{ + OnRequestSentError: errors.New("Not recognized"), + }, + action: func(gsData *graphsyncTestData) { + gsData.outgoingRequestHook() + gsData.incomingBlockHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestSentCalled) + require.False(t, events.OnDataReceivedCalled) + require.NoError(t, gsData.incomingBlockHookActions.TerminationError) + }, + }, + "incoming block error will halt request": { + events: fakeEvents{ + OnDataReceivedError: errors.New("something went wrong"), + }, + action: func(gsData *graphsyncTestData) { + gsData.outgoingRequestHook() + gsData.incomingBlockHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestSentCalled) + require.True(t, events.OnDataReceivedCalled) + require.Error(t, gsData.incomingBlockHookActions.TerminationError) + }, + }, + "recognized incoming request will validate request": { + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestReceivedCalled) + require.True(t, gsData.incomingRequestHookActions.Validated) + require.Equal(t, extension.ExtensionDataTransfer, gsData.incomingRequestHookActions.SentExtension.Name) + require.NoError(t, gsData.incomingRequestHookActions.TerminationError) + }, + }, + "malformed data transfer extension on incoming request will terminate": { + makeRequest: func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.RequestData { + return testutil.NewFakeRequest(id, map[graphsync.ExtensionName][]byte{ + extension.ExtensionDataTransfer: testutil.RandomBytes(100), + }) + }, + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.False(t, events.OnRequestReceivedCalled) + require.False(t, gsData.incomingRequestHookActions.Validated) + require.Error(t, gsData.incomingRequestHookActions.TerminationError) + }, + }, + "unrecognized incoming data transfer request will terminate": { + events: fakeEvents{ + OnRequestReceivedError: errors.New("something went wrong"), + }, + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestReceivedCalled) + require.False(t, gsData.incomingRequestHookActions.Validated) + require.Error(t, gsData.incomingRequestHookActions.TerminationError) + }, + }, + "recognized incoming request will record outgoing blocks": { + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + gsData.outgoingBlockHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestReceivedCalled) + require.True(t, events.OnDataSentCalled) + require.NoError(t, gsData.outgoingBlockHookActions.TerminationError) + }, + }, + "non-data-transfer request will not record outgoing blocks": { + makeRequest: func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.RequestData { + return testutil.NewFakeRequest(id, map[graphsync.ExtensionName][]byte{}) + }, + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + gsData.outgoingBlockHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.False(t, events.OnRequestReceivedCalled) + require.False(t, events.OnDataSentCalled) + }, + }, + "outgoing data send error will terminate request": { + events: fakeEvents{ + OnDataSentError: errors.New("something went wrong"), + }, + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + gsData.outgoingBlockHook() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestReceivedCalled) + require.True(t, events.OnDataSentCalled) + require.Error(t, gsData.outgoingBlockHookActions.TerminationError) + }, + }, + "recognized incoming request will record successful request completion": { + makeResponse: func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.ResponseData { + return testutil.NewFakeResponse(id, map[graphsync.ExtensionName][]byte{}, graphsync.RequestCompletedFull) + }, + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + gsData.responseCompletedListener() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestReceivedCalled) + require.True(t, events.OnResponseCompletedCalled) + require.True(t, events.ResponseSuccess) + }, + }, + "recognized incoming request will record unsuccessful request completion": { + makeResponse: func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.ResponseData { + return testutil.NewFakeResponse(id, map[graphsync.ExtensionName][]byte{}, graphsync.RequestCompletedPartial) + }, + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + gsData.responseCompletedListener() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.True(t, events.OnRequestReceivedCalled) + require.True(t, events.OnResponseCompletedCalled) + require.False(t, events.ResponseSuccess) + }, + }, + "non-data-transfer request will not record request completed": { + makeRequest: func(id graphsync.RequestID, chid datatransfer.ChannelID) graphsync.RequestData { + return testutil.NewFakeRequest(id, map[graphsync.ExtensionName][]byte{}) + }, + action: func(gsData *graphsyncTestData) { + gsData.incomingRequestHook() + gsData.responseCompletedListener() + }, + check: func(t *testing.T, events *fakeEvents, gsData *graphsyncTestData) { + require.False(t, events.OnRequestReceivedCalled) + require.False(t, events.OnResponseCompletedCalled) + }, + }, + } + for testCase, data := range testCases { + t.Run(testCase, func(t *testing.T) { + peers := testutil.GeneratePeers(2) + transferID := datatransfer.TransferID(rand.Uint64()) + channelID := datatransfer.ChannelID{Initiator: peers[0], ID: transferID} + requestID := graphsync.RequestID(rand.Int31()) + var request graphsync.RequestData + if data.makeRequest != nil { + request = data.makeRequest(requestID, channelID) + } else { + ext := &extension.TransferData{ + TransferID: uint64(transferID), + Initiator: peers[0], + IsPull: false, + } + buf := new(bytes.Buffer) + err := ext.MarshalCBOR(buf) + require.NoError(t, err) + request = testutil.NewFakeRequest(requestID, map[graphsync.ExtensionName][]byte{ + extension.ExtensionDataTransfer: buf.Bytes(), + }) + } + var response graphsync.ResponseData + if data.makeResponse != nil { + response = data.makeResponse(requestID, channelID) + } else { + ext := &extension.TransferData{ + TransferID: uint64(transferID), + Initiator: peers[0], + IsPull: false, + } + buf := new(bytes.Buffer) + err := ext.MarshalCBOR(buf) + require.NoError(t, err) + response = testutil.NewFakeResponse(requestID, map[graphsync.ExtensionName][]byte{ + extension.ExtensionDataTransfer: buf.Bytes(), + }, graphsync.PartialResponse) + } + block := testutil.NewFakeBlockData() + fgs := testutil.NewFakeGraphSync() + gsData := &graphsyncTestData{ + fgs: fgs, + p: peers[1], + request: request, + response: response, + block: block, + outgoingRequestHookActions: &fakeOutgoingRequestHookActions{}, + outgoingBlockHookActions: &fakeOutgoingBlockHookActions{}, + incomingBlockHookActions: &fakeIncomingBlockHookActions{}, + incomingRequestHookActions: &fakeIncomingRequestHookActions{}, + } + manager := hooks.NewManager(peers[0], &data.events) + manager.RegisterHooks(fgs) + data.action(gsData) + data.check(t, &data.events, gsData) + }) + } +} + +type fakeEvents struct { + OnRequestSentCalled bool + OnRequestSentError error + OnDataReceivedCalled bool + OnDataReceivedError error + OnDataSentCalled bool + OnDataSentError error + OnRequestReceivedCalled bool + OnRequestReceivedError error + OnResponseCompletedCalled bool + OnResponseCompletedErr error + ResponseSuccess bool +} + +func (fe *fakeEvents) OnRequestSent(chid datatransfer.ChannelID) error { + fe.OnRequestSentCalled = true + return fe.OnRequestSentError +} + +func (fe *fakeEvents) OnDataReceived(chid datatransfer.ChannelID, link ipld.Link, size uint64) error { + fe.OnDataReceivedCalled = true + return fe.OnDataReceivedError +} + +func (fe *fakeEvents) OnDataSent(chid datatransfer.ChannelID, link ipld.Link, size uint64) error { + fe.OnDataSentCalled = true + return fe.OnDataSentError +} + +func (fe *fakeEvents) OnRequestReceived(chid datatransfer.ChannelID) error { + fe.OnRequestReceivedCalled = true + return fe.OnRequestReceivedError +} + +func (fe *fakeEvents) OnResponseCompleted(chid datatransfer.ChannelID, success bool) error { + fe.OnResponseCompletedCalled = true + fe.ResponseSuccess = success + return fe.OnResponseCompletedErr +} + +type fakeOutgoingRequestHookActions struct{} + +func (fa *fakeOutgoingRequestHookActions) UsePersistenceOption(name string) {} +func (fa *fakeOutgoingRequestHookActions) UseLinkTargetNodeStyleChooser(_ traversal.LinkTargetNodeStyleChooser) { +} + +type fakeIncomingBlockHookActions struct { + TerminationError error +} + +func (fa *fakeIncomingBlockHookActions) TerminateWithError(err error) { + fa.TerminationError = err +} + +func (fa *fakeIncomingBlockHookActions) UpdateRequestWithExtensions(_ ...graphsync.ExtensionData) {} + +type fakeOutgoingBlockHookActions struct { + TerminationError error +} + +func (fa *fakeOutgoingBlockHookActions) SendExtensionData(_ graphsync.ExtensionData) {} + +func (fa *fakeOutgoingBlockHookActions) TerminateWithError(err error) { + fa.TerminationError = err +} + +func (fa *fakeOutgoingBlockHookActions) PauseResponse() {} + +type fakeIncomingRequestHookActions struct { + TerminationError error + Validated bool + SentExtension graphsync.ExtensionData +} + +func (fa *fakeIncomingRequestHookActions) SendExtensionData(ext graphsync.ExtensionData) { + fa.SentExtension = ext +} + +func (fa *fakeIncomingRequestHookActions) UsePersistenceOption(name string) {} + +func (fa *fakeIncomingRequestHookActions) UseLinkTargetNodeStyleChooser(_ traversal.LinkTargetNodeStyleChooser) { +} + +func (fa *fakeIncomingRequestHookActions) TerminateWithError(err error) { + fa.TerminationError = err +} + +func (fa *fakeIncomingRequestHookActions) ValidateRequest() { + fa.Validated = true +} + +type graphsyncTestData struct { + fgs *testutil.FakeGraphSync + p peer.ID + block graphsync.BlockData + request graphsync.RequestData + response graphsync.ResponseData + outgoingRequestHookActions *fakeOutgoingRequestHookActions + incomingBlockHookActions *fakeIncomingBlockHookActions + outgoingBlockHookActions *fakeOutgoingBlockHookActions + incomingRequestHookActions *fakeIncomingRequestHookActions +} + +func (gs *graphsyncTestData) outgoingRequestHook() { + gs.fgs.OutgoingRequestHook(gs.p, gs.request, gs.outgoingRequestHookActions) +} +func (gs *graphsyncTestData) incomingBlockHook() { + gs.fgs.IncomingBlockHook(gs.p, gs.response, gs.block, gs.incomingBlockHookActions) +} +func (gs *graphsyncTestData) outgoingBlockHook() { + gs.fgs.OutgoingBlockHook(gs.p, gs.request, gs.block, gs.outgoingBlockHookActions) +} +func (gs *graphsyncTestData) incomingRequestHook() { + gs.fgs.IncomingRequestHook(gs.p, gs.request, gs.incomingRequestHookActions) +} + +func (gs *graphsyncTestData) responseCompletedListener() { + gs.fgs.ResponseCompletedListener(gs.p, gs.request, gs.response.Status()) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/message.go b/vendor/github.com/filecoin-project/go-data-transfer/message/message.go new file mode 100644 index 0000000000..d9b07dded4 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/message.go @@ -0,0 +1,90 @@ +package message + +import ( + "io" + + "github.com/ipfs/go-cid" + "github.com/ipld/go-ipld-prime" + cborgen "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/encoding" +) + +// Reference file: https://github.com/ipfs/go-graphsync/blob/master/message/message.go +// though here we have a simpler message type that serializes/deserializes to two +// different types that share an interface, and we serialize to CBOR and not Protobuf. + +// DataTransferMessage is a message for the data transfer protocol +// (either request or response) that can serialize to a protobuf +type DataTransferMessage interface { + IsRequest() bool + TransferID() datatransfer.TransferID + cborgen.CBORMarshaler + cborgen.CBORUnmarshaler + ToNet(w io.Writer) error +} + +// DataTransferRequest is a response message for the data transfer protocol +type DataTransferRequest interface { + DataTransferMessage + IsPull() bool + VoucherType() datatransfer.TypeIdentifier + Voucher(decoder encoding.Decoder) (encoding.Encodable, error) + BaseCid() cid.Cid + Selector() (ipld.Node, error) + IsCancel() bool +} + +// DataTransferResponse is a response message for the data transfer protocol +type DataTransferResponse interface { + DataTransferMessage + Accepted() bool +} + +// NewRequest generates a new request for the data transfer protocol +func NewRequest(id datatransfer.TransferID, isPull bool, vtype datatransfer.TypeIdentifier, voucher encoding.Encodable, baseCid cid.Cid, selector ipld.Node) (DataTransferRequest, error) { + vbytes, err := encoding.Encode(voucher) + if err != nil { + return nil, xerrors.Errorf("Creating request: %w", err) + } + if baseCid == cid.Undef { + return nil, xerrors.Errorf("base CID must be defined") + } + selBytes, err := encoding.Encode(selector) + if err != nil { + return nil, xerrors.Errorf("Error encoding selector") + } + return &transferRequest{ + Pull: isPull, + Vouch: &cborgen.Deferred{Raw: vbytes}, + Stor: &cborgen.Deferred{Raw: selBytes}, + BCid: &baseCid, + VTyp: vtype, + XferID: uint64(id), + }, nil +} + +// CancelRequest request generates a request to cancel an in progress request +func CancelRequest(id datatransfer.TransferID) DataTransferRequest { + return &transferRequest{ + Canc: true, + XferID: uint64(id), + } +} + +// NewResponse builds a new Data Transfer response +func NewResponse(id datatransfer.TransferID, accepted bool) DataTransferResponse { + return &transferResponse{Acpt: accepted, XferID: uint64(id)} +} + +// FromNet can read a network stream to deserialize a GraphSyncMessage +func FromNet(r io.Reader) (DataTransferMessage, error) { + tresp := transferMessage{} + err := tresp.UnmarshalCBOR(r) + if tresp.IsRequest() { + return tresp.Request, nil + } + return tresp.Response, err +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/message_test.go b/vendor/github.com/filecoin-project/go-data-transfer/message/message_test.go new file mode 100644 index 0000000000..2f023f3ad9 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/message_test.go @@ -0,0 +1,196 @@ +package message_test + +import ( + "bytes" + "math/rand" + "testing" + + basicnode "github.com/ipld/go-ipld-prime/node/basic" + "github.com/ipld/go-ipld-prime/traversal/selector/builder" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + datatransfer "github.com/filecoin-project/go-data-transfer" + . "github.com/filecoin-project/go-data-transfer/message" + "github.com/filecoin-project/go-data-transfer/testutil" +) + +func TestNewRequest(t *testing.T) { + baseCid := testutil.GenerateCids(1)[0] + selector := builder.NewSelectorSpecBuilder(basicnode.Style.Any).Matcher().Node() + isPull := true + id := datatransfer.TransferID(rand.Int31()) + voucher := testutil.NewFakeDTType() + request, err := NewRequest(id, isPull, voucher.Type(), voucher, baseCid, selector) + require.NoError(t, err) + assert.Equal(t, id, request.TransferID()) + assert.False(t, request.IsCancel()) + assert.True(t, request.IsPull()) + assert.True(t, request.IsRequest()) + assert.Equal(t, baseCid.String(), request.BaseCid().String()) + testutil.AssertFakeDTVoucher(t, request, voucher) + receivedSelector, err := request.Selector() + require.NoError(t, err) + require.Equal(t, selector, receivedSelector) + // Sanity check to make sure we can cast to DataTransferMessage + msg, ok := request.(DataTransferMessage) + require.True(t, ok) + + assert.True(t, msg.IsRequest()) + assert.Equal(t, request.TransferID(), msg.TransferID()) +} +func TestTransferRequest_MarshalCBOR(t *testing.T) { + // sanity check MarshalCBOR does its thing w/o error + req, err := NewTestTransferRequest() + require.NoError(t, err) + wbuf := new(bytes.Buffer) + require.NoError(t, req.MarshalCBOR(wbuf)) + assert.Greater(t, wbuf.Len(), 0) +} +func TestTransferRequest_UnmarshalCBOR(t *testing.T) { + req, err := NewTestTransferRequest() + require.NoError(t, err) + wbuf := new(bytes.Buffer) + // use ToNet / FromNet + require.NoError(t, req.ToNet(wbuf)) + + desMsg, err := FromNet(wbuf) + require.NoError(t, err) + + // Verify round-trip + assert.Equal(t, req.TransferID(), desMsg.TransferID()) + assert.Equal(t, req.IsRequest(), desMsg.IsRequest()) + + desReq := desMsg.(DataTransferRequest) + assert.Equal(t, req.IsPull(), desReq.IsPull()) + assert.Equal(t, req.IsCancel(), desReq.IsCancel()) + assert.Equal(t, req.BaseCid(), desReq.BaseCid()) + testutil.AssertEqualFakeDTVoucher(t, req, desReq) + testutil.AssertEqualSelector(t, req, desReq) +} + +func TestResponses(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + response := NewResponse(id, false) // not accepted + assert.Equal(t, response.TransferID(), id) + assert.False(t, response.Accepted()) + assert.False(t, response.IsRequest()) + + // Sanity check to make sure we can cast to DataTransferMessage + msg, ok := response.(DataTransferMessage) + require.True(t, ok) + + assert.False(t, msg.IsRequest()) + assert.Equal(t, response.TransferID(), msg.TransferID()) +} + +func TestTransferResponse_MarshalCBOR(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + response := NewResponse(id, true) // accepted + + // sanity check that we can marshal data + wbuf := new(bytes.Buffer) + require.NoError(t, response.ToNet(wbuf)) + assert.Greater(t, wbuf.Len(), 0) +} + +func TestTransferResponse_UnmarshalCBOR(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + response := NewResponse(id, true) // accepted + + wbuf := new(bytes.Buffer) + require.NoError(t, response.ToNet(wbuf)) + + // verify round trip + desMsg, err := FromNet(wbuf) + require.NoError(t, err) + assert.False(t, desMsg.IsRequest()) + assert.Equal(t, id, desMsg.TransferID()) + + desResp, ok := desMsg.(DataTransferResponse) + require.True(t, ok) + assert.True(t, desResp.Accepted()) +} + +func TestRequestCancel(t *testing.T) { + id := datatransfer.TransferID(rand.Int31()) + req := CancelRequest(id) + require.Equal(t, req.TransferID(), id) + require.True(t, req.IsRequest()) + require.True(t, req.IsCancel()) + + wbuf := new(bytes.Buffer) + require.NoError(t, req.ToNet(wbuf)) + + deserialized, err := FromNet(wbuf) + require.NoError(t, err) + + deserializedRequest, ok := deserialized.(DataTransferRequest) + require.True(t, ok) + require.Equal(t, deserializedRequest.TransferID(), req.TransferID()) + require.Equal(t, deserializedRequest.IsCancel(), req.IsCancel()) + require.Equal(t, deserializedRequest.IsRequest(), req.IsRequest()) +} + +func TestToNetFromNetEquivalency(t *testing.T) { + baseCid := testutil.GenerateCids(1)[0] + selector := builder.NewSelectorSpecBuilder(basicnode.Style.Any).Matcher().Node() + isPull := false + id := datatransfer.TransferID(rand.Int31()) + accepted := false + voucher := testutil.NewFakeDTType() + request, err := NewRequest(id, isPull, voucher.Type(), voucher, baseCid, selector) + require.NoError(t, err) + buf := new(bytes.Buffer) + err = request.ToNet(buf) + require.NoError(t, err) + require.Greater(t, buf.Len(), 0) + deserialized, err := FromNet(buf) + require.NoError(t, err) + + deserializedRequest, ok := deserialized.(DataTransferRequest) + require.True(t, ok) + + require.Equal(t, deserializedRequest.TransferID(), request.TransferID()) + require.Equal(t, deserializedRequest.IsCancel(), request.IsCancel()) + require.Equal(t, deserializedRequest.IsPull(), request.IsPull()) + require.Equal(t, deserializedRequest.IsRequest(), request.IsRequest()) + require.Equal(t, deserializedRequest.BaseCid(), request.BaseCid()) + testutil.AssertEqualFakeDTVoucher(t, request, deserializedRequest) + testutil.AssertEqualSelector(t, request, deserializedRequest) + + response := NewResponse(id, accepted) + err = response.ToNet(buf) + require.NoError(t, err) + deserialized, err = FromNet(buf) + require.NoError(t, err) + + deserializedResponse, ok := deserialized.(DataTransferResponse) + require.True(t, ok) + + require.Equal(t, deserializedResponse.TransferID(), response.TransferID()) + require.Equal(t, deserializedResponse.Accepted(), response.Accepted()) + require.Equal(t, deserializedResponse.IsRequest(), response.IsRequest()) + + request = CancelRequest(id) + err = request.ToNet(buf) + require.NoError(t, err) + deserialized, err = FromNet(buf) + require.NoError(t, err) + + deserializedRequest, ok = deserialized.(DataTransferRequest) + require.True(t, ok) + + require.Equal(t, deserializedRequest.TransferID(), request.TransferID()) + require.Equal(t, deserializedRequest.IsCancel(), request.IsCancel()) + require.Equal(t, deserializedRequest.IsRequest(), request.IsRequest()) +} + +func NewTestTransferRequest() (DataTransferRequest, error) { + bcid := testutil.GenerateCids(1)[0] + selector := builder.NewSelectorSpecBuilder(basicnode.Style.Any).Matcher().Node() + isPull := false + id := datatransfer.TransferID(rand.Int31()) + voucher := testutil.NewFakeDTType() + return NewRequest(id, isPull, voucher.Type(), voucher, bcid, selector) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message.go b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message.go new file mode 100644 index 0000000000..dc5c116ab0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message.go @@ -0,0 +1,36 @@ +package message + +import ( + "io" + + "github.com/filecoin-project/go-data-transfer" +) + +//go:generate cbor-gen-for transferMessage +type transferMessage struct { + IsRq bool + + Request *transferRequest + Response *transferResponse +} + +// ========= DataTransferMessage interface + +// IsRequest returns true if this message is a data request +func (tm *transferMessage) IsRequest() bool { + return tm.IsRq +} + +// TransferID returns the TransferID of this message +func (tm *transferMessage) TransferID() datatransfer.TransferID { + if tm.IsRequest() { + return tm.Request.TransferID() + } + return tm.Response.TransferID() +} + +// ToNet serializes a transfer message type. It is simply a wrapper for MarshalCBOR, to provide +// symmetry with FromNet +func (tm *transferMessage) ToNet(w io.Writer) error { + return tm.MarshalCBOR(w) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message_cbor_gen.go b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message_cbor_gen.go new file mode 100644 index 0000000000..c49b260de0 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_message_cbor_gen.go @@ -0,0 +1,116 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package message + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *transferMessage) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.IsRq (bool) (bool) + if err := cbg.WriteBool(w, t.IsRq); err != nil { + return err + } + + // t.Request (message.transferRequest) (struct) + if err := t.Request.MarshalCBOR(w); err != nil { + return err + } + + // t.Response (message.transferResponse) (struct) + if err := t.Response.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *transferMessage) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.IsRq (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.IsRq = false + case 21: + t.IsRq = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Request (message.transferRequest) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Request = new(transferRequest) + if err := t.Request.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Request pointer: %w", err) + } + } + + } + // t.Response (message.transferResponse) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Response = new(transferResponse) + if err := t.Response.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Response pointer: %w", err) + } + } + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request.go b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request.go new file mode 100644 index 0000000000..765e6fc1e5 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request.go @@ -0,0 +1,108 @@ +package message + +import ( + "bytes" + "io" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/encoding" + "github.com/ipfs/go-cid" + "github.com/ipld/go-ipld-prime" + "github.com/ipld/go-ipld-prime/codec/dagcbor" + basicnode "github.com/ipld/go-ipld-prime/node/basic" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +//go:generate cbor-gen-for transferRequest + +// transferRequest is a struct that fulfills the DataTransferRequest interface. +// its members are exported to be used by cbor-gen +type transferRequest struct { + BCid *cid.Cid + Canc bool + Part bool + Pull bool + Stor *cbg.Deferred + Vouch *cbg.Deferred + VTyp datatransfer.TypeIdentifier + XferID uint64 +} + +// IsRequest always returns true in this case because this is a transfer request +func (trq *transferRequest) IsRequest() bool { + return true +} + +func (trq *transferRequest) TransferID() datatransfer.TransferID { + return datatransfer.TransferID(trq.XferID) +} + +// ========= DataTransferRequest interface +// IsPull returns true if this is a data pull request +func (trq *transferRequest) IsPull() bool { + return trq.Pull +} + +// VoucherType returns the Voucher ID +func (trq *transferRequest) VoucherType() datatransfer.TypeIdentifier { + return trq.VTyp +} + +// Voucher returns the Voucher bytes +func (trq *transferRequest) Voucher(decoder encoding.Decoder) (encoding.Encodable, error) { + if trq.Vouch == nil { + return nil, xerrors.New("No voucher present to read") + } + return decoder.DecodeFromCbor(trq.Vouch.Raw) +} + +// BaseCid returns the Base CID +func (trq *transferRequest) BaseCid() cid.Cid { + if trq.BCid == nil { + return cid.Undef + } + return *trq.BCid +} + +// Selector returns the message Selector bytes +func (trq *transferRequest) Selector() (ipld.Node, error) { + if trq.Stor == nil { + return nil, xerrors.New("No selector present to read") + } + builder := basicnode.Style.Any.NewBuilder() + reader := bytes.NewReader(trq.Stor.Raw) + err := dagcbor.Decoder(builder, reader) + if err != nil { + return nil, xerrors.Errorf("Error decoding selector: %w", err) + } + return builder.Build(), nil +} + +// IsCancel returns true if this is a cancel request +func (trq *transferRequest) IsCancel() bool { + return trq.Canc +} + +// IsPartial returns true if this is a partial request +func (trq *transferRequest) IsPartial() bool { + return trq.Part +} + +// Cancel cancels a transfer request +func (trq *transferRequest) Cancel() error { + // do other stuff ? + trq.Canc = true + return nil +} + +// ToNet serializes a transfer request. It's a wrapper for MarshalCBOR to provide +// symmetry with FromNet +func (trq *transferRequest) ToNet(w io.Writer) error { + msg := transferMessage{ + IsRq: true, + Request: trq, + Response: nil, + } + return msg.MarshalCBOR(w) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request_cbor_gen.go b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request_cbor_gen.go new file mode 100644 index 0000000000..8407ee0f49 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_request_cbor_gen.go @@ -0,0 +1,240 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package message + +import ( + "fmt" + "io" + + datatransfer "github.com/filecoin-project/go-data-transfer" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *transferRequest) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{136}); err != nil { + return err + } + + // t.BCid (cid.Cid) (struct) + + if t.BCid == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCid(w, *t.BCid); err != nil { + return xerrors.Errorf("failed to write cid field t.BCid: %w", err) + } + } + + // t.Canc (bool) (bool) + if err := cbg.WriteBool(w, t.Canc); err != nil { + return err + } + + // t.Part (bool) (bool) + if err := cbg.WriteBool(w, t.Part); err != nil { + return err + } + + // t.Pull (bool) (bool) + if err := cbg.WriteBool(w, t.Pull); err != nil { + return err + } + + // t.Stor (typegen.Deferred) (struct) + if err := t.Stor.MarshalCBOR(w); err != nil { + return err + } + + // t.Vouch (typegen.Deferred) (struct) + if err := t.Vouch.MarshalCBOR(w); err != nil { + return err + } + + // t.VTyp (datatransfer.TypeIdentifier) (string) + if len(t.VTyp) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.VTyp was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.VTyp)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.VTyp)); err != nil { + return err + } + + // t.XferID (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.XferID))); err != nil { + return err + } + + return nil +} + +func (t *transferRequest) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 8 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.BCid (cid.Cid) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.BCid: %w", err) + } + + t.BCid = &c + } + + } + // t.Canc (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Canc = false + case 21: + t.Canc = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Part (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Part = false + case 21: + t.Part = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Pull (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Pull = false + case 21: + t.Pull = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Stor (typegen.Deferred) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Stor = new(cbg.Deferred) + if err := t.Stor.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Stor pointer: %w", err) + } + } + + } + // t.Vouch (typegen.Deferred) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Vouch = new(cbg.Deferred) + if err := t.Vouch.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Vouch pointer: %w", err) + } + } + + } + // t.VTyp (datatransfer.TypeIdentifier) (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.VTyp = datatransfer.TypeIdentifier(sval) + } + // t.XferID (uint64) (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.XferID = uint64(extra) + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response.go b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response.go new file mode 100644 index 0000000000..b51cd0fb04 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response.go @@ -0,0 +1,40 @@ +package message + +import ( + "io" + + "github.com/filecoin-project/go-data-transfer" +) + +//go:generate cbor-gen-for transferResponse + +// transferResponse is a private struct that satisfies the DataTransferResponse interface +type transferResponse struct { + Acpt bool + XferID uint64 +} + +func (trsp *transferResponse) TransferID() datatransfer.TransferID { + return datatransfer.TransferID(trsp.XferID) +} + +// IsRequest always returns false in this case because this is a transfer response +func (trsp *transferResponse) IsRequest() bool { + return false +} + +// Accepted returns true if the request is accepted in the response +func (trsp *transferResponse) Accepted() bool { + return trsp.Acpt +} + +// ToNet serializes a transfer response. It's a wrapper for MarshalCBOR to provide +// symmetry with FromNet +func (trsp *transferResponse) ToNet(w io.Writer) error { + msg := transferMessage{ + IsRq: false, + Request: nil, + Response: trsp, + } + return msg.MarshalCBOR(w) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response_cbor_gen.go b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response_cbor_gen.go new file mode 100644 index 0000000000..3947af917d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/message/transfer_response_cbor_gen.go @@ -0,0 +1,85 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package message + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *transferResponse) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Acpt (bool) (bool) + if err := cbg.WriteBool(w, t.Acpt); err != nil { + return err + } + + // t.XferID (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.XferID))); err != nil { + return err + } + + return nil +} + +func (t *transferResponse) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Acpt (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Acpt = false + case 21: + t.Acpt = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.XferID (uint64) (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.XferID = uint64(extra) + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/network/interface.go b/vendor/github.com/filecoin-project/go-data-transfer/network/interface.go new file mode 100644 index 0000000000..8cd05ad3ad --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/network/interface.go @@ -0,0 +1,56 @@ +package network + +import ( + "context" + + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" + + "github.com/filecoin-project/go-data-transfer/message" +) + +var ( + // ProtocolDataTransfer is the protocol identifier for graphsync messages + ProtocolDataTransfer protocol.ID = "/fil/datatransfer/1.0.0" +) + +// DataTransferNetwork provides network connectivity for GraphSync. +type DataTransferNetwork interface { + + // SendMessage sends a GraphSync message to a peer. + SendMessage( + context.Context, + peer.ID, + message.DataTransferMessage) error + + // SetDelegate registers the Reciver to handle messages received from the + // network. + SetDelegate(Receiver) + + // ConnectTo establishes a connection to the given peer + ConnectTo(context.Context, peer.ID) error + + NewMessageSender(context.Context, peer.ID) (MessageSender, error) +} + +// MessageSender is an interface to send messages to a peer +type MessageSender interface { + SendMsg(context.Context, message.DataTransferMessage) error + Close() error + Reset() error +} + +// Receiver is an interface for receiving messages from the GraphSyncNetwork. +type Receiver interface { + ReceiveRequest( + ctx context.Context, + sender peer.ID, + incoming message.DataTransferRequest) + + ReceiveResponse( + ctx context.Context, + sender peer.ID, + incoming message.DataTransferResponse) + + ReceiveError(error) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl.go b/vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl.go new file mode 100644 index 0000000000..8815444517 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl.go @@ -0,0 +1,165 @@ +package network + +import ( + "context" + "fmt" + "io" + "time" + + logging "github.com/ipfs/go-log" + "github.com/libp2p/go-libp2p-core/helpers" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + "github.com/filecoin-project/go-data-transfer/message" +) + +var log = logging.Logger("data_transfer_network") + +var sendMessageTimeout = time.Minute * 10 + +// NewFromLibp2pHost returns a GraphSyncNetwork supported by underlying Libp2p host. +func NewFromLibp2pHost(host host.Host) DataTransferNetwork { + dataTransferNetwork := libp2pDataTransferNetwork{ + host: host, + } + + return &dataTransferNetwork +} + +// libp2pDataTransferNetwork transforms the libp2p host interface, which sends and receives +// NetMessage objects, into the graphsync network interface. +type libp2pDataTransferNetwork struct { + host host.Host + // inbound messages from the network are forwarded to the receiver + receiver Receiver +} + +type streamMessageSender struct { + s network.Stream +} + +func (s *streamMessageSender) Close() error { + return helpers.FullClose(s.s) +} + +func (s *streamMessageSender) Reset() error { + return s.s.Reset() +} + +func (s *streamMessageSender) SendMsg(ctx context.Context, msg message.DataTransferMessage) error { + return msgToStream(ctx, s.s, msg) +} + +func msgToStream(ctx context.Context, s network.Stream, msg message.DataTransferMessage) error { + if msg.IsRequest() { + log.Debugf("Outgoing request message for transfer ID: %d", msg.TransferID()) + } + + deadline := time.Now().Add(sendMessageTimeout) + if dl, ok := ctx.Deadline(); ok { + deadline = dl + } + if err := s.SetWriteDeadline(deadline); err != nil { + log.Warnf("error setting deadline: %s", err) + } + + switch s.Protocol() { + case ProtocolDataTransfer: + if err := msg.ToNet(s); err != nil { + log.Debugf("error: %s", err) + return err + } + default: + return fmt.Errorf("unrecognized protocol on remote: %s", s.Protocol()) + } + + if err := s.SetWriteDeadline(time.Time{}); err != nil { + log.Warnf("error resetting deadline: %s", err) + } + return nil +} + +func (dtnet *libp2pDataTransferNetwork) NewMessageSender(ctx context.Context, p peer.ID) (MessageSender, error) { + s, err := dtnet.newStreamToPeer(ctx, p) + if err != nil { + return nil, err + } + + return &streamMessageSender{s: s}, nil +} + +func (dtnet *libp2pDataTransferNetwork) newStreamToPeer(ctx context.Context, p peer.ID) (network.Stream, error) { + return dtnet.host.NewStream(ctx, p, ProtocolDataTransfer) +} + +func (dtnet *libp2pDataTransferNetwork) SendMessage( + ctx context.Context, + p peer.ID, + outgoing message.DataTransferMessage) error { + + s, err := dtnet.newStreamToPeer(ctx, p) + if err != nil { + return err + } + + if err = msgToStream(ctx, s, outgoing); err != nil { + if err2 := s.Reset(); err2 != nil { + log.Error(err) + return err2 + } + return err + } + + // TODO(https://github.com/libp2p/go-libp2p-net/issues/28): Avoid this goroutine. + go helpers.AwaitEOF(s) // nolint: errcheck,gosec + return s.Close() + +} + +func (dtnet *libp2pDataTransferNetwork) SetDelegate(r Receiver) { + dtnet.receiver = r + dtnet.host.SetStreamHandler(ProtocolDataTransfer, dtnet.handleNewStream) +} + +func (dtnet *libp2pDataTransferNetwork) ConnectTo(ctx context.Context, p peer.ID) error { + return dtnet.host.Connect(ctx, peer.AddrInfo{ID: p}) +} + +// handleNewStream receives a new stream from the network. +func (dtnet *libp2pDataTransferNetwork) handleNewStream(s network.Stream) { + defer s.Close() // nolint: errcheck,gosec + + if dtnet.receiver == nil { + s.Reset() // nolint: errcheck,gosec + return + } + + for { + received, err := message.FromNet(s) + if err != nil { + if err != io.EOF { + s.Reset() // nolint: errcheck,gosec + go dtnet.receiver.ReceiveError(err) + log.Debugf("graphsync net handleNewStream from %s error: %s", s.Conn().RemotePeer(), err) + } + return + } + + p := s.Conn().RemotePeer() + ctx := context.Background() + log.Debugf("graphsync net handleNewStream from %s", s.Conn().RemotePeer()) + if received.IsRequest() { + receivedRequest, ok := received.(message.DataTransferRequest) + if ok { + dtnet.receiver.ReceiveRequest(ctx, p, receivedRequest) + } + } else { + receivedResponse, ok := received.(message.DataTransferResponse) + if ok { + dtnet.receiver.ReceiveResponse(ctx, p, receivedResponse) + } + } + } +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl_test.go b/vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl_test.go new file mode 100644 index 0000000000..9c78f88e4f --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/network/libp2p_impl_test.go @@ -0,0 +1,138 @@ +package network_test + +import ( + "context" + "math/rand" + "testing" + "time" + + basicnode "github.com/ipld/go-ipld-prime/node/basic" + "github.com/ipld/go-ipld-prime/traversal/selector/builder" + "github.com/libp2p/go-libp2p-core/peer" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/message" + "github.com/filecoin-project/go-data-transfer/network" + "github.com/filecoin-project/go-data-transfer/testutil" +) + +// Receiver is an interface for receiving messages from the DataTransferNetwork. +type receiver struct { + messageReceived chan struct{} + lastRequest message.DataTransferRequest + lastResponse message.DataTransferResponse + lastSender peer.ID + connectedPeers chan peer.ID +} + +func (r *receiver) ReceiveRequest( + ctx context.Context, + sender peer.ID, + incoming message.DataTransferRequest) { + r.lastSender = sender + r.lastRequest = incoming + select { + case <-ctx.Done(): + case r.messageReceived <- struct{}{}: + } +} + +func (r *receiver) ReceiveResponse( + ctx context.Context, + sender peer.ID, + incoming message.DataTransferResponse) { + r.lastSender = sender + r.lastResponse = incoming + select { + case <-ctx.Done(): + case r.messageReceived <- struct{}{}: + } +} + +func (r *receiver) ReceiveError(err error) { +} + +func TestMessageSendAndReceive(t *testing.T) { + // create network + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + mn := mocknet.New(ctx) + + host1, err := mn.GenPeer() + require.NoError(t, err) + host2, err := mn.GenPeer() + require.NoError(t, err) + err = mn.LinkAll() + require.NoError(t, err) + + dtnet1 := network.NewFromLibp2pHost(host1) + dtnet2 := network.NewFromLibp2pHost(host2) + r := &receiver{ + messageReceived: make(chan struct{}), + connectedPeers: make(chan peer.ID, 2), + } + dtnet1.SetDelegate(r) + dtnet2.SetDelegate(r) + + err = dtnet1.ConnectTo(ctx, host2.ID()) + require.NoError(t, err) + + t.Run("Send Request", func(t *testing.T) { + baseCid := testutil.GenerateCids(1)[0] + selector := builder.NewSelectorSpecBuilder(basicnode.Style.Any).Matcher().Node() + isPull := false + id := datatransfer.TransferID(rand.Int31()) + voucher := testutil.NewFakeDTType() + request, err := message.NewRequest(id, isPull, voucher.Type(), voucher, baseCid, selector) + require.NoError(t, err) + require.NoError(t, dtnet1.SendMessage(ctx, host2.ID(), request)) + + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case <-r.messageReceived: + } + + sender := r.lastSender + require.Equal(t, sender, host1.ID()) + + receivedRequest := r.lastRequest + require.NotNil(t, receivedRequest) + + assert.Equal(t, request.TransferID(), receivedRequest.TransferID()) + assert.Equal(t, request.IsCancel(), receivedRequest.IsCancel()) + assert.Equal(t, request.IsPull(), receivedRequest.IsPull()) + assert.Equal(t, request.IsRequest(), receivedRequest.IsRequest()) + assert.True(t, receivedRequest.BaseCid().Equals(request.BaseCid())) + testutil.AssertEqualFakeDTVoucher(t, request, receivedRequest) + testutil.AssertEqualSelector(t, request, receivedRequest) + }) + + t.Run("Send Response", func(t *testing.T) { + accepted := false + id := datatransfer.TransferID(rand.Int31()) + response := message.NewResponse(id, accepted) + require.NoError(t, dtnet2.SendMessage(ctx, host1.ID(), response)) + + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case <-r.messageReceived: + } + + sender := r.lastSender + require.NotNil(t, sender) + assert.Equal(t, sender, host2.ID()) + + receivedResponse := r.lastResponse + + assert.Equal(t, response.TransferID(), receivedResponse.TransferID()) + assert.Equal(t, response.Accepted(), receivedResponse.Accepted()) + assert.Equal(t, response.IsRequest(), receivedResponse.IsRequest()) + + }) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/registry/registry.go b/vendor/github.com/filecoin-project/go-data-transfer/registry/registry.go new file mode 100644 index 0000000000..4dc037079c --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/registry/registry.go @@ -0,0 +1,68 @@ +package registry + +import ( + "sync" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/encoding" + "golang.org/x/xerrors" +) + +// Processor is an interface that processes a certain type of encodable objects +// in a registry. The actual specifics of the interface that must be satisfied are +// left to the user of the registry +type Processor interface{} + +type registryEntry struct { + decoder encoding.Decoder + processor Processor +} + +// Registry maintans a register of types of encodable objects and a corresponding +// processor for those objects +// The encodable types must have a method Type() that specifies and identifier +// so they correct decoding function and processor can be identified based +// on this unique identifier +type Registry struct { + registryLk sync.RWMutex + entries map[datatransfer.TypeIdentifier]registryEntry +} + +// NewRegistry initialzes a new registy +func NewRegistry() *Registry { + return &Registry{ + entries: make(map[datatransfer.TypeIdentifier]registryEntry), + } +} + +// Register registers the given processor for the given entry type +func (r *Registry) Register(entry datatransfer.Registerable, processor Processor) error { + identifier := entry.Type() + decoder, err := encoding.NewDecoder(entry) + if err != nil { + return xerrors.Errorf("registering entry type %s: %w", identifier, err) + } + r.registryLk.Lock() + defer r.registryLk.Unlock() + if _, ok := r.entries[identifier]; ok { + return xerrors.Errorf("identifier already registered: %s", identifier) + } + r.entries[identifier] = registryEntry{decoder, processor} + return nil +} + +// Decoder gets a decoder for the given identifier +func (r *Registry) Decoder(identifier datatransfer.TypeIdentifier) (encoding.Decoder, bool) { + r.registryLk.RLock() + entry, has := r.entries[identifier] + r.registryLk.RUnlock() + return entry.decoder, has +} + +// Processor gets the processing interface for the given identifer +func (r *Registry) Processor(identifier datatransfer.TypeIdentifier) (Processor, bool) { + r.registryLk.RLock() + entry, has := r.entries[identifier] + r.registryLk.RUnlock() + return entry.processor, has +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/registry/registry_test.go b/vendor/github.com/filecoin-project/go-data-transfer/registry/registry_test.go new file mode 100644 index 0000000000..87fbf4a7ce --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/registry/registry_test.go @@ -0,0 +1,42 @@ +package registry_test + +import ( + "testing" + + "github.com/filecoin-project/go-data-transfer/registry" + "github.com/filecoin-project/go-data-transfer/testutil" + "github.com/stretchr/testify/require" +) + +func TestRegistry(t *testing.T) { + r := registry.NewRegistry() + t.Run("it registers", func(t *testing.T) { + err := r.Register(&testutil.FakeDTType{}, func() {}) + require.NoError(t, err) + }) + t.Run("it errors when registred again", func(t *testing.T) { + err := r.Register(&testutil.FakeDTType{}, func() {}) + require.EqualError(t, err, "identifier already registered: FakeDTType") + }) + t.Run("it errors when decoder setup fails", func(t *testing.T) { + err := r.Register(testutil.FakeDTType{}, func() {}) + require.EqualError(t, err, "registering entry type FakeDTType: type must be a pointer") + }) + t.Run("it reads decoders", func(t *testing.T) { + decoder, has := r.Decoder("FakeDTType") + require.True(t, has) + require.NotNil(t, decoder) + decoder, has = r.Decoder("OtherType") + require.False(t, has) + require.Nil(t, decoder) + }) + t.Run("it reads processors", func(t *testing.T) { + processor, has := r.Processor("FakeDTType") + require.True(t, has) + require.NotNil(t, processor) + processor, has = r.Processor("OtherType") + require.False(t, has) + require.Nil(t, processor) + }) + +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype.go b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype.go new file mode 100644 index 0000000000..19071e5845 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype.go @@ -0,0 +1,52 @@ +package testutil + +import ( + "testing" + + "github.com/stretchr/testify/require" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-data-transfer/encoding" + "github.com/filecoin-project/go-data-transfer/message" +) + +//go:generate cbor-gen-for FakeDTType + +// FakeDTType simple fake type for using with registries +type FakeDTType struct { + Data string +} + +// Type satisfies registry.Entry +func (ft FakeDTType) Type() datatransfer.TypeIdentifier { + return "FakeDTType" +} + +// AssertFakeDTVoucher asserts that a data transfer requests contains the expected fake data transfer voucher type +func AssertFakeDTVoucher(t *testing.T, request message.DataTransferRequest, expected *FakeDTType) { + require.Equal(t, datatransfer.TypeIdentifier("FakeDTType"), request.VoucherType()) + fakeDTDecoder, err := encoding.NewDecoder(&FakeDTType{}) + require.NoError(t, err) + decoded, err := request.Voucher(fakeDTDecoder) + require.NoError(t, err) + require.Equal(t, expected, decoded) +} + +// AssertEqualFakeDTVoucher asserts that two requests have the same fake data transfer voucher +func AssertEqualFakeDTVoucher(t *testing.T, expectedRequest message.DataTransferRequest, request message.DataTransferRequest) { + require.Equal(t, expectedRequest.VoucherType(), request.VoucherType()) + fakeDTDecoder, err := encoding.NewDecoder(&FakeDTType{}) + require.NoError(t, err) + expectedDecoded, err := request.Voucher(fakeDTDecoder) + require.NoError(t, err) + decoded, err := request.Voucher(fakeDTDecoder) + require.NoError(t, err) + require.Equal(t, expectedDecoded, decoded) +} + +// NewFakeDTType returns a fake dt type with random data +func NewFakeDTType() *FakeDTType { + return &FakeDTType{Data: string(RandomBytes(100))} +} + +var _ datatransfer.Registerable = &FakeDTType{} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype_cbor_gen.go b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype_cbor_gen.go new file mode 100644 index 0000000000..f9a35e37d8 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakedttype_cbor_gen.go @@ -0,0 +1,64 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package testutil + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *FakeDTType) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Data (string) (string) + if len(t.Data) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Data was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Data)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.Data)); err != nil { + return err + } + return nil +} + +func (t *FakeDTType) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Data (string) (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.Data = string(sval) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakegraphsync.go b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakegraphsync.go new file mode 100644 index 0000000000..b2722b5d52 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fakegraphsync.go @@ -0,0 +1,228 @@ +package testutil + +import ( + "context" + "math/rand" + "testing" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-graphsync" + "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/stretchr/testify/require" +) + +// ReceivedGraphSyncRequest contains data about a received graphsync request +type ReceivedGraphSyncRequest struct { + P peer.ID + Root ipld.Link + Selector ipld.Node + Extensions []graphsync.ExtensionData +} + +// FakeGraphSync implements a GraphExchange but does nothing +type FakeGraphSync struct { + requests chan ReceivedGraphSyncRequest // records calls to fakeGraphSync.Request + OutgoingRequestHook graphsync.OnOutgoingRequestHook + IncomingBlockHook graphsync.OnIncomingBlockHook + OutgoingBlockHook graphsync.OnOutgoingBlockHook + IncomingRequestHook graphsync.OnIncomingRequestHook + ResponseCompletedListener graphsync.OnResponseCompletedListener +} + +// NewFakeGraphSync returns a new fake graphsync implementation +func NewFakeGraphSync() *FakeGraphSync { + return &FakeGraphSync{ + requests: make(chan ReceivedGraphSyncRequest, 1), + } +} + +// AssertNoRequestReceived asserts that no requests should ahve been received by this graphsync implementation +func (fgs *FakeGraphSync) AssertNoRequestReceived(t *testing.T) { + require.Empty(t, fgs.requests, "should not receive request") +} + +// AssertRequestReceived asserts a request should be received before the context closes (and returns said request) +func (fgs *FakeGraphSync) AssertRequestReceived(ctx context.Context, t *testing.T) ReceivedGraphSyncRequest { + var requestReceived ReceivedGraphSyncRequest + select { + case <-ctx.Done(): + t.Fatal("did not receive message sent") + case requestReceived = <-fgs.requests: + } + return requestReceived +} + +// Request initiates a new GraphSync request to the given peer using the given selector spec. +func (fgs *FakeGraphSync) Request(ctx context.Context, p peer.ID, root ipld.Link, selector ipld.Node, extensions ...graphsync.ExtensionData) (<-chan graphsync.ResponseProgress, <-chan error) { + + fgs.requests <- ReceivedGraphSyncRequest{p, root, selector, extensions} + responses := make(chan graphsync.ResponseProgress) + errors := make(chan error) + close(responses) + close(errors) + return responses, errors +} + +// RegisterPersistenceOption registers an alternate loader/storer combo that can be substituted for the default +func (fgs *FakeGraphSync) RegisterPersistenceOption(name string, loader ipld.Loader, storer ipld.Storer) error { + return nil +} + +// RegisterIncomingRequestHook adds a hook that runs when a request is received +func (fgs *FakeGraphSync) RegisterIncomingRequestHook(hook graphsync.OnIncomingRequestHook) graphsync.UnregisterHookFunc { + fgs.IncomingRequestHook = hook + return nil +} + +// RegisterIncomingResponseHook adds a hook that runs when a response is received +func (fgs *FakeGraphSync) RegisterIncomingResponseHook(_ graphsync.OnIncomingResponseHook) graphsync.UnregisterHookFunc { + return nil +} + +// RegisterOutgoingRequestHook adds a hook that runs immediately prior to sending a new request +func (fgs *FakeGraphSync) RegisterOutgoingRequestHook(hook graphsync.OnOutgoingRequestHook) graphsync.UnregisterHookFunc { + fgs.OutgoingRequestHook = hook + return nil +} + +// RegisterOutgoingBlockHook adds a hook that runs every time a block is sent from a responder +func (fgs *FakeGraphSync) RegisterOutgoingBlockHook(hook graphsync.OnOutgoingBlockHook) graphsync.UnregisterHookFunc { + fgs.OutgoingBlockHook = hook + return nil +} + +// RegisterIncomingBlockHook adds a hook that runs every time a block is received by the requestor +func (fgs *FakeGraphSync) RegisterIncomingBlockHook(hook graphsync.OnIncomingBlockHook) graphsync.UnregisterHookFunc { + fgs.IncomingBlockHook = hook + return nil +} + +// RegisterRequestUpdatedHook adds a hook that runs every time an update to a request is received +func (fgs *FakeGraphSync) RegisterRequestUpdatedHook(hook graphsync.OnRequestUpdatedHook) graphsync.UnregisterHookFunc { + return nil +} + +// RegisterCompletedResponseListener adds a listener on the responder for completed responses +func (fgs *FakeGraphSync) RegisterCompletedResponseListener(listener graphsync.OnResponseCompletedListener) graphsync.UnregisterHookFunc { + fgs.ResponseCompletedListener = listener + return nil +} + +// UnpauseResponse unpauses a response that was paused in a block hook based on peer ID and request ID +func (fgs *FakeGraphSync) UnpauseResponse(_ peer.ID, _ graphsync.RequestID) error { + return nil +} + +var _ graphsync.GraphExchange = &FakeGraphSync{} + +type fakeBlkData struct { + link ipld.Link + size uint64 +} + +func (fbd fakeBlkData) Link() ipld.Link { + return fbd.link +} + +func (fbd fakeBlkData) BlockSize() uint64 { + return fbd.size +} + +func (fbd fakeBlkData) BlockSizeOnWire() uint64 { + return fbd.size +} + +// NewFakeBlockData returns a fake block that matches the block data interface +func NewFakeBlockData() graphsync.BlockData { + return &fakeBlkData{ + link: cidlink.Link{Cid: GenerateCids(1)[0]}, + size: rand.Uint64(), + } +} + +type fakeRequest struct { + id graphsync.RequestID + root cid.Cid + selector ipld.Node + priority graphsync.Priority + isCancel bool + extensions map[graphsync.ExtensionName][]byte +} + +// ID Returns the request ID for this Request +func (fr *fakeRequest) ID() graphsync.RequestID { + return fr.id +} + +// Root returns the CID to the root block of this request +func (fr *fakeRequest) Root() cid.Cid { + return fr.root +} + +// Selector returns the byte representation of the selector for this request +func (fr *fakeRequest) Selector() ipld.Node { + return fr.selector +} + +// Priority returns the priority of this request +func (fr *fakeRequest) Priority() graphsync.Priority { + return fr.priority +} + +// Extension returns the content for an extension on a response, or errors +// if extension is not present +func (fr *fakeRequest) Extension(name graphsync.ExtensionName) ([]byte, bool) { + data, has := fr.extensions[name] + return data, has +} + +// IsCancel returns true if this particular request is being cancelled +func (fr *fakeRequest) IsCancel() bool { + return fr.isCancel +} + +// NewFakeRequest returns a fake request that matches the request data interface +func NewFakeRequest(id graphsync.RequestID, extensions map[graphsync.ExtensionName][]byte) graphsync.RequestData { + return &fakeRequest{ + id: id, + root: GenerateCids(1)[0], + selector: allSelector, + priority: graphsync.Priority(rand.Int()), + isCancel: false, + extensions: extensions, + } +} + +type fakeResponse struct { + id graphsync.RequestID + status graphsync.ResponseStatusCode + extensions map[graphsync.ExtensionName][]byte +} + +// RequestID returns the request ID for this response +func (fr *fakeResponse) RequestID() graphsync.RequestID { + return fr.id +} + +// Status returns the status for a response +func (fr *fakeResponse) Status() graphsync.ResponseStatusCode { + return fr.status +} + +// Extension returns the content for an extension on a response, or errors +// if extension is not present +func (fr *fakeResponse) Extension(name graphsync.ExtensionName) ([]byte, bool) { + data, has := fr.extensions[name] + return data, has +} + +// NewFakeResponse returns a fake response that matches the response data interface +func NewFakeResponse(id graphsync.RequestID, extensions map[graphsync.ExtensionName][]byte, status graphsync.ResponseStatusCode) graphsync.ResponseData { + return &fakeResponse{ + id: id, + status: status, + extensions: extensions, + } +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/testutil/fixtures/lorem.txt b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fixtures/lorem.txt new file mode 100644 index 0000000000..c558923539 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/testutil/fixtures/lorem.txt @@ -0,0 +1,49 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae semper quis lectus nulla at volutpat diam ut venenatis. Ac tortor dignissim convallis aenean et tortor at. Faucibus ornare suspendisse sed nisi lacus sed. Commodo ullamcorper a lacus vestibulum sed arcu non. Est pellentesque elit ullamcorper dignissim. Quam quisque id diam vel quam. Pretium aenean pharetra magna ac. In nulla posuere sollicitudin aliquam ultrices. Sed arcu non odio euismod lacinia at. Suspendisse ultrices gravida dictum fusce ut placerat orci nulla pellentesque. Feugiat vivamus at augue eget arcu. + +Pellentesque nec nam aliquam sem et tortor. Vitae tortor condimentum lacinia quis vel. Cras pulvinar mattis nunc sed. In massa tempor nec feugiat. Ornare arcu odio ut sem nulla. Diam maecenas sed enim ut sem. Pretium vulputate sapien nec sagittis. Bibendum arcu vitae elementum curabitur vitae nunc sed velit dignissim. Duis ut diam quam nulla porttitor massa. Viverra mauris in aliquam sem fringilla ut morbi. Ullamcorper eget nulla facilisi etiam dignissim. Vulputate mi sit amet mauris commodo quis imperdiet massa tincidunt. Nunc consequat interdum varius sit. Nunc mi ipsum faucibus vitae aliquet nec ullamcorper. Nunc sed augue lacus viverra. Lobortis scelerisque fermentum dui faucibus in ornare quam. Urna neque viverra justo nec ultrices. Varius vel pharetra vel turpis nunc eget lorem dolor sed. + +Feugiat nisl pretium fusce id velit ut tortor pretium. Lorem dolor sed viverra ipsum nunc aliquet bibendum. Ultrices vitae auctor eu augue ut lectus. Pharetra massa massa ultricies mi quis. Nibh cras pulvinar mattis nunc sed blandit libero. Ac felis donec et odio pellentesque diam volutpat. Lectus proin nibh nisl condimentum id venenatis. Quis vel eros donec ac odio. Commodo sed egestas egestas fringilla phasellus faucibus scelerisque eleifend donec. Adipiscing diam donec adipiscing tristique. + +Tempus imperdiet nulla malesuada pellentesque elit eget gravida cum sociis. Libero nunc consequat interdum varius sit. Et pharetra pharetra massa massa. Feugiat pretium nibh ipsum consequat. Amet commodo nulla facilisi nullam vehicula. Ornare arcu dui vivamus arcu felis bibendum ut tristique. At erat pellentesque adipiscing commodo elit at imperdiet dui. Auctor neque vitae tempus quam pellentesque nec nam aliquam sem. Eget velit aliquet sagittis id consectetur. Enim diam vulputate ut pharetra sit amet aliquam id diam. Eget velit aliquet sagittis id consectetur purus ut faucibus pulvinar. Amet porttitor eget dolor morbi. Felis eget velit aliquet sagittis id. Facilisis magna etiam tempor orci eu. Lacus suspendisse faucibus interdum posuere lorem. Pharetra et ultrices neque ornare aenean euismod. Platea dictumst quisque sagittis purus. + +Quis varius quam quisque id diam vel quam elementum. Augue mauris augue neque gravida in fermentum et sollicitudin. Sapien nec sagittis aliquam malesuada bibendum arcu. Urna duis convallis convallis tellus id interdum velit. Tellus in hac habitasse platea dictumst vestibulum. Fames ac turpis egestas maecenas pharetra convallis. Diam volutpat commodo sed egestas egestas fringilla phasellus faucibus. Placerat orci nulla pellentesque dignissim enim sit amet venenatis. Sed adipiscing diam donec adipiscing. Praesent elementum facilisis leo vel fringilla est. Sed enim ut sem viverra aliquet eget sit amet tellus. Proin sagittis nisl rhoncus mattis rhoncus urna neque viverra. Turpis egestas pretium aenean pharetra magna ac placerat vestibulum. Massa id neque aliquam vestibulum morbi blandit cursus risus. Vitae congue eu consequat ac. Egestas erat imperdiet sed euismod nisi porta lorem mollis aliquam. Dolor purus non enim praesent elementum facilisis. Ultrices mi tempus imperdiet nulla malesuada pellentesque elit. In est ante in nibh. + +Facilisis gravida neque convallis a. Urna nunc id cursus metus aliquam eleifend mi. Lacus luctus accumsan tortor posuere ac. Molestie nunc non blandit massa. Iaculis urna id volutpat lacus laoreet non. Cursus vitae congue mauris rhoncus aenean. Nunc vel risus commodo viverra maecenas. A pellentesque sit amet porttitor eget dolor morbi. Leo vel orci porta non pulvinar neque laoreet suspendisse. Sit amet facilisis magna etiam tempor. Consectetur a erat nam at lectus urna duis convallis convallis. Vestibulum morbi blandit cursus risus at ultrices. Dolor purus non enim praesent elementum. Adipiscing elit pellentesque habitant morbi tristique senectus et netus et. Et odio pellentesque diam volutpat commodo sed egestas egestas fringilla. Leo vel fringilla est ullamcorper eget nulla. Dui ut ornare lectus sit amet. Erat pellentesque adipiscing commodo elit at imperdiet dui accumsan sit. + +Tristique senectus et netus et. Pellentesque diam volutpat commodo sed egestas egestas fringilla. Mauris pharetra et ultrices neque ornare aenean. Amet tellus cras adipiscing enim. Convallis aenean et tortor at risus viverra adipiscing at. Proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo. Dictumst vestibulum rhoncus est pellentesque elit. Fringilla ut morbi tincidunt augue interdum velit euismod in pellentesque. Dictum at tempor commodo ullamcorper a lacus vestibulum. Sed viverra tellus in hac habitasse platea. Sed id semper risus in hendrerit. In hendrerit gravida rutrum quisque non tellus orci ac. Sit amet risus nullam eget. Sit amet est placerat in egestas erat imperdiet sed. In nisl nisi scelerisque eu ultrices. Sit amet mattis vulputate enim nulla aliquet. + +Dignissim suspendisse in est ante in nibh mauris cursus. Vitae proin sagittis nisl rhoncus. Id leo in vitae turpis massa sed elementum. Lobortis elementum nibh tellus molestie nunc non blandit massa enim. Arcu dictum varius duis at consectetur. Suspendisse faucibus interdum posuere lorem ipsum dolor sit amet consectetur. Imperdiet nulla malesuada pellentesque elit eget gravida cum sociis. Sed adipiscing diam donec adipiscing. Purus sit amet volutpat consequat mauris nunc congue nisi vitae. Elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl. Mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Sit amet nisl purus in mollis nunc sed. Turpis tincidunt id aliquet risus feugiat in ante. Id diam maecenas ultricies mi eget mauris pharetra et ultrices. + +Aliquam purus sit amet luctus venenatis lectus magna fringilla urna. Id diam vel quam elementum pulvinar. Elementum sagittis vitae et leo duis. Viverra aliquet eget sit amet tellus cras adipiscing enim eu. Et tortor at risus viverra adipiscing at in tellus integer. Purus in massa tempor nec feugiat. Augue neque gravida in fermentum et sollicitudin ac orci. Sodales ut eu sem integer vitae justo eget magna fermentum. Netus et malesuada fames ac. Augue interdum velit euismod in. Sed elementum tempus egestas sed sed risus pretium. Mattis vulputate enim nulla aliquet porttitor lacus luctus. Dui vivamus arcu felis bibendum ut tristique et egestas quis. + +Viverra justo nec ultrices dui sapien. Quisque egestas diam in arcu cursus euismod quis viverra nibh. Nam libero justo laoreet sit amet cursus sit amet. Lacus sed viverra tellus in hac habitasse. Blandit aliquam etiam erat velit scelerisque in. Ut sem nulla pharetra diam sit amet nisl suscipit adipiscing. Diam sollicitudin tempor id eu nisl nunc. Eget duis at tellus at urna condimentum mattis. Urna porttitor rhoncus dolor purus non enim praesent elementum facilisis. Sed turpis tincidunt id aliquet risus feugiat. Est velit egestas dui id ornare arcu odio ut sem. Nibh sit amet commodo nulla facilisi nullam vehicula. Sit amet consectetur adipiscing elit duis tristique sollicitudin. Eu facilisis sed odio morbi. Massa id neque aliquam vestibulum morbi. In eu mi bibendum neque egestas congue quisque egestas. Massa sed elementum tempus egestas sed sed risus. Quam elementum pulvinar etiam non. At augue eget arcu dictum varius duis at consectetur lorem. + +Penatibus et magnis dis parturient montes nascetur ridiculus. Dictumst quisque sagittis purus sit amet volutpat consequat. Bibendum at varius vel pharetra. Sed adipiscing diam donec adipiscing tristique risus nec feugiat in. Phasellus faucibus scelerisque eleifend donec pretium. Vitae tortor condimentum lacinia quis vel eros. Ac tincidunt vitae semper quis lectus nulla at volutpat diam. Eget sit amet tellus cras adipiscing. Morbi tristique senectus et netus. Nullam vehicula ipsum a arcu cursus vitae congue mauris rhoncus. Auctor urna nunc id cursus metus aliquam eleifend. Ultrices vitae auctor eu augue. Eu non diam phasellus vestibulum lorem sed risus ultricies. Fames ac turpis egestas sed tempus. Volutpat blandit aliquam etiam erat. Dictum varius duis at consectetur lorem. Sit amet volutpat consequat mauris nunc congue. Volutpat sed cras ornare arcu dui vivamus arcu felis. + +Scelerisque fermentum dui faucibus in ornare quam viverra. Interdum velit laoreet id donec ultrices tincidunt arcu. Netus et malesuada fames ac. Netus et malesuada fames ac turpis. Suscipit tellus mauris a diam maecenas sed enim ut sem. Id velit ut tortor pretium. Neque aliquam vestibulum morbi blandit cursus risus at. Cum sociis natoque penatibus et magnis dis parturient. Lobortis elementum nibh tellus molestie nunc non blandit. Ipsum dolor sit amet consectetur adipiscing elit duis tristique. Amet nisl purus in mollis. Amet massa vitae tortor condimentum lacinia quis vel eros donec. Proin sagittis nisl rhoncus mattis rhoncus urna neque viverra justo. + +Nullam ac tortor vitae purus faucibus. Dis parturient montes nascetur ridiculus mus mauris. Molestie at elementum eu facilisis sed odio morbi. Scelerisque felis imperdiet proin fermentum leo vel orci porta. Lectus proin nibh nisl condimentum id venenatis a. Eget nullam non nisi est sit amet facilisis. Hendrerit gravida rutrum quisque non tellus orci ac auctor. Ut faucibus pulvinar elementum integer enim. Rhoncus dolor purus non enim praesent elementum facilisis. Enim sed faucibus turpis in eu mi bibendum. Faucibus nisl tincidunt eget nullam. + +Cursus risus at ultrices mi tempus imperdiet nulla malesuada pellentesque. Pretium nibh ipsum consequat nisl vel pretium lectus quam. Semper viverra nam libero justo laoreet sit amet cursus sit. Augue eget arcu dictum varius duis at consectetur lorem donec. Et malesuada fames ac turpis. Erat nam at lectus urna duis convallis convallis. Dictum sit amet justo donec enim. Urna condimentum mattis pellentesque id nibh tortor id. Morbi tempus iaculis urna id. Lectus proin nibh nisl condimentum id venenatis a condimentum. Nibh sit amet commodo nulla facilisi nullam vehicula. Dui faucibus in ornare quam. Gravida arcu ac tortor dignissim convallis aenean. Consectetur adipiscing elit pellentesque habitant morbi tristique. Pulvinar elementum integer enim neque volutpat ac tincidunt vitae. Pharetra pharetra massa massa ultricies mi quis hendrerit. Dictum at tempor commodo ullamcorper a lacus vestibulum sed. Mattis pellentesque id nibh tortor id. Ultricies integer quis auctor elit sed vulputate. Pretium vulputate sapien nec sagittis aliquam malesuada. + +Auctor augue mauris augue neque gravida. Porttitor lacus luctus accumsan tortor posuere ac ut. Urna neque viverra justo nec ultrices dui. Sit amet est placerat in egestas. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar. Tincidunt eget nullam non nisi est sit amet facilisis magna. Elementum tempus egestas sed sed risus pretium quam vulputate dignissim. Fermentum posuere urna nec tincidunt praesent semper feugiat nibh sed. Porttitor eget dolor morbi non arcu risus quis. Non quam lacus suspendisse faucibus interdum. Venenatis cras sed felis eget velit aliquet sagittis id. Arcu ac tortor dignissim convallis aenean et. Morbi tincidunt ornare massa eget egestas purus. Ac feugiat sed lectus vestibulum mattis ullamcorper velit sed ullamcorper. Vestibulum morbi blandit cursus risus at ultrices. Volutpat blandit aliquam etiam erat velit scelerisque. + +Et egestas quis ipsum suspendisse. Amet consectetur adipiscing elit duis. Purus ut faucibus pulvinar elementum integer enim neque. Cursus vitae congue mauris rhoncus aenean vel elit scelerisque mauris. Tincidunt eget nullam non nisi est. Aliquam purus sit amet luctus. Dui ut ornare lectus sit amet est placerat in. Fringilla ut morbi tincidunt augue interdum velit euismod in. Felis eget nunc lobortis mattis aliquam faucibus purus in. Suspendisse interdum consectetur libero id faucibus nisl. + +Scelerisque fermentum dui faucibus in ornare quam. Lectus proin nibh nisl condimentum id venenatis a condimentum vitae. Fames ac turpis egestas integer eget aliquet nibh praesent tristique. Arcu non sodales neque sodales ut etiam sit. Pharetra convallis posuere morbi leo urna. Nec dui nunc mattis enim ut tellus. Nunc sed augue lacus viverra vitae. Consequat id porta nibh venenatis cras sed felis. Dolor sit amet consectetur adipiscing. Tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla. + +Metus aliquam eleifend mi in nulla posuere. Blandit massa enim nec dui nunc mattis enim. Aliquet nibh praesent tristique magna. In aliquam sem fringilla ut. Magna fermentum iaculis eu non. Eget aliquet nibh praesent tristique magna sit amet purus. Ultrices gravida dictum fusce ut placerat orci. Fermentum posuere urna nec tincidunt praesent. Enim tortor at auctor urna nunc. Ridiculus mus mauris vitae ultricies leo integer malesuada nunc vel. Sed id semper risus in hendrerit gravida rutrum. Vestibulum lectus mauris ultrices eros in cursus turpis. Et sollicitudin ac orci phasellus egestas tellus rutrum. Pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at. Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Porta non pulvinar neque laoreet suspendisse. Suscipit adipiscing bibendum est ultricies integer quis auctor elit sed. Euismod in pellentesque massa placerat duis ultricies lacus sed. Pellentesque adipiscing commodo elit at imperdiet dui accumsan sit amet. + +Pellentesque eu tincidunt tortor aliquam nulla facilisi. Commodo nulla facilisi nullam vehicula ipsum a arcu. Commodo quis imperdiet massa tincidunt nunc pulvinar sapien et. Faucibus purus in massa tempor. Purus semper eget duis at tellus at urna condimentum. Vivamus at augue eget arcu dictum. Lacus vel facilisis volutpat est velit egestas dui id. Malesuada fames ac turpis egestas maecenas pharetra. Nunc faucibus a pellentesque sit amet porttitor eget dolor. Ultricies tristique nulla aliquet enim. Vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat. Dignissim diam quis enim lobortis scelerisque. Donec ultrices tincidunt arcu non sodales neque sodales ut etiam. + +Vitae proin sagittis nisl rhoncus mattis rhoncus urna neque. Fermentum leo vel orci porta non. At elementum eu facilisis sed. Quis enim lobortis scelerisque fermentum. Fermentum odio eu feugiat pretium nibh ipsum consequat. Habitant morbi tristique senectus et netus et. Enim praesent elementum facilisis leo vel fringilla est ullamcorper. Egestas quis ipsum suspendisse ultrices gravida dictum. Nam libero justo laoreet sit amet cursus sit amet. Viverra tellus in hac habitasse platea dictumst vestibulum. Varius vel pharetra vel turpis nunc eget. Nullam non nisi est sit amet facilisis magna. Ullamcorper eget nulla facilisi etiam dignissim diam. Ante metus dictum at tempor commodo ullamcorper a lacus. + +Etiam non quam lacus suspendisse. Ut venenatis tellus in metus vulputate eu scelerisque felis. Pulvinar sapien et ligula ullamcorper malesuada proin libero. Consequat interdum varius sit amet mattis. Nunc eget lorem dolor sed viverra ipsum nunc aliquet. Potenti nullam ac tortor vitae purus faucibus ornare. Urna et pharetra pharetra massa massa ultricies mi quis hendrerit. Purus in mollis nunc sed id. Pharetra vel turpis nunc eget lorem dolor sed viverra. Et netus et malesuada fames ac turpis. Libero id faucibus nisl tincidunt eget nullam non nisi. Cursus sit amet dictum sit amet. Porttitor lacus luctus accumsan tortor. + +Volutpat diam ut venenatis tellus in metus vulputate eu scelerisque. Sed viverra tellus in hac habitasse. Aliquam sem et tortor consequat id. Pellentesque habitant morbi tristique senectus et netus et. Consectetur purus ut faucibus pulvinar elementum. Aliquam malesuada bibendum arcu vitae elementum curabitur vitae nunc sed. Malesuada bibendum arcu vitae elementum curabitur vitae nunc sed. Sollicitudin tempor id eu nisl nunc mi ipsum. Fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate sapien nec. Quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus. Bibendum neque egestas congue quisque egestas. A iaculis at erat pellentesque adipiscing commodo elit at imperdiet. Pulvinar etiam non quam lacus. Adipiscing commodo elit at imperdiet. Scelerisque eu ultrices vitae auctor. Sed cras ornare arcu dui vivamus arcu felis bibendum ut. Ornare lectus sit amet est. + +Consequat semper viverra nam libero justo laoreet sit. Imperdiet sed euismod nisi porta lorem mollis aliquam ut porttitor. Cras sed felis eget velit aliquet sagittis id consectetur. Dolor morbi non arcu risus quis. Adipiscing tristique risus nec feugiat in fermentum posuere urna. Dolor magna eget est lorem ipsum dolor. Mauris pharetra et ultrices neque ornare aenean euismod. Nulla facilisi etiam dignissim diam quis. Ultrices tincidunt arcu non sodales. Fames ac turpis egestas maecenas pharetra convallis posuere morbi leo. Interdum varius sit amet mattis vulputate. Tincidunt praesent semper feugiat nibh sed pulvinar. Quisque sagittis purus sit amet volutpat. + +Sed vulputate odio ut enim blandit. Vitae auctor eu augue ut lectus arcu bibendum. Consectetur adipiscing elit pellentesque habitant morbi tristique senectus et. Scelerisque eu ultrices vitae auctor eu augue. Etiam dignissim diam quis enim lobortis scelerisque fermentum dui faucibus. Tellus integer feugiat scelerisque varius. Vulputate enim nulla aliquet porttitor lacus luctus accumsan tortor. Amet nisl purus in mollis. Scelerisque viverra mauris in aliquam sem fringilla ut morbi tincidunt. Semper eget duis at tellus at. Erat velit scelerisque in dictum non consectetur a erat nam. Gravida rutrum quisque non tellus orci. Morbi blandit cursus risus at. Mauris sit amet massa vitae. Non odio euismod lacinia at quis risus sed vulputate. Fermentum posuere urna nec tincidunt praesent. Ut eu sem integer vitae justo eget magna fermentum iaculis. Ullamcorper velit sed ullamcorper morbi tincidunt ornare massa. Arcu cursus euismod quis viverra nibh. Arcu dui vivamus arcu felis bibendum. + +Eros in cursus turpis massa tincidunt dui ut. Urna condimentum mattis pellentesque id nibh tortor id aliquet lectus. Nibh venenatis cras sed felis. Ac felis donec et odio pellentesque diam. Ultricies lacus sed turpis tincidunt id aliquet risus. Diam volutpat commodo sed egestas. Dignissim sodales ut eu sem integer vitae. Pellentesque eu tincidunt tortor aliquam nulla facilisi. Et tortor consequat id porta nibh venenatis cras sed felis. Aliquam ultrices sagittis orci a. Id interdum velit laoreet id donec ultrices tincidunt arcu non. Dictum fusce ut placerat orci nulla pellentesque dignissim. At erat pellentesque adipiscing commodo elit. Ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet. Lectus sit amet est placerat in. Montes nascetur ridiculus mus mauris. Libero volutpat sed cras ornare arcu. Mi sit amet mauris commodo quis imperdiet massa. Sed id semper risus in hendrerit. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-data-transfer/testutil/gstestdata.go b/vendor/github.com/filecoin-project/go-data-transfer/testutil/gstestdata.go new file mode 100644 index 0000000000..e4eb2a2f32 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/testutil/gstestdata.go @@ -0,0 +1,242 @@ +package testutil + +import ( + "bytes" + "context" + "errors" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "testing" + + "github.com/filecoin-project/go-storedcounter" + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + dss "github.com/ipfs/go-datastore/sync" + "github.com/ipfs/go-graphsync" + gsimpl "github.com/ipfs/go-graphsync/impl" + gsnet "github.com/ipfs/go-graphsync/network" + bstore "github.com/ipfs/go-ipfs-blockstore" + chunker "github.com/ipfs/go-ipfs-chunker" + offline "github.com/ipfs/go-ipfs-exchange-offline" + files "github.com/ipfs/go-ipfs-files" + ipldformat "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-merkledag" + unixfile "github.com/ipfs/go-unixfs/file" + "github.com/ipfs/go-unixfs/importer/balanced" + ihelper "github.com/ipfs/go-unixfs/importer/helpers" + "github.com/ipld/go-ipld-prime" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" + basicnode "github.com/ipld/go-ipld-prime/node/basic" + "github.com/ipld/go-ipld-prime/traversal/selector" + "github.com/ipld/go-ipld-prime/traversal/selector/builder" + "github.com/libp2p/go-libp2p-core/host" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/stretchr/testify/require" +) + +var allSelector ipld.Node + +func init() { + ssb := builder.NewSelectorSpecBuilder(basicnode.Style.Any) + allSelector = ssb.ExploreRecursive(selector.RecursionLimitNone(), + ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node() +} + +const unixfsChunkSize uint64 = 1 << 10 +const unixfsLinksPerLevel = 1024 + +// GraphsyncTestingData is a test harness for testing data transfer on top of +// graphsync +type GraphsyncTestingData struct { + Ctx context.Context + StoredCounter1 *storedcounter.StoredCounter + StoredCounter2 *storedcounter.StoredCounter + Bs1 bstore.Blockstore + Bs2 bstore.Blockstore + DagService1 ipldformat.DAGService + DagService2 ipldformat.DAGService + Loader1 ipld.Loader + Loader2 ipld.Loader + Storer1 ipld.Storer + Storer2 ipld.Storer + Host1 host.Host + Host2 host.Host + GsNet1 gsnet.GraphSyncNetwork + GsNet2 gsnet.GraphSyncNetwork + AllSelector ipld.Node + OrigBytes []byte +} + +// NewGraphsyncTestingData returns a new GraphsyncTestingData instance +func NewGraphsyncTestingData(ctx context.Context, t *testing.T) *GraphsyncTestingData { + + gsData := &GraphsyncTestingData{} + gsData.Ctx = ctx + makeLoader := func(bs bstore.Blockstore) ipld.Loader { + return func(lnk ipld.Link, lnkCtx ipld.LinkContext) (io.Reader, error) { + c, ok := lnk.(cidlink.Link) + if !ok { + return nil, errors.New("Incorrect Link Type") + } + // read block from one store + block, err := bs.Get(c.Cid) + if err != nil { + return nil, err + } + return bytes.NewReader(block.RawData()), nil + } + } + + makeStorer := func(bs bstore.Blockstore) ipld.Storer { + return func(lnkCtx ipld.LinkContext) (io.Writer, ipld.StoreCommitter, error) { + var buf bytes.Buffer + var committer ipld.StoreCommitter = func(lnk ipld.Link) error { + c, ok := lnk.(cidlink.Link) + if !ok { + return errors.New("Incorrect Link Type") + } + block, err := blocks.NewBlockWithCid(buf.Bytes(), c.Cid) + if err != nil { + return err + } + return bs.Put(block) + } + return &buf, committer, nil + } + } + ds1 := dss.MutexWrap(datastore.NewMapDatastore()) + ds2 := dss.MutexWrap(datastore.NewMapDatastore()) + // make a blockstore and dag service + gsData.Bs1 = bstore.NewBlockstore(namespace.Wrap(ds1, datastore.NewKey("blockstore"))) + gsData.Bs2 = bstore.NewBlockstore(namespace.Wrap(ds2, datastore.NewKey("blockstore"))) + + // make stored counters + gsData.StoredCounter1 = storedcounter.New(ds1, datastore.NewKey("counter")) + gsData.StoredCounter2 = storedcounter.New(ds2, datastore.NewKey("counter")) + + gsData.DagService1 = merkledag.NewDAGService(blockservice.New(gsData.Bs1, offline.Exchange(gsData.Bs1))) + gsData.DagService2 = merkledag.NewDAGService(blockservice.New(gsData.Bs2, offline.Exchange(gsData.Bs2))) + + // setup an IPLD loader/storer for blockstore 1 + gsData.Loader1 = makeLoader(gsData.Bs1) + gsData.Storer1 = makeStorer(gsData.Bs1) + + // setup an IPLD loader/storer for blockstore 2 + gsData.Loader2 = makeLoader(gsData.Bs2) + gsData.Storer2 = makeStorer(gsData.Bs2) + + mn := mocknet.New(ctx) + + // setup network + var err error + gsData.Host1, err = mn.GenPeer() + require.NoError(t, err) + + gsData.Host2, err = mn.GenPeer() + require.NoError(t, err) + + err = mn.LinkAll() + require.NoError(t, err) + + gsData.GsNet1 = gsnet.NewFromLibp2pHost(gsData.Host1) + gsData.GsNet2 = gsnet.NewFromLibp2pHost(gsData.Host2) + + // create a selector for the whole UnixFS dag + gsData.AllSelector = allSelector + + return gsData +} + +// SetupGraphsyncHost1 sets up a new, real graphsync instance on top of the first host +func (gsData *GraphsyncTestingData) SetupGraphsyncHost1() graphsync.GraphExchange { + // setup graphsync + return gsimpl.New(gsData.Ctx, gsData.GsNet1, gsData.Loader1, gsData.Storer1) +} + +// SetupGraphsyncHost2 sets up a new, real graphsync instance on top of the second host +func (gsData *GraphsyncTestingData) SetupGraphsyncHost2() graphsync.GraphExchange { + // setup graphsync + return gsimpl.New(gsData.Ctx, gsData.GsNet2, gsData.Loader2, gsData.Storer2) +} + +// LoadUnixFSFile loads a fixtures file we can test dag transfer with +func (gsData *GraphsyncTestingData) LoadUnixFSFile(t *testing.T, useSecondNode bool) ipld.Link { + _, curFile, _, ok := runtime.Caller(0) + require.True(t, ok) + + // read in a fixture file + path := filepath.Join(path.Dir(curFile), "fixtures", "lorem.txt") + + f, err := os.Open(path) + require.NoError(t, err) + + var buf bytes.Buffer + tr := io.TeeReader(f, &buf) + file := files.NewReaderFile(tr) + + // import to UnixFS + var dagService ipldformat.DAGService + if useSecondNode { + dagService = gsData.DagService2 + } else { + dagService = gsData.DagService1 + } + bufferedDS := ipldformat.NewBufferedDAG(gsData.Ctx, dagService) + + params := ihelper.DagBuilderParams{ + Maxlinks: unixfsLinksPerLevel, + RawLeaves: true, + CidBuilder: nil, + Dagserv: bufferedDS, + } + + db, err := params.New(chunker.NewSizeSplitter(file, int64(unixfsChunkSize))) + require.NoError(t, err) + + nd, err := balanced.Layout(db) + require.NoError(t, err) + + err = bufferedDS.Commit() + require.NoError(t, err) + + // save the original files bytes + gsData.OrigBytes = buf.Bytes() + + return cidlink.Link{Cid: nd.Cid()} +} + +// VerifyFileTransferred verifies all of the file was transfer to the given node +func (gsData *GraphsyncTestingData) VerifyFileTransferred(t *testing.T, link ipld.Link, useSecondNode bool) { + var dagService ipldformat.DAGService + if useSecondNode { + dagService = gsData.DagService2 + } else { + dagService = gsData.DagService1 + } + + c := link.(cidlink.Link).Cid + + // load the root of the UnixFS DAG from the new blockstore + otherNode, err := dagService.Get(gsData.Ctx, c) + require.NoError(t, err) + + // Setup a UnixFS file reader + n, err := unixfile.NewUnixfsFile(gsData.Ctx, dagService, otherNode) + require.NoError(t, err) + + fn, ok := n.(files.File) + require.True(t, ok) + + // Read the bytes for the UnixFS File + finalBytes, err := ioutil.ReadAll(fn) + require.NoError(t, err) + + // verify original bytes match final bytes! + require.EqualValues(t, gsData.OrigBytes, finalBytes) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/testutil/testutil.go b/vendor/github.com/filecoin-project/go-data-transfer/testutil/testutil.go new file mode 100644 index 0000000000..da2d0f1646 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/testutil/testutil.go @@ -0,0 +1,95 @@ +package testutil + +import ( + "bytes" + "testing" + + "github.com/filecoin-project/go-data-transfer/message" + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + blocksutil "github.com/ipfs/go-ipfs-blocksutil" + "github.com/jbenet/go-random" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/stretchr/testify/require" +) + +var blockGenerator = blocksutil.NewBlockGenerator() + +//var prioritySeq int +var seedSeq int64 + +// RandomBytes returns a byte array of the given size with random values. +func RandomBytes(n int64) []byte { + data := new(bytes.Buffer) + random.WritePseudoRandomBytes(n, data, seedSeq) // nolint: gosec,errcheck + seedSeq++ + return data.Bytes() +} + +// GenerateBlocksOfSize generates a series of blocks of the given byte size +func GenerateBlocksOfSize(n int, size int64) []blocks.Block { + generatedBlocks := make([]blocks.Block, 0, n) + for i := 0; i < n; i++ { + b := blocks.NewBlock(RandomBytes(size)) + generatedBlocks = append(generatedBlocks, b) + + } + return generatedBlocks +} + +// GenerateCids produces n content identifiers. +func GenerateCids(n int) []cid.Cid { + cids := make([]cid.Cid, 0, n) + for i := 0; i < n; i++ { + c := blockGenerator.Next().Cid() + cids = append(cids, c) + } + return cids +} + +var peerSeq int + +// GeneratePeers creates n peer ids. +func GeneratePeers(n int) []peer.ID { + peerIds := make([]peer.ID, 0, n) + for i := 0; i < n; i++ { + peerSeq++ + p := peer.ID(peerSeq) + peerIds = append(peerIds, p) + } + return peerIds +} + +// ContainsPeer returns true if a peer is found n a list of peers. +func ContainsPeer(peers []peer.ID, p peer.ID) bool { + for _, n := range peers { + if p == n { + return true + } + } + return false +} + +// IndexOf returns the index of a given cid in an array of blocks +func IndexOf(blks []blocks.Block, c cid.Cid) int { + for i, n := range blks { + if n.Cid() == c { + return i + } + } + return -1 +} + +// ContainsBlock returns true if a block is found n a list of blocks +func ContainsBlock(blks []blocks.Block, block blocks.Block) bool { + return IndexOf(blks, block.Cid()) != -1 +} + +// AssertEqualSelector asserts two requests have the same valid selector +func AssertEqualSelector(t *testing.T, expectedRequest message.DataTransferRequest, request message.DataTransferRequest) { + expectedSelector, err := expectedRequest.Selector() + require.NoError(t, err) + selector, err := request.Selector() + require.NoError(t, err) + require.Equal(t, expectedSelector, selector) +} diff --git a/vendor/github.com/filecoin-project/go-data-transfer/tools.go b/vendor/github.com/filecoin-project/go-data-transfer/tools.go new file mode 100644 index 0000000000..51b8ceae58 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/tools.go @@ -0,0 +1,7 @@ +// +build tools + +package tools + +import ( + _ "github.com/hannahhoward/cbor-gen-for" +) diff --git a/vendor/github.com/filecoin-project/go-data-transfer/types.go b/vendor/github.com/filecoin-project/go-data-transfer/types.go new file mode 100644 index 0000000000..552e56edcc --- /dev/null +++ b/vendor/github.com/filecoin-project/go-data-transfer/types.go @@ -0,0 +1,169 @@ +package datatransfer + +import ( + "context" + "time" + + "github.com/filecoin-project/go-data-transfer/encoding" + "github.com/ipfs/go-cid" + "github.com/ipld/go-ipld-prime" + "github.com/libp2p/go-libp2p-core/peer" +) + +// TypeIdentifier is a unique string identifier for a type of encodable object in a +// registry +type TypeIdentifier string + +// Registerable is a type of object in a registry. It must be encodable and must +// have a single method that uniquely identifies its type +type Registerable interface { + encoding.Encodable + // Type is a unique string identifier for this voucher type + Type() TypeIdentifier +} + +// Voucher is used to validate +// a data transfer request against the underlying storage or retrieval deal +// that precipitated it. The only requirement is a voucher can read and write +// from bytes, and has a string identifier type +type Voucher Registerable + +// Status is the status of transfer for a given channel +type Status int + +const ( + // Ongoing means the data transfer is in progress + Ongoing Status = iota + + // Completed means the data transfer is completed successfully + Completed + + // Failed means the data transfer failed + Failed + + // ChannelNotFoundError means the searched for data transfer does not exist + ChannelNotFoundError +) + +// TransferID is an identifier for a data transfer, shared between +// request/responder and unique to the requester +type TransferID uint64 + +// ChannelID is a unique identifier for a channel, distinct by both the other +// party's peer ID + the transfer ID +type ChannelID struct { + Initiator peer.ID + ID TransferID +} + +// Channel represents all the parameters for a single data transfer +type Channel interface { + // TransferID returns the transfer id for this channel + TransferID() TransferID + + // BaseCID returns the CID that is at the root of this data transfer + BaseCID() cid.Cid + + // Selector returns the IPLD selector for this data transfer (represented as + // an IPLD node) + Selector() ipld.Node + + // Voucher returns the voucher for this data transfer + Voucher() Voucher + + // Sender returns the peer id for the node that is sending data + Sender() peer.ID + + // Recipient returns the peer id for the node that is receiving data + Recipient() peer.ID + + // TotalSize returns the total size for the data being transferred + TotalSize() uint64 +} + +// ChannelState is channel parameters plus it's current state +type ChannelState interface { + Channel + + // Sent returns the number of bytes sent + Sent() uint64 + + // Received returns the number of bytes received + Received() uint64 +} + +// EventCode is a name for an event that occurs on a data transfer channel +type EventCode int + +const ( + // Open is an event occurs when a channel is first opened + Open EventCode = iota + + // Progress is an event that gets emitted every time more data is transferred + Progress + + // Error is an event that emits when an error occurs in a data transfer + Error + + // Complete is emitted when a data transfer is complete + Complete +) + +// Event is a struct containing information about a data transfer event +type Event struct { + Code EventCode // What type of event it is + Message string // Any clarifying information about the event + Timestamp time.Time // when the event happened +} + +// Subscriber is a callback that is called when events are emitted +type Subscriber func(event Event, channelState ChannelState) + +// Unsubscribe is a function that gets called to unsubscribe from data transfer events +type Unsubscribe func() + +// RequestValidator is an interface implemented by the client of the +// data transfer module to validate requests +type RequestValidator interface { + // ValidatePush validates a push request received from the peer that will send data + ValidatePush( + sender peer.ID, + voucher Voucher, + baseCid cid.Cid, + selector ipld.Node) error + // ValidatePull validates a pull request received from the peer that will receive data + ValidatePull( + receiver peer.ID, + voucher Voucher, + baseCid cid.Cid, + selector ipld.Node) error +} + +// Manager is the core interface presented by all implementations of +// of the data transfer sub system +type Manager interface { + // RegisterVoucherType registers a validator for the given voucher type + // will error if voucher type does not implement voucher + // or if there is a voucher type registered with an identical identifier + RegisterVoucherType(voucherType Voucher, validator RequestValidator) error + + // open a data transfer that will send data to the recipient peer and + // transfer parts of the piece that match the selector + OpenPushDataChannel(ctx context.Context, to peer.ID, voucher Voucher, baseCid cid.Cid, selector ipld.Node) (ChannelID, error) + + // open a data transfer that will request data from the sending peer and + // transfer parts of the piece that match the selector + OpenPullDataChannel(ctx context.Context, to peer.ID, voucher Voucher, baseCid cid.Cid, selector ipld.Node) (ChannelID, error) + + // close an open channel (effectively a cancel) + CloseDataTransferChannel(x ChannelID) + + // get status of a transfer + TransferChannelStatus(x ChannelID) Status + + // get notified when certain types of events happen + SubscribeToEvents(subscriber Subscriber) Unsubscribe + + // get all in progress transfers + InProgressChannels() map[ChannelID]ChannelState +} diff --git a/vendor/github.com/filecoin-project/go-fil-markets/.circleci/config.yml b/vendor/github.com/filecoin-project/go-fil-markets/.circleci/config.yml new file mode 100644 index 0000000000..1e0afe2124 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/.circleci/config.yml @@ -0,0 +1,198 @@ +version: 2.1 +orbs: + go: gotest/tools@0.0.9 + codecov: codecov/codecov@1.0.2 + node: circleci/node@3.0.0 + +executors: + golang: + docker: + - image: circleci/golang:1.13-node + resource_class: large + +commands: + install-deps: + steps: + - go/install-ssh + - go/install: {package: git} + prepare: + parameters: + linux: + default: true + description: is a linux build environment? + type: boolean + steps: + - checkout + - when: + condition: << parameters.linux >> + steps: + - run: sudo apt-get update + - run: sudo apt-get install ocl-icd-opencl-dev + - run: git submodule sync + - run: git submodule update --init + build-all: + + +jobs: + mod-tidy-check: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - go/mod-tidy-check + + cbor-gen-check: + executor: golang + steps: + - install-deps + - prepare + - run: go install golang.org/x/tools/cmd/goimports + - run: go install github.com/hannahhoward/cbor-gen-for + - run: go generate ./... + - run: git --no-pager diff + - run: git --no-pager diff --quiet + + + docs-check: + executor: golang + steps: + - install-deps + - prepare + - run: + name: Install Headless Chrome Dependencies + command: | + sudo apt-get install -yq \ + gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \ + libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \ + libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 \ + libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates \ + fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget + - node/install-packages + - run: make diagrams + - run: git --no-pager diff + - run: git --no-pager diff --quiet + + build-all: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - run: sudo apt-get update + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go-fil-markets/go.mod" }} + - run: + command: make build + - store_artifacts: + path: go-fil-markets + - store_artifacts: + path: go-fil-markets + + test: &test + description: | + Run tests with gotestsum. + parameters: + executor: + type: executor + default: golang + test-suite-name: + type: string + default: unit + description: Test suite name to report to CircleCI. + codecov-upload: + type: boolean + default: true + description: | + Upload coverage report to https://codecov.io/. Requires the codecov API token to be + set as an environment variable for private projects. + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - go/mod-download + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - go/install-gotestsum: + gobin: $HOME/.local/bin + - run: + name: make test + environment: + GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml + command: | + mkdir -p /tmp/test-reports/<< parameters.test-suite-name >> + make test + no_output_timeout: 30m + - store_test_results: + path: /tmp/test-reports + - when: + condition: << parameters.codecov-upload >> + steps: + - go/install: {package: bash} + - go/install: {package: curl} + - run: + shell: /bin/bash -eo pipefail + command: | + bash <(curl -s https://codecov.io/bash) + - save_cache: + name: save go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + paths: + - "~/go/pkg" + - "~/go/src/github.com" + - "~/go/src/golang.org" + + lint: &lint + description: | + Run golangci-lint. + parameters: + executor: + type: executor + default: golang + golangci-lint-version: + type: string + default: 1.21.0 + concurrency: + type: string + default: '2' + description: | + Concurrency used to run linters. Defaults to 2 because NumCPU is not + aware of container CPU limits. + args: + type: string + default: '' + description: | + Arguments to pass to golangci-lint + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - run: + command: make build + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: << parameters.golangci-lint-version >> + - run: + name: Lint + command: | + $HOME/.local/bin/golangci-lint run -v \ + --concurrency << parameters.concurrency >> << parameters.args >> + lint-changes: + <<: *lint + + lint-all: + <<: *lint + +workflows: + version: 2.1 + ci: + jobs: + - lint-changes: + args: "--new-from-rev origin/master" + - test + - mod-tidy-check + - cbor-gen-check + - docs-check + - build-all diff --git a/vendor/github.com/filecoin-project/go-fil-markets/CHANGELOG.md b/vendor/github.com/filecoin-project/go-fil-markets/CHANGELOG.md new file mode 100644 index 0000000000..4129891195 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/CHANGELOG.md @@ -0,0 +1,440 @@ +# go-fil-markets changelog + +# go-fil-markets 0.1.0 + +Initial tagged release for Filecoin Testnet Phase 2 + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(release): document release process (#206) ([filecoin-project/go-fil-markets#206](https://github.com/filecoin-project/go-fil-markets/pull/206)) + - update types_cbor_gen (#203) ([filecoin-project/go-fil-markets#203](https://github.com/filecoin-project/go-fil-markets/pull/203)) + - Upgrade to specs-actors v0.2.0 (#204) ([filecoin-project/go-fil-markets#204](https://github.com/filecoin-project/go-fil-markets/pull/204)) + - Storagemarket/provider allows subscription to events (#202) ([filecoin-project/go-fil-markets#202](https://github.com/filecoin-project/go-fil-markets/pull/202)) + - Add a test rule to Makefile, use in CI config (#200) ([filecoin-project/go-fil-markets#200](https://github.com/filecoin-project/go-fil-markets/pull/200)) + - Update to specs-actors v1.0.0 (#198) ([filecoin-project/go-fil-markets#198](https://github.com/filecoin-project/go-fil-markets/pull/198)) + - add multiple peers per payloadCID (#197) ([filecoin-project/go-fil-markets#197](https://github.com/filecoin-project/go-fil-markets/pull/197)) + - refactor(storedcounter): use extracted package (#196) ([filecoin-project/go-fil-markets#196](https://github.com/filecoin-project/go-fil-markets/pull/196)) + - Feat/no block chain ops (#190) ([filecoin-project/go-fil-markets#190](https://github.com/filecoin-project/go-fil-markets/pull/190)) + - Add a max piece size to storage asks (#188) ([filecoin-project/go-fil-markets#188](https://github.com/filecoin-project/go-fil-markets/pull/188)) + - Update proofs to v25 params (#189) ([filecoin-project/go-fil-markets#189](https://github.com/filecoin-project/go-fil-markets/pull/189)) + - Update Graphsync (#184) ([filecoin-project/go-fil-markets#184](https://github.com/filecoin-project/go-fil-markets/pull/184)) + - Support selectors on retrieval (#187) ([filecoin-project/go-fil-markets#187](https://github.com/filecoin-project/go-fil-markets/pull/187)) + - Add optional PieceCID to block unsealing (#186) ([filecoin-project/go-fil-markets#186](https://github.com/filecoin-project/go-fil-markets/pull/186)) + - Add Selector to retrieval params (#175) ([filecoin-project/go-fil-markets#175](https://github.com/filecoin-project/go-fil-markets/pull/175)) + - use PieceCID if provided in QueryParams (#181) ([filecoin-project/go-fil-markets#181](https://github.com/filecoin-project/go-fil-markets/pull/181)) + - include rejection reason in client response (#182) ([filecoin-project/go-fil-markets#182](https://github.com/filecoin-project/go-fil-markets/pull/182)) + - Do not create CAR file when propsing a storage deal using Manual Transfer (#183) ([filecoin-project/go-fil-markets#183](https://github.com/filecoin-project/go-fil-markets/pull/183)) + - add selector to BlockIO classes (#178) ([filecoin-project/go-fil-markets#178](https://github.com/filecoin-project/go-fil-markets/pull/178)) + - rename list deals interface & impls (#174) ([filecoin-project/go-fil-markets#174](https://github.com/filecoin-project/go-fil-markets/pull/174)) + - Feat/configure start epoch buffer (#171) ([filecoin-project/go-fil-markets#171](https://github.com/filecoin-project/go-fil-markets/pull/171)) + - send tipset identifier to node when interacting with chain (#172) ([filecoin-project/go-fil-markets#172](https://github.com/filecoin-project/go-fil-markets/pull/172)) + - Support Retrieval By Any CID, Not Just Root (#166) ([filecoin-project/go-fil-markets#166](https://github.com/filecoin-project/go-fil-markets/pull/166)) + - v24 groth parameters (#167) ([filecoin-project/go-fil-markets#167](https://github.com/filecoin-project/go-fil-markets/pull/167)) + - Add TipSetToken to SavePaymentVoucher (#165) ([filecoin-project/go-fil-markets#165](https://github.com/filecoin-project/go-fil-markets/pull/165)) + - retrieval client node interface passes tipset identifier to node (#164) ([filecoin-project/go-fil-markets#164](https://github.com/filecoin-project/go-fil-markets/pull/164)) + - send state identifiery when getting miner worker address (#153) ([filecoin-project/go-fil-markets#153](https://github.com/filecoin-project/go-fil-markets/pull/153)) + - chore(deps): update to ipld/go-car (#152) ([filecoin-project/go-fil-markets#152](https://github.com/filecoin-project/go-fil-markets/pull/152)) + - add TipSet identity-producing method to various Node interfaces (#149) ([filecoin-project/go-fil-markets#149](https://github.com/filecoin-project/go-fil-markets/pull/149)) + - conform imports to schema defined in CONTRIBUTING.md (#150) ([filecoin-project/go-fil-markets#150](https://github.com/filecoin-project/go-fil-markets/pull/150)) + - Refactor Storage Provider to FSM Module (#145) ([filecoin-project/go-fil-markets#145](https://github.com/filecoin-project/go-fil-markets/pull/145)) + - Feat/update to fix 32gib verification (#147) ([filecoin-project/go-fil-markets#147](https://github.com/filecoin-project/go-fil-markets/pull/147)) + - ci(codecov): remove cbor gen files from coverage + - ci(codecov): ignore cbor gen files (#146) ([filecoin-project/go-fil-markets#146](https://github.com/filecoin-project/go-fil-markets/pull/146)) + - Storage Client Statemachine Refactor (#136) ([filecoin-project/go-fil-markets#136](https://github.com/filecoin-project/go-fil-markets/pull/136)) + - upgrade to libfilecoin version that supports cache clearing (#138) ([filecoin-project/go-fil-markets#138](https://github.com/filecoin-project/go-fil-markets/pull/138)) + - fix(cborgen): update cbor gen for dataref (#137) ([filecoin-project/go-fil-markets#137](https://github.com/filecoin-project/go-fil-markets/pull/137)) + - allow manual piece commitment (#135) ([filecoin-project/go-fil-markets#135](https://github.com/filecoin-project/go-fil-markets/pull/135)) + - fix(retrievalmarket): handle self-retrieval correctly (#134) ([filecoin-project/go-fil-markets#134](https://github.com/filecoin-project/go-fil-markets/pull/134)) + - feat(retrievalmarket): support wallet address (#130) ([filecoin-project/go-fil-markets#130](https://github.com/filecoin-project/go-fil-markets/pull/130)) + - allow specification of 'wallet' for ensure funds calls (#129) ([filecoin-project/go-fil-markets#129](https://github.com/filecoin-project/go-fil-markets/pull/129)) + - update to filecoin-ffi with shared types (#127) ([filecoin-project/go-fil-markets#127](https://github.com/filecoin-project/go-fil-markets/pull/127)) + - feat(sharedcounter): persist counter to disk (#125) ([filecoin-project/go-fil-markets#125](https://github.com/filecoin-project/go-fil-markets/pull/125)) + - Use go-statemachine + FSMs in retrieval market (#124) ([filecoin-project/go-fil-markets#124](https://github.com/filecoin-project/go-fil-markets/pull/124)) + - storage client: Call EnsureFunds more correctly (#123) ([filecoin-project/go-fil-markets#123](https://github.com/filecoin-project/go-fil-markets/pull/123)) + - use latest specs-actors with uint64 lane and nonce from paych.Actor (#122) ([filecoin-project/go-fil-markets#122](https://github.com/filecoin-project/go-fil-markets/pull/122)) + - Update go-sectorbuilder to latest that uses specs-actors types (#121) ([filecoin-project/go-fil-markets#121](https://github.com/filecoin-project/go-fil-markets/pull/121)) + - Import spec actor types (#118) ([filecoin-project/go-fil-markets#118](https://github.com/filecoin-project/go-fil-markets/pull/118)) + - Update README (#120) ([filecoin-project/go-fil-markets#120](https://github.com/filecoin-project/go-fil-markets/pull/120)) + - chore(cborgen): update cborgen + - Merge branch 'head/lotus' into lotus/merge-02-10-2020 + - Storage Market integration test (#119) ([filecoin-project/go-fil-markets#119](https://github.com/filecoin-project/go-fil-markets/pull/119)) + - fix(storagemarket): add back in cid recording (#115) ([filecoin-project/go-fil-markets#115](https://github.com/filecoin-project/go-fil-markets/pull/115)) + - fix(storagemarket): assign net member (#114) ([filecoin-project/go-fil-markets#114](https://github.com/filecoin-project/go-fil-markets/pull/114)) + - Fix/flaky tests (#113) ([filecoin-project/go-fil-markets#113](https://github.com/filecoin-project/go-fil-markets/pull/113)) + - Storage market network abstraction (#109) ([filecoin-project/go-fil-markets#109](https://github.com/filecoin-project/go-fil-markets/pull/109)) + - Remove Sector ID from MinerDeal (merge from head/lotus -- PLEASE USE MERGE COMMIT) ([filecoin-project/go-fil-markets#112](https://github.com/filecoin-project/go-fil-markets/pull/112)) + - No Filestore On Storage Client (#107) ([filecoin-project/go-fil-markets#107](https://github.com/filecoin-project/go-fil-markets/pull/107)) + - take miner address as parameter (#108) ([filecoin-project/go-fil-markets#108](https://github.com/filecoin-project/go-fil-markets/pull/108)) + - skip flaky 1 block tests (#104) ([filecoin-project/go-fil-markets#104](https://github.com/filecoin-project/go-fil-markets/pull/104)) + - use go-padreader instead of local copy (#103) ([filecoin-project/go-fil-markets#103](https://github.com/filecoin-project/go-fil-markets/pull/103)) + - Handle sector id in the `OnDealSectorCommitted` callback (#58) ([filecoin-project/go-fil-markets#58](https://github.com/filecoin-project/go-fil-markets/pull/58)) + - Properly Implement Retrieval Lookups Based on CIDs (#57) ([filecoin-project/go-fil-markets#57](https://github.com/filecoin-project/go-fil-markets/pull/57)) + - Add Stop funcs to retrieval providers (#56) ([filecoin-project/go-fil-markets#56](https://github.com/filecoin-project/go-fil-markets/pull/56)) + - refactor(retrievalmarket): switch to payload CIDs (#55) ([filecoin-project/go-fil-markets#55](https://github.com/filecoin-project/go-fil-markets/pull/55)) + - Move to an explicit piecestore and explicit unsealing. (#54) ([filecoin-project/go-fil-markets#54](https://github.com/filecoin-project/go-fil-markets/pull/54)) + - Improve test coverage, fix any bugs (#53) ([filecoin-project/go-fil-markets#53](https://github.com/filecoin-project/go-fil-markets/pull/53)) + - Techdebt/1 block file retrieval test (#51) ([filecoin-project/go-fil-markets#51](https://github.com/filecoin-project/go-fil-markets/pull/51)) + - ci(config): use large resource_class (#52) ([filecoin-project/go-fil-markets#52](https://github.com/filecoin-project/go-fil-markets/pull/52)) + - Sync up DealState to match spec (#50) ([filecoin-project/go-fil-markets#50](https://github.com/filecoin-project/go-fil-markets/pull/50)) + - Support arbitrary dag retrieval (#46) ([filecoin-project/go-fil-markets#46](https://github.com/filecoin-project/go-fil-markets/pull/46)) + - RetrievalMarket: Query + Deal integration test, + bug fixes uncovered during writing the test (#36) ([filecoin-project/go-fil-markets#36](https://github.com/filecoin-project/go-fil-markets/pull/36)) + - Remove filestore as a go between with StorageMiner, pass direct io.reader to StorageMiner (#49) ([filecoin-project/go-fil-markets#49](https://github.com/filecoin-project/go-fil-markets/pull/49)) + - Feat/find providers (#43) ([filecoin-project/go-fil-markets#43](https://github.com/filecoin-project/go-fil-markets/pull/43)) + - Retrieval Deals, Spec V0 (#37) ([filecoin-project/go-fil-markets#37](https://github.com/filecoin-project/go-fil-markets/pull/37)) + - Lotus updates ([filecoin-project/go-fil-markets#45](https://github.com/filecoin-project/go-fil-markets/pull/45)) + - storagemarket: close channel on return (#42) ([filecoin-project/go-fil-markets#42](https://github.com/filecoin-project/go-fil-markets/pull/42)) + - Feat/verify data before publishing deal (#40) ([filecoin-project/go-fil-markets#40](https://github.com/filecoin-project/go-fil-markets/pull/40)) + - Use CAR and padding for piece data (#27) ([filecoin-project/go-fil-markets#27](https://github.com/filecoin-project/go-fil-markets/pull/27)) + - Upgrade Query Protocol to Spec V0 (#25) ([filecoin-project/go-fil-markets#25](https://github.com/filecoin-project/go-fil-markets/pull/25)) + - Merge branch 'lotus-updates' + - fix(retrievalmarket): add mutex around subscribers (#32) (#33) ([filecoin-project/go-fil-markets#33](https://github.com/filecoin-project/go-fil-markets/pull/33)) + - ci(codecov): disable status, display report (#31) ([filecoin-project/go-fil-markets#31](https://github.com/filecoin-project/go-fil-markets/pull/31)) + - Flaky test fix (#28) ([filecoin-project/go-fil-markets#28](https://github.com/filecoin-project/go-fil-markets/pull/28)) + - skip flaky test (#30) ([filecoin-project/go-fil-markets#30](https://github.com/filecoin-project/go-fil-markets/pull/30)) + - Network Abstraction For Retrieval Market (#17) ([filecoin-project/go-fil-markets#17](https://github.com/filecoin-project/go-fil-markets/pull/17)) + - Use CAR file in generation of CommP (#26) ([filecoin-project/go-fil-markets#26](https://github.com/filecoin-project/go-fil-markets/pull/26)) + - filestore: track close err, lints (#20) ([filecoin-project/go-fil-markets#20](https://github.com/filecoin-project/go-fil-markets/pull/20)) + - Deleting datatransfer files (#19) ([filecoin-project/go-fil-markets#19](https://github.com/filecoin-project/go-fil-markets/pull/19)) + - Use shared go-filecoin packages go-cbor-util, go-address, go-crypto, (#22) ([filecoin-project/go-fil-markets#22](https://github.com/filecoin-project/go-fil-markets/pull/22)) + - Storage Market Extraction (#15) ([filecoin-project/go-fil-markets#15](https://github.com/filecoin-project/go-fil-markets/pull/15)) + - Retrieval Market Extraction (#13) ([filecoin-project/go-fil-markets#13](https://github.com/filecoin-project/go-fil-markets/pull/13)) + - PieceIO improvements (#12) ([filecoin-project/go-fil-markets#12](https://github.com/filecoin-project/go-fil-markets/pull/12)) + - fix links in datatransfer README (#11) ([filecoin-project/go-fil-markets#11](https://github.com/filecoin-project/go-fil-markets/pull/11)) + - fix(build): fix tools build error (#14) ([filecoin-project/go-fil-markets#14](https://github.com/filecoin-project/go-fil-markets/pull/14)) + - fix(tokenamount): fix naming (#10) ([filecoin-project/go-fil-markets#10](https://github.com/filecoin-project/go-fil-markets/pull/10)) + - feat(shared): add shared tools and types (#9) ([filecoin-project/go-fil-markets#9](https://github.com/filecoin-project/go-fil-markets/pull/9)) + - add circle config, let's ci ([filecoin-project/go-fil-markets#7](https://github.com/filecoin-project/go-fil-markets/pull/7)) + - Skeleton readme ([filecoin-project/go-fil-markets#5](https://github.com/filecoin-project/go-fil-markets/pull/5)) + - Feat/datatransfer readme, contributing, design doc (rename) + - Piece IO ([filecoin-project/go-fil-markets#2](https://github.com/filecoin-project/go-fil-markets/pull/2)) + - Feat/datatransfer graphsync movein ([filecoin-project/go-fil-markets#1](https://github.com/filecoin-project/go-fil-markets/pull/1)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 38 | +27080/-10375 | 455 | +| Ingar Shu | 10 | +1315/-6870 | 127 | +| shannonwells | 12 | +5500/-70 | 48 | +| Shannon Wells | 20 | +2671/-940 | 109 | +| ergastic | 4 | +1835/-501 | 47 | +| Erin Swenson-Healey | 9 | +516/-408 | 112 | +| hannahhoward | 10 | +497/-150 | 79 | +| Łukasz Magiera | 4 | +379/-139 | 19 | +| whyrusleeping | 3 | +239/-87 | 19 | +| Whyrusleeping | 4 | +192/-96 | 26 | +| Aayush Rajasekaran | 3 | +93/-13 | 14 | +| Mosh | 2 | +37/-8 | 2 | +| Ignacio Hagopian | 2 | +9/-11 | 2 | +| Alex North | 2 | +11/-7 | 4 | +| Alex Cruikshank | 1 | +1/-9 | 1 | + +# go-fil-markets 0.1.1 + +Hotfix release for spec actors update + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - chore(changelog): update changelog for tagged release + - Upgrade to specs-actors v0.3.0 (#207) ([filecoin-project/go-fil-markets#207](https://github.com/filecoin-project/go-fil-markets/pull/207)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| hannahhoward | 1 | +9/-1 | 1 | +| Alex North | 1 | +3/-3 | 2 | + +# go-fil-markets 0.1.2 + +Hotfix release for transitive dependencies to use new go-ipld-prime + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): update changelog + - Upgrade IPLD-prime to latest (#215) ([filecoin-project/go-fil-markets#215](https://github.com/filecoin-project/go-fil-markets/pull/215)) +- github.com/filecoin-project/go-data-transfer (v0.0.0-20200408061858-82c58b423ca6 -> v0.2.0): + - Upgrade graphsync + ipld-prime (#49) ([filecoin-project/go-data-transfer#49](https://github.com/filecoin-project/go-data-transfer/pull/49)) + - Use extracted generic pubsub (#48) ([filecoin-project/go-data-transfer#48](https://github.com/filecoin-project/go-data-transfer/pull/48)) + - Refactor & Cleanup In Preparation For Added Complexity (#47) ([filecoin-project/go-data-transfer#47](https://github.com/filecoin-project/go-data-transfer/pull/47)) + - feat(graphsync): complete notifications for responder (#46) ([filecoin-project/go-data-transfer#46](https://github.com/filecoin-project/go-data-transfer/pull/46)) +- github.com/ipfs/go-graphsync (v0.0.6-0.20200408061628-e1a98fc64c42 -> v0.0.6-0.20200428204348-97a8cf76a482): + - refactor(hooks): use external pubsub (#65) ([ipfs/go-graphsync#65](https://github.com/ipfs/go-graphsync/pull/65)) + - Update of IPLD Prime (#66) ([ipfs/go-graphsync#66](https://github.com/ipfs/go-graphsync/pull/66)) + - Add standard issue template + - feat(responsemanager): add listener for completed responses (#64) ([ipfs/go-graphsync#64](https://github.com/ipfs/go-graphsync/pull/64)) + - Update Requests (#63) ([ipfs/go-graphsync#63](https://github.com/ipfs/go-graphsync/pull/63)) + - Add pausing and unpausing of requests (#62) ([ipfs/go-graphsync#62](https://github.com/ipfs/go-graphsync/pull/62)) + - ci(circle): remove benchmark task for now + - ci(circle): update orb + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 10 | +5409/-4023 | 151 | +| Hector Sanjuan | 1 | +27/-0 | 2 | +| hannahhoward | 3 | +16/-8 | 5 | + + +# go-fil-markets 0.1.3 + +Hotfix release for critical graphsync bug fix + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): add release documentation + - fix(deps): update to tagged data transfer + - chore(deps): update data transfer + graphsync +- github.com/filecoin-project/go-data-transfer (v0.2.0 -> v0.2.1): + - chore(deps): update graphsync +- github.com/ipfs/go-graphsync (v0.0.6-0.20200428204348-97a8cf76a482 -> v0.0.6-0.20200504202014-9d5f2c26a103): + - fix(responsemanager): add nil check (#67) ([ipfs/go-graphsync#67](https://github.com/ipfs/go-graphsync/pull/67)) + - Add autocomment configuration + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hector Sanjuan | 1 | +68/-0 | 1 | +| hannahhoward | 4 | +20/-12 | 7 | +| Hannah Howard | 1 | +4/-0 | 1 | + +# go-fil-markets 0.2.0 + +Asynchronous operations release -- we no longer synchronously wait for chain messages to push + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): update changelog for 0.2.0 release + - Storage Market Changes Based On Lotus Integration (#223) ([filecoin-project/go-fil-markets#223](https://github.com/filecoin-project/go-fil-markets/pull/223)) + - Merge in hotfix 0.1.3 ([filecoin-project/go-fil-markets#225](https://github.com/filecoin-project/go-fil-markets/pull/225)) + - ppl can sub to storage client evts (#217) ([filecoin-project/go-fil-markets#217](https://github.com/filecoin-project/go-fil-markets/pull/217)) + - fix(storagemarket): set miner peer id on deals (#216) ([filecoin-project/go-fil-markets#216](https://github.com/filecoin-project/go-fil-markets/pull/216)) + - chore(release): merge hotfix 0.1.2 branch back + - docs(release): update release process (#212) ([filecoin-project/go-fil-markets#212](https://github.com/filecoin-project/go-fil-markets/pull/212)) + - Nonblocking storage deals [#80] (#194) ([filecoin-project/go-fil-markets#194](https://github.com/filecoin-project/go-fil-markets/pull/194)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Ingar Shu | 1 | +993/-608 | 13 | +| Hannah Howard | 3 | +101/-59 | 14 | +| Shannon Wells | 1 | +106/-31 | 5 | +| hannahhoward | 1 | +8/-0 | 1 | + +# go-fil-markets 0.2.1 + +Hotfix release -- updates to try to solve deal stream problems attempt #1 + +### Changelog +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): update for 0.2.1 release + - update to v26 proofs (#232) ([filecoin-project/go-fil-markets#232](https://github.com/filecoin-project/go-fil-markets/pull/232)) + - Don't Keep Streams Open (#230) ([filecoin-project/go-fil-markets#230](https://github.com/filecoin-project/go-fil-markets/pull/230)) + - Round-trip storage/retrieval test (#229) ([filecoin-project/go-fil-markets#229](https://github.com/filecoin-project/go-fil-markets/pull/229)) + - feat(storagemarket): improve human readable constant maps (#228) ([filecoin-project/go-fil-markets#228](https://github.com/filecoin-project/go-fil-markets/pull/228)) + - fix(deps): update data-transfer 0.3.0 (#227) ([filecoin-project/go-fil-markets#227](https://github.com/filecoin-project/go-fil-markets/pull/227)) + - docs(CHANGELOG): update changelog for 0.2.0 release ([filecoin-project/go-fil-markets#226](https://github.com/filecoin-project/go-fil-markets/pull/226)) +- github.com/filecoin-project/go-data-transfer (v0.2.1 -> v0.3.0): + - feat(graphsyncimpl): fix open/close events (#52) ([filecoin-project/go-data-transfer#52](https://github.com/filecoin-project/go-data-transfer/pull/52)) + - chore(deps): update graphsync ([filecoin-project/go-data-transfer#51](https://github.com/filecoin-project/go-data-transfer/pull/51)) + - Refactor registry and encoding (#50) ([filecoin-project/go-data-transfer#50](https://github.com/filecoin-project/go-data-transfer/pull/50)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 5 | +1841/-1303 | 59 | +| Shannon Wells | 1 | +511/-141 | 19 | +| hannahhoward | 1 | +11/-1 | 1 | +| Erin Swenson-Healey | 1 | +1/-1 | 1 | + +# go-fil-markets 0.2.2 + +Hotfix release -- updates to try to solve deal stream problems attempt #2 & v26 params update + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): docs for 0.2.2 release + - feat(storagemarket): revert protocol changes (#236) ([filecoin-project/go-fil-markets#236](https://github.com/filecoin-project/go-fil-markets/pull/236)) + - Feat/cbor gen check ci #231 (#234) ([filecoin-project/go-fil-markets#234](https://github.com/filecoin-project/go-fil-markets/pull/234)) + - update sector-storage and break transitive dependency on lotus (#235) ([filecoin-project/go-fil-markets#235](https://github.com/filecoin-project/go-fil-markets/pull/235)) + - docs(CHANGELOG): update for 0.2.1 release ([filecoin-project/go-fil-markets#233](https://github.com/filecoin-project/go-fil-markets/pull/233)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 1 | +701/-614 | 22 | +| Erin Swenson-Healey | 1 | +5/-265 | 2 | +| Shannon Wells | 1 | +11/-0 | 1 | +| hannahhoward | 1 | +8/-1 | 1 | + +# go-fil-markets 0.2.3 + +Hotfix release -- final fix for issues with deal streams held open + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - feat(CHANGELOG): update changelog for v0.2.3 + - feat(network): tag connections to preserve them (#246) ([filecoin-project/go-fil-markets#246](https://github.com/filecoin-project/go-fil-markets/pull/246)) + - docs(CHANGELOG): docs for 0.2.2 release ([filecoin-project/go-fil-markets#243](https://github.com/filecoin-project/go-fil-markets/pull/243)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 1 | +112/-7 | 10 | +| hannahhoward | 1 | +7/-1 | 1 | + +# go-fil-markets 0.2.4 + +go-filecoin compatibility release + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): update change log + - Buffer the done channel when adding storage collateral (#249) ([filecoin-project/go-fil-markets#249](https://github.com/filecoin-project/go-fil-markets/pull/249)) + - feat(CHANGELOG): update changelog for v0.2.3 ([filecoin-project/go-fil-markets#248](https://github.com/filecoin-project/go-fil-markets/pull/248)) + - Unified request validator (#247) ([filecoin-project/go-fil-markets#247](https://github.com/filecoin-project/go-fil-markets/pull/247)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Ingar Shu | 2 | +221/-230 | 7 | +| hannahhoward | 1 | +8/-0 | 1 | + +# go-fil-markets 0.2.5 + +go-filecoin compatibility release + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): update for 0.2.5 release + - Fixes from filecoin integration work (#253) ([filecoin-project/go-fil-markets#253](https://github.com/filecoin-project/go-fil-markets/pull/253)) + - docs(CHANGELOG): update change log ([filecoin-project/go-fil-markets#250](https://github.com/filecoin-project/go-fil-markets/pull/250)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 1 | +138/-68 | 7 | +| hannahhoward | 1 | +8/-3 | 3 | + +# go-fil-markets 0.2.6 + +Remove data store wrapping + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - Feat/change prefixes 256 (#257) ([filecoin-project/go-fil-markets#257](https://github.com/filecoin-project/go-fil-markets/pull/257)) + - docs(CHANGELOG): update for 0.2.5 release ([filecoin-project/go-fil-markets#254](https://github.com/filecoin-project/go-fil-markets/pull/254)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Shannon Wells | 1 | +6/-15 | 5 | + +# go-fil-markets 0.2.7 + +Custom Deal Decision Logic and cleanups of 0.2.6 + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - docs(CHANGELOG): update changelog for 0.2.7 + - refactor(storagemarket): remove storedask from provider (#263) ([filecoin-project/go-fil-markets#263](https://github.com/filecoin-project/go-fil-markets/pull/263)) + - Deal Decision Custom Function (#262) ([filecoin-project/go-fil-markets#262](https://github.com/filecoin-project/go-fil-markets/pull/262)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 2 | +142/-27 | 11 | +| shannonwells | 1 | +19/-6 | 1 | + +# go-fil-markets 0.3.0 + +Deal Resumability release. We now attempt to resume storage deals when the application is shut down and restart, and we support a more flexible deal acceptance protocol. + +### Changelog +- github.com/filecoin-project/go-fil-markets: + - fix(storagemarket): fix validator, add to test + - docs(CHANGELOG): update changelog and add detail script + - both StoredAsk and storage Provider are scoped to a single miner (#276) ([filecoin-project/go-fil-markets#276](https://github.com/filecoin-project/go-fil-markets/pull/276)) + - specs actors v0.6 (#274) ([filecoin-project/go-fil-markets#274](https://github.com/filecoin-project/go-fil-markets/pull/274)) + - Restartable storage deals (#270) ([filecoin-project/go-fil-markets#270](https://github.com/filecoin-project/go-fil-markets/pull/270)) + - replace AddAsk with SetAsk, to convey intent (#275) ([filecoin-project/go-fil-markets#275](https://github.com/filecoin-project/go-fil-markets/pull/275)) + - Allow custom decisioning for a provider to decide retrieval deals. (#269) ([filecoin-project/go-fil-markets#269](https://github.com/filecoin-project/go-fil-markets/pull/269)) + - Feat/module docs #83 (#267) ([filecoin-project/go-fil-markets#267](https://github.com/filecoin-project/go-fil-markets/pull/267)) + - Tentative acceptance protocol (#244) ([filecoin-project/go-fil-markets#244](https://github.com/filecoin-project/go-fil-markets/pull/244)) + - docs(CHANGELOG): update changelog for 0.2.7 ([filecoin-project/go-fil-markets#264](https://github.com/filecoin-project/go-fil-markets/pull/264)) +- github.com/filecoin-project/go-statemachine (v0.0.0-20200226041606-2074af6d51d9 -> v0.0.0-20200612181802-4eb3d0c68eba): + - Serialize notifications (#11) ([filecoin-project/go-statemachine#11](https://github.com/filecoin-project/go-statemachine/pull/11)) + - Run callback in goroutine (#10) ([filecoin-project/go-statemachine#10](https://github.com/filecoin-project/go-statemachine/pull/10)) + - Finality States ([filecoin-project/go-statemachine#9](https://github.com/filecoin-project/go-statemachine/pull/9)) + - Documentation, particularly for FSM Module (#8) ([filecoin-project/go-statemachine#8](https://github.com/filecoin-project/go-statemachine/pull/8)) + - Call stageDone on nil nextStep ([filecoin-project/go-statemachine#7](https://github.com/filecoin-project/go-statemachine/pull/7)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Ingar Shu | 4 | +1407/-695 | 35 | +| Shannon Wells | 2 | +1515/-467 | 20 | +| hannahhoward | 8 | +862/-191 | 21 | +| Hannah Howard | 1 | +263/-0 | 2 | +| Łukasz Magiera | 1 | +48/-43 | 15 | +| Erin Swenson-Healey | 2 | +39/-42 | 10 | + +# go-fil-markets 0.3.1 + +Hotfix release to get `use addresses from miner info for connecting to miners` task merged for downstream dependencies to used + +### Changelog +- github.com/filecoin-project/go-fil-markets: + - use addresses from miner info for connecting to miners (#290) ([filecoin-project/go-fil-markets#290](https://github.com/filecoin-project/go-fil-markets/pull/290)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Whyrusleeping | 1 | +53/-5 | 9 | + +# go-fil-markets 0.3.1.1 + +Hotfix bug release to address critical issues affecting node startup + +### Changelog + +- github.com/filecoin-project/go-fil-markets: + - add locks protecting retrieval market maps (#311) ([filecoin-project/go-fil-markets#311](https://github.com/filecoin-project/go-fil-markets/pull/311)) + - fix(storagemarket): run deal restarts in go routine (#309) ([filecoin-project/go-fil-markets#309](https://github.com/filecoin-project/go-fil-markets/pull/309)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Hannah Howard | 1 | +13/-7 | 2 | +| vyzo | 1 | +10/-0 | 1 | + +### 🙌🏽 Want to contribute? + +Would you like to contribute to this repo and don’t know how? Here are a few places you can get started: + +- Check out the [Contributing Guidelines](https://github.com/filecoin-project/go-fil-markets/blob/master/CONTRIBUTING.md) +- Look for issues with the `good-first-issue` label in [go-fil-markets](https://github.com/filecoin-project/go-fil-markets/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22e-good-first-issue%22+) diff --git a/vendor/github.com/filecoin-project/go-fil-markets/CONTRIBUTING.md b/vendor/github.com/filecoin-project/go-fil-markets/CONTRIBUTING.md new file mode 100644 index 0000000000..00c2471262 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/CONTRIBUTING.md @@ -0,0 +1,91 @@ +# Contributing to this repo + +First, thank you for your interest in contributing to this project! Before you pick up your first issue and start +changing code, please: + +1. Review all documentation for the module you're interested in. +1. Look through the [issues for this repo](https://github.com/filecoin-project/go-fil-markets/issues) for relevant discussions. +1. If you have questions about an issue, post a comment in the issue. +1. If you want to submit changes that aren't covered by an issue, file a new one with your proposal, outlining what problem you found/feature you want to implement, and how you intend to implement a solution. + +For best results, before submitting a PR, make sure: +1. It has met all acceptance criteria for the issue. +1. It addresses only the one issue and does not make other, irrelevant changes. +1. Your code conforms to our coding style guide. +1. You have adequate test coverage (this should be indicated by CI results anyway). +1. If you like, check out [current PRs](https://github.com/filecoin-project/go-fil-markets/pulls) to see how others do it. + +Special Note: +If editing README.md, please conform to the [standard readme specification](https://github.com/RichardLitt/standard-readme/blob/master/spec.md). + +### PR Process + +Active development of `go-fil-markets` occurs on the `master` branch. All PRs should be made to the `master` branch, which is the default branch on Github. + +Before a PR can be merged to `master`, it must: +1. Pass continuous integration. +1. Be rebased and up to date with the `master` branch +1. Be approved by at least two maintainers + +When merging normal PRs to `master`, always use squash and merge to maintain a linear commit history. + +### Release Process + +When creating a new full release, branch off master with a branch named release/*version-number*, where *version-number* is the ultimate tag you intend to create. + +Continue to develop on master and merge commits to your release branch as neccesary till the release is ready. + +When the release is ready, tag it, then merge the branch back into master so that it is part of the version history of master. Delete the release branch. + +### Hotfix Process + +Hot-fixes operate just like release branches, except they are branched off an existing tag and should be named hotfix/*version-number*. When ready, they receive their own tag and then are merged back to master, then deleted. + +For external reference, his git flow and release process is essentially the [OneFlow git workflow](https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow) + +Following the release of Filecoin Mainnet, this library will following a semantic versioning scheme for tagged releases. + +### Testing + +- All new code should be accompanied by unit tests. Prefer focused unit tests to integration tests for thorough validation of behaviour. Existing code is not necessarily a good model, here. +- Integration tests should test integration, not comprehensive functionality +- Tests should be placed in a separate package named `$PACKAGE_test`. For example, a test of the `chain` package should live in a package named `chain_test`. In limited situations, exceptions may be made for some "white box" tests placed in the same package as the code it tests. + +### Conventions and Style + +#### Imports +We use the following import ordering. +``` +import ( + [stdlib packages, alpha-sorted] + + [external packages] + + [go-fil-markets packages] +) +``` + +Where a package name does not match its directory name, an explicit alias is expected (`goimports` will add this for you). + +Example: + +```go +import ( + "context" + "testing" + + cmds "github.com/ipfs/go-ipfs-cmds" + cid "github.com/ipfs/go-cid" + ipld "github.com/ipfs/go-ipld-format" + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/go-fil-markets/filestore/file" +) +``` + +#### Comments +Comments are a communication to other developers (including your future self) to help them understand and maintain code. Good comments describe the _intent_ of the code, without repeating the procedures directly. + +- A `TODO:` comment describes a change that is desired but could not be immediately implemented. It must include a reference to a GitHub issue outlining whatever prevents the thing being done now (which could just be a matter of priority). +- A `NOTE:` comment indicates an aside, some background info, or ideas for future improvement, rather than the intent of the current code. It's often fine to document such ideas alongside the code rather than an issue (at the loss of a space for discussion). +- `FIXME`, `HACK`, `XXX` and similar tags indicating that some code is to be avoided in favour of `TODO`, `NOTE` or some straight prose. diff --git a/vendor/github.com/filecoin-project/go-fil-markets/COPYRIGHT b/vendor/github.com/filecoin-project/go-fil-markets/COPYRIGHT new file mode 100644 index 0000000000..771e6f7cd7 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/COPYRIGHT @@ -0,0 +1,3 @@ +Copyright 2019. Protocol Labs, Inc. + +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/vendor/github.com/filecoin-project/go-fil-markets/LICENSE-APACHE b/vendor/github.com/filecoin-project/go-fil-markets/LICENSE-APACHE new file mode 100644 index 0000000000..546514363d --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2019. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/filecoin-project/go-fil-markets/LICENSE-MIT b/vendor/github.com/filecoin-project/go-fil-markets/LICENSE-MIT new file mode 100644 index 0000000000..ea532a8305 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2019. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/filecoin-project/go-fil-markets/Makefile b/vendor/github.com/filecoin-project/go-fil-markets/Makefile new file mode 100644 index 0000000000..bc9b60cc70 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/Makefile @@ -0,0 +1,61 @@ +all: build +.PHONY: all + +SUBMODULES= + +FFI_PATH:=./extern/filecoin-ffi/ +FFI_DEPS:=.install-filcrypto +FFI_DEPS:=$(addprefix $(FFI_PATH),$(FFI_DEPS)) + +$(FFI_DEPS): .filecoin-build ; + +.filecoin-build: $(FFI_PATH) + $(MAKE) -C $(FFI_PATH) $(FFI_DEPS:$(FFI_PATH)%=%) + @touch $@ + +.update-modules: + git submodule update --init --recursive + @touch $@ + +pieceio: .update-modules .filecoin-build + go build ./pieceio +.PHONY: pieceio +SUBMODULES+=pieceio + +filestore: + go build ./filestore +.PHONY: filestore +SUBMODULES+=filestore + +build: $(SUBMODULES) + +test: build + gotestsum -- -coverprofile=coverage.txt -timeout 5m ./... + +clean: + rm -f .filecoin-build + rm -f .update-modules + rm -f coverage.txt + +DOTs=$(shell find docs -name '*.dot') +MMDs=$(shell find docs -name '*.mmd') +SVGs=$(DOTs:%=%.svg) $(MMDs:%=%.svg) +PNGs=$(DOTs:%=%.png) $(MMDs:%=%.png) + +node_modules: package.json + npm install + +diagrams: ${MMDs} ${SVGs} ${PNGs} + +%.mmd.svg: %.mmd + node_modules/.bin/mmdc -i $< -o $@ + +%.mmd.png: %.mmd + node_modules/.bin/mmdc -i $< -o $@ + +FORCE: + +docsgen: FORCE .update-modules .filecoin-build + go run ./docsgen + +$(MMDs): docsgen node_modules diff --git a/vendor/github.com/filecoin-project/go-fil-markets/README.md b/vendor/github.com/filecoin-project/go-fil-markets/README.md new file mode 100644 index 0000000000..5e67594bcd --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/README.md @@ -0,0 +1,53 @@ +# go-fil-markets +[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) +[![CircleCI](https://circleci.com/gh/filecoin-project/go-fil-markets.svg?style=svg)](https://circleci.com/gh/filecoin-project/go-fil-markets) +[![codecov](https://codecov.io/gh/filecoin-project/go-fil-markets/branch/master/graph/badge.svg)](https://codecov.io/gh/filecoin-project/go-fil-markets) +[![GoDoc](https://godoc.org/github.com/filecoin-project/go-fil-markets?status.svg)](https://godoc.org/github.com/filecoin-project/go-fil-markets) + +This repository contains modular implementations of the [storage and retrieval market subsystems](https://filecoin-project.github.io/specs/#systems__filecoin_markets) of Filecoin. +They are guided by the [v1.0 and 1.1 Filecoin specification updates](https://filecoin-project.github.io/specs/#intro__changelog). + +Separating implementations into a blockchain component and one or more mining and market components presents an opportunity to encourage implementation diversity while reusing non-security-critical components. + +## Components + +* **[storagemarket](./storagemarket)**: for finding, negotiating, and consummating deals to + store data between clients and providers (storage miners). +* **[retrievalmarket](./retrievalmarket)**: for finding, negotiating, and consummating deals to + retrieve data between clients and providers (retrieval miners). +* **[filestore](./filestore)**: a wrapper around os.File for use by pieceio, storagemarket, and retrievalmarket. +* **[pieceio](./pieceio)**: utilities that take IPLD graphs and turn them into pieces. Used by storagemarket. +* **[piecestore](./piecestore)**: a database for storing deal-related PieceInfo and CIDInfo. +Used by storagemarket and retrievalmarket. + +Related components in other repos: +* **[go-data-transfer](https://github.com/filecoin-project/go-data-transfer)**: for exchanging piece data between clients and miners, used by storage & retrieval market modules. + +### Background reading +* The [Markets in Filecoin](https://filecoin-project.github.io/specs/#systems__filecoin_markets) +section of the Filecoin Specification contains the canonical spec. + +### Technical Documentation +* [GoDoc for Storage Market](https://godoc.org/github.com/filecoin-project/go-fil-markets/storagemarket) contains an architectural overview and robust API documentation +* [GoDoc for Retrieval Market](https://godoc.org/github.com/filecoin-project/go-fil-markets/retrievalmarket) contains an architectural overview and robust API documentation + +## Installation +```bash +go get "github.com/filecoin-project/go-fil-markets/"` +``` + +## Usage +Documentation is in the README for each module, listed in [Components](#Components). + +## Contributing +Issues and PRs are welcome! Please first read the [background reading](#background-reading) and [CONTRIBUTING](.go-fil-markets/CONTRIBUTING.md) guide, and look over the current code. PRs against master require approval of at least two maintainers. + +Day-to-day discussion takes place in the #fil-components channel of the [Filecoin project chat](https://github.com/filecoin-project/community#chat). Usage or design questions are welcome. + +## Project-level documentation +The filecoin-project has a [community repo](https://github.com/filecoin-project/community) with more detail about our resources and policies, such as the [Code of Conduct](https://github.com/filecoin-project/community/blob/master/CODE_OF_CONDUCT.md). + +## License +This repository is dual-licensed under Apache 2.0 and MIT terms. + +Copyright 2019. Protocol Labs, Inc. diff --git a/vendor/github.com/filecoin-project/go-fil-markets/codecov.yml b/vendor/github.com/filecoin-project/go-fil-markets/codecov.yml new file mode 100644 index 0000000000..30c84f38ed --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/codecov.yml @@ -0,0 +1,10 @@ +coverage: + precision: 2 + round: up + range: "50...90" + ignore: + - "**/*_cbor_gen.go" + status: + project: off + patch: off + diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd new file mode 100644 index 0000000000..2f64d3feb5 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd @@ -0,0 +1,74 @@ +stateDiagram-v2 + state "DealStatusNew" as 0 + state "DealStatusPaymentChannelCreating" as 1 + state "DealStatusPaymentChannelAddingFunds" as 2 + state "DealStatusPaymentChannelReady" as 4 + state "DealStatusAccepted" as 6 + state "DealStatusFailed" as 7 + state "DealStatusRejected" as 8 + state "DealStatusFundsNeeded" as 9 + state "DealStatusOngoing" as 10 + state "DealStatusFundsNeededLastPayment" as 11 + state "DealStatusCompleted" as 12 + state "DealStatusDealNotFound" as 13 + state "DealStatusErrored" as 15 + state "DealStatusBlocksComplete" as 16 + state "DealStatusFinalizing" as 17 + 0 : On entry runs ProposeDeal + 1 : On entry runs WaitForPaymentChannelCreate + 2 : On entry runs WaitForPaymentChannelAddFunds + 4 : On entry runs ProcessNextResponse + 6 : On entry runs SetupPaymentChannelStart + 9 : On entry runs ProcessPaymentRequested + 10 : On entry runs ProcessNextResponse + 11 : On entry runs ProcessPaymentRequested + 16 : On entry runs ProcessNextResponse + 17 : On entry runs Finalize + [*] --> 0 + note right of 0 + The following events are not shown cause they can trigger from any state. + + ClientEventWriteDealProposalErrored - transitions state to DealStatusErrored + ClientEventReadDealResponseErrored - transitions state to DealStatusErrored + ClientEventUnknownResponseReceived - transitions state to DealStatusFailed + ClientEventWriteDealPaymentErrored - transitions state to DealStatusErrored + end note + 0 --> 0 : ClientEventOpen + 1 --> 7 : ClientEventPaymentChannelErrored + 6 --> 7 : ClientEventPaymentChannelErrored + 6 --> 1 : ClientEventPaymentChannelCreateInitiated + 6 --> 2 : ClientEventPaymentChannelAddingFunds + 1 --> 4 : ClientEventPaymentChannelReady + 2 --> 4 : ClientEventPaymentChannelReady + 1 --> 7 : ClientEventAllocateLaneErrored + 2 --> 7 : ClientEventAllocateLaneErrored + 2 --> 7 : ClientEventPaymentChannelAddFundsErrored + 0 --> 8 : ClientEventDealRejected + 0 --> 13 : ClientEventDealNotFound + 0 --> 6 : ClientEventDealAccepted + 9 --> 7 : ClientEventFundsExpended + 11 --> 7 : ClientEventFundsExpended + 9 --> 7 : ClientEventBadPaymentRequested + 11 --> 7 : ClientEventBadPaymentRequested + 9 --> 7 : ClientEventCreateVoucherFailed + 11 --> 7 : ClientEventCreateVoucherFailed + 9 --> 10 : ClientEventPaymentSent + 11 --> 17 : ClientEventPaymentSent + 4 --> 7 : ClientEventConsumeBlockFailed + 10 --> 7 : ClientEventConsumeBlockFailed + 4 --> 11 : ClientEventLastPaymentRequested + 10 --> 11 : ClientEventLastPaymentRequested + 16 --> 11 : ClientEventLastPaymentRequested + 4 --> 16 : ClientEventAllBlocksReceived + 10 --> 16 : ClientEventAllBlocksReceived + 16 --> 16 : ClientEventAllBlocksReceived + 4 --> 12 : ClientEventComplete + 10 --> 12 : ClientEventComplete + 16 --> 12 : ClientEventComplete + 17 --> 12 : ClientEventComplete + 4 --> 7 : ClientEventEarlyTermination + 10 --> 7 : ClientEventEarlyTermination + 4 --> 9 : ClientEventPaymentRequested + 10 --> 9 : ClientEventPaymentRequested + 4 --> 10 : ClientEventBlocksReceived + 10 --> 10 : ClientEventBlocksReceived diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd.png b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd.png new file mode 100644 index 0000000000000000000000000000000000000000..40a734d644182ab9f8462b8dfa3c715640986dfc GIT binary patch literal 521600 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%0AUV)IrNa!U3pu%+lYETaA&S#JTB)w*>J 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�tyBlS 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 literal 0 HcmV?d00001 diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd.svg b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd.svg new file mode 100644 index 0000000000..026dc0ca15 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalclient.mmd.svg @@ -0,0 +1,6 @@ +ClientEventOpenClientEventPaymentChannelErroredClientEventPaymentChannelErroredClientEventPaymentChannelCreateInitiatedClientEventPaymentChannelAddingFundsClientEventPaymentChannelReadyClientEventPaymentChannelReadyClientEventAllocateLaneErroredClientEventAllocateLaneErroredClientEventPaymentChannelAddFundsErroredClientEventDealRejectedClientEventDealNotFoundClientEventDealAcceptedClientEventFundsExpendedClientEventFundsExpendedClientEventBadPaymentRequestedClientEventBadPaymentRequestedClientEventCreateVoucherFailedClientEventCreateVoucherFailedClientEventPaymentSentClientEventPaymentSentClientEventConsumeBlockFailedClientEventConsumeBlockFailedClientEventLastPaymentRequestedClientEventLastPaymentRequestedClientEventLastPaymentRequestedClientEventAllBlocksReceivedClientEventAllBlocksReceivedClientEventAllBlocksReceivedClientEventCompleteClientEventCompleteClientEventCompleteClientEventCompleteClientEventEarlyTerminationClientEventEarlyTerminationClientEventPaymentRequestedClientEventPaymentRequestedClientEventBlocksReceivedClientEventBlocksReceivedDealStatusNewOn entry runs ProposeDealDealStatusPaymentChannelCreatingOn entry runs WaitForPaymentChannelCreateDealStatusPaymentChannelAddingFundsOn entry runs WaitForPaymentChannelAddFundsDealStatusPaymentChannelReadyOn entry runs ProcessNextResponseDealStatusAcceptedOn entry runs SetupPaymentChannelStartDealStatusFailedDealStatusRejectedDealStatusFundsNeededOn entry runs ProcessPaymentRequestedDealStatusOngoingOn entry runs ProcessNextResponseDealStatusFundsNeededLastPaymentOn entry runs ProcessPaymentRequestedDealStatusCompletedDealStatusDealNotFoundDealStatusErroredDealStatusBlocksCompleteOn entry runs ProcessNextResponseDealStatusFinalizingOn entry runs FinalizeThe following events are not shown cause they can trigger from any state.ClientEventWriteDealProposalErrored - transitions state to DealStatusErroredClientEventReadDealResponseErrored - transitions state to DealStatusErroredClientEventUnknownResponseReceived - transitions state to DealStatusFailedClientEventWriteDealPaymentErrored - transitions state to DealStatusErrored \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd new file mode 100644 index 0000000000..b16e88de72 --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd @@ -0,0 +1,53 @@ +stateDiagram-v2 + state "DealStatusNew" as 0 + state "DealStatusAwaitingAcceptance" as 5 + state "DealStatusAccepted" as 6 + state "DealStatusFailed" as 7 + state "DealStatusRejected" as 8 + state "DealStatusFundsNeeded" as 9 + state "DealStatusOngoing" as 10 + state "DealStatusFundsNeededLastPayment" as 11 + state "DealStatusCompleted" as 12 + state "DealStatusDealNotFound" as 13 + state "DealStatusErrored" as 15 + state "DealStatusBlocksComplete" as 16 + state "DealStatusFinalizing" as 17 + 0 : On entry runs ReceiveDeal + 5 : On entry runs DecideOnDeal + 6 : On entry runs SendBlocks + 7 : On entry runs SendFailResponse + 8 : On entry runs SendFailResponse + 9 : On entry runs ProcessPayment + 10 : On entry runs SendBlocks + 11 : On entry runs ProcessPayment + 13 : On entry runs SendFailResponse + 17 : On entry runs Finalize + [*] --> 0 + note right of 0 + The following events are not shown cause they can trigger from any state. + + ProviderEventWriteResponseFailed - transitions state to DealStatusErrored + ProviderEventReadPaymentFailed - transitions state to DealStatusErrored + end note + 0 --> 0 : ProviderEventOpen + 0 --> 5 : ProviderEventDealReceived + 5 --> 15 : ProviderEventDecisioningError + 0 --> 7 : ProviderEventGetPieceSizeErrored + 0 --> 13 : ProviderEventDealNotFound + 0 --> 8 : ProviderEventDealRejected + 5 --> 8 : ProviderEventDealRejected + 5 --> 6 : ProviderEventDealAccepted + 6 --> 7 : ProviderEventBlockErrored + 10 --> 7 : ProviderEventBlockErrored + 6 --> 16 : ProviderEventBlocksCompleted + 10 --> 16 : ProviderEventBlocksCompleted + 6 --> 9 : ProviderEventPaymentRequested + 10 --> 9 : ProviderEventPaymentRequested + 16 --> 11 : ProviderEventPaymentRequested + 9 --> 7 : ProviderEventSaveVoucherFailed + 11 --> 7 : ProviderEventSaveVoucherFailed + 9 --> 9 : ProviderEventPartialPaymentReceived + 11 --> 11 : ProviderEventPartialPaymentReceived + 9 --> 10 : ProviderEventPaymentReceived + 11 --> 17 : ProviderEventPaymentReceived + 17 --> 12 : ProviderEventComplete diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd.png b/vendor/github.com/filecoin-project/go-fil-markets/docs/retrievalprovider.mmd.png new file mode 100644 index 0000000000000000000000000000000000000000..a5004d70c85868ff5b776f5eba6278426655c4ec GIT binary patch literal 291898 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

    c#^N6 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�hkR2uTTX-0uu|G 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%0DvPdLW67Af5#mr=Ejh z1WOJzy8JAt2OD)b*3~}})Ux3!c9!z2*CM8C#*35y3QoJo_rA%~h!_&UDG*Wg!A-zY z&Oiq?NBnaSM6wT_I3mM}sF_cWbocf4_O7nfVo$C*L@*m(3s-{08 z2XjJ2Tem$uV$%MJA0uhWArcl(gqV^W8c<4M@52G^6<89QAQlt@SOT#)o>jN z2_#E4g9JsPxy{OFkJPz-K|^ z|6?3yBEe50aA{D<-rdY~dHwxxtkjYORLo#DIDTVkbXXA$9gWaRs|@5(aS*YCBQOLz z4SYIiRRT`ObU`a!?YM{R7X&T{YH9#>Dg?SoOH0e#SQRfQwAKNR$Yx&JZh4UJS+YBo zObQBm@)X!qY)LpcB4OI_xvHwz!`pR6rjDfsz}s;GTOAS-@;zT$5Snlb1Wcii7LK)Q z0Hg>lV98*N5soEHC6Jpseo+Sq4!qfM;Bs-#9rk@nJ_?4uNthRufU9i>waq#(Z>4_< zT7hP86`D1G+Oz_8`YJv?OxYgZ;j}TxGzG`2JU`V+AA%#Y4oH{bx4?ikJmgRqLzAQ~RjOXl@LTSj=<;^5Sdz%Fo)IbXJv0p#Pmh=_?LBoKpv z_y!DG)ZAJk=}?JiVnUCkZhBnr5jw^epXYR8oOLHhiLizW{xG7Y8GT4M7RC0{0ph$i z(~{9X0~OE*M#SD|;5eFnr&NNE4+B>0ukwW)gn5NfHGy*p-A)MS!=hsJU>^v8njms_ zG3ElK)Q==y05zz8d5Mv&P-SB3lMru?Fn?j)0`RH}bTK=4j}G*PRldArL5TC9 zlez&K{fI~@EI?>z6$IHz_JyoML>KXArQ?lTx2yr_!w8zBlUs1tc8fzSM(di|yl2mz zeV|$zU^&^aI_^${P!8deN+-N%DCz0-fpZiR9&X)C7XBSTpKw50qZxp(T)+kbCmmsg zgFXYyB;AMpqS;T|{WWNJoR_KOAMO{3W#s`fZ0k-n>C#+c+)z4iWpM_sArGRTP0Np9}{#0o7>y#Cs&bI3g4}i zr-@-!60KrZ_8yFiv^q{?*q8C@mTl~p(3VL}LxaGH0XVA%Kr+lL#z1`BhbD-1ut%`P zT4C!T0*;8wMYJ}Hi^C9#5~yAT!PFwqkd;0g-~i+9#oAP}@6g5fPY`T31XFJt@4jj) z9YZ&9^^odY-mUDfo@y@=s08&J0lfH806m(_+9v~np z%E%|$f%`6k*o5$?1FjkgOu<@#?Lx$&p_JydHt6*6)g}k3+;+YuxU>EACrH?rS!Ho> zZ_P+{ifMtwDXpI=h#O}NF0a9Re%v~F8f-jb7uGwtI?roDbHFU(bdI)<&_v(&j(0cA zSn9$y0|x+rH*p|1L)$Lm5oP7&*Eah#PD6vL9hh;r2j9Ez%F8+7bq~U@IFL#VY|FR! z?%GGm7#9;So>eV(Z9S0aqSb6ycR15;+;yPnEtV`jo zmZA3+E}S_f7R!nI21FGnT_Bb=L`0ees<-x)@rk$wv~4K0jole}D4|XCUl~C=_-aIU z9Hc&|P(Wp3>~rM43w^~J2)rzjxCVNO-$8RfG}^(iavm60V7fK|jHMBnSEV2njj#j| zQCIMaJBQB5rUo5x1Z@M-q>}(;PsqvX80di3PHd2}tpV^iyxPm-77?J&8U$Vk6^O9` zL%1gkxU8LkP}26O;0a zicKJMk034_=aa*sbwmq+L&4NFqQuI5xY2#E9(ObaR%r_C-V6or?ga>qN`}QB4s1*X zL5dIzkc}1iE0w}zp1jar=8HyyMmw;H89|@_sM+;?x7ldJ<^#oQfa1&# zm(U~M1N%oo-SItmBgi9m=Otadh8N9NzlM+?%@W%x^sh=Bn@8pOtx^apy2a$fDLX1D z1Kng*7C`Y5`HDex5QetF2q1&ObG@Y%4!TkBy`-?w@OUjOB4=u)~3^1z;+p4=PX`33d? zmjH9O)}R~jT6Hi@4};Xf(b26CqKIi_AoXbAypjWPOQ$W3>ozQ?9QI4zVeMv&#TepM zt>%LTXAK;ke!;_oFo*-FluhSNI-+k~@KLvFCUa-WfxMQ;dAnllMUgVX8v&VMPB6FQ zL85fyfB}H{ivu!gq-t4g>}u0GsXSU$k+Xu*Fp6*lUOVD}OPAd2dx1Kk*HNT)T?toZo$ETrG&B zVd@7$R>WIDBo*^|YY=uiD)7zh*;}gBV3t7@WVv)INEFecM?!Vj=>SZ`%k6Ik*lhHo zps6V>(!gz5rmAY&D~AHDafHmPst<4iWJF;jkx1(K^T%MwP(Y-k;N^u`g)LyeT&V^@ ze|wo~;EU!}DiOHPi$mbYWbE;Nals&qYAROp%Cf0n1VbX?0W<5r>sd z;(q4%SF@GFqu|p(4e3Z5y10+c$Z{D?K~4_CQ|H0O)hnx~}HJniq5!E|AQ2t{tgXGm1~WDNi10L|zXI^05hMg+r(w|FpqL0Eh*QL4HTYk**~BtU z8Daa!vS`qq{?%q(vAWpNE*rMDT1G;l?ObGb-4%aZA@cxjzk80>7u#lWC=@&hBb1Mv z_qyYxm6V#1cjxbN0Bl|@m~%4BoaDR$`to|RUIc(aLiQR+>l=^b82tHmiGB(OZ{iaY z-hweic$Lm;!EuQFg~tBA2FkVdbqF7!#(@hcc)=yf;O5)b2G7;h+CeKEDj_eRsMH_~ z@6+xqvFj*c;qYI`L$W#ae6)bfopGxhA$T;f4?qar4$91TxE&s%fZcQX4x=07X)r~n z?K28L7rz9l-2fkf7Ut#g#$Io$C0@71C-}XiXsuka81I7(!%L$7SF>wkn6)ZHmOe$- zKvkiZ0qvO0ot>D!N~#V`gNIqg_J78FIDKm@E+LZ)i1xrC_XAAXxCOhzOr-u!rwdwJ zwuk+BZH*T=RyITJ<{&c2lcgZJ1l$s~viPZED7PlqaTvy!u;IkdCgO2&@b=f>C&D`5 z<@oN3$p9a?>c9<}?I;)*dtlD4DW#}5pcQ>ZMiY`sUjQjoHQPaZ_o_>mG}(C$CumEn zsM;!kz5qBxB}-Mgp|)3V)$BVDJ!#73kBbkehAGceFXpGBGu3eO-_2bT^Lf zFN=9(xUp7O7j)*_xh@!gL4lQQLt>+wOIMZ2Sf$$Sede+kxtOn_8RFxcP&kW+}Gtdy+*Vf z1=(sK=8VA(E%otk?YvC9@=>OuOuP^QKANxM{^vwsv=>N>3L3OpL1;z=iIt(TnW_Ti z_}9cg8yhjJg$80EDn~L1NW$wSiiapXJL7mYObE6Phg4qNng$@ovj$Z>KwQ8why#}R z8Zb3pig+leRVHZw7HBlrh{}xk3PyS>&Y_3X$IUQ7U+b9uk@9dSUJrZkyWcJ1Dwgq zN8slltezG8^!>23q=XH1i(Wkms0JuV50Q&EBL|(id%#Krm2Vix1x0z7i&)H9g>f(3 z!Q{lx*7%}qLqX!$i$HC(6S=j`2 z8G1VbGL4eg11j7^>=xBKZRpw7Vc%_tDZJ~SJbiiwED~jigp-Qq@Hzuys8+*aq(5M*gm_RLPsW)6Qdy(WYBB74XX{F3ZoxA)If}SGmvBj zhkyVnX9C{*{(}dX-+;jX%>fs6^^cYxb6B@!!Y)Mb?(R0I%34@h1kPqMkHshCNEsH> zwjX@*XxcoP=t6e7G#$c8fjJ0-5dF~w?FgqOjS#eRIPE;NAGN)O@CnPeN9~FBx0h3a z{s9vG$pZ|dqoa;cLk1g#h2WR~j{@M2+sz+Q5a%M;Jz#@c|L&oJ3A_&2`$!f9if1D> zGC#7*>FoD548Hc;rY*HUdFDq7cUo1#LYrWe_;}!yrEnF7ErPDqe_6%JVf| z75Pgg3giP96FC%sDLfkOT__g=@JGQ_8!%pvz#Y?U<_|xD$^{JIEWpH&7gD%^3K|%( zckpw7*immbySUg6rwK@12FbS&C=$F(h|DY@tAt5L6bMi8!Ey$!6LRY#Fs%-$L_Sc& z5~)87=;$kR6!ZFO?{{%% z-|&U^h+t=t;~qaEUJ0PqL#}d86AFn9FM(A=3dD6lF+dJ4GZBGMtsoUciXK2_!NJ38 zf#h0RGuAkEcqQwPkG`%-iFcf~Y4fY2$So55KG0+AZZ5U2baMU#WeX4q+CFpk><@&- zn^h3ek1>4d8NK4sOxtfeqkgQ zy@r?y!nk;_M=;y#-P9xmEbbOCj^6I>m;fNu1)BpY2!s$;y=8H{+K~GrtZPWaz!^2b zLI#`SE_G+KWnC_6`MG8PoY8QYo->^Eyp%rfphe6>$fajRKkmX}0k;MS_(J<-b=2P0 zVk>0Pm$LND-|Obye%@8e|KT!H76xQjAk;K~g2)6MF({LxOlb4eT@Gzi#3B(R0>>#B zpMV6Vm@QwuRqSlZa2kMO#1xJIt$Fczpd8k^Qi+*byu2(J)=3zM(t?s99C+QzD%X-uZ{04ZD5v`T6w|8n?={o(9j2q``g>w`Vg>+ z#jpp$kD-<;D0(yujIVfY;DI!pj!f{YDz!#VP}Ci#aY4HC67pV1Qb0))Z=c3&9|=1_ zU=0e$zV1qVe0&WYP=B6)^k09Z)Di|T-@%T*j)#Z9xIm?qn(-sPu!KC1yS)Z6+TdKH zi$p4)HNDyV^GF`av+SJA$9_A|DtY!7s;`|_a)9@gx2jo{K5dS!z3>9yc-Em72O0tF zKv&0l47ePG-vs01EPYIoVo3P|vdvpY*3Q!dK(au}Ct$z=z-)n-CJ*5Dlr*Ee+DvcQ z(=U&kifZppH(@z*6eLy`w9aDw@$>^MBK1Rg!x>vTjct*w&Y0NaDi4wYU#E~bbB~m? z&OwSDSbo4Ytq$Yn&}q5~>%-Uw<`mDv(O3<9R5j>Ein0j8_}uauWP&(A7XykJJVuBl ze1SAgtbG?U5~S<^?|cFh_-`hxOb`ZChm8O!^||&TJk)D9Zq&h60(L05rZLeGFo}?| zCtOS}=eCUON3mVq!A?;m z?nX-sZmANplE;30XUqvi1e`$PP&t)&I06d_3R>CRWTC#GO2xr(M?+&w+CMTnT2xsX zPp`17&KCZ28pKEW`-e<9H?0A()6vl(5cI2PXHkcI@Qyrne_I2vYlw*AjPH`Lu;A+J z>sMA*`g9@(Yc})O;04t4JP;8Uu4!+-f{pEO{Bw3QC?dimJY2!kbkr*d%9s$n0*{-@ zZWzSOvgD0j*L4^p&6-4_-R;#Fud(2lY>lU|hF&mnFr8IJm*yTh`n(|OX&fxt!7M|Z z8?iL{k7Ddobu*rl(Mg40>tK-~FmBZ$f@MZbPoF#B7=Zk%f`Xj%OV7nPK(`W@r;g|<8{P9v~YlxbT=84fCt!VN-hgyUGy`SFR1i(6&f2=(IB zP}s)`weigJeX1A7x)`Tq5CarquN#_2)!*?kPl;lxK@{%+wpo%} zd$%AX`;H8CxU|)3#-AsXeLs7?)Gz$T7l}On9*FMhiw=ehN4nw}H|Z+ks9W9ItGve~ zbgal(-~BEcO;_qC3>PUsqUxlR96(TQgoG05$fxE|6#Y+qD$v-9iYlDHf*z-Em-uV1 z+6B;w53uW3um7v(V6w-JTWxPnFgu=ayRssmplE5-S43t+{;^%}XvTY|KjZ0lakhp_ z!2l@U{^a(L%zc>|ojDGzOZMkW9I7HMvooya=cMiY7A0q^!@QGXI#cQw_0IX__?9Ti z_#D4UV%-KbKCPMj{X>zJ)d2^+m#VbpQ#@^*~52flqhF>E?|lgC`!O*?E3)< z=^-={eptt8ESg>a7DZ*o93g@|pla)FcZ*Ide!&z2>?(dWR>6XK^{l zD>^*oT5APU{vGP^_zv& z+q?cfnl*LZ8(8P7yBi08AjFLu|62t(f%pT1laVGWfga6gN`5X1YCf_T{420e{J67* zMd?77n=VJ9$N2a3oCS4=YoamJp$5h66(`fmb`f7NRBQZ43MZ)?JnJ$HHIWWo>z%V* z^fOk&kDPnVrr<3hR}Ia?7Y_w{wI&nJP&=~AWV)*7Ros025sTDli(}6}YkCer>0JKj z1s;C`T6tKWbZzoh>IK7v+BdVtG)gD+wj_dumvOw&;iN0Wo??RT(($sFvfNx~*|fB~ z2nms_ithpH|G$94qiHOL1)KGO*srFK%pbnW#LcK>uyc|gdqA8rfzuyz+a&{q>xiV1 z+q>4XCcf3X5eNb@f>`T6KVl$1!X~BCDP*txOW7+San(^VzrQe*r|3`UL?cTB1?nnv z$ZvT4ZZU1#R@Pa52qmEI*Tfv^_(>qYP3hCE zRkKB<-XG&3#li@@@<9Jm!jrp)(&$ztAI~p>x!IyF zOIaELzviB|B-d7Stz=BRHMdm|1mVd4-@~Yj)V^b)?Bt3Q$DCwz3|E>!c`O_LUig)FNVFIenaET%{{NsHFrh^T(u*=J`%Iq|qp6}=sfj0^zVfmvNn)nV`5o{4X1b*GBAL|a=& z-ZlJS^esWV*MEisq^D+;Zqisc#A>Z9*rrdVuni%rPU?TFPUvjdh6?META0uPQ%2Uw z_O?o_I2s&EBA>p>vY;B+dW0p%Didr~WMNN_`Lu(UvA4yrpZgxe?4vqoH$#9%VI{yInGT7=GiHho6?l|?mOxiBd4FTyI& zs;Q)$=Cnpy`$tLU_b6mtK)yHNH!5#6kE*RJg2;sNKRs)}?K_mqp*7>sb{} zkzvo!uqzH22vz)Bf|!40QekcN>-9&Gni2h4o_qNBM-fz9jeB;GfBD)(Vd>Sl`u95~ z+Jmr`q%-5)PbXH`r3;r4@CKM2#6*5<9CDmZ>;3-DsAwduxB4_2b}#L9u$tokvQfBA zo*EBy^roa9HMReUKY2q!9M<=Fyays|oDZo&p?+4MV{fCuskWy=Bl}j{L`*rp6Aagl zw3~Qc9q#a>4IC?Wb1#d-P47oi4vvhQ)0z+Sran*{*r!01c^>D+BlpKxzLO@_hHC^kMM#^0oYiY+KHQ0}f zipwbe9Nr?Q<||kDK)yIv%t|O?`h9fj_0Y`np$xy5@-a!O;8$G#yY}W~^rX=l>Yf~@t z;zZ+;E!FXBIB^X^@Aa%s-BJiXw$rfQn=izuF>kKhTWvX&NjDjEvouh|9e_qroP>~&3<_!D z$=AZ+vNyX=y9g-?8ie%SK?5&*{%dPXOQ`5TmCLQj$U7)z(;=^7Q?9E7s$+`!-`q+( zy_7pLCCx4xVM; zjm@6q1rzJmc>tCEN>BZms9f~B|8o^wXMyD;p1SjHEF%}>u%k}}bCaYJucE&0&M+bW zyZg$79W>FHSN1K#k`p@A45w#i)|Oo)br5Bro^%=iq@+vGz2f`k%@CI4z(L~d!b?>c zucadTw^8U&lD4+YPRj5+F%m9yT+3pByzfX#QHP%cO~r?_M9w?ZkWkaFi$vSO>E-)N zNBkh<4rw+PBwtC%YQ(gQLHQk$yrz1i@TQ&$>yqe*ZerN>|fu5@J;(9 z?K<8@NinS*pQXR}RUB^^xF6R`jA9Yrg}!HN>z(@m zmq_4y7mWzY0k#KKS04*7-Xi!%waHepN=b#`$j*$`c4$nDkiducdhN>ia@}9Pyk6Pb z!uZv%p*>J!jE@4cNQww9lj)GnuP_y5i&d?Q_^eqo1Nr=LKKCP8)PCr5S-TLOT8SAh z+%O>N^=8_rP#a6Hd6$;%9_&m$Fe^(YGaVYyt1EEYeFBx1xv``BpnAx_Pysromj(xw zn2r0Q!f1!bCuPdMGwkfjB}&A;Bqfa@fsD9rs_!)BR>A9ia%hx1kCg*WlwW|h%@(GT zEzfH1H}gF{4&-5yK#SdGzAHA0<@6rK z36ATmu=PLzNaxL|<|tH=aX%Hao@@`JAHgmzQCtghF@A*nzSEiVw8`*5Aff_!G+!VG zv`3f3^Sci#6_UTza2^y)6kzKvGRDr3WjGB?9Ep?OQzpAVJD{qj1pLnHP_Cw5S|S^( zZG?w@xF-iKP*HE*DBH|kHIikeUD_M!)E6H1@(|ih{l6>}aCCItT4YSLxowSyYpwKf zZ|6P%h#IQd--}IEjQS3YGXh{KSfCFaKRQf!YV{)xexNE!21Mr+yG7pq7Be_*24XB= zC*WKe7{rI^t4CSTl7o~Lk!utct?lgehqf9x_;FwOx(o-kP??f={1^qT`kL|6&>nUV zx|3WECW#bYuPEL`>O@e$11(aF-b@V@RhyDf(4LaQtS<6ZPA8+3s&-MEM{b}zy4M`=Z zLPimy5GtvV>@6xI8CfA)(}_@KB4m${y+;FC$(|uIdz8KI=hZpq`#9(OyYI(+|8;vj zPM!GpeBSTteO<5dd_7;!mu{~01W}tX&wkdfW z6GS!@EG=dmTTTbtFBVa3r@vCaQJI_{y)P|YcB_`@W7K-w< z0`sZ|>}N_=Zt%yGXAlqoT1`e59m|>R)jfUsw27J7;nNH2irjF-NPU z?!{!HYxn?+eh)8D!dz-eK`Z|X|4^&JxDBWH`F|KN=ihZ()_?EkjV8LZj}PI!@l2&fdG|emAP~IX1lH!3~lG+JW33qY@{1V z+_vR9kg@dGus*6VMqV6*8PSC?;a#u`L+$zgm<6!rc-jggzUIkTf!b~Mr@Lte%9YUM z+(B8fBJ~e9^^&2c_K8jxqw3_oTn6>_SVQFOJwgBQ{H468HU)Z@*|V^-us8#L0+@?Y z*hPJW7>AlT+mFSox4@ABpLpVn@HQ&{)w-!FD^xkVf>KR;#K5(8R^tJEMo7T^7HGv! zL36|Ou*#0nWt&1j!imEk>+0_p1z4_}Z!Z93%0cwKjyH=u(GCMP!%jwF?&hCym z(n12i+CX>3Sx-_56rz8-h5<^b1^Gq>9gt9JT-Dvzmwb18KPFLlU_Xw150%8JQN?#_ zLPS*A)GvPvTHaq2B4UOSZ`(zd0u4C*KxaCM=SsbYe~J#0bACqx_lV?LZ&`tU7xe%k z2cOaWW#{zvB`=lK`%eu)-y?f0b2u&j6n{1*6OHbq%>@woHAT;y^~2*_GQ{YKt3Y{} zD3|Ln>|(t25Jq0D?PxKgzQLoY-JbWV)l|G}CFa_+Hq4m$^Q4a#tP*yn9c|4_Cc6`p z*Sc#YBfow7_HJs}|1PcyJAwV~Xf8VrIU`svs8t1B`}Ax(Oy7>3?AKCv+jE#q4LM+# z#0jvu_S5n|_VD$+Nw06eytsptlk?P_?-Z1tKNc6SkV;Sw-QjNaIl${ zjoFs#hFdIoiqendFfyuxSmk$AU{z|A=gwZXStaKDi%5AIH zts@;0nBnsgbq^Savoz`!R*;MfE0S6`J_SeAR z;4DN!S`{yQ?pimqm@v{WC=A)(&W_sz9rI^X!`UGI>I7Q#o<+-rdEJa&Lp%y->B*YK zyM2!N8-1K_F}k_bv3)rnUY5||ABp?QY)Vl{w}IIK>CqR4pB+_@gMs$el)g%8y8xT1 zh1F*up^YjgdN55|46jCG)%h(95Zn5G`ouu_Il6qD(Q~-1zA|C&(h~Q^r>WOJ=;>6< zoy1PzG!8zdT#Y$7MXvtFQwFDD)IZ=~3URmB78Y-i; zY~50TPOqnvD_81m-%-8G5x?01A5d}fWTc+F5GC|c)*}D-yhW<3=3Y)MdP=sX5$lw# zww97^{Tr(M#od))Igyc!u6w_3UI;v|R{zV#zW!6J?N^M~qjvksfhNED!7O*wu0g4{ zBvk1`hYy3+38%QVJX`&K)!$rzKmmVX=+(hzSA~Rz!XN95b-b&Mk$2&``S~|0DiJlc z{U}L8bNY$@?W`y0u-MI}b_w<=6TEF#JDds9LqM2)Tlb$jbLGlbR3SS$u4%qP{Qw`x zdw1;jEqhP=E-08M^#=1L>G}9xf^oTW)vA6_-dy*!sH|f=as;;KhD!Qv3Cy@c<**PN zt1rkQ?_-zylPA}~)kfqKeujS#6n#=|#4RqM85rptL;5GM5F(C^w;n5-jtZ7DI0ZeuGI8#Fe7h|7~#4rSQgU?J}Q?tgMwC zU0n|_KmA@;+uQ4_Fggvzpc)V_ZfEr~QjoY*)PL8w^~K_Np1hr_;rkCCcpa8bOA5}? z1CJW6%Nn4YCX72-=+!7T&OaJ=5DDZ&t+}baav^ z8)Cvos7$z6(S(QFI;N?48*WTSLb~xBi-La0b6`tkg2z5Sl_v0IxyM(dF|A^XQvcz@ z12_mO{`$Hbt54ZX9R*7kRdX(cK###UjYTB{Uk(8R;~dA2|509kIkaMGpV6*7BV&`q zMf(F7(seT^cT=Os0a;nYx_K@xF7Z}HDXFV%R()I;b5)i-y5wonrH*znes84>C<1xJb0YeC%>}&_SdCS8`0#dp;NT62kdE(~lj)8~tAfoglYI^waM4`ddv6RIg zaCbIQw$d#g3l|<^P?`FG-Exzm z$iK1UOT2w5B^$OG_2p}6^!KN2WI#>C@mTb4zcVlt>b5U}0O*M_C6YaDkV_68Ja}G2 zgtWkr5;bAnf|gS0!65#>U!eh!une~h$(j$CmU9*-@N(66k0r#z`r;kBP;92p}DrIs_FvgbSqn*a*_>hs%5Guxuat^2*)2rw{^nqYR}X zg>Qk4e6Qh}&8oYQEX-VrCa+>o-SI^gc|9yncILM?zaPg-se#r#Y zYZS9VyR6ReK`&`}kWdi34PoWWV2T60RS`H^mo8m8Uf-1OAcV;3V?)D~acY=;I}R^S zQz4p~U_JewzeO>XbU2aLKQvh!!X!{a!Uq$&V|3I#D2R@J@+B34!9MBgN`_|iyxTgp+nm2EP6DQcki}5o%imo zXc-$XmUU5EF88ZJ*I_pJ6Aw?e?U6)$gJD#H8g|@ywe#pNVOX{HbWwV{{kzw~LN!_D zHk!)z_IcxdsI-C>V2A)2{CCd_uD5$<#zW!!ws~7?Ffi=O%Ff0JywNZD%O6mRTzA=T zVgt;W2&3l8);l%FD1a5>KAE2uFnkgT#>lRj(}GL89G{2Hwit~o#nrET@>)@^J#Q1V zfqOAl_d24dAKjjnD}URgtyv;xvtR zR@T?etdHkrybRMHxlqfVvf&BDq{-cxtsg!pY`L>A6OCEEy)TQFxc>BQKEGz)QN7r( z)7VZ$6QIGRLLJT}28VUL%ClO^@kWm-&~}*!^UGt{yjtq_6~`DD9)Uu{0m3C3de${I z`$40c^u%C)lTHI{N6_!Q;G+~_ghsOsS zfeQ_-ka}O?8~YToU(=F3Jr} zO}M7W@k&rMS42sNt|bI?H08jouQ2}kT^gLha!`+)Vq;m!yMZ4_+ z%4&ihTZqXxkHlZ_c}h8V6QBRFA&tccc78S3d+Eq>Le6cgD$Iu#0X6wf8ahyWC3R#?Otpzz_z@k-ZnCxH$TEUW_L+6Q9x_! zmMz+Zu8m{fQ|7ymN=5OF(ux9s>DCYaMtRDe96pRiNcaVj+rg5eEA(6Y^3us)%YBtF zv%-erkX8bxLm1=q`PC?yQ>=RX);na(f4H;Hyni9^yt-{_ercYLJBCk3M`yu^wk5ZD z^vS(^MVsGt|rXdoz4@;bsWWY`XAa3sq=A31GZRJ%6Bx>Nk()0ra(86x!?Mz9_a zG>fw<0uF=fQ zrOH~&C@n?YxI(w__-ZEGyuByheqCqO_%^G+!uQDVxvGZrlwT(;;?F3ON(pMMw?ASr z!`|9tj?{gp&1H!GVD@bQ2^hOpEaOvjuY1FDN4=oB1FZ)AC=78u;u-(Lb2 z)vblrDCxspm4rcwzNABlH}N6A(a>x-gXUcdai%b@?=WL>ny++KW`ZZtf*U5x2GIB3f*MHrT0`S(af=AS_oMp&$CyT5s`3^8MG(Ex z)3<3(Mp*3^w0(iTTN2g|G$csk=7>`T{Wu&3AD|-Xji&59p<96X56R_kU^#^VE3sV| zFFt?af+@It`-Z>pBkOEzZq^uX_PqeCo&pkVfmV{X@BHj6l}hE(*Pml!9i%y%w6=i| zH#0lyJ#aU8Y?fQ(w#YX?!CNbib@=D z-QXRfo6F#%DjX?NZSh>7O+b*F+=V`)Ym+-&wb=7}5$+;S8UxY1^tTv1co6yg_HB));E~mF?GJ`pzwtxhvnN5muDX?&RbT! zQP$tF!(Ov0gqNUOMtOdf!rQj=Xe?Vl;m{1!>L@5i`mF=dMlM$272DOU<^IuzH_Gi_ zV&rYG-UV}$XNs!-lld->1UPXTu`nEJH(ELiNgt<{$qC-@8;$%xWSTe%!U^iRPtO-stIc=D2VI4cLgabkR`o~S zWc9sM<|Om6J1sRcZ<7huuWY7i&$*z;@Nhyk+p%w-KE2fY(Y~w`Vmm_@`M&~!mvR3^ z{|Ub-Noh?tI&$DZ;0fI?FF*t5(*4pU7r!tsu9x0geINcJ0CS6j)@;&QnWoT25O(0E z*mn~@YeN0F2lu5JwLb-jfJ6TQSY?v^q8`T2J_dxknU>EPU~Hn*50#fEZjs6w!8Us< zsvM75jb`?#bE~Vw$g}?O?m^J?clZ6C(iz2e*iV05M9cY64F`dH4vT{f1wLbUXU5nK z+V)GpZ7eLrR7K04oWcZd(5;p7?YVKhA~cJo$TYGmS9m}}r*(Y$cHO6n3gim=D3+Gn z5Q1#(D$0HAD4NM*M1n{8|Pj3t}tlJ@#!g}mO-9*;O@2cw0w=~BQYBJ+ky2$$f6Ai{v@WQwPi$v zUdX*)q7{NW!EAV!5>KIC*t6qP%fNki+az4OnXlkmY#ENhE^m>S5(78>ev{FT{c8D* zKe#Q1Y;5O;`_5l@oNN>{To@lAp}MzD<=%}1qg!cI|5fHc`4){4)Veh4US)Jr_l}k9 zWRhF)MSZ-wxL6^xFz_w>hZ<(8z5iqTVP}cnWT6>8M5~D=jnn+#*@s$pdc&0}Yn6vz z=k&`!+pFIxlS9b=XyG-X@w6iUh!%d?1G&V)%VIV$(G6IdlYQXe6Nx9%o8st5DRQTi z1iu}kHe1m~a}9idlGZd9r8^UXJOU*QVglwB2F#^k)cY{#%%xrKLh3ivP`S8)AebmH zImWqWU%eHdn>!p@r}A@^@OMFx!bB}qxHdbFP(MA}cjudd#Pk@Ea-p3k2dZ$%jkl^^Qn(ZlYi3+<)_&RuxC zCb@|k2oFX>U1~`a^6I6AQ2pS}f=QHw6ZeDvd!-j zrr6%P6}{$0ntpp8SMtq-j?TheEb^vY_8M#N4kcbcJ=OSj<>2%%|Fb;1b$f;S`uZ>} z{Er}w)N>qb*3|XXNamAa@~3Vh1YT30=s*n=8hDi}2FBj&fdIhO*CxJ4o0K|kYP82d zGa>nlHKeS9#JpRPvU9`>i}sbF+zN$;wUvVNEI`X<=H{rf6xl}Rd~{UdyW8XK7%!6= z)UU7Gx~RsiG&okuK3yXzv?4!!gVC4Z71%8|Ar0nuZ2Q|&Q!#hy zRD3~Sc(j_b3gB!CN&~aM%%1Ep+JBODDu7%Yy-sUv$a0u}aMs3Lgx@A4^p(H{P9dQn zSn?InI@l(KmhF{;8i9LgER2K@qa&g~*J44V@8U}$AQKP}u%inB4=wWL3)Ou+C5hpg zQ+2V5>o8U2aM46pvHLy;3k!<~^cFywY7D5u?mb6Hv9xh0zUS`JA5l?E1VQ|oeUgoh z?E-g*M`yCo`t&2TzKj><`4IK7BsY>gpu3X8-)<9wely~9nhl;7ij3Eh^lI`ftBbZF zB|tIN<#K(>kFl{}J^B2V?4YYNE-Wl;q8FT-m1p$|Pz-m@l=Aq!amT#a!0Kx}^Gng^ zg~-OUwx*gXuc(NVDp!n=DOCGiIXT6kFVr}x*L!~3`Y3rO^nI`=(?1Pf zQ>>jeH8FYDo`2yN3$sDW5NcLfZ@pO@ll-t;0UK7Kq3Zor(W36F;EvfK0baB=`=D!G7W6^xpU_z zs%yRk2mjvL+4;RD(mhcU*FioSL5~$Wg}y^8fdIWKsm{Z}>>Tt}e}sk;`l(vKe#Mma8|VOE^BEIjKkN~(J^?O%F#4!4Yn<#Ggd|qL$r7x$ zCXk(U05KraY-cJ~u+oSq_Y!-SM{WnKu z!R}82;hzsxOir$B00#;NoJdb0{9hAn)Sd?vE2+R5Ax4n_&(7VuE$U31Hq)GgK@nP- zIgBz}FzSE+`ygjPX=I5Z{Y@nOKoe+^kwo)u7XIBXQTIm8ttUZakD; z(+m7g8`v7b$_x1ZtA&LO??U!$CJ~p5Q-_(-!hR=>4xl6_NWrgkK^OxAo+?nVS@D)Z z1MMU($a3{+qu#+ay#QK5FnI%>A4IRitoJgi1T=hiqD3OuH3CW(paWSL&x~Eit2b=i*opR;!UNgA z9^I+7SC(zUKYHU(wC*kqLhR|w)#Iz3|2s*AX2ofn%$|UmhsM?ZU);j5fTrw&kH9Fr z)1Tn9)?r;km$k}KAI@70fslxjk=c=#SD0Rd*?>h24e6h>MW9#2aO~KYi^KSR8xn*A$!cc>nU2n*}z z?VWOJK6I|%z0Vz*CLyLhrA6Zy5#Bj4pmO64D)xj)F|*{wSoEvkgH>HUKV9^M-{qJT zLMoJby67)+%7(=$Eq4J_>r0uwp06rBo+O_BA-#%FeN8{e{u(ksmI({>0Ua^p)9kY= z`cvuk@5eD%ik7^bGLOM%Cy6d~m)JtvxMI0oXgfLg!~sArC?C7BT>-EYCn%WB$x%~R zN2RFPaHIIR-(|&Ioik7H+e&4f$beNeByQmbNaxGFAaT#&!I2SlCg$W597|OX<^TL} zP=!wYgY<-pCtp-Dd39CW|L}5{vmsT|f1J+lwQ@3RE=0fBQQ7@%KxM;`n-?!0(q3qu+{Gn%)8}~WjYN$3(8~zmz<^XbqpSBdlI&bo+B?NStgIZxdog+O% z|6ujW>DDjU{!J}EUwSZ>n@&GIH1t_g$RKn0b3dI&wihoF9`&J#hN#_2Pky>&N$+5G zb=lCgy4Kv1bT|Bm@YucFls!7e6r1ASm0uEeWh3+I^#>o`{{C8g!^-Mi+nGD>JKx_J zKgZ&1u6-=~&6@L?Mt?Z2rrNb$=G?PAtC_1;Ri9T`uggRu!)VvLc$hzV^$yNUovRn^ z<6T_Jf1Eb^yy*4YNPx}f6_j6J@toXx)=U|0k#0kuP0g9kq^9dv(4^)IeyY1pp`3rm z_~)yB{h6_G%YIqai2+>FC4RpG(S$nexv_Qc<_4(eCb$32eI%PFL}~LPvJ+_KFw>SNB-qm6QeQHU9s2 zgN_*Uu8ia1bgWNfn>n<&KQMe5bvEV-%3Z*@xYrUR=~kL)swVnTdRj{-4+YSHtmLqGg&a;J80&28tDU`b1|N4AN#tj93FKxCv=6fg?XfuOy%$8E89K5M4?2b&2Y0*C#<_Fs1gzvln>6|?dG<7!ATx3+GH-?{=f?s8w^UstqI|9M5-K?+66@ZS#u zFOn)`YFz!#7h_p&{QJT?oN4H-W@VgLQqEY-FymnwQ*mWwm+a~o890t-&fVRw{VYA9 zs_uHQhq2JNr*9v(dA#c&KcY|;9yQVT^eJ8a$HP`k>^u~E)K4US>nc1^;We{7Jw3a! z`8Lb#7&#JPGGQF3m7GbI8tf($bs~^c~xF%*QuK z0>$R|tv&2z4Gj(C#wipBmPd~su`n@VHKVj{2a4!@DSEXqDftP*s@fBNqQCWoPSWZ>5&V|gZt`kL4C=Lbb&K>Y$IpcZx{mSa9KKLG*hK@7#&-QCh0M}SfgR1F9=6(!xCo*w4o$EDD|@BH+s9B}aNUWLgY zlCK2qRFL*Xqk}pI#St$X65m9kcG?e(*PM{07@PPzfWRtVa0u^q5kb>r3{td#`nXtx zUu9U@6KOF#XgjCnH9ZgMNzOf+k^1^TeN_!@MzKkKMF^=(a3y1rXa2S(0cm=5EPfR_ zNO_cx?k=8!3Y-jrxR{Bhe6-us^4+<#vpoB|Q(GeP&@}Q#gC}-Y>&ISxQ0KBL3mShc0R9`VCjmJg5vU=|WucAk%A%k*e6P*76~0MHT%q9$(|8ea7wz(`F?w|8$0sj&Te{^_XL3;F z*#0&Z#>yx#M<7;Jij)je5EFA&w;dOec*Q3VVd+;$7-LdK5r;CP9^87PBIcTqhN8-> zVUF8=0lASSM8vGW|9%EUg({>YKamp+KwZV--L;ujp*fAH(S-nH%{l=)4YSxz{*5Sg z08w%kq{SjolDmbjaQUUPnRwX%$bpJreZ-~&ZOY_Rgg(g&RGAZ?p5UG70R4u&5a~k2 zKh=6tuOd)D72$mzSQ)gD&Ftj~3){9T_@K9U0DKbdkxiR7%h}rIfU10_qhN(Zz$s~@ z_0<4qu|Fr*U7VZ0ISbvm3;eLXj9aNh-@mJ!amT2v=Rtaf1p?z8WM8I z4kgXzT$^<8A!@@!cWwbb!O=*_OpxJG&CAOZyK+SVY>(zN!&tzyrFd(c^!n$TPF{Z6 z^&m|!h(Zj=%#W)A+m(rvQwAnO#>6DC^=sMkqy}~g^h<-0qQ>GF?>&C)Of*lNLM#%~ zP~2BP1ox0%J%>RGfBW{WOLLOa(U(FFc~38dLKfJrWKc)3&CC>!hE~v43GxP2$WQNd zf7*^~JOkE(N8t_WbLZ{@`et`FEF2utz|-pi;Xrb?`}+|= zL3OCuz)S&=X{HyQKwEk0&q-`#Q2h9?)4Y|Hl%)evsB8E3YmftDQ^?!j-+u&pzA|1cRo^ghr9>wO>S~}S@e@U?OCDr>VKmTs zd=4-KE0qi05G*uq2)Z28$WzO<7?#n|iCDREWeWIkhHW{@*id?{8Htds3x*95_tnPw=Nb;7vg$w9LS>~#{uZq zF?lAd=$!bB3?{X1i_fG-jLatoGpU2tFtsZBZ&C0F2 zh|*#GcQDf73<}sK7Mc!^Fz9WFvnby5FItKLKo449S+S?ih)*dW8 z%2ur0-10if%E%$bBqZc=m$kVxyui5g&+m#tQAX8pGzrj_L02kG_9@ zB?CQu6z={dpLqpy)b7KRmelzX{$ub*r46=^M;N$8 zr>H(WnvO(BBzEbNaSAU2A{ah$aQ1TPT#mk90VW;Okt4;@Z)YJN%FM=gMW)2#C+dtZ z`7PrK)d0}uWwL-MN6JH;=G7^a_f78U8iZa6=AB7Ob( zYbgA`0o;qC(Iv2I>JY+3Lihio5Lrn`+Jxbk^`QPnwg?KT`&S(Td}R&wUGTeKD{9!u zlMujuAp;FO8*=9cVu@7Q&Kq0)&7=kw0v@Ul$$eS->ji*B@g;R;m41< z@GE>aQ*WT)Lo6q>7ti3bJmI7efQN%8CxG&TTayNfz|k0YiEMv3kl_sVsTE;p5z>RY z4cQ^U^P)k~lA52|U;8}N>E|~mIv*?c+u6eoT)yBki-Ij@lQ}&M#j`pTu%i(}^%Fk? z&<*=Df%FE=fmn3{s&96X>S@li%O*0$UjafRy5=+MeTsd`u4jY?sgkVY3c2znndGZt z)etvU9GHYQ^sfE;hwj>aGc&b+j@VFQ5}#lC;e#+5I-Ffy<@NMpVCvqWjz{)CNijOR zy11_uP#|}jRLaEaoD4vX@mnu zqCXff*^yL|YD!tboS+Xwu;LZJqDL(_0WNNs$&!b%DFaLoqF`dN!Sp895idP~Vq}FM z*G0rr)zHk+=JZPedFA4}Uc|*mME3&k1?&sA9tKg-<|=y?m6wFJDsth%fa}RNsY{ps zfJrh3&-|1dkmW#GtH3)Z>UbOnM0@(g5GEz#{=8qj_|DXblBXYiG+=OF?=BQDWl+I- z0~=0-^bF!nx>&1$mh^-`+X>NMmX5Gkzd|%syKNgT8yqrS$ng^M@--_Jtv6H%d2mH4 zF!c&JzT}1_UK~G*ez9;wes}DGmgabFg`?gV_x$ihF&4iPS(#`mZj>Fs_c;yUaORBQ; z!ppZ)2+7I<$KMD;fi|ykha+-~ESVM}I$akf{b9UWi}Mx+3LvnCc(Xq!>M=0XG4Nu< z8iaYQtVEEgi}Y#^`AIE?62Ka;96WdyQDt+6Nhl`KNB0zb_Vx9RM5Xrvqo*jM7aw|> z&1+#GKADtbb7{e=pep$4w3Q4<{$6sNWrbL!J41~eu-alCDE<#H&GF|Of6?OXhm5>Q z&h6%u=&nH&M{eQ3gYQ<2Qp5g7Aye7|3h`>pq9j;A%FG}N`8Z$t;xn)0I9Z+TtWrVx z5V?4f6-FJZ&fz+5j#k2Xb`KB7;a+Z$5RFUcDOo4+>Q_dHWv1@P^(;%?Ya2;W2&LQUk zy$oI#-1d{ax*s%Y5^+OtH4G+;nU624{1jXRgLn7gsr?}ChtzU>?zNh-_*|(!R9fbZ z!ySSi8B8_QCgy=eFqo6_)p{@vB+nYu<5QZ>fvm^}X4EGzOy{~R_d?>_xPi^GcxpOBK4NWvq zj8lRSn;;NfEHeo>;Tb)m*rw<1kgmImyy6SY*e)6xUM^9$j&hT`WZ(*^m$0)tGksc?n_( z5QFWaqf0%I>?Q0_|~N4&^_4<}hEjQaiuH+zWCG`%PZY{70sDOY@W6gBtE z>B<8iW-Ci(haL#ah?>L$P`Ps_1$@5!EyG-&1B7NQuKOdh_7L0XdPL&o9ciHpp;hAn z0YdvK>Y@|`j7p@q+o!Ro&&VUCP=L*ogCpmLsRMN&fYm1Hwy72iqmklzybRq zR_+l7$`-*KNQC=FAr=@?$uPDN!KzYy_qO-byVn8X39*e}rnG%lKG=ZV8?|d9v^h zO|S^7jz0Lw6H`+PIF&@kFtW>=9x1e_>8|Z!zMlt6yO0&Ue}67=Zu92NwLoE_5r2J$ zCY+45byim(-_8e%)4O^Egg%q(g}xuIFGDwI@qurpz;pm{=!hy*p?>GLG+XIF%xh2D ztYWF_ir}nYkUfC&V`I@+R&`rU-#gjFk7mKxRw9w##&po4!^ zdy0yVj$M?`ZZ0MHwW4@`@eg``2`YsdQd5916=t@G+c%0=i)225@)~_VvZEN~ zC^1PlZ0WtT-)-9lpY0!jifQ!bVKB!P@N8>v4o?tVcXqZP0*huxZP-MwHc!`wP$iQF z+>37g<>u_}Tvo5_dOx%Fz;S>a3=Ky4IT*b<+`M^zbz$_LA(1yzA#LJ_#~locmkbgx zwxo3%FKBIpV82$u*dvFF1v#Z3bSVqlx8vs=!bw1$J>k%@5x0&nIS;hEh*EFczX&S5 z$5Ohj8p2qTBpg$Edq$>&)1)V{av<~ihqXQ3-CkCg(VIiRXvE8rJ+U_2-W_qFs0Yd3 zVCPS5WJEZK=D0XiuTME2bTC>D3{)>I=N!apQXQDb-HUr@&T`K?hS(J_0EY7L^6==q zD+!nb;Y8$@FH(pAgkig$H5t@Hcw9Wy?weyZw9Mb&9{{w}LD~#N4s}<#ujgoJRTPd4 zl8g|!s)R+Wq#%9ep~`yriLzJnh4$q@NLX35$nD9$L5AxQ24zS7w5EJPhs<$uERkW5 zM*vsOra}|^hUX;AK<`p%`HxbxxW7i@p&l>^Rwn}5d9^=VQwv0sF8xR?img0HO+Russ2%R_+&{T6uO=slc}6EEL4xPd?1ein z6SxRp5GDBH`d{TV`FQx$EKJ5o1(QSoBa*T}W5H^Mz#K;bpdr9SS0iE;W}yD*t)?yr z7^H9eBi-C9V4Z?@j3mwqan{C7o6L6Eh!J424jP?>#l?fDMUc1_1}=mkCrD)7&OQ_8 zMUn)F_LWPT&`iezWER9NgPoCzwh7{;!`=LjU%!9A`ujm7Cw9NEOF$+-->|)Jf#>&G zjZai2a_iR=?UuEO*gO!VI63rQHMkPA6r zl69eAa)e}g=BXld!O`RHJLzoZxPd2-a&!ivvVSKxeWHS(pRi6%>>J zy!VvOTUb(xR4%w6a!78i0q&TC;X(2emsULqQ}tPoo_ ze*L2}IL*QcAXVO8y9ehM2E@HhnkfTIF2emp;d-7tHV!h2K`kDCVp}4c*@)#y273J( ztK{vk(elX2NgqPZXd7}rar5(j zgtmw@W>-E(-75u6ODN=AjyEDl-X7nf5Iu6|XyVxd|mE==(0Kp=vro;rn>Rj?b^z;VV^xImKsh)NWag({8 zjR%pA-8u;jK_6K#$;SY+{(`C)%JL*YT_trk0^J}46Zb&ueK@v`C0gsT*TfAUF`bRP z`Ri*(?yWmue3aD^&v_7yR@u7GB1vkChd2qYQ9qRTedUt6XW(X)zL|FQ4c5NSmXS$g zMI8WN#1|lH-#;3JCmA}7SgIe$o5j(cZE>n6(QoU_=&uy31K6R_%&A>OA;{@=&iDm8 zD3s21y0DW9%3>GY@)vY1hCwRmth7W3Lv-!BNyv?>-#*&sV7HX1es>FN>0kh_Q8aye zE08GCO48Gy4SIPP_}Q<4QAC4;M^$v~_@1B8vQQ=AJOFLYh>A@vv=?3Xh683pPAAI3 z{N*SMi)p#7a_EIEWNoc6Eye4_izsxSqgY9>a2P*g z@2N0DxQ}9N% z@Ts9;+C!Yir%)%k9}v&P^fdc)E+~&lDskcQo?$NPiWf(P#$Af?YcE}JpID~|d*?V1 z^7gG1zy|MX>>VEC-L} z&y9GN3Kh5e@7uR|txof5N3nvQz^`7q{d0o*o9!fLR8UW4uo8k>CE{oz%Bv#aA0;i5EB(84|(|cA5C@ zLhnL9wJ6SsoC!HOH5D4(c&=G1E4G|o5Y4c@4NZ4kcnp-|hRrQlh`ZfpWJ?zdv=TN-TYX*x47rkVL&Vy|AR;4=ht__#{LbM$dl;pmPMC! z{MHR%hCKS)mY#w@x!RHWJFk;IH`nF}Pipw=Bj-F|+(sw&{3LaU>c#18HX74Qp`NkA z(L9K^gH?@kQ)?$WDUSL7sXjaEeb!-}1&;$cmU-{(JBrUVUc`QgQh*Fm6wW%KwVdJp z*84Xxg1qk6*V546kkFt1J`+AR#gWAaaPYrLFjCADrY=`$5w!m|R|voPzoTLN;v|95 zqkH00_vk+fDo->P7nFbTQ`Y{2pHi5a`P>&?`hb1eCX#itvZa-H$anuqY>|6rBpX;b zFmPN-6l9>HlEYRW6}^8ETMCuqx)~@GFQ>m3^v^r_-_WAsU%dN$&BF{(T>j_n8H3}) z{NwU-!Z7%Y!u0q1kiY*2c}nd1oyc8aV@-_7?)c{my+blS4GjE7C{6!f*#d1*{ui+e zYJJXJ+lEU`=9DOurSkuN$p)j&P@}%Zh?-lo%PqRkY;9e`-Bh!`r%af+^z;Zn!Kqs~ z@lTFWfwoH?o7ARu(VEv+c^UQ@$lSh?NY5i zj-*E?$E8E-^Hch}f~$i4Q_kTPwrQ#Dg5;Ynb~~g0~YLgVkOqh7XHPGDlFuoqR#s3EuMQz(>MM3 z7E2q;`yYu31x6Z}C2sr?7r%8~-5-(e(&}xu=NK3+=7)7>@a>m7ESPs;jgwW3`c67Q zgY_NkuK(Ji9bOWwpYfFL8LW-g$#CDeNsV@U%+4UnwyS1_!4p<&#`kh^ZVb2ED~PO7 z*s_;8!tpmTpLhi;UWFcIXYZSdEbNg=vzdjZ=}Owk%~~aF%-z#JIaydkr3yuOW@q+! zo5f%9=6spO`ZDG;+*dSoxLew@&FK>-A$tie|DUFIPlwxAZ9#N~`n zSGaBQ+#t)7P5d6b;k54A&srg{LtMwPDs0w%sEoUTZ0!b;gS6ugz0_pL#JeYbmVg^ds_S35&w#%tOja zOR7(;;xF;~iIkQc^vreN}1B7$P+x8S;Q^Q0G6D97$=ch^m?l6EE| z4NdPNRi$gPMMi7*#>L~^=-x72uNUPu>`Qoip-r!fH#kgXS4Qc-seEj=`lkD8CwJ@A zuQu++VMCJdq+4k zGUp89)s%#d9&!Klp&y?67U1*w)a$V#M)S;rQKdH*R>!RT7fUZ#4NE@pnrZDBhKUKT zfuRyLMW=D6(Xup^G$BEFjp$je*Ir$#CR#u6*~Rr$~zDFSIhpu zt;yKmPF#3!x|{kt+wvL9*)`s~G7zPSDRNN>ptDYn|pu# zs!)vEfJRr>z*|b>FAVrUJ1+i{A6F#z&Cm1b@KQ7}d45h5PG4^(j$&1#nu^P8Nj(p|+`PFg* zs8$;`)P1j-mQ!xuME$wOi7qeRkBgf5^y!e+F4QaHs91ORPqmDCzq`hiYV__tZ)ruU zZuyJ(*rQiOoAZ~CKqTiXs`k{i3GEX3*{`V8Uxek_$bv=|OE1c$lf$5)Ap~YfeA2nN zFV0jh$Yppyq+&Xek~UDgp@F+0r567!e7I5IU6QQi{YpBjJXr(>-Dg(rZ1l#y^#qLectTm}8A4i!_?`_Uu5iXwUi7I~f62VQB)a1Oz zKbgiEF-k|9#4i2eOFujF!pmR(IlbLnKR;+94za>c`mAy6{uL~uNh&V1EfyoKAr4DF zwu{QdDpZMyHpQUHc`(BN!X=N-ueb)w*oEZ%d1%dtQ#pL=+96}2zqHVVkt|N~$vSaj zyiQnrP&5-tTdAq)V#GG_#MOHYDypg7Dd{@uV}L=KP8-)pz4kXcpsd&ac#Hm>siA%r z_QsSZ1CKCd$gFzBddCzXiPAM0Bj1kIvGCqy;4_^Ag%eP^*x4r+4~hyuZjBi4qKor+ zROs6!mRB6JhLEIX>YL6Ld-N#Ngy-{Q?dzt)HoLa%QSG>wdysVMfR%6gQyMv$s3$^! zMq4Z=_im4&Ezz+PoP6QG~E=3UPVNZLtAWP zBeS#nvP^?|i!9oCXCEAnQ&XG}n7YXHDV3QkRH}(an_8GH8)B&G$nXw8F z)Ay#bF&F*ZHucOY@^zdd2Vi z+G041iLuuj^+WHL_DZ2qc_pO`RC^AKnp#>aK3MC@fH66_&|4M748PdP!Gv2eitI9W zbFEU>H2{NE*T?N+5Zy#wgwp;Q^Y35e0WsG>Dhjzv_}K@K`8yl4%tMjAJ6(91AFD5^Abh@3wGDo%Qd)`WS^k&`DCV-@T|q3s%V{X+zw$)Qv^4X{9~BP0e>ZdP95 z*8Otcu*E{ICPEq@A7>A9?)>clTia50M==S3knV18P$)C7ck5F16I_}zYwdi+bZWt0 zONE^0QHN#9nl+EqY9$pEB2X?30Z7Gk{P-m>!W0|g8@%~?8#E+!CkJ}?tR^zh5Buin z(`4U_X6>LdKqlTVtCjU(Z|b#AsVw?~k@ z5BQGkojXTd57;F{NIFQjq%TK7e(!rLZ*u(`(OT#zz*HvQxG@)l)7~>O62Ca_fIHN$ zi>!17x|bIkhx-Swgga{_Yl+jpav;6^3aH5zDv39qW752oC!_S)9r;Crbns)j0Vh>>iiPBx~=Ev9P1-(Sbi@UwqI?wRfa==!FC4!Rvu@ zEjzcX{Ji}#sbYomK=SDs@7Jm4>?0(NRXdC#Eje7c79@0Uy;R z1wE_&fPkYwwp2ZSma(t%dTvsmSZg6-_v*ACI^?&Cf^e2r+R_4CgWFS1=5+rkom9*< zE(YybG}p-joH`dN89BH#zsxAQaa%&d!-sdjTJ^2|YEo?H)`djg%h$K>?(ny7;JQWS zAU{FpG)v_v)fnDCx=gHP-V;ja#g(s?pkqJ<<}3`T;tDn>@sv4T2!t*wd?0n{vyG z$7ty+UTAB3S-Z&oAS$+aLT9iv{Fqn`X*i^}aT|6X@TAXOoGMevwa&zWFrUzRNq?&< zWR!h2#|vP9qDS}eRhjkkB}a^I^^`KWErJXvk5lFB`U>9B0c-cH&?9tyG^qQOPF08% zxsQXwOA&x-70mkV>FMY^??2FIIX3))9Hfj4cWs`VOs8}5s;k|Y*=|2>vo-Sx2~puS z|7%Yw&^T{2pgtxUXrA_Sv)}Uy36@W+ezY}0pRQsf>NUPsv_CttalM7F6ScV3viD}Y z<7(|iixF_Nd{diD%}fdnvdmLbjX7ov{u|TnenI0DE-|yaLyfpH{>JVigvxWe~d= z!1F5Az0=@tv~*Ealogc>9^zpjI4*VWTuzaj-6ag&#GA;=RBr?V9$T9Xp@|23IlFmK zzILVMKaWEKfcmvUTnNbWTTzBju%G$HFCvnP#u8PQoRd@n`o41q%r4xv7#CUdLiy$< z+GMTWRL$LVLkNuBJ@Ox%mJ=$K<5cZ+*mR;$uP5V7dyBsQBy~SuRzt|A-p^D9s~lGU z%_jV1InQ`wvazSTyC^U-FxB&J_^;a+>*~gW0)si1BdE5)?OA+-2#8wUjbk)A5u7sqWnShm@ zqm^^1@4B=iYa^AXLP*3Zv*tQIdK>xvwD3)13k(leW?NWNQc290E9q6sc!R7)jBQ#0 zq$eeupFIZa63J3iUnj|^s3ZgATbQb}1JaWvh;ly-3z3Kcz?rPKIR=!%Ou(0g)2{b& zR1hH3@l(>yGn13?em1j{1!p7=t@LH6~o6TYcl{nGbYq z&XgS$zp2>q=9Sk*9k63CRX9Zu<5qRPE;!#F6=$z&nrQZY01GDl9dx;^kF3hHm*zk%N+f9f{c)&|e<8hM zOmJ|vaPWHnRNd9N8EGja`5w9P7aJULxw&y?XZuZnf?I=uPYaCD{2^6QF%;gsb~;`e z-Cb&F<9B!evu=l@5H7`Ns_R7${aUxCH%y0|{$5^7S#+xQD(33%_KJMGy{)DNgu4ym zc-TUe3kV4ak}0Lfd!W=Ph;=Z5k%rPzMp|k*M2-}HW?WGqzg6M0@)pd#ZBrxK7d3 zS2(pRHXEzRLvQ)%>PC{c;qr)GmBB_p1kyO`pF;U_ z(x|k5eG-LnEgSD1blJ`;Uo(dOSE$=Dy56iVo+vj$$4l3RY%b&>tAP|#c`_V2 z50|1$2LQePy=@<;^IV*c2k|6MJ8{b+HlG2i$*RFCly>}8mFw017@H)d!2ROS)*j2| z8GH{t6W?x&=-9WOav%?-QlV)zE*{GU0hFa+@o_nL#7xYcONR^UmPaZuvxwo@<1;ZK z$K{FUIUOMnfL#(*dGJ8e2j4jdIghZp8I;tWLan;Z6A}t{hqODFo}Jq%Nwr+}4Vr~@ zRHCPz`h%up)F$JN-7X+@nyyCyAPC$4j%Afe)#*6XMAa(7T0Tf!J`I@3_4QAt9_zaO zS+@1DL-Va0x9)scgn*7_ip)T_!*+_1WK8n9v)4!ak<|u zXTE;xC}*K6c+Lnn07F3d$i>UM(<7~B8*AEV}v#7Xo9 zzMfxTFq`akF^({Dfe;rmv_JfL5X`4DlvtzJ$ByIWvH-V#;S7zwtbC*vs4~u%aMoh5 z*H%Sejx-h8P;uMPWz@gNBVHL^80Hclc6WdA`HO9vxsgvpZ3Ocp(dgioHxC#XzOYT4 zd;CBT;WD?8yS+eEW zE`E2NskaFQ1%~zjfykc`z@>eDriyZ%;CG02#>R&WGyV3)sH(uRm&!=iZps0H;tdqU z;Ua$ZIOPF8Jq1vADB&5ueDlWX7KVFL?@FO6O}X_7X0_103iKh)cjH)k^Nn|Ozq&>z->PY(Y^`?J1%l%~W#L1@PsxLTrsZP9%@$ zOwi+;&*cb#d%W;Ry3u9S_hTE_j;8}HdR@GZKRE+~APbq3jDM3mg4 zt1A;sRDwb7O0v-K(&;hw-0{Yv;4ikmP@R2_i0Ck_qP>bp)1gRY$*Ed#Is@MDd4J~A zmv&te`*b1qCg5TLgJ%!Chrw4@4}3p8YCel^jDOUhI3tBi>42pOLb6w3z|6~6E7w%W zZlzBzo$C0r+ErY;PzikOuS49Tw6xoL3#r!cF8-$q#U|t+2o_2uTdP>QrMGiL^W%qO zbmTPvmLmFOU?RZeXsd3&N5mUSHFdHj>Z=`ha>6a>yC@XL6Cj-;LI9}2i}50%c})DV z0Fo{v>qF~G78V6H)>e1|mQ%GHaK3jOZVQ7vn>PUe=>r3Iqa*iSFUEmGN`>#;{hOdf z3v#+)^-c7aL`|UCv=DoI^}DW9yAM59f>6NOmv#yuM?4Q8Ib9muKu=7Hx(Ry~#DTZA zTE)Awl})|9F@#?Z+1G82#>l^&~ zMhin@{X#X^2)BTH49bzuE=?wQ*n?F6V}LJpxLzz@>Y5@|v(=>8UU2RNZLycA)$q#BE{&exqD#v&6Ky)gPk3S)yFZKPdoTq60ogn>vlx*IXZqN zOCQP8#1#?}ff!=FvIp|ubj-SrO9YRosLJZCmnY7JLqzZ(7bBi1^})j5|IkSp`f4e$K;->4-yu zAZ#@dfi(PtM~2pZXrj6 z4Aa#oOD*jz-3jVu-%l(5g9Z2u3(>}$7Wa#uK2dA-EKJBWZ=ro}?owR9qSX%G@I#t84ttu4A4?rqe|O4&tyP1F!c zKc=ODr&h7DJnt8TzWg|>MjDDfhoW)%e7|9uvF2ouxyk;_eDT>YJo(YQZ@xUd%@^}EXxLldtz;M zJYT|NYm!{qVU;o8p84Hj36mGrVb)bL^-oM%j)&eyCnpDk(s=BbFNzSbru{#$CQSdm zg`XW-`S+i0obg1y+tS%Mvf{)nJ6@NSv{M~mQu<;D2ij3aT z^1haxL-*pO{pElE9tfHf-p+V7O!W9=aFuLiqKVi3{~w&_D3_)Ls zf`d$84Y14^39f_S+|Ap!1wmOAkevKk{p0yZ)Ck)>4^lRuZZSl)g9&>t$X_5J@v0xU z_0*(oYOBt6=>ct83*^D&zO(=O9tBE$4=HZHfA_Or2aR+cM~+&?=c`IhAuv)PSQ{27 z(SpcJegyzu0X=x7@Tk*I5g5}EKuH5Sj|j*^h>SI9<&!VGrsy@k2epmt;_i{uJy0X7 zHxAhN3e0z)g4BV892yqZJEQaO3);~4N6aan2ULE@81f!|jmis_>A+1$1bCj<)hBD) zT0neh0^q0V5IsBl7jWxxffH?1ZY|XH^aw#UQspDiG;f<=6q09sGb+?fOhM2(Jfr7QGk{J!2&2Be!{cb15pb@! zoevH$NzDBkN!|DYzaJqCF7WUJf&)N>)6#)R<0>gf9cxzfr5g^V? zE96h~JVOSA6Ntet5C?eUC<>((5rB$0?J${L&gH6@*y?FtOj6n z*OC=t%?1?Jw0ZvAK@gz60%ECN;JX6*4}PVm+liT)+6U-K;P@9A2)6d1sv$uY3XBL# zAXD$yKh1hlKUpZ>F!|^RLX%>V(H#_^VI;x6Ljk9-IQT};b?1ZaW;YusgocTkz4+t; zFI*~M5}_&G2x}CCYZ*WQ2Qq>%u66hsJE)?9choIlc=~Uyj)0_JEnFzL5^@2nT5F=x z330fCJ(?+#0jUQ!hzF#=w}I(OBjY2yF=j9%0Epx!cr76p2<$!|zJy6w1j)eqLIgQG z%uk`?cNGP?n~b2YClXx_!fEgxbOCPu>I;J_h)Qr=h{7A=Lb>wM6%fN9H|qAwhypyy zKpYyRMK4#wt3>1&DJd!4+}*nY8w_w=Vpg@|$l-4~*I+WG3BYTJBV7JCckhZC8d3qL zg-9gjTkRljHApfmRM@lP)2k)JMZ)pQVNE|I{QnBFInojmC@yJfk2J2~U0B?;Z`v9I zIr%Q#MQwt5v0xG?$8O$Njc`AA)MI@*uV%liy> z58nZ(;AB`8pn1vwOmP$l!C>I^21G3oWq7cSOZdRGhz$b32pRhn&rexGq8eBrpr(lh zFzri5nuxSD?#-KsMtcjGF@jqj4#aSCCv7dQF2ll-@^Xld03J<8HplONNCsyx89)R)V zQeOtHNJ>w}U@wp+5JgTn=-`ok1L*ROeZ>rSG^y*K+{v^2i&S=fujm{SwE55^(MwAy ze|J4rRsB@L-)Dj``V=pRj$g*YRd(#T3GRPR^XVcOcUyoe2b2id5?XikD%3hbF}uwL z^)reu(aVBsQGPTd4q2Q_aUIZpr zh(8`ob-(j4dLBHkmVuNEtIB}ti-pt#Ki6J9zNA* zXn-(nUzR*JEG^K$X=!dw|E-o6T>YmbRIl2m^-bcl={xH?NG+f4=I!(K7M_9%vW#Cf z$a!OY{j-ekgnRS;?`6CL0$=qL$2&`i&=HaIpkX0g^3@b6ST(b-^P{9^4OI0jyfF7hmKF+}L{}$)`{Zv90b9Q>9S3|iQDLIy284aBCsC3a zR3@*a#~p!L1Qy09z|AOu9stk)T#Q?m-xk8*h_hATA-i_nPS>i&WNrYAC<83uf`C>6 z&zm=^A6yNVFy5XorNte<|NcCnA0Rj(<_A2P7eFUG1bPa%NIU{x0r=&X@0IF_D zvuTW-0Sah8&12z=hqXxzxgQ+vei$2f95lYend|TW6>k0od;`Mf?fhi|YA62BiXrI$ z;>)0<^o#utpaLP@9YCKlb7Nhzz5w++-p3kVcoc9l1Zh{2k&%_!Za!E5!SHC0nDTNi zNUWjpzyV(cCMYcsZ}?y$3bq(fEoI=TAzmjI7EHiuNCYm6KZhT1+WxMcznxoN&b2ZA z(b3QzMp>E13~j`>wrcVJ(-txjf-Mhy;)g6OA<)PPU(7)V}Q;#y}YEuYGFD#pG90 z|E?+^;6~ml6-%x)bZotMyb%D4R%DD$A2C8zn(($e(NNzm^ zTNy0ifi-I7o5A5WZofiXT{;+iS~7S=*VO%gXWr}2#VRK#*Kans-}c5x(awCVe&o*A z@)qOI(Gw0W4~_mz^@G!Weg&G_hJ%%H{>0^y#U>$HqQ@hVj5DI&zA>SqVP=a!7ZmYf zhBgpg&guZH1K&E2eMuD+0W-75vYBp{=ckw;`hNxQnW85K^7N2A^RQ&P>|SM|5^Xgm z@!o2}D+i4n*z${3oB&-AhNS~EbV^HfGY9;(zP>)D6(nazoTT((?NWb8mnG=x{kj~sfrq}Wssm}}|%hE29`%4hGX|}M63vON zj;i!(Uk8q=#}yFyU>N%x#14^a1~6V=PwD_JWEr)V;0X2CUipnO|z{f^$pc)Wc2<1=6ufl2jsSg=hHFNrnBx7LXrJO);{Qigx2TkfT_ z#^4bWia>Fpkgw&Qlw<%q3w0sqHLN}qkX;bF_nl?y?ctv-V8a+H;?-C_opJ%$E1UaC z@8qWwLN{>N@u=7$#3l3N(Xd0d{QtJA%o1j2zk|MuIJ4=vm00XajO9WQBuaF!A8!G6 z#M0Uh3#{lNJ=#}MZB*9D(&0g>}0{MmO zVCX!Cs$5(H=PTH5PA-1ZUocvD#pST@!eO6J5Ago-0mzO!+M zDK7DW+_hwK{0~+Mdw_gaFe5EDdMz*WY8=zblYz#OL%apD2@>6Y2 z;CE0}9WWjNiu2tk^%MDGHq)JR3kyy0&p*Bt6PrgI)S!Mwl-PlY28&q}4m6@;U_RpJ z(T0wJS`<^$&d$yo$k9;{VRB%}xdPFb<3lhCvO_>p9XYEZNBeFz#RpkwClu>oMC~PA z2tX%S$l%9+PZZV^17GoCQG67z<+YD}=qu6wIJv=*uUP5Gf#?ZLoSzj-Hx)Tdx?V;3 z0ut^JvgSdizL8C9Y3Jq6%2XqnygCQKoN z1X7jNdoj-@cWvc0P|#5hK)IA1ly9VWxtQsAVMKs35;O)v4rZ6Gn>NIh=;h=( zZ_T#MsR3w^4blIpF1qyNmr>5|@l6oV2L%EY?!(z&BxAjN?e=d-7s$ZUXa#|opV{R=NrlrN(*@4FvA#kBDEGlriwOL)z;nYD3ePP_Xn_{o z?j%n7uU$9Va0}(zXa>>?5z)+7kZjIf9%t@b7YU&fp7#2tNF$dy@MD*4^>4GJMD;56 z`qaTD8D!v4h?7_t-Ww-M*;PE=m*;_CXgV*4O8_Cu+8A}6NQ7r zP>hCt-xU`2THIA^i((^oiG6zY1_41^t-Iy#ee7i2_A&^TgcUr&kVt_ke8WsYK=s(z zm}Jv@`&$l&y;~ozK2tWdO)bbr<^(ZZY`~p=-Wls`H84_c^9TwmjmhdXC@FJ(4?{-= z7GMYT7@&`y3@}rWupufen?`%7p}`Qt`4sv(BjA+l4~PsiI8b0DP5L^rpjM+Ni-j|ltFb_V1~Qshn7o38()0F60MRB;%VrMo z8A8p7d3PGLC+>@+1PvE%fHhq#SlXjN$5Ifch0tngcG~ZUVchM$?7Qv_T2l}v!OSft zF_91EZs1rh>gXs!=eIgH2aAsO4(E;?#p@%Nf2LPK!JUw-a>Bn7dk=d{x03_}2QE(5 zdqFyHlpq>TA|N1R;~VNy(i`3@__^j+Aj20u~s3E zU9)vK9%Z;vUFn1lmjE}Le zY7xWYuBd0Ywb+%92?A(+CU8*ubFPY(?t_wSJr8gUeeXSsg>vfyRCeenF=DVFo z2=CGC<{zL#6HbuC(&2mU#*G`iP<%kY2aqx*Y`&IjjH}L-dycu!Z1grFdJL=HDZ@@2 zDmMM&wF(SV{}p+pit7deDI~u`vKd4P! zkOiR)l(C>j=)S9a-1R4Y^AwrstKk+~@0{t@%le;rSot(Fs($~|>V{BHF3l$I>yUyM zEY5E%O9_zcv@zo{pK*6O$@KQ8{2gUDNW8OW%%4z8URWg5S>J}>#h};0!gIWO7viAm zbUuhgL2sR3Mus003F~0sdWUVD9Hu_aFvEhO_0EnA3n49#vM+!QkyJn+7|VlI9B*zX zIHT3)t5|_aIk^1p!>DC8ziF6*O|1|W0VQ&)^{LUYOOCIA!1zRA%kS-Q!z?L3E$HLNC?z<HBVs_3X4YoCY^+ACN*y8y?{QMUMm)|oNY#BAyjq(APC?{m~?&;!CV$vu~R)M zw*Yw80&`XUp*(aj`g#Zm61ctFeu6$89#`$1ZiBK!6=%^JA&ugdsjxhsgRk_xb^z}#7;w*yU3`zbZQ$ZRVFD40)TM8X1x8j3ZIpb7WdJ6AxJ?^Hk>Cm zVGf+odzd6w4!vlPZhbSA@4G8AV9k6JF0nsru)bHi?lWm;Po-11)WW`r_1Qi*T})e2 z)9;^~cfw(UgtJoyDy0!1?hE!ct=A({L=Z9_xz_x3h5 zTeAscjh9oYj2}yqRL1X3%F_vwa?n?S9x9<<bS$k-@%-Kv zD%}B-9f+fEKtRs_#`0R3^uDiJuFdjMXiB0(6HgUqOite+Sc-s;-_090Cj02=T-J_* z5X_d;P73k&#JAe#k>+bE)S)6x++jkTMt}C=XhWajWwlD1`6vq{F&tIyTgT`#>CxI& zOL!-pxEZ!_Ebt3jC~gCvv7-Kz0JYXoC!+A0nJr=l0DT^ww&l8tl-Jts3fr_F8;?M? z9AsWZ;N{tvqdKzKlX8ry4bO{0{OrI`-}DMJ2f#Zl3h|w6k7S2~`Gt%O3ksO@AxUO@ z{0%IU(N^HYH-ix#veL+e&hA0W`~f9pU~W~cO`SR5UDO;mK}E=k2+DX#Nm68=fo9(* zG`rrd-hj6ZF7bS&gR@8Z(U?IYHpV25c~N9v;kajlQS>7*B1-13b`^bnt)M;^1^eiN z*@RPJOGn3r`>)s4vKfJ;Q}uZa7B_gR6jv}zS`ShN-Ph~fK|{Vc7_oo z36k(^HhFBXelPNOymMzsfkqeQHf>}p9P_qQ?)f`Q%$L9fk-n-Ph7Hn+Wh|d4UMpEF zNnt#7z?zIZcSK?ki0*<@>dzvYt+oi!uB8j?*(R|h|G@&-nqdQjp>!&GYs&(XfOxWp zin(emkp2v+9b!Qm;6?_D0p>rO}4Ycv=b9BuExvlK!(Xb!yiV{dpHX4bCh>7R(WOFZ1KEp!1Y z6g>NIO-=8?8>uTXr)P9J!UuQjUdHvwnocH->R_a~wUlNGsEbf|oZyBO0|2wO*i%dx z+v&Kg>b;mtl*)jSB%Mv%H$E*L$*lglPpmZqta*tu; z%@Jr)Qag^j_g*>SAMIL-zDB5a@1+b?D4S7vXtkl;48_BTd7ujnX-^}_f7&$FMw%_G zM|iKdd&^jDggmJll*;M{iSW@r#<9`SpO~+>ER9X()C&JsW6*V!2C79Qp%owxiPEWk zR$nnq+@MPOD2c%I8M=}8w>y@v2`uOIF8*mUOmR{KuN`-vocxfwC!aO;n1+TXKihbu z!(XQnD#hw(j^3A|e z^z|*o2v6Uy;t;K&9mfm6DudwyS@#*xfQ%L*F_6?6i86if2{2!>Jor+F<^J!g{Lpv? zm^{kjXlXgwjic&|#NflExxbG1R!`4_qju#^NC@e19rsM2yd7*rm8h_PjdgGQDl`)I zQO!;cGy#)`R$XMg0v_@gp=Dy(rV38z&?Uy*o_`HGvf&2fC$4up-cD8rS$2J2KoRm7 z)NNM^j1U6BtA4V_~5C@5$}@L5Q1&+oAp^f}KR`ZM43I^UtdOj}W_?TInTC1@-5 zq)S>pF;x?-`&2Zk4-lhn{Q@G+0(_U(Q3EL8?urX-gE2-y0Mrq2SX6IvqAmhz3I!00 z0I?!QM^_dWE$4gra&D3R&?ZTSs#Ud8X;c}4l?uD$OON+DS5c`y!hj%Ya0P6%9(QtY zx4k}BesHGL@g6hqKh5G-8B*ZQ2ty8JQBWmJ^Icmf*}5`bQQOY%Iv_v(6IX|tChw-o z>wnP_Z4ezZ8>89_SBO}Ye+1NkdU~ZZl-V-d7DmEbE1z_|%Z76ewP4PIYbgx2(7LL|K_dc)eZr>pu^Mzso z8le{eqb2ZyRUoZApI-?KAGBNcoX?L#?~=%88OO*2%Bsq7t3?@lNeYRHgiI!*O>XWl zz*u)XIW27q0FZ}k#dE%dyMz!YC~*{)M@zZDJJ8Kd24)&^{?(Mcj*c`Cb8$4TInU27 z5?iCfoCDoY5XLyIOGEk8QEa)-le&8nUyNAf&J{xXh>H5$KcxWr+?T6CaPoa!<(?gl zpWItzsp7B4>L-UVi&jznaBywS^ELS@&%`sG!viivvoZxgTso#Zt>+I z>z3*fow@1Mp-)%AG2k&M-yTZsmsWmU$bOvdZ@-&}j-A`_GqehToDU)Y0o?m&kAe%? zs7)3t;B6TIC<>}%3sI(x+j}G0UpRN0EH38b;Pk^pZQpd6T`Al6*ZiuHlh+z03o5Vz{tCSIAX&VU_v z9rixOlXs+WQfh6_7w#;x{x169Fg{)sHwL|fV`B6brR<&peoro1u51GS*oZ5}Chrfo zs+3?7uL=(z_hr=OKTVq?q=W&2e7Nvz0#yS# zcEvK{c94FepWu{S2ImP<=o>tLP70k`9K8M;6+Au&XxSF@GzC+nV6LW(MLaAjB4XhM zJ@p5X{{`U8S@s%8m<>YrUZZO4uN#Z?o2Yjd8DCTbKfts*hwrbGu0DY?Cm?2JyUMz*YOlt?YTqd$JzW= z?N4z7u3Tx4z&y7RX7KfIbDs+BuRBR*jSc;+zACD3 zPy6u0gMX&`-3tarT}eXDN4pNSOZme^YxVxbQ3vx;n_vckgP1H9t;wugk~sd>1k{v( z$WJ?fgybu$2^KpYdkj@La0OFTh_4I~gKzvrh_I%HzQq$H{1E=3V{{oBTPSB}^5eqo zQO|&8W9{ju>Irz}s3+Jr@ry6Hz-$l41&2%x;0HpC?^ewaXm<>!B!VP{)DFU!Ct!si zK{-OC-N-GRt9B9K?;l=A$<55owF8gj^5LPKFF|(zptaLPLK)tzeY?z*C4;VA^Whf} z*SpUEJ_pE#IZ7m}Lv_Zma!~>8+sgk67{(r|jfXMaR9l2J6gp5*CykWpIvsI~sf^wP ztzC7bKLM#2(n|u;x9)HOK~v8H9uQQYLY=F1b`k;2OHGE^-tztUk<2v{Dg6R7v+uDJ zxE70D^k05+63T}^T*tY4JEdo93dQk+oavE@&^ph*4K)1P_1D8zP2@FB3m$S%6!Zjc z#%i>&O4CaDNRh9o`h24d#ki0q@(-^#r37f|8Zc@HlyaU%jZt+`$RT*vHqQiLS81O2 zgk7gMHP|^jjT6X_K}ws=)BRvnH0)geT%dCKjpV56VG#|r1CQWWi8(7^4Qwtw$yFa1 zp}T+oGqjH_cNU+QS=kk|5dvCKVQtu&0@CRIEN2~v5rEwZ^B`HSfj=9=c{R92Kwn=L zP_IJph@eO&V477NF0kv$h!n|{mNl%P3iXDxI`UuEKJe9xKdGC^e&;SYz-Xf&xNPia z(QR^g+p8Es^QrG#UfK&#ZpO0wNxUutSQ_g&SB*>ve*l=_ z2uS$C#gCgieP)MSFOatb2OL1>uVOzNEf>hvX_tpshv1|UbTF((C~T2X2@2~JciD1u z0nhC3G*Y+%O`SC8MVV&Igj)N)%?*yp&Aq4YxcL+rBfu>x0%#s`E`UT!K^6QUPjNiI zwl0eiPJ!F>u}x5Gqr$-RR3d9*ZQtI4>GkRn?Z@Q0Lk;&cdJo)NbkA12xn@Q;uH1UO z?w!)rQ1M!`;#XzspAeYX)BHoFK9eKdZYz5kAd!DIxo3ls&QVFP?^&Whg66Gu4;I|} z+LFAnXeJ;2fGXp}h}ox-yYn~px}y*=vTV>uQNH#1c%AM&cq%k#cEkatgiC03HCNT@ z*M38CGBQk4(+TBuD|ATqg`gf>Tbt=)gh^`0Tq|XLeSJ9E(wH|Cd9PBnU>0b)bO@C} zTibPbs3uuhdZ1DPtS5e6UWtf=;Z>ujKw;KrNwMMYTlo&P>cPP%K^TzgV8Kr<*v$My zh5BiHoTvDf9OSwPT32fnvfrD7P7v3o>f_r~Qp46o9<0GZV&9BM?6tIX0bb|BML2K?fIQH286kwV z9&*Q}0zWzJ7SqavFu^vBzwyn1TQ-rTO>J9Cl)eWN@4IDXu>K)GOMFU8sY@(!su8Rw z0^n`=A>-LVt;L$hSFDN635s#vgv={{3#iQ45}!Z>-azqy@?f~{4+M3=GD9#=2m4$;Wg4u#`MzwL3>=B`cMi27^Z z^sBLIB90gPY>&&Q=5x$8f1%6wrr~Y()^Ga~s*gZtPx6B!+n?_@$A?A15b;$ZJN|PV z7n1au%MOG-$Q*ryTIKNky?=zLp5G$hsEVq0dNN(?6R9^WGjle_qD+6M!=xhkIFe)i zrUMG9?9Vgz+0j?HrAJw=9W=O#884D4 z@Y(rds0tGWY&u-1NNf#5{l#LG)DJn1)ZR@c2V(k2*%^FrV|_74_8-ucimfqbgS*`5 zQ}TRD?g6pR1E6Yp*A*{5$g{_?`L!_N5LjFHjXOg<+@ybU0a6k4+! z>T)K)dCTI>ut}VgINxgL(j zU^tdoYDl%+8&ldcg7~>XS$fsZtn=NH?&Ur8x;j2W~H5wFZL{t_K44fh0n7J727W;wo_I|-jM=W7zSJM>*5^# zQkUO9H#xXm8d@s;ymBr;B5iyiWBcdf1&i;m9^W!MR6*q_yIU7Mc=k&*=|p-NpFAa& zes&=Pf05@a2J2n>(lR2_pX71Ne}L|zbKDh1f8PO`i%*)LTYpgXe8r>!AJ%)<_4`?- zUQ9+u9Dd;x1Ll8&9)tS6T0xb>`@7dz`Y)6UAS7kMUgac{1FUa#BjJ{loK5)8XG( z7BqK-)bvkq3Tkd=k~~LMhljlmx8o~Nd~R9x(zATR)z5x-A6<~rkMmE^xTH}yiKa6g z&e$nZXx%E4k^8Roy15YkSBk_O+7LxGc@Ds1UH?!kiY+2{8{_i9mGn)_$6W7aWi&|X zM_xhTu(MZA->#+nNY)jR#x^ydP_4Z1DM0M?OIGX|b?)?Vi_hUgE}HYO>aj=XP= z-=5T1E)3e|Zy4jh@V7T8xrpwLXje+}a)U%S~?o%?^H{s;d7Dwzcu| zpMMsf+<1{=t`2n;uVu*OF!A9Ss`^GRSD+sA(I!G4J} zxDC^)w`aN1z&_zy$*QE5UuhPjpWjJvgnZ}Ww+QSp580X#buH8B^@lb&$gxtd+R-ZC z9=d(`KLt^B#znh=HR4&gEn|^#iROlfWW+};D&BY3CgPj;lkWfUZ~V{1XXH&Av-;X+ zMMrCNOXZi$BjdEp^|#xu=gtV%6%}dB6EB6?`7A%#CEeB{O<}oo^KVKj(kz z;iYs&JjH)6M1_XF)h)^+D3kT6s;YO%YmZ{x-b!(#MhumhPtlSJzGnC4i`C#C-eF19 z8`V<6##gk7&HAKs1%XgEJ`Tlbx;cMFYU0+v*YK>KSoL?@2<^7qQ}+9wcT8h+f0uAR zen?H`R)XmupO&;MDODKuBf$Dmsomq>RY#^GcD{DHTb6AE7DiJYCq&F}=r=<|K5F0_ z*;8Q_Nx4wP%Qnh=OaF%~{B3(&IyIkB4YwN}fWd}MPC|%BqC_4`NG`J5?#}IVjh4WI zc2@Vcb~Cf(oC<2H7IoA9tOVEa-3eY+Kd$A)J(*w6Wl7hc{I91_Vot93w{7NZ180lm zcULR&l98Cva3S+R_urgbuI`Up4BfwYE!ZBma{kMm`9f;H=uvQGe`%wBAzv5K@FopE z*gB=T$nmh>KcWVQq|a#4-Px0iWVoDqH(iR__H0JU@w|hQ^Lo0syvyA(4V$k$;=E{6 zm!$LE+kD&~-s`M;rtl(5=z@xB&qUZ$N8v9HrN?-93JmiRjI)u9^O20R5s#UaTG|U} zo3P@=sZ*QvQ>!&N(AppQdzo3^NxZ4VddwtVrCRqleDR%RE7E=rRdVAgByh54j0nGG+!~Q~ zJ3)d9EjOixKT80AT2R6Gb;^2}UDoK+P~XFESR-L+mT%r(F(DC=>J;Ti-Q3qH{J_T( zX)eMmi_KjqLRhd#_AR0~s})DgY+q)2J)@q!`Ovxbs~iK~FP>r+JVnN+Yz10CR|84( zu`Gs+;Rrpdt-j1-S?6hVG)duqM1*OQ$$P7UVuFm2Kb^m3N6z2Ts6FH6L<7ATSl7h{ z{i~uZOUeA?8$(_zG|?fi7HUWj#VViH0W|3{2cJ;A>TSgC4TKy}3x1CLHM~Cf3aHaKn-3m@tE5HMw&5 z*C-{kZ}JWrQ(080qwUa(U$on={7M)jaM-StV+2l89}P4PUzV+Z=*DEl7sQhmD5~}n z&FuvNTJI&xK-`{@D$uuou*R!mLBQ%kWKRZO^|Lp3$HK0dI3!x;wSH!n$jfjonKdih zmG(e4SPPaHDVeIVYGX9yKpfyLp0NJnR-htMpo)gSSrnpWh^#a+%x>Tq+~=8VM%%6= zoADCIq+*us6@g>!b zveMFU8PTo{%&n!Wny(EKa(*@>?zbY(Wt#O00A2-VlSjqq!$j2Ye=pj4$_W&G6n_@H|x<~gQg@-J7_Ct;mDZN^nU zA8_-DUkBtq4oX^`X!f(uic85w9PtJ$pCpuqUOI{pm{V%jKl11$Z50T3&iK#@t%*qc z`n#nE7GBFvIy4ozzByvxp4wTV+0f73OoyNP0!^?ZO-NK zokXRP#j@GH%$eC5)u+1s;K_ExgZDcEdVIT@ek{s|isU54;aR2wRd3;9N_U2`Ner_b z6WWI7C3KBbg3W?mKRVp?62~H=&xXFjJGN^>u|Jqcu~bh zT<9j(r>o_+N>LQvj4$jZ_3iMtt18=4H*cBs=m86FLuq-MQ93Lh!EDSPjkaD>6yKcQ)=}!LcO8pso(5% z--M0y5{+=cHZKJJTO9(w-g9vc4s3oLk^1=eY4EFeWZq|PdbNMHoavOGk!7)Y)_YvK zv9IdoEj_d+rI%s$ZSmBCiO%OuyZVQj3iVsWjQI}8Wj*@e8V z?;?iOF)EBafqiYBf9~-?k9SfxziMHwsIF=#Zg?HPU0?-A{L%xapS(s=1o>W-8oEYO zk2hN?d39w}^z&NraY`2zRz|-b{s`i4c=ze`D+(@o^&UJNgU(w+;4g_|AT(bkEtpHK zwHs%LEF}FA`P;}>va*s7r8FB1|LCioy2&-;Jjytf^76A&aSCj4Y{uzN506xd@2y%O z8~f&*g*{XOQu1qw`8BU)6>+WmE6tFr%f;8i<@b8M=gt(|`@qxp$(7oOMhPcH6@gim zbdFh#-5*qZF0RjB#%tqC=ZW6L3AE(>x0+|8a^GgqSTh{mzRUsNFdVFUcbOxvwb9zf z2JIcC1tHKL| zJzqK`R;R*7dda1gZOOcGFXd#>s|{8y{H512fOnh7Pc4Ta?gqRjmep~Y&YzuB5hv#< z!K1=tx%9F+?(gI}vmVwOy{X3(hH!$7EQ1F@J|(68 zo6|(9SCWEPRDyYx6*nM)n_i; zr>GgkWTvRWuQfU>=X~SssS-IrpQ*br%qch#BoaPuKk-~(Rx9P-OPbN&`8GKwMe%Hu zawr8}Tl0R%elGt*8w|b4Lc)*l86S`6>HTW*XjwMUoqcoJi2lWhJcy8%x?{zVE!xO( z6PKqa!P{<5`MLDFM`9*%d^$Oy(YYEPF4J@k35h-yt`NL|i^EVKgK*=A29#TwY!E69+QCB z$Fb$9iF5Xs=ULM&cW&XXTFl;pc=LoVBXvsycW^XPM62nyM)<=8NvA@ejiM(IaLJuM zHFi5&ahtbj*3gN~pEe56<{yumlfHET1N&ruI~*%fLd~M)uu=qpGNN=||Yf$(>yU*Bd`; zgp(t?#5KF)b;aDvgKss{hU;NVi8a&pN-GrES-HXQtoT4suo7pkQb(Pj_l+DOoE;r; zwCYMjRlOqXp6q4&^0?S=9Q8e*2e-IY z^o1~PpkyQ2l&CWS^Y}h)@C^}}=*A9j_>!izt#7uCq|sv7+8c{5ls^epgWyF!{1-RV zFrKhU$PG33v!(rgUL3B=7FT^z!-Kh){9A?UFP9T>cwB}EXJCMt;&8WRRdfF5rdNE+;M#a4v7Gn2;RD^*v=yJ~ zdse&&ddgp1DW`#;AR07yt%y^8rQ=H>-PiWCv+Y-sLbYG=y)?gQJH{|2&G21RWx^CB zZuWxBquDA7? z?isz+n8dzGu=CLkS@8pbG;kd?qHos% zZ=^c^lG{kN#Ae1S_gG|C|II{|^CG-$e(r{KBdlP9l+3o8)D+fwicgT{OZ~}HZvT6G z3zfFT(SgCiUc!Bgf^e4_792llVio;c=X6$yi5Xtp`KTI1l%k*JXG~2?;74k;g!>{+ zGrxvTxFg|WxzTF7X?$fPED&-%jqBl%pMvyM08v*G~=@e=B&#mXa}U!Zd?&8xjOBV^@wS;C$ z;16jLJLM)-{Swq9Bs~XPnqstm$ia1Vu{SDxy ztv}UnojOHFzqsR@{D{5jUhaUHJJ@)G3%vU$&RVv7weel(Rr}$z)z%L_K3`2|ppN4% z91iVVyb3P8uMJ=A1FgxC+Y=*}bpsN)zuJns!)w3$eJ2q$`Wlt~)ke^YHPe(PN~w-= zy7*DbLT~XKsJA@k;*%5`1jud+cnkerhDqFJ*c|j)#{vx^<^l=@Mnbtku}fn{1_P_S?5?F+pDPMUDr*P zry!GmKa}OfDnav8qxue712xX;B%Hc|plc0s=nXU;!smI%%~{wu)}ctby=+sn1a4YHMG8N+ri?l@*sMQO+7#9ah4D z6GI$+WST5xxCAjAiln-us@QJ5p*Mr~Lm*m~TK@3nY0<_>i%h$7xW!3_XzzFS-(-Zc z0S{lB5+}>+cKqQgwhm(n(tjV$=QjTY7QB|Lyxci5sNUoT$3sZ7z8`SU<|HznN99WoUQAAY@g3h`L?Qc|*OO-(z| zD^o(_#7$wm&S~xC*3&&e8mX8Ixlh7wAeP%ndiyri;(4THWaePhG~bD{7a0KK=;5~k zoMAqB;v5=zT^oMv!dN+}a;q$_3kwhnAZq%H!^n#}+}yDsm<;g8CN4H;4&f}=TFosq znQIC@-E^);jL29m?CtZjE$EAxw38%|%K>|>wblYYYGGj^xo@Lf%`-eyXKig+h^b&OJs!XsR~+5ZI$IV?<~XkSPp#i3 zug}m`u3S-jNxL@b8tStl;Q&ZaG?Qdn+I@k0Cgvu$a^18-AIt4`7)fmvOm7t?X>NJS zGG-@SWdi?%85b89bRskHdn(GxhmDlyKyCBvam7vb*u?@^{)E>FG$Yw<&D-$y z9M+MNl7im0$Ch<%wB(oB74BNyMASIlWITMUxH#IRYBiF9X>v}q%kyoG4W1u6PgB-3 z>s{|D3jVn*ikiay*kvK=Lek6YA#63^x$G@!=-Di8d*Q77*b5uJP=&d307e4|=cXWS zQKi)+KeT)|MgnlrUN`HUV0x;Y>2hUwIoVmFm*DxZYh0&e%K=QF zRtFY#g!?FqINz+()!=6)$Fiv=+{yZ$#Hd(x5L2S@h&DZkbqilvu^ zo)D=bORS)6mt_;6AoVw$av|b|_zVP{p+Xc(q422I5n&(&=A+D42aL^fPgDx|<->6_%JR*UHk0zXhga z)E+k49t@CH22d$X_e^-`$&XN73Tyw2@zrmESnpEqpj$)HQl$;@AO3iZPkzARjWXa` zV-?RFJIPYW`uf%;wpOB{2W6$W#I0a?oPEbe3%nN;)=Wp!=SR>8zfM&kp0x}dlQ)3t zNtcd3Tx9jeIuu2vTitam14vRZ2-N{psi>qxpsA_p+gS$`Nq8$aF$0p5$pAOJv2}I; z2xMWIe{WPXRkg z1Y<*BvtqtxF#gROkg?QC8W_yERx1+l3IFqoD$yL_GOBHE-c@8I@wAuuw?6usjLGZI zv|A&%N*$`0-g;>?M-Q%@hGD#;!6O<4=U1YyTwRbtN(MV?nCOe#DGV5ujo$iL{PX)q zRHxP4reGwflxRz4_%l3`dR^pcZSY+Sc=_W=p866`&Y-jS0~YN@I=!Pf%0 zjKdwW=Ov?UotH|zp=cVNc4}f`;`N8# zip>UJwqd^KE_~LkQ#GQwc^rU)<#0p0%7FpC8w#?7ZEbDWr-s^J{vNOM6aW}_gH<^v zm^hUoI_m!S;*ye_HZvldmA@$7d;ZY`5nvNY4-@$8X@St-ur?G9L)4X2R2qd2CLV*8 zqi1GDP%}4(i9vJS1E&W1I5BKiJ&lZv7HstfZr{GGSz$v3ptMh*@*{&26|c3nx(Y&P zRxL{6FtS?}r(#^Ga%yTs$Ta{m<6juUhmU4X;r(&I_}_wxxvL;|_vu_TfMe$Y_cbsA zV4P?VtV2-H_F26f=oo=`1mX{R=qXl^m&b**GlW^W@ZTZiH9&5m#KT1iawntArT%eS z*QB!6_CN2=J#DP4SddpU5ew2&5a4BiJRJlE9i5#k#-}d7!`$?vX?(nKl<>WYs}~@MrOXG@x@FU*RSO+S~VGj zGT0rP^84#gRRT+gkO*&LPnDRuD?mTavAsxpvip*}o)qW9dtrIHN{|ut$J1Obb7B87 zR7KDFa_&h~$}Y7)V8}WorTd_8AmPk8tVba05!z!wO-<-Q5s8sIc-5!f=u=)^7^qE4 zK=C1hf*1iX6^QUt*L9Hy2yn1ls90GeZ*iJzAJkufyhasGf06u$2k;*99(KIxS^owCzCj`3v3hoA1P0za z!0?Gj5)u-*miAyl5G)%a3Ga+!{gvW8H488r6BrH-91b?;&1bMzZ(?G@LG%UJWH(gr z^s*1YV|IV4C|;^#TZS3u$ZZP1#zJuPMDOTBXCyIZG_)sE_)wm22l{F$lx>uhlpuyU z)$`A-@@X&kJ4LSWilI|l0l+Vy6U+SkISBAf$v`m%=#*{sBnZz7)!t-${Td@l;d*zQ zwB3*zqZEtUXvv-8^=G%FbR&kJZ71shYIv!&X4g)Vor zcf|pHXrP`_MoLN_&^zEk2j&)3F&43=0PX-_xR*fA+&pWueK;Q(otjF?tB?p7ImE;u z-x<&Wh+r93kLjkYzFrmVrJS6c3Wz=!?%xLn_?eHjn7fhD-O0^mbgH_G-qe@w$rgII z0GkERg)kOCB<3~450=vaI5&bP>m?w8e+RN`@c!T~gZVJ=aIpg4@vpA6K*()jKp6Uh%;2EK%?&34%ZU#@?~z(r zuY$C1c)0A#k~S*(br(3vHunbr({^-BmB?G={TO0N)D4 zHsFxs0M+yoys>S!4}GgMy^0rClDb#h$Pj9c^uQy&=FF)L)JePS^yoI_RBt-)=wW+zdh$35Id^;8jcAQ5` z!@bliLmLn%(15xD@qQXCxFJSK7V-HheANRGIWD!jx-PR0M7Zv+4P0+ zY=b`-l84vs0;w7_Omu+nD*^@wViO=9ScXdnAC$om2_b7=KIN7>=!8VO3EY;X&Qq>* zfUI0>6+UN&o6N`B=*Ze@?>1N(2{?vuxz1$?pD{qsD?5CnIT%=O1Rz0(My@o_pZmgfS-r$H~h_ zYZ_0Vw!syBx&DQ*@fFc~&J(s6@GA6y{qZ^=U>7d`VwgY=nv@pcrXaQeupf(l_z!t! z-O4gr#>TXC-B#{_Ao&nzuB4cG6OO|=SsrAN^~eRM5i$cwBHMY!Pk>0gy_b5CoMcsn z71@f4xb8mPCWc^zTcp<8~ z_Cdb&%6UYffO~v2+UwN)j0Mkf>sI0@50w|6mLuwhsn{iw{s> zz+hAWzEXQI8G<01NWlgmjjl{q^MF9>IXpgqcmpIUJz*R=33v+)tX@0Vx}N)L@MlnD z64^_zyY4$xrvNbF06`N2^REx!wO;$VdOI-jemgq#G<`5m`4q0c$Cj4Nu)hp|e}>}Q z6KgqIPkiGBoBfg;IzB~L>iKUvxXs{``umk(1C4z>gJ&aHelr#OOH7+02|UFpK=p!8 zf3#odEe~X3P&HiX1Xo1M*lKoF1#n z#hXB1)P!(?J1N|}pfUhL+>VY8l(zQvkKjiD9q=PbEAlMX8S&sO>j_2A~Y z$1`E`ICq*(J`ssxQ0tSrO=#s4Ujuv|!hN8eLYe?vcsw-3h;~4Ctx3_0c>IUzFhsM%<)<9?wL@C+ft%4_4{!U3il`ISD_)rZwVkH`OP z$;Po<(TA*{@BF>!_8S%9WmfgE3j4{Xord#UbDm%?(aRpGs}C_y;uG*y|BlFpYGV-F z4xJfOqOO9eX%N3z*hzz5G-CGq`Se>o<3dTLGfk(41S8>`Qd!)=|;OKKKP!#*BY~tNDt>0$7_UO z4AgL8foovmTMI8g037W7&RUY zsEl+TEC>Pt(ulB2rNFxh^LFGVvn(iQ<~o+_E5j*(wuFwBuv>l*=fU-WL;B#enzQ`& zhPRf}rNYmjQ83X?Pa%`t3`DcbC;8DEG?7ja-=F~PcARl}x_^a?m`ulBRwYx8iu=!q z2`Lb90lyFoaA{=-i~&6azw$XGRecr0QILox@@PEvd0X01{wA`~(?Z{NPXJgExPFn!C&vC9_pw#q!dpm`Xs z!A#9&xETSmp_JP>R_uLn(G9*vMCJO4ReiJ&-3QCaZpfj7Z2~M+L2E7SY~kP1uaTXN z!nWB;t|>Tw4fiJT{})b|*i|BH`7_+QT>A@X-@~W}?Qtd%^GE~qQZV^D6 z7ZumQYo#qFc;UZmD5f#?HE<|;gq#Iuuyy!rREgZ_ouAtB3Eqf%fbwKlhekV28#9#c zTFSMnEP9gbRmWP;>S91BiiOSdJ&(b1_OMQXPnMXeKA6t`&YM4sk&lQI!1K1oU; zE1$ltKdr?w=(KevjoY=Di-e=fCb36@dKw#HlIz zf#AF5Qel~UFP?-oBobpn`37lM(o$}0Fk3ub>lLp#5%!11LuqK$M2a@{l9FEM!<(ne zJ8}iJ%}KG9fQfEaJ1MLit)B0w) zlSZ$ple34==Zf*6U`!esQQ)gtmB(#Mq3$p|Pj}>sN|-%opwRo`he7C%{SExoWl$SS3x7C>^nF%ow}@3Z0Nn6- z-K>0_Ph$pfd%=c8h=~v`k}cm{EVKsBkR^1N1NsOHU^|wUmbrV7jYRFFh@|^b+qr1B zGpM0=$p-lKXcT(hf$|r}fe=U#?S(UNB zHjFCyXPRzYl7g9;8P^AN;n3e6>7G*J`pkwJ4q+PjDG+Jg_5lPnYTafEgx25;aBcfz z)elVKA4l4s>d-{~g66Cn#3PXR^W7V(Dn#4>phQ7_2oOT$oIq~gBG>mXab{Z9v-Zwf zyAI$_W60vKPgF)DSsh3_=sArVqxcql@;X=gJ?(swvdnkM(%r(&&JI#Hz$86OKcJ!h z6+5K`t*!)7>d=d6a57xlwVdZk#bgLWhm@1m4a2QfDZ45O zu2joFya!5Ug;BenPEhbBOeIy2^Po>*30(-;k#3@0wamhn?tV@e+o*s?Zi*Aeec-n3 z*wYpC!TrKCKqpn~S@EkbXcQs@n{4Qp)Pl}a=Ef7Q&huw!8ueHCQ|^G{mHw@}rfTqGi|F^CAXS417bKYb7eX7R+;Occl z9Vi3>N{9rY>PPGY`5{)DS}?D`WNQGHcMCHFzWw{ieTxw8pgb(N{SEbWJ5V@1J3AQG z3XT7|JV1njoWBj0GztkIA+wH*80bk606xTpYZv{&JW}rf^PrWx$M3k>6vLo`qF0^< z3@=EPR-PZPY3Fw;dLOGGtYL^9A6iw+qC-G}zyu*$5S%sLn7;*lUAPkG5bqPdE0p_? zymfy0R0q_@q!bl@fxXHE*BmMMzyJY>2(or?CgX+Nxgq~O3&~3Zh<|(?Nd;ZlP_EM{ zEYu!MLB6_VkOU@uVc0<~i35_8z>oa~iG-1QZ(*1WvII^szDFB=9UC&71#%X?Kl1go z%g$id4N_D;I+?!cfpB{i=zWltu$|#HFf^Dr%(@R{DF_8%5J@jYTeiGpryJJZs59^t=OA4yv^l-MHJysMOpw#sPQ5rvwanQ$ zUMu_s#SUWtOheq01Q%He#MxUq)lk=?WnqcXwyN}pY|$RLIvlRMMi8wt(9_RAIfzE+ ztnC*W-57ZJMjW=StU0%R)bg&%VNCvb}8sbQKbp_0yEj`oa=hCd@j+6!2}4q&Pt6DI$Nx z8&cFGO$Yi=XQ_dJ0%*;j;39$kgajmrLxMT$x}yLB8i^v;Jrktrfw)whW61ULb@5B( zM%g%wvA;f6)0Ixcl~Z>8*}?aSRB5m$i->l)GyAb9Vk2m2MBalP`OB@C#RH|j@r5VLhKq*t|cwC-9uNQ!&mRr zoo60gtNYDbUXcfF)+P}NV=`H+E~9fu*dG%XWZ1(KP*$rQ)jI#(^!Em~!q8%ycS>4o z=4h=h=eCCoYbIOqs@UJ0c33&cpru8r~<9l-6UUYx%8Thp=_ z5djuC*m7D(;vc)|@%*T$;DrQ#{SNrzkXM(~)ujLvdB33IRc0nFzzHvxyZ&}N8qR>! z7*LYc<8Ubid9NwJsHfRjZL8-{ENTt=T(>`@%}yFFm&6?ol|XWzuC6XaiE@f9c1zbO zm~RC96HcgvBE>;K1V_cjB7=A?&q{7zk@fnWMtQ03%`d>4BZYnB58QP;^(T{Chn;%o z4amn~T4chw56H+tIqb*k4lexa?5y{5aN8L{fDSd7D?U*9rYO%{go2eT#B3x`8f1^0 z&o1+XnLdcu49T8)S19oU@o%o6deZ>Bd*AU&C{knM>wK%DMf5Ub-&pCzzTtTL)lJRTH4ogRhS$u6|f!1cR@~JUS6Kc zP<%{G6PTXABNd>a3`~~WP~{THcY{P8>V^4!wr)wJ^AV)|q@<)UA=PRC$qbYUn?_uu z0Fz(f{K@mKO_%vGm?K#gmFqC(<)RhhKDeIlftd&ip}F2M=Jw2{Ch_c7cLL|H_)bV; z=7{JI2zPkG^_5=`os`rGq_tK6B)7q+B1~XE2?FQw+x*T~*XcMIJOtijFQmzukZtkp zV1&F@NL2JrX-ROyhI+Am+E`5?8VR=r2{M@pIL1Y~S#BN*4zAh}R}`J9&-Z{$rzp6C zhGejjL@x^50D_xmtt~CPP;%IVbZjs(8RFu6>*C?!xeyiA-$4<8j*Nm@@0XW@jF8=| zSk1}(Tv%v5@JHa7Z^il3-<%ojjU6D7?n2E>=!rWdVItjysqHpjyYw!FVZ!}NV5Y%{ z&wsc&a5Z51jaVy7=3n*1WfACQ1eflHr+LQLqNw%Gv=uwo8 zqa<=OFeiiNOo1~E)CZO`Meg89JkS#Ioyq82$*5~_O-D7c-|n|^oG)^R5ZNH)B|)); zu9d59=c4`5@y3peR`~S8>+Jw{)GiP!xbpCSSI1 zqYDoFW-nh}4WkfF99{z^<=go9_-|6(TTqPE2ezmGjSVLOE-o%)I06BIZPzq>=5?UI zL$PLNJXSrobkGuPcH#m8@y&8V~fT$tMO(A*p3*?$rH8d#gE8C5(dd!N8^^pH-mR?AQ*1@G3+czw= z-8hvj>?4biO}*DPEnc#$eP4Wf3>NmUI8WootvG0ft_jrz$LX=S6S!A%KQ0MC>lVmI zq}B+fwKT4iS4+Holfypxea^|vlbo|t%el*;y5?>c4Dh{4foV$Xh(jl++%88Dwbi)s z`?%^^8IFD#rZzf@c^~coi3#L1XRx1g2QtmSZDc3m<@UH`e7C{ld96fhHx#au1^)I> z&RAUGUYxM6uCdUudj2C`#hV~2Cnp4s)LZDr!-Q58s8@POd{pK;fKHkJwaY|tYgT^< zf$%2Udq|o*5xUotbNSYdF7V7hgqo-qeio5ZN$aT>j%)1vi27$Kl@^b(Xx`3k9jg%3+_qE~lmA$AX`D=l4)zqN#Il4+h?8PwM9B8YZ5 z&bP>T##u3U+K^C`uV_4A_%ZBvpOxjFIHi_vuFRn?;a=eK(AcLg&_?Q=hD(UrW3I?s12GL(V#TH=r!6upi#y*E4P(49b6(_-`DnM#%&E?P4dRa7CtB0`qQ?WdCT6Nm1i?YmuyiJfJ@mb0zL_Q$alMhOwpK8@4T;i$MgM*S;{yRMG zqq`aYpbx2d`I3XYSnjVc#B%xG70JtqT!G|9+<}~&c3pSV1Fpcq2^dBtx+hP@@9H*W&M4OJ}VZxXc8ewUEOJ|-F4qG z+CA=im~q@rEHu2^kT;BIB%#%#PrH7q^US-8mPyoF1Re(Oe-Bfl%Bv}umJFM|ppN0* zUrTVMY5tELY&DF7W3QJTt$$OVP0u{~sXY6keTfPhNI+ey%t;-jfQgI78UFFONK}l40v=hr zamO!?S-@b-l7jTM$M8-CmP4t<;08yBPrJokM(!A!=vgTgl@!*$YcclDx~?ECyRZ8L zI~J1cSori$p%#?pq%wr&3*YjqxJb#TCIwLPI;>jJ)@t8f z8C`AhU<}8#%8?<@Z%Du`Wl`qmg2j?cH^Hj+NOKGjcUa(= z9LF|FOX1QmvOE|u4h{M`x8F}z@cZyp9P_JK-@f^>n>4LSg#+2uw>qD<+WN)ids!3o z;9zU8A+lcx(@pXn+1Co2Ck{>u{{LT_2zn@+Iq{yeHH=jA6Ov})Z-It|vwE-*`tm?5 z;z9lZUmy`RF)ICqWdE1Y%ZYR=K~Bl%WU`=PW{T*;6pl5YPIv^W1nTgX@6#Mtcm zyYAVpCcIhLQg`@-k{5nsLSW6-O6sR$Rjr@vtfCFl+x;8^q-lif%1|31g*yeFu#NAFi7pYMR(&aRRmUyqZ%HvZv)I!~Po(6B z^UDy9x3T2N1!ty1BQ2#i{5?%APT(_(v$B$bHQo#ESts}_33aLI4th^G#YVqz8szVX zv*N#Izn}6`{jee7<1G4|N<)zBpEJ-_UmrfLekDh3mwB4joMa&x$dnY9)a%SA_|#kn zM9|3!k%iHVwpBV3@n@X@-wy@E zPR~=_w{>wbC!67aLQ6X`&}jtz83z`CKIqdx@9wLgdGYf`#)l+5$lT>{U<@we<#Z%o z?nJD8_k*Z6q&Jt}-y$L=UAJS^avUsJQb@o9p}KfhSDPuSEy$mF0y*XZZx+{x75e0x zw3tG7-^j#lai6TAU#{A)tlpiy5jK!LWf(;g?c-m#l9=BGs@p#NA8UH@S z#_)+EG5g9#hq<@=SFAy7`M+nVoSWpXJI;IcdtIs^@$D-m8cA`nSFPBK;!Yh0NT0uo_>B*zeoV8?busCCP2v}VG{eqe;G3@7Y%xhrNQn|=t# zwYVD+5MvOW7sM?Mk+Y$uwIn@G{QK>x`?aRR9vkg*TwJVAI=iSkPMz;KXZEJcGrkr{ zCkgTKk@}^YUvnSRkiuhT=Vu?Rc=v;{uMEvJD8Z%yHC)vU-|fm zV7`u#PLaDfV~>`m#kxjK(s5SBQjoy+tBY@%k0Eidw)fZL@`3Bx?)22ut!V!pyB8(r z7af|smXt4a-b$oW^$bx&1hrv(tQqNjPdVA=V={|}Zz(Wl>i#yIJF2xQ=6dy2BS&$R z;fIvsM-(C0f>A!1#3h42jM!A3e_zU_-;wl-$E8HAyC!XB@^+x>ZiXbqK*KwZ=>D!I z2I6~mqF5R=dHF_~h0QMMW5&r;5&fdpI&7ST-yUeIJoD*m|v+Ym{TX)Ehp8D)U*o$e80xiY-(q zsSp`$MUej4{QS{I5?5C-s6$!rLHuZ0S_(Jc&=7@5Znnb_!{}OuLuB0B+S!hTd+xO) zIJOH8_WECj(I4cemzL^(xzFyxrt4hv=o%;YhlJ$^gZ>MrTHkMoxV}QRk!KtQH&LRuRw`N&cFJvxe(JDe!sz$m#ont zUjCx=|2~3LF6QB5rUcEds%B#x(svT6A9E@gsO{)ar=IY}R}QEU|H#AYU%Gocf!yM2 z`xp2(fj_UWv$iYi&PC!HZ|*!P9u93bxm%j=|C2j**-%D1RBM7lp;Ki-MDlbPNAG9gEw&d%a0daxO5-SiLR4L9e>s^m?)XD1%vxjGWB z;)lj^;&NR6849~+pBeY|W;-&_}Hwe9){K4mD4W zjFIDHNVqxX@HOg<1@%3`o(BnPnfdB$m_(&S9Jd2FWIcYWUXhaF0tiDUFr*(`56(6r z3$E&5>0cH7d4+j$mV55Kn;Nru4z;hWvn72=!PU&~Bvw>brNd<;JYsqRgz`@<0!CKj zqEIqNbEeb&GbtXaXD{&KFe}&{2RlBl43d)lrwF5#e3zJm(kaYpJUPeF!^`T=DUnH- zB`QR1m;CZZ53JV8lnpOun%}#yKk6I;BU0ARr-7WEvZwp65_Dy-J!3Za3AY2K%nY#t zIme$$wSN`U!#?z+Vw5>mjXC~IAO4k@bzfz1cb;)qNoO`PfIWImtzAwISEDUVQTdL_ z!ms|Kv5c%LTY;TKH(yyrN1sEZ>sQ8KetO;!pvIi!_LUFk>Bg)~JbK!zzc2u}j$B+P z9_9TR2~Ijloo){@=WI8%7FsT&rl#Zn&vJdfvF(3oV#P4s#qe>u$i`;Cz{_ zko0Sw1}oCp;l(HH|jr zj9dTyWK$PKLU%fIum#NCSLMGdSh0v(YjH7q8^jsuMge|Fn){nSElgVuFY_NnWVQOF zr`o=zwrjw8)Mte+el%r6KXBcsb5$nK>G2`U-k%{;sXdomho?FeAB+l#HJ(>^x?1v< zOyB?!gfj?#nSguAyQye;l9T#i-+`#!<^f72-5JBgH1s7}vKN-}f?swo6?t z^yVmKJTM+p6LexqiHa@;5A;4Zn~!s4>m2sg>ku?DVg)8I8!r^?}_g|6SALj_YbRJiKak(d$@JGdd0IWI!}SyM1fv^ngzdHa7roVhnQI6zfQCu zGW)XpTmx9#yIDyqKRMsCcoLFYmaNJWcbdf6Y&_<>n?a#R#Xw+2&ZYJ!WLN0M2A)P2 zQ^&!RXEXO|Q~ZBRVSnhti` z=QZ`CPJOw<{w-`JwN2|!%`Q5;1NwK!3c}1dDX^Y#Uwuw$csbFQ@vov9%+PMM-0isD zP09%e$~QrMrg!r56SiXCsl;q8CU^F)2>cu!dwhd{j}cLa!cS{nLkfj@7xPD(tU%b% zKTeVtmaBFNg|DYhDg0@7VyUOACX!^JZvFIDNH@gUoq=(CCL6EV((~RWJ$lkEWN%OP z$hcJ-)@QiNtKA`MVER4F7=p%ea6~`;tJ#90hM#ZWe-Nz>Q-(MkZs}5llsruH@e-@s8y-GrllB`eSxq+1y5- zZmYZOgJMv8NxM0}?-wsIuyf`v^>2SKn5xHY&7S>ozN{b0Gk4&>?e3ReUShM+$d@k& zhcYehpCsC@>pttw-o~kNowinwS)=kYPgiiW$;?JpnTpcta7r?DvECrjC3sBwv5kz1 zJG&L*ew+h@1<9j5G7=cK%`Cf{=qRfP-6r2%>Ii9g$KLtpX!}HT!8*I8v^Vg(6z`i` zSSGYD;%R2(uuax>ZUyWPp=CRWYsFNbst%Rik3{3R-+B6V%_6I6LQz!aZqO~P7qmm} z%yxoU{;U2h=6>(?U&XTfcDi*&D|g*EUAB6%$nk8y_<2TWyuOK1WxJin`TM^n3nDWD zk9}K$T;eK&SRF4#?oqmNZ8I@yYDwY$jB~~8f&ZbC7sLH}o4!)L%bPhU+QaJ4zuc~v zdvDQSlAkXmMqqaDy9hmL2NTQo+#cF!RoPXa-%dCC$26sTi{IYFGHW6C^C!sdG=H3+ z+d=)k%SOPSQbOff1;2^gp`KRkJF%?b1)M$Gfx6n*>DyNW*>oK9+jC#~B}A1iitsul zkQD?a%shx%hA_l{_WLa_OZ6bRh)1(Oj4jP~MC6ieMW5)-g=V{H){kZM-VVdk8e88V z59ZO;z1{V7G(0|Hz^43fv>Fsd7T-#~0LwFH1$sc+<50o%JJ9(pJ6O@eE5#n)!*o9$?9Ph==tv~SlXqY=?wA6J5yMA(;tYd*2 zxk;5xzptXZo>u%oq+J)kz;nuUQ7&}w8mChFxh!;!!}^S^+aivPU!wKF3$WE|F2B<84{L;D6C4*E`PLf>}spuH4ruy*X;;t zB;uTpmItfX-d1Ly$R=?)VU~NT)lFO~m5#85X-{Qkw;7GoJnqDkitw#GSZ8p!!0~~1 zB9?`fJCAnq=uMh3_`5CSO=|_i1`|5Ob-#a_3s6++pw#n-slO0VGd`F2*g1A{eh7V# z)$;0Jb``Ad*QfL%3zu`h{yc0g@5|2en;rgKwWMgv2dt*+;^VxVmDxEL;vB+3%%#x|UU%hkBz0tR8Oy6XO zf>lC=%*+!0*H0$diVW9SqIsqF-M=gRRAUb5nSU#(FJ#m-QCdFN)mg#EU>oSZo0T9f z!zrF)qGgkr6gi6RG?l2YLsIfnk2PNNfb|BBMoXBpgw{I&d2lwQr6QQ@6N?za7=&q3 z=~OjFi?fT2@4mkEBB)Vq8Mn|LV@Ea6n#7Ex;Om%qt`;dxC(S!H!^`pLUFx2x2we?+ zPRZ)dzs6gxF@B*-94YCZ9Bbsu^cPL^<|9)cgE6V|%j|3k@BIk1-Fd0)UjOGr%IDDI zZcmj6+btPe!gq~+V;4jBK@4qJmo>v(DDS;qlco2nLzm8-J=e#u`RN(915gvM=*nCb z1YeQEKJRXprc~$E3)${siox015JK+?Mw6(>T?4(Yy=yVO zgkv(HB{-%m2!enoE!}9^z@qIM;;ev_^h)dy#am32?;=5SlN3&tc})hvhHXS<`9gOI_%8n! zHb``Yc*=R+OJ%QL85w&_5OtHDWqW%+=Caq$g0FXg(54hoMJgXXG0yAOr^T(e&0cK6 z6saP66(TcD_5Lv}DNA!Iu1--cZS0+PNxh)HUs%Z1(}@c>I-XZE$_2u)n>8rF{thNKQ2bl1CG7?S_jG)QM-UmMj}3SOC7aK zUX*97rd2|25PODqcHFX=jj~MDEpC;C({S&~l&Mrn&4}bnOE%8?6a9kuDPYHUf+7~5 zydyqgV8y~<>kRdbAwHtNk0p$M_}D0Q{hNLeHU_7Pd>w@VDO~&B!nJhFaF!?B;r?e`Txk7 zZafcaQ;ZoJ3K<>aRjqig$)_jJ`f2MLopg5KIo)&dY~g3j_K|eEBzR`Dnek~voB{_j zGhurTRNX^2a9-2j-wgy1WnqjanU~dr7ID-BFzQB2BW)XTQp#GqpIyIZGvbT+#i>O( zEnE`5vGGR?JocTF$Kg58X)_bsR*gcLurVIsO1_v&HFas^Tjz3~FLg=*OW%%`y)7Jk2W@@_!HX7*C)-M|0 ze+VVAvykd8F5YU*8KMXXA~X3Hb4i6gVG|P%E`&EiEv$q|KcYomVlf!Ua#NnQ!GQC} zi_d#LTZJt6VvNRa)F0(o@3{*;-H_-nZcyVKcXovTJNhdVHoD=O>i1m8I}VI=Q}I57-`Jy=6-Q~HYT;PixGEecBC`i z)Y!w*%SwNIOiDRS-{vUwdFbW;>ZjUQ2aFw8(Te+L^6Hg&^*S3Ie(Wq-lf_=~5RhC; zHKP4)M$LS`tjgH3SvFLDTH}8Yy^ifKy53o62Fv(Bo9)`C;-AxFjn|?Y<^Hmz2>6Ve zo5kgl4;2L|@O^z!!@{^1pmBY@BrqyI-r;E^bd%v()t_D6tl9G_sM&2<-Zk#5GwDgb zP<~nwxUg`ehj(6%rE2-ATxQyqx9xDgcJt{`N#e7(*x2v;!_!_rJkk6fO?m7YgT$o! z4HeCSyRH@pc$|-h>(6^$V^Kz@OwQ76$VTYePfvEXEE1vM)CrR33Xy$dypI=nDHMB^ z(IobU3meHib$(a=SHAWZ2GnS&&f?Q`D#=IzlKc=&$c<&c)zn>Yd~Zt4(0v2XBr|d4 zN4GC$cNd=_N06e`q`)F--4h+{-QudU1r&b)!9HVj6*4So+PRcWo9%ux>U#rnfd#X7 zOlmmET4D@SdvAwW-lxFT8p3`ygwA~1;@3fd0i%}5*Yde+yq4E&=DE)#P!skW;&SZ% z<;(ywCI~Grp%u?E4n1@UuSfH(r1vB{jfuc0TbHMi_Mf`EZxCO8$LZ>{ax}ldEVBaZ5XG^LQNgqL+@eCs24fnQm_nHCF$$?wVQXi z27TMAS{})zF+`N{Ipy3x>-&(=O<~5q$@Vt>C3T}!cn!CH@Yg%#W4My?;!ppXIfAHp z7>LekTPb6>B<$0uEb_4~w#z%_T_uQ(E^Jn_U$B|}n0d@UrI;Wvn!42GZ87$nJk^ss z1&9RXW#3Fxeih6L%Gk@Lo>KsNWi}_*>bpq^dF&U+eTMxD^!g1nbR0RICw6WFcj9S{ z%ca7aU1G0;YIkT@N56H;GGfG5_}G*hWveDy(!@mj)JwS9=`85`HM|mN(h7oUv8Brq zZ7?~=2jo%YLpwumtJ!fRyxYk)Ylm0lX5kRgadDloMao1tTML)sTFcWPS7mlYwi|rg z!tS$vdKHyLN@&jTGb6Ux_`Bi42u=0%tf~ge{D_1YD_Vv@vGHh&KJKN`cOu>_n;mZX zZJleS^pUUGH?SnY(x%dv2!gYTE z^VKo`R@I_BjYW<@)xs1Pi&9y?x_keEVI)6aSvh%&$BNLaJ{2}!uPp0X0`w#Wudm}J zyDt5pahmY!_J%Is6zDb{_%h!fShJP-|0sJ4uqxLrT6iHM27-kk5-K2#qJ*>sNGmBw zN_TfE3JLo^zo#HJyAN5g?@Q?3CnYO_|-^_pCpgaLd@V&EOnzD?#Os`Ff>`;xo!C z6TKQF8fz0Q`Nv1Y=%d_XAox|ix0%dBll^SOx4%S3#DtYH5&twsl-$Z}a-Y5N4SsHkV{+he}smK}yOVo_LY` zPlT*&d%FSxu5}IjryW7ci|Fo#)z|g&Fn0%?XQjx>3}c&wuDE7(_ZJ?*;NLPeY|h&_ zq@YE{v6a=|5#ZO+;M7$XHW1e9UwhWD=H2r=j&tb3d8OO2!CDUAoMPUL3izC9j+kx{ z^JMQam28C9^qEgGyLj!8sbmqT+j@TlU}?;TAX-_-Cdyhc_jUwJhpJyg;GBPF23n&M zidxRzHe8AEq1H!ddKD+XW-LLW)9qr*`MpWn3BTRVEs9GZl+_Y$2hByLCjEK=_w@&c zU!Mq}k)~JMT}w|)pp1Xw;_->lia|?jv}~k&iY(YTa@TWg>=rncQ)N*+>phti5nGF* zuXk2nU~+c7nG*4sIH;|0pNFp3izw!hFt}kb62Sufe{N{#&FWx7zqbrO0uk?P_ooO5 zJuF9lOnU?e^X-ng$-ppcaowWJ`NGdUZY5>Y>)xTEkKu)9PM#>*U$W%=l=lJlT!!(a z7_?vk4bMrt{VmUu+>}Nhg`q3vO9LX)&G~^%SErgn$`y~+a9{=q$6Dm+)8FAyrTWZ| zb?9`gl_|ByMJc2Q)DrJAL2qG&z6I*8N{vLEsDmdAZJl!=4PPBsRNh(;jouHuPvJQ* zuvE0s_GRxf<}))pFT&z1!<(R}S)FkK?l&sd!dhyW32 zQPil^(z&a)&2D$Nh>FF{)~A+X`Jufmv1LG!@+n|FghK}J^P2u8;sv&ck8z^;6!}5> z7iKZ(P`$mZjlr8|z|r8r-qbL)iD(goR=JJrUfmi^Mp#kwAaJ)dlXsOqw4vYN*oPwA zGCZ@HE#TWXF&MRVZIG;ouJ7F8GIf*YT=-A4=aH*kf6iw=zb1>})SKK6wMQi}#)SB` zGCN~RkPhsUET~Q2W+{JoTKbDilr7HHLa&$(^kXgjvrM|LmOQiQa7wXHeaN8|g}kz_ z=5ej~SfwQ3mH5JZ^b=DM151`;J(pBS=d>zzghB}38D-w2*SABU6!C+r`{Lyv5*Ssa zcSdk{lBK$E6qr*iWsdV(@%gmA;H0xVmS3?bqYePOrL{=A`8crVnT-+p)sT|1Kg-j2 z=36HFkJ4iqV8;pkb`P(vPUN-_ek~?R5ynGn>)R$%6RSfumo1m_9ehIi48X7qYUCDX%Q0nSNCv(p;K&*6eVwGcFY;Y=f6u7!0bshA8ARicn!8SH# zV^D8o+BvkpExgB)sV*F!knnk7fpBfz;&TAYdtkNlQ7GO6%B!k$2RkBqX)0FMu&8~K zd#Ys2A;op+i65Rl`CU0sR=F4Sy}4Pr)y#cAh~Ppz;e}7U2tfoEOi*8giM1HTQZ!*=U^UWL8Lu%bTCG9Ei_gGJ z2Z__E^Jp+=e-6aoN4Sr7F~NaZz?FSE%woCnEGan|pHcI)me#e2N#W7#?r@c@g_Y{} zu!)W{z!c`_4^}0oi*UrWlzwPUA%%_;lcFd~Qct+IpWK?25aGnZXhKVhASe1s$#if(p zf@!y|oL#Lr=kU5YwCKrRk@14eVXRwN$N*|$OR!4(@(2L9_f&P+;={*d3OIg5vc+-t zRTOMqZId}50*VPHLFAeWhFGGRz zgD5j^vT87G(kIKFcad=)zpA+xDy)1fP+qzB&^S0KEM)NA+m3TDyKv;XB#VSZSZXD5 zvRFU8)HQ;<0gKx3S8oHX&D0w-$($$*jKZE0yK^wLcD2%3{yXP32apWjLY#zw!#<6I z!=V-QqBl7;^D|C9Tql9sZ#nX&)@r4kJ#W%q(dcM5;OVf%uVtxZUw=@GfhXtM9#jvS zh{KwtKqNt@ifEjLX6ErB8-uFx)vARC?Q90CHKDfl`@qVD;mKi)2SX4@=s7WI_YMrh;r8*H z7t!=8{W)|4cH7zb?ze&ZB(o*)Luk(*t64vuSgvoObQeF6orUm3W8G{O$e4p>@fT7Q zY%z>TyM012@%EQF3p&94{y}2+Db|{ZxgsE7- z%=&su={w;NW@K;8%~3CyV*+&)R}2H;f^Bz4#|nfPD!J_VOmoI4@D4LQs}oPyJP2QL zEZw+IapiL$}#iTjKd37l(DZj8i0IqFpx$ay@Q`+5~KE^<9 z1~BE^ED)BGVn)2t@^-GK$e3m5aZd!qKq#fm-kITJU4MG{suDY!x<=jpsQhSj(0;@P zP1Ew3R+a7k>J%xMw&E9UITWqm$t^v6P#=UB?}c<5G<{mV`))=% z$;r&`Zo^!Xl9XR(va8Het(VfLGx9YQL7FDsbZto-MUCN+_gpcd1T;teQmR|>TgrI_ zYn{htopkdU3_7Y!Ta(6wa5(Wc?moa6zEINE$U5$_Sx`#nAyotzyF`Sz<5F$|95<{h|SGfwb zFIQNTrRZRG%&jL=gN29ZJ;UMz!1=tHS%||k?y=pSoJNJ(8e23@8Qxfj!HQ|n!tI>c z;)?JDe{u<2mb7BnGktv=U=659w>Oi|^z4ljz6$Ie+z>;YgAplQlX9@6)w=A;6%UXX z9q&6hs7`!u1rjs*ypd1pBsBO~#D<4V-2*^u5PgmNNK(CN@7>zky>QF1U8g0B(TaTJ zKEM>rz@tEdTPq0ZzuE8;yV^mae(@;9$zO$Tvc?~Y^6EiJXPWiH!b5=(azxGJH%wWI(e3yt464{Dg_Sp3ckfNm-6tFS)2JC6pMA z9|gd=2L>4K2ZSCGj5#--@OpzyfziECP+ZN>AEb5++}gNx3p4sxi!$NW5EcW~gB@v9 z-dcUgT>^LDrE+1?k@_4_>H}F*tKO3@hDy5IOJP9v`5wkfywl`G(dL%6Qi|Q$UT2*6 zYM?0p{VTNjhcsQalkYzfy>;u!VwiuSxt`|`&)K^MLqc%q`70F+D9hr}E%G-HZxpz9 zYFAED#}*ZRiiw$+S%V4COxxYDnGC1$8~r(**|a$CAD=vd*4B0p*i7SLf(RXE?>-Cx zBo7lo*y=-ul|)sw6sV^(x?SPP&II8B;B0gBGSOZZm|lcrjlrU{el@wfmp^M!lYF`9 z1hxEVMDlaWs>U;g*Gw#Ipve<|Oj8c`{#wB|TGW^4S(nuH+}5fjF6*(wwhB^Zqm^Xy z#Qk!^y~1}tS#vhEl&j5|{_>Ci$>4ab5Z?WrEv~lSwBYHI|g0gS1L6<1G_ky92Ul8 z)7-LAu_k=NK@g5(oa35yzP=R6=Q+e}r7NOAeYkf%GA8B&oIt{h03?B{4HdoU<@DlL zw}Pzh>KKNEgzt;zpIhcShf#*ZcAnmTxY(zF^wR*`aew}F`1QPud8{WvOrRCw~3Q>@v!yyLZl_4Dj*li350?8l{kd`yzgvqi? zA)-;QR4|msQUS0YjPv z>Se(O4K;N=@Ry9GWHwL2jF8~bs%I&K;m8F@q&33K=%+*PznyHrTdz1L3KOGBB}dj= zz|r9v?goo-Wv#(sw4TNQ_Wn1OT4pvgwtSh?TFmnV^=~mEfRCsUfT$Z+>Gs~@()goR z7IPaOEM~oNA8PNgV(r<@>D869+oZGI8SOt9!wX=r-gw!U(=-Kvh~8|jBO&@!vEp~< z*vZ!J97|FoqvyWMY6m1auiaQi8nd3#DBXS_9HYiMhr#Gxt9Ndp;D*}ah}w;~HMIw( zGTTMWpJ%t6$1l=2p{SkgN0pEk}v~+aFLW=yX&C#=x094Czxdl9ft=8VI0Q?KB%hdY9wojnr~*+cmQ{rV81nR%VSHf@Vog@u$JUf1uY>P8S^y4u~eEmv6A-vcotX1A-+{ zgmthM$Rj!Q-fV!??xY5c>U~5#2%`#hIEsaU9vBj~2i9L5?Y2zswnq@37|H2hQfrS} zewj6M4#s((2?|a(vo9k6Ng$iqC1f!{mIF&65JG;Gj7%@^ojCvjA+94>n*rPPLEDYi zr!cT+gyMBC2+dG2h>29f19~)Z6mrpE?vv#*MM-m#WCOU?lNu46pCpt0?}M4SO1l&K z2EAnzSzUk^XPC|324;~`TDb=SM~5x1!6yZ>7~H;4@~RVXEXZQfA{~x1fvTnuSPLqZ zPP+^SC;6T+?2?%_F2@MCr&iA{6tsp7!}nvOF2_|cQdjOxevTDZRqJ-wFkj_*Tj;vo zxO-{U{N`P|y?vqZgWE6+catLiGI%}iS)0cm3jJMD)kRzTPp}?vzh5p*Ec4Q=Q2nSf z@;)&}xy(ub-20s%<)c#vwpz*|plP zGt>fkB24poR8=z(KM{|JHJ905DxU4zyn-ABEW?i<>l!1t-S~ZmMh>^RJrg~sZ++u7 z`qEcW_tPXkEYBe*30A235YkW5byy%53sjka2@s@01;E$$idS$j@nLjsUfzcZRgFfX zU_U=xaBsYdczDaC^vytuBu`Z67upGRilOvu#I^Ml2cO3G#PnnFJhenyQIzN95>W$7=j*V za60#VVp0+rYp>P!abJ}ul&47!%+75e9ICG6=E<-nzZ>MvJA-Cq^x0c~%6T~KR^V4C0SQjzH!16WTT{#1+*y@j`bj_i6Os&; zlD{}Is9|Badl-hjY@eKLRG7>!C}?18XEH^GZFWR@;q-G^*-!031ou7LLjT;7tfzw0 z9v+OP!z3mLLHD_*V7ZRMJUlzxbJmpF`eBJ`Po0MRi2xZFv(j5_1ro}LT-Q_kt0Efp z_TAOh)i7v#F*7Cc-1YOvBl%;NkQlDAi;DThsAgmt@~{+hD`tzKDX^XfosXbuIQ+aj!!5|DW{)RL5* zdnna4O7{*Lx96D_4;;85s)iwrNM4B%OodDowv4| zt6b0-{`m1X27;Irk_sUKCS^SXclz8O_a4I0Y4zkj*WaBGu(7{?`~tqdXm9SRfS}-S zuu=P)YvPCRZ+^Ev+%hH<6uB=hc@-db>25M?XSwi4QWWe`g=k|HdQGY3?|%&x{X)R8 zZjCfVE%0T=%eM}qqsxTh$vf89US3b-}dY8iFaT8XOQ=_JrkC6 zWI87xYlDAlP5j-h112?_n`{`zDcC|M?6MSA;dM zb@asJ+Nmdm<#~s4Gk9Jq{zv!8kb`pX8FSy@pveANM14egdj2Z$j>syUn$sQ8+Hve7 zA!w@l^U&fvMH+nkS%vo~j@n-C)zHt%WaE!M^j`tFSC?A$yy%lZuSWj$A{G8~y^t^a z&x0@U&no%PbI4Es@6RV@V3pbE3@%O`j7V*~^Av91{tL%rjbjV473 z5ql1U*&G=F#U4%S6fC)z;Azq8>Y7Qd2Ph(JKcBze1ym0vl=SptKpZi!oP#7)%pr@B z`*NlBOfbwpfmfR6QdLC;n(_Qojdg&L8ASCXevRE+7nDyf;Nc^z{Phb+Q21VmzmMTl*9hf_ z9i)zUe8hcMyF(57`A~5}R+tejwPxLeU42hj#~`xEUvExE&48nV;>F91*Jpr}diElY z?kOiUs4Am6JN*C$>|M^u9om~$$6zi!+B*jxt$t-RdZsh^PPx+8R_1e88`S}>>{;}f zc^^F6K0IA>-JwpH z4Ea?mIZh_-PuB)_y)nx?u;Elc*kn9W6Aigr0 zTwe@^(Xg(YKhnYR`CUfL-nwfq^{Xt`W)GG2z5STDIFeN(MvJ4zPh+Tlqr^9n;xV(n zT2kB`nwHxFFa((O0z0`J^%AhX^*2r*A1(BslzAr$I#k*ppUM=MfMf0FZYLyzaQM-)E@O0NoLg%Ih{hK)`EVX7&IDYqMwu z2x)BhW-&Jw*&XNR1pH}t&qlX?r^`KXg#{C>(NcmG$7i-6>|WWmm9yV9Yudxo&jkV# z8Dted6Bdq^PPY%Wo|_F6azB9THW0;L9gXK#VoWk6qxZ6dC=7pMcEid2h%xxOvBHgRK~1qd#`y@dNGm44(5B)Lc` zV_8gGU^-i~JFQ3{PM#HcBjQfU&L{aodnE6C{Q?l4|4 z{gP?i%1WifSX>DG6w>GLRT+i3mT=g*>eKcnT3IoE; z4ii&bktr#@I_bsd-KsAU)xv%SvhH)R0d#!AGJ^ZMq4tgB0KjO&uuerIMXP+cCkc#( z!Y@;EB5dUko>|_((TjkCd4Nn-SmSn9hD(ed+93^VURhdQv_QsPZn_dv+Qg zz24uVqg6aI^XWHV9twfN;VIKF#iw(>J-*9A;c^%1E^JNrt}wf;yC`P8J#65?lDenW zRvN9>o}5GtVdU;szZx+4&hK;9j8&i8K~gVJxClWmbDhud#2ZZF>9^pmHZ4(b@AccdhAIZC5CjzZ0V$%Wp^`R)OgKI^6xhIr!UmQRI z(l<>`4$jhwhcw`3klPP+MHJVOrLxbPCMY2>XowIa&}qp&F*z64O?BX?n9QiPZz?cL z{@PE3LU07wP~(#U!xf_+U@aOZbWKu|v$MOvw<5JFe*PC(sRvLNw_3=sF)U05biH|P zQW3T;@3suhg%xq&QL)pz7Zf#4%zcEb-g3lPpbr+o*rag1P0&F3UeL>8Yt{(6t7-Vw zb>z}4G+)n*p5p*hgI>l@VRq^Uw*v(ZhvBOY9eD|f?_l^?VY6Aye4*&gP`Um;s+km^ zmZA!|F4}jfC3p~xy4^+U15jTg1FR8h@ay}-!!G^u!rf`{PfMj8_WR?naoJw6FXi4d zqo=0+6y6P8FhwgBAscg@0SFqhGrkSL|5w>mV9!Q~o98!XO==!FT>Xz1npjDo`-A|= zfwxYff`ar|H#^!vx lLz)U|hJBsnGxeL9CYwS^-EuG$e^qFm3*DKRj$4zZ6>p2$ z`yf?_X(QN-$2+yd-@j{C0>RGU#LJMrZlr<&2L#L`)hC%js-%2>`Pij3I=xDh@i1n7 zY=3;awwWDNCxH1|O)VB~6)re}hC8Jmkcn$`Sq*?G_T;#9v;axz`*YK4Tm8oqA1T78 zAxGCU#yUTJ2R0&M7$4{bO&^^nv~3oADnk3m9netrU_9jI4dI;!wq+3wfsH6$P@63A z14JMa$W%%XCSL%&_EdQ^{Pwb#X}$nb`-X&dw8g>xJwS>+0AB)&sKU|FcKn0s(9u>s zQAj0-?RTg^i3=%d85D04H2B*!t&HLU5vc)06DR~P0n#81CaAtfj0 zVHgi$UX+I_Fw5SaD^1#TS|Ks2Vi?D6FSI=J(UZFb!bJyb_ib0JHB#gYy}?r$9v?c~ zU|^Y#x&79k|kh-6K{}>55NQcFbqo5W;b>|N3$_QoH zOaSn_hOqQpS+pltC0JbGHvIw=_U`LjFkQZF zD`aktX@6iugB0(eQ>lAq8vU!Ro=`Z4&&GxjkP?=YdJa?reJ~Q4fxrU;%AkZ5BmO>= zKuW)Wi*4GI(Zp~3-9n0l2* z!A+M>Zx0Z)o^oTLNmROtF&l7Kle8wb*8#=7dxnY&Q5$|=woVI>J3WH_nTaWL4S>P& zmP}_lV(HHo7rPBS6o}wdl6pAC= zrS|y1Rs&&Y70K}qH?*}L`V7tcz*^x>*G3a-x(TYF+DJSn|=cLutbJ$>r zl^W!Om?YZb#`dfU8(6c7iW4^un9u^D;R+It=*3Z-NsUMUvB~zq4{x9dHIGPb4~M7M zc>;*)Ie1LcWV+dYFikpXJvfFgtozy>le7TKR#)$%cIJ}vQK5EQE9i?!ttHqzf@y9f zy0n|qL}~d`T@j3@9FgMibIPaCRU?%u>oK_WAwS1~vc6spp$fbKpd-uBj^N0TsUj$V zMxG5p(lX=k+RHZ%kM=iBmxpN7m`>U2>w z5lia{E*&oBegT$Qm5i5B>E}3V<=>;Bcb!a4`abNZ~umm6RF-bs#Vm#0RIlwiXA%AgVyXwxub!3H-Va1jXrz zpY>Av(xoY{yzWjTd9#9%;KVxV%Y_8W!fE}G;earNAY6O^h%#jLpn4SUw3K@@{{H*i z;iEflSDVJ6w1EUJflZ?=;_O2Zt*-T`Y%^M?mn*53Ic5R@pbgSgVlilT9#7$cbK#Qp zjlKNq-(*uEQpwcm_H6xOl&*02I%l>k6%XmKtf+W9!xP{)3SH(93@I zRUHjw&r<;aO4nxqJ^?CAHBexJZkzL3-}ODyYjEWYN;or`73!6q-*%NS{4G;&5{$A=$5-6+%;j{xNK}sY9Z| zE&YKh?YszZqU(J+%ilCx@j%+aVLYRDNqHcT9}}zUao*hIpau8Naev`*0%c2)`*`=2 z_g`jiM7AwlQc2h0aVIBmXCN5Na!)JJzr++WM&M(&Ei5z`MOBj*7yOz(s_Mfd9$n28 zhL>NXGj6^{=e_WmZJDH~(N&Ds_tWG)tA^-=)zX@cewE4AXz;$d?Jd))5AkIDbgy#S zI}%A0#f1ZCtY3(2oEdNhrv6U$WuX^RQgP~yJF@QAhf|~ZaOP*@X^yiS%^52JW*F6&ai zLY@-HHAc;K8%&%wQ?MemZOvd+Q0NRzJBDWF?$0+pXPt0{y7)+nNuyh5I$BPkemzEN zPGiw>@N3n2L`Z_H9xVsxeH1{In#`^G$Y-QxA@55#K+Epp+7 zM0BsVoCp|COTu|rZxTHJk`dG9usxR2Hsq$bYZG6eWq(KwGG>}1WiE{BjrZ3!Hrl}C zCIF-(xBjxhpRR4HX`a!1AyfNDWX3q#@-CX(N77a_6w0s(=yl2A%fV;0)%j2mc7uWd z@Z)Ea@dJ%|>dFpJt!MfxJo$x!LH*J=BUgo6gshjAO-U3L9n6*no_KkUx_-iv?$05b zTvnV9p7J}o-cfk4;Y*#W zSf+X^s23$yRlR$Cn5HK0_BJnsIn}J7#ZM$m;74n;i`nsE6; z$=`1{>n0Mo;!QRSM1>##;6MI-J1`J8)_$!=AEs9Bh?YQIaJ9NyGG4?^ukVVu_CC=0 z3V0JRX^SmP4o<#SVG;CJIa<5I34(jV8#UM4$@$^riW~y=bX|^^-g8gC5`9}@9gUuzggE_=3irvg|LKeEn5 z@zScC>&z*wDKg?rN@dT3gw#`IajEz{2AOIJgkCHJf5d?K&&s;u=EV09+qM&#M9Z!a~_wqPy-rT%$;X+JLPg7qO6>o2E zFA$to?6T;~MY|AN7ggEA>5EH9yaU;iD5LS)e)!HkLXi%IER#O6=}h$!2RO0*7eQ%_qc?a&jrq4Ew6mne%30@k0s`LdnBDcU9)&?PL0; zu>FsHS+faruezvi$F0NyCP*rgDrcY`y+j=R?}xiw+gKUUgYid%i1TqwCcjt?i}ZhL-d= zn0esI$apm|Exle~?zpkBLA@Q8oe7{xVpB-B7Bv6EGF>vZu#gU*=WJMLkFG6->tNv< zX!-bXkMo9w#r9cFzFhrc_^R8*>&;ip7VzWTuXn?@obP7j)mpB05Da76d@dxEg&ey1 zBAZsFGn1=3-2fxVghh1b=sZC6O%U2q{PE_wRqA_o#?hIB3md$ZDFYx<uSSBY28DVEy% z!3@By#FfikE!@Yhb6t8j_`%A(#X98#8D%&~43P7053)Q3jP-FwLH%Cg+>(APC=+h9 zI2?J>Ud7p5;(WM0#6A;jfA!BI>`sT>63jGzy?B2~NA{cQn{n%w@NMmicL5WVlD6W` zYxbf>v1>yz?Ckp8Y1^99&3dxM)iFS_D{c7NmC& z+>vg3DPK4gP0BZhOLQ0w9a^!7mu1c{+`1-Ub4TF?&$t4sh71!-LWskvja*q_J&O|& z4RSO(Z86=9W^>7X-_(lxauyTbpu12pFgyaML%_Un#>&$2%Kl;X+9dbPOlzfgj2{iD zTayVmj1E}0L+j|2HA)(u@^EHyw`XU_53_cPtUXVg7l<0KS@E0i?(Ge)Si>6e4GyLy zAsK$nPOOkTF<}CZ(|oQyN=plm(bm!cB&j0+{fMqGxeAIHK81zVMlsvj-})B?`1$?Q z(<8(e+uP_V!7OocmD~#wBG1X_6;rzxG_fe3`k0Ad41CkV)(JRHsRV~nlQ3y_g5&cV zw<#i|H|M(Um3Gh0YQdYjInoF9rH$8Et*j(zR+k^Ct2>iD$q=n=4qE?+tb3EGr%Bq9 zEJ00E$qF^NpkO1dt^F;fivahiP&+dgWH}3~j=J|UmF|2l*{@Z0cgTJ5UK<=c@^I|u zSGO*iI^KWh%ptu-B}Kkf*Z3LyR$n%HSl`BotnYSnp9~&-kLtZ30Xqx3$MBc{Xc$m+eboA~m)Ix;XS$ku`oR@_{uHT*c`ANy!aMZTNh|rT4vL{x&8}(jG#qf=P*{}W!7u@V!9;|^s-a!eLynoDiYNyYa;hc*9v7tegz z8%_e&wb^-W9Rcr7iG zga`uJdSIopb$h!y$$wv3SXH?}_m9cJ^HsWd{vh@IWNgNYGOYde&I9h`Y-h*{9zA+= zGmRdD<>OE>W`bHnPST6$HFGZv}ul6jo;%(F{Q3XsDCS$Y*0__6ohcTz&G? zDVn=?dpgyAz7qa2lz;0qpI2}aH zS2iuV0c9BWt!;f`NzK^o+V6K5ihs2X@eT5)=#`g0GZLDz!C_^&9!`=scmX-UhYUkp zlB##{eFMZt=EP8PF6T5%t~?(e{OdH!gh{`?;mOHlO`}IQ6tEUZJ9si6Cx6QE`lnxC z&43?!RX$m3yWom+z=;vI1%-%|ob8>wfbR z_j1s^p4h@ZtJx)wPC5BYzpu}LuX#%L?8GQ7?v-apH?OK`tnTCFg_qw5s=CDR7_{W%jvalfZmF&Tm+Zs+1b%d;>ynH=f)0m!=yR0Pc%VGI@c?AS0zxO|{ z>F)!B#c)=JnVnyl%`*AXxjS&4C>G8f`M;L?ub2Hlt*XC1`QiJQMNRhz&cjVX>7V)6 zx|Db(WgUL@?85*2B?|RlixzimO4<7jBrj!D|Mf}c>Lm+=AF)v)H-B#6zYYL}dS3VQ za{lL;gbO}(lt>O#cJ04D#@_x7na5L1l*Z3R`=9rqQ2%xQ5+5|oGC$q^U$1_C^BUfo z#OD^T8Po{YiIBg44E*f(YeoO{tm9dRYv;WmTp~h+KKi*Q|N70t_Y-(MD(vXm(U{wzxml;(ql*w*Id)e(c_Fv@g{l}ZAW6J3H&7}j- zP`M}nf3FR4p7#q2{_z1LxmT`TOO!7(hpd1PG({wolp=!}wW2^Ga-Sv00VMlm^NnMV zHsZMxA+jgW=`D3A1t5y5_+YJJZn*T=tSQ%YR;;?VHo($gr0mVv^XH4xRtIaZbPE9Fn+k*O? zgsG|N$8C^1F_l*dNhVPJY@%Eb4Y!i((=CwhagsYY9KYTM4QVD&;^@_7hRA~Q!Go7D z_5>MAsP)!@l{}L|`rEfB_{Hq)kC-+ydv$|Z48lPHBpPm!1g{oKpW&a2-H>kXrm z32;eB(m_B|yETeut}i>eFV{dZaovNM6T-VqF`wJQ)Mnu{hrr+;yEG&7!ip7yZ!D5v zE;R%)J!*FXrlg)th!qY2YV>JRZ-?qm3dqbuUJ0=gAE>|@%`OFZkAnb%>{q2X1dN)9 z@gE@j=Z+llfKVeApb%})YS{x3m_*QI$%X<0oL(oWmoQnbC?U57RFA|3SBz{DZ;&CSh)+Z_A#>s|gffUs{uL=IE6Y*Qc--wq{jTzq^=x9X_zT2Ddmxz1z? zSeJ>0d`%z(y4aHez{?PL<{HWDxY$@NPyl4J-T9g#m5h9#{$K&?QcDPnD3f-_bC83{ zR&OGRjf+E$QH{&N*!WvTWo2i=3)0P{!G0r728I`2US4~H%l7dwjZFzy1nAGSg>%}# z75@3EdB_Cpd%vkAK}RYFCnxUZ%h90y2p3TR#8+MP*f&zzx>GJx9-YLF?gK9UuRtzo%F92^{w@q;eh4+!)- zzo`lG@bcEHXHqdTN`Sse2b2b~&E}=7Y;2N2A<4tY$J;v#w9{cdJ%uiaR`?2ucoCvO zfEC~frGj*%`-1cG^I>jJhWltInoJ9%l>`I?#GXC-0J4;?^c7LLcmBD1^Ty>1O!>Vh zmX_%GVcq$FBqnl_Fm%Q54Tzc%T)Vj-jqn$bAHNM|)=Prx|1Tq@b5QD$8 zqYw@6*jXJ{%j}(4UQUOv)dFE|*zct;@1kC+>e4;;Irl6*$7a=Al_KtxK{NBZ7J{?j5 z2}uCg#NljonL}Xo&G++X0MRMQDJbTli1}Ph%-e&A{dVHY2Xk0`AY#DQ#pexui*N3g zLRL-J2C^M$*|L+1i>aWV)D*@p4U)+c(7~ByGA&}aI~lOHvhq1SJ^j+9OIbjbk33U7 zw+DhFj5=MkOnQA1ATomdm#of6(Hlm*)8U@8m$*n%>jTj+TK6*Wlp(n(G6iHH{QRX|+KJBG_{PZOj@tQRtBU7Ips z$MEp+A?xid4o)}B(j-A|Or6oNey$F{W#4*rt&b14afyl3$OZiq_&kXrKW>AoMyRL9 z9CBMIFcNeeX8=I(>pd7g9B{@aN&?f82+1!2r*&3L#mLmM!?6um0&Tbv-e;Y{U=lhG&AE7rza4Q-a84s9DZ$r`0&|>W)L?XCS;VLJC7|h;OhykNUGhs0( z4%as}c0dEDL<*P_6(*2{LM#dVM6gD7!q zmv~n&NG(6#oa=0d;TcMPg8S;9xQ=#IKv}IOu>_^BxbP1j@5tT;ijA&zoL~^aK9=-k z1LT#^;WmoBd>IHr%TXZO1+sub-dV4! z&+-X_d-O(tK|b#*4m*x2)8EU=9zt#<<}DG;dp=u#P!>cn>swkN(WGAOjjf2Bp4{{$ zV`lDpq0^e?3l86}w6qk;ZAnE%9DMzt2F=zLmEaszAe*Im69)%paUeglXNQL`<`wN# z=wh@32bK*^B`!2H^wK<)jxbn2>8VUPQ7~Q1|1w>qh*w@(T0)F76lpCwmx8@bL7$ra z$ac1k9Q-YEaQgcC9`ii4>JeOavSP~LO+ebb586;*)SiqVMt_wO%??0$>ns+Q#Npni zV3DG!kcF*n5hz(%b{;lVeunW)$<8E6K|&1>?o5(O?UU>-E-prV8?dNQf}Mp`>;osr zX0en4Mt>G0@4RCGmsjlU)}`jOm$-sWch=ND4)nIz3`ZP6YEB^a5VVOsrVHi3)ntJ; z4&!zxX=HVUjtjszk|HA`8_nOmdE%T*om4YSslVDx=DwZWM*Am$Au+Grj;$ZNC$iw8KkAl3rz;tDGWFu4=5 zw#{0n^Sn@6hYq$@fL@U>DX2-k))E#^7udS=ISb9&YMt=;dXxsl6{aI)XnKPMlFG`; z0UU!Rzb5QZeE-A>qD708M|70^6$}=3@)-@pzz`dNkg<)vJ;6MD2RM!#8 z2oRuvbUPK8UG_BC5%K`6t4bw`@qmsSavaEEBYULL2oxy&ASOF~Mj>$~Z=o|;nudjC zo0p?rl7Lw^0SGU&!5MkS93AcpQrk{}^#g<}%)?OiV&NdY39eK7%@-CH7W{4C3tZ(% zU;~iNj(c*`=cIvVvj^#no5u%FH#d_3Q9;3W=-LDa{kwMwuqV_!c0r&VIa=$Z-DxIJ(}O5N3jC$VzJh{+HOS^{uGW(1 zbR@ih=<74UUdUGD1XVsb??CZv2Y8e8;s~qi_X{A(%kPa?S!lE4gl^9yh2nzfCg{^l zJahTB=0Z;fvhh!#qa%S3$aZN>Jh{V4#JB)mPtYLy1!SLOK}8qB{~w@B+mWRu4$5?j z(13>+YjAvMGPGCqhKgjsDnmeh_S`vf#M^1M-U4Ho1ojI?Sw53NJXxQ(+pq=_q|dy! zmWR`01p@@UK|+^?KS{nYXRa$XnZ$kvu$4yyT(*`$I%{Bv1*oygWmBa9O??c8nwpaG zIr#0cxpO01Pyd)d3~EHg@~jJL<1Q?;GGU4X^5|$!=ScX_AYqCJ3e(Wz(62&48Dbo|K`n`(nPZg zVuL*0SMMm;b{0c7D*K5L9=?3MMN63&9=EG|(BB#hg2=P5OT5TrQl+2(@enRMd73!? zTPG(b*h+T$i@DbGskvnQaCy9Yb-O?_5ckrhsQ2ga=0G{jp9~^@O=zV;LUowL0CSK8 z9|*H!0&uAzX!w!Y!j+7Me#*D-)a0P(vu8ixO-q5>P!4Y|dxK82UF&{59%gt2hV8b) zoN-7LmV#l-B1q`=A;{5pf}8khz`bJtf*ts}dD3v6p{G~yA4#9Z2QW@l+}y{`pZr2Y zX+=dvYg@ae3oKWo5Lm6R^Bbdip**ORu5E78Wj4XWg&0SEuBe-oiAj=+i%V^YB}m94 za^?#W-XxxcBo`AH+-U(B85s~v_wLlDW8jc6rM1?Y2VtO8h+@EyvDp#YXyq6Tr$M8( z0(1enA_fv3_qw?`IpraMuTGQCzby@ZLmKin223Q7U;|F`+QW-==0ye(3ER=6A>D(WuwV zN0-bjP4%dyBYCELnGfV>WqvyW7yovfQI6sj&O7r1b-IUl*JGL~)Y;RPk6DGe8-;uo zBSQ$XR!o)OqYT&Y^(>kfCcFLpjVME%9ad@{?(}CbB;8)TIZs>PK=q^UiHvv5#p73^ zo!Wu&ayL-}p*_k-W$v$sV>`6kI~UnC*4I)0$SA(%@pWo>uk%LA8I;<;uJlOohEgfLDg53djIup$PZ~UJr^9V zxu5Dxke56!Yw16XhFUWGH=dODSU*Re0!L%6B3};fNgg1X-XYZq+Du8B^J{?n8Vjzi zFxTDrE{wK0C@+83aoDk3Keu0A{vT1n$}6^_^(ga{!W$-%(c0bX&-F!0k_9V>DA_X~ z=4AGI52lriVk9N8W8Oy3z5mZ`lNTNOATU;sM!a*q^&#M(&%B!>ied&C>a0gv(2}%o zW}O*G+nGJ}w-YNPBHa{9dtK3TsjEu3`c98L-STSZn9N6j{vVS6stEjfwIh4Y7E_`& z@zng>J;&soQ~AlR)hRwM-{jy#1Rno$C0TsRJQJXrD$@z@IQiOEV$}MTYTRZN>e6%m zr;jA!zaeJezu)sIizDAE820@0TP&hJfY1N0mmxbmNFFJU{pVqLe|N%XTQxJ5nuUdL zXsA;%S05dsh!;?5*WZ!D;U18-80?e-4_wh2{=Ha%9-)BRirKPJ(`nI{w*miQA z$*&A{4p;;f6vCk}8C7g!L49*HP`fK76-vv=e4ZsxT{G6wBTrp5SR5%Y-fK|golAEJ ziz=~OwvZu0$+`U#Niz)UOb)117xb$h`;w9(RJ)m>64Cxu*&%Oq9jQtkg@%X6K})5e z_v0ra)Z~*zuT^qqhHOX-Pcm0lPE)e5NPBXz?FCQe8`qZ1>Hh4EO)FA>_V5opf)d zG9T)1?d483n@9TwbM2zT($AlN0MGP7Yn_*e&Yujx#{Rk9bp`&m^wJs{O3J6+63?GU zigJf3e32)(e92>We|b7lp_rE?O^KhxZo^}1p*L}VnItYgJUD?`GU>a1?tD*%;^h3i z!;|T~RJj&5^oLsiGG4JzSA#3;2P00>(Ad=KLUNS+Qt3Wi_t&qbW*{s(d-}B4bTemX zp3!Cg_k~pYJzshEw`*rB-b-X_wZBkSE^ZhwTH9GA^^S=Xe#Mr?q>Dedv(7Ty=no~n zEl^k`^QlXzB{}vX(}ME+mFtB({QMM>rS>YDv-h6^?&?oQP7%@lP0fvrAKE;+X4^lW z#ZCh-YN;JMj$ro2o^x*oUougwdR0!Ro0p0<#S>blVxZCrS(6haW3kZ9lqi|Jr9F`M z5unz{Y@KMN;RiT;{Gr@Ob`9%PXSyN>ez31^0@AfIQ8$j9P`n7|6$0yAvRUYxK^ixR zZC5VB0DG|q33pUvB-`Au!&iE_ue0$HQdD${Z;`eaK!_#-HL6|71pu{)P!t9{iRY@D z3p}0r_3Mxab1Y19BtxQ@0If^!-*t#baBV}~K7GK9K0RF`FM3LpJGHAhtRG6d!T>a> zb)6V#{+9)$yt#n_GI(#iNP0lu`k=k<>kHPZ-XXfG4+SW z04VH599!|q$ON4|uQ&HH8AeB*rz>p3wSU?aw4PB>ISoyA!eXPX8|U!sQ(>nft1dWi+HqOE4AYHE=cuEffX34-T}o zC+nZttvBfkhwXg?+(vAUjlDe=us(>kTcPPlHGA*-aH&5ml;_%Xs3k()f7K!e&Yn2& zmK`HTQ8~4O{ZfQB1vA`22yf5M10W*kAfvefTN)hB8Q&xsty(F#! z!!(HW)34nx@h5xl(&B|+8;ZzHCexbu9?zsw(+y>3t@!Z$l~Hs6Pdm!q;LNs*;%N^R zsX=1)(L1K9>hdwSy_4Af^yK94p0+roczj>oHdT~M<_7elz%&95q(~3?%x8Y^tWVK( z=MM8GLk|qZ%aGHJBWHIOM{)hQyc@T=Cif-B#-Ifa@+5Qv89>lzld4cGRA^r9|FR`b zzH|m^BpsaF8`73L1WjRu632Vpw9x7{7wsA6m*3pH;r{Vs7hLO(etv$5(6j}uY)@fxNkZN$HeU0d&z6FW5G02~psW5_ zttUw<+_J%7-n#ZGwr}?MJ3JkjD$nU;vMnj#I9G`UIe}i;G6$p^vx7T-C>D?f#tT zw{IVl@te&v8=ky(Cp|+jzy@*xwY&HoY4Q~OVuj{miY6zKU<}?1<5U;qYF&64DF3qUL{^$=g9e?5t*;n zBi3xL3o^WAu-wxgnMUBQ)H^9Z_j4UfraEW&hSMp=fI z7|bRqe|>X_#1sc_^b03U?i6Twn_X|=ey*yT2klw$P@(ugjh%T^Q)e2+v7XwF3pgE+ z)2d~ZU=f8V7OaU8D;DMkwJd>1lpqrX1VmH_0;Y%zT17ySW!Q`g0f#_R0tgZW6%iE| zwt(zdL@^+geG{1Hwx=H9%pb#F_mG@>lYHNOzxR8d-}~OU20V+p)w}i!L`d9@^+P8` z*&M;p>qM=ttbA_uI_cJQ5}QG75e$z^PTnUv1UilS{%fNY1-D-kq2;$7dnNJ&kMV&r zTA(ojRL4OfP1UXw+lmbcS<@nBR(@B(c#i93W>HYj3n!u)*jJJAO4+Yg%7SMjjAO4Z z;`U-mxuu5XpLoBSW3onTW6=S0q_K1<}|<}YNRvL&z?PdCBXeUulz}chPt}idWmBRcCmj&nZYWO(%Z_o4Mvmd4ls=! z?vdYQktEGr>I?{K=v{slr)X@spucQa`0~+z-z%;Ej^EZSJLvGAZp++B7v|$}s7b;- z(G(J_@ohanHe5euSUx;35KDoRwFcY#y!*yKbO&}K#IU10Z?a&+(MZ1X4>I<{@SQRQ z{}|ABdozVVecojXR!BVpq+;RTCJ1_BHq{2xVPaHkJ-$*>(mid(;NalO!%tr8(F7CG z9o?i%Nq?)n$g7fEHjlWkDK9?CbJ{T2Up_;@rGAiX?CM0-13-9N3DW`L+M9)U-Tc( zp3Kfp)PW2!?4v#PesBQ>J;j18JzAALjBa)Mb$tVU4u`sXcC|eS@3R9;48GFe;rYDw z5ncj1ny9liXF2}wm)(>SwjCpO@#5&>=k_PYR=`N;>S?Iq6#86(M(vPH^R*^{P+nyC zrMm|#-!%r)PIybPoaF_M@{y$-dYW)Bfi`T5N$@?mTw35rE_U&xU$bt@coJ%5g|y>q zh;!$@8EOxSB$pA)*Q)0xM}R3^M=)_8eC<2Y)b?QArcI{E(rUjE7Ky_&YliPFlIm{Q zuoqY`8D>0tmJ!wHT*b0Hz|M2GJB$=(L5LMzMExr`qtNo3n?33{;7es3!S5(+z|h6! z7X8MOpnM>955ZZ&9=OUYSFP|g_83-nCT#ArA*@Gx1>i1i5Ob`(yd>n>i(dSX+?M%`wAMFcJ$X9tF=q>@P)u?UBxEE2G}}t! zCWf~wGH3RJu`)k6VIHHixMwP{rXWW_#G;Kvp4f6w=$YfaIp-a$w z+~8>FfBoV@c+2(qpN*(5^1MR#GsC3Fbt-jFW(0B&tLjm9ELJMAqI?uzO^%O?ZPI&b z$0*!=`O~Rjf!{ufw}E+|1vD8(cM68O=Cxnv$P!h9#dmufhr?7?ya0fysz*sJhPRga zEIIH7b}*vp7A)w^t&2x0Mmzo_iGB}!UOeH{)X%+vGD$OI*JjTrh+?9&H5KLMY?qwz zjLEfYAHlpR?BE6jBp}ks_O6dGMyGg4mHb@7LVh(V$#Z;c?6I@nt-3#;%2>Hv-qBbV z_SP`|NksOdg$sd3tfEqnm?r`pAJsTEp7i}=xmLGS~E z!R)A{&!LdKEy%r+*aEMRP|&Qu?K-@(vlzc-tDa9oXXbm+_{0Ll_N%hlCxdcfQZM=W ztvN&j%hhrR_rSjlW?4Q2(!r^wE*-6JKx>-}J-8*hv4=JZ4nfMd88pap8I|JKO(fiA6)~R`8 z=Cp0?ProviderEventOpenProviderEventDealReceivedProviderEventDecisioningErrorProviderEventGetPieceSizeErroredProviderEventDealNotFoundProviderEventDealRejectedProviderEventDealRejectedProviderEventDealAcceptedProviderEventBlockErroredProviderEventBlockErroredProviderEventBlocksCompletedProviderEventBlocksCompletedProviderEventPaymentRequestedProviderEventPaymentRequestedProviderEventPaymentRequestedProviderEventSaveVoucherFailedProviderEventSaveVoucherFailedProviderEventPartialPaymentReceivedProviderEventPartialPaymentReceivedProviderEventPaymentReceivedProviderEventPaymentReceivedProviderEventCompleteDealStatusNewOn entry runs ReceiveDealDealStatusAwaitingAcceptanceOn entry runs DecideOnDealDealStatusAcceptedOn entry runs SendBlocksDealStatusFailedOn entry runs SendFailResponseDealStatusRejectedOn entry runs SendFailResponseDealStatusFundsNeededOn entry runs ProcessPaymentDealStatusOngoingOn entry runs SendBlocksDealStatusFundsNeededLastPaymentOn entry runs ProcessPaymentDealStatusCompletedDealStatusDealNotFoundOn entry runs SendFailResponseDealStatusErroredDealStatusBlocksCompleteDealStatusFinalizingOn entry runs FinalizeThe following events are not shown cause they can trigger from any state.ProviderEventWriteResponseFailed - transitions state to DealStatusErroredProviderEventReadPaymentFailed - transitions state to DealStatusErrored \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd b/vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd new file mode 100644 index 0000000000..82c00d85de --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd @@ -0,0 +1,62 @@ +stateDiagram-v2 + state "StorageDealUnknown" as 0 + state "StorageDealProposalAccepted" as 3 + state "StorageDealSealing" as 5 + state "StorageDealActive" as 7 + state "StorageDealExpired" as 8 + state "StorageDealSlashed" as 9 + state "StorageDealFailing" as 11 + state "StorageDealFundsEnsured" as 12 + state "StorageDealCheckForAcceptance" as 13 + state "StorageDealStartDataTransfer" as 16 + state "StorageDealTransferring" as 17 + state "StorageDealEnsureClientFunds" as 21 + state "StorageDealClientFunding" as 23 + state "StorageDealError" as 26 + 3 : On entry runs ValidateDealPublished + 5 : On entry runs VerifyDealActivated + 7 : On entry runs WaitForDealCompletion + 11 : On entry runs FailDeal + 12 : On entry runs ProposeDeal + 13 : On entry runs CheckForDealAcceptance + 16 : On entry runs InitiateDataTransfer + 21 : On entry runs EnsureClientFunds + 23 : On entry runs WaitForFunding + [*] --> 0 + note right of 0 + The following events are not shown cause they can trigger from any state. + + ClientEventStreamCloseError - transitions state to StorageDealError + ClientEventRestart - does not transition state + end note + 0 --> 21 : ClientEventOpen + 21 --> 23 : ClientEventFundingInitiated + 21 --> 11 : ClientEventEnsureFundsFailed + 23 --> 11 : ClientEventEnsureFundsFailed + 21 --> 12 : ClientEventFundsEnsured + 23 --> 12 : ClientEventFundsEnsured + 12 --> 26 : ClientEventWriteProposalFailed + 12 --> 11 : ClientEventReadResponseFailed + 12 --> 11 : ClientEventResponseVerificationFailed + 12 --> 16 : ClientEventInitiateDataTransfer + 12 --> 11 : ClientEventUnexpectedDealState + 16 --> 11 : ClientEventDataTransferFailed + 17 --> 11 : ClientEventDataTransferFailed + 16 --> 17 : ClientEventDataTransferInitiated + 16 --> 13 : ClientEventDataTransferComplete + 17 --> 13 : ClientEventDataTransferComplete + 13 --> 13 : ClientEventWaitForDealState + 13 --> 11 : ClientEventResponseDealDidNotMatch + 13 --> 11 : ClientEventDealRejected + 13 --> 3 : ClientEventDealAccepted + 3 --> 26 : ClientEventDealPublishFailed + 3 --> 5 : ClientEventDealPublished + 5 --> 26 : ClientEventDealActivationFailed + 5 --> 7 : ClientEventDealActivated + 7 --> 9 : ClientEventDealSlashed + 7 --> 8 : ClientEventDealExpired + 7 --> 26 : ClientEventDealCompletionFailed + 11 --> 26 : ClientEventFailed + 9 --> [*] + 8 --> [*] + 26 --> [*] diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd.png b/vendor/github.com/filecoin-project/go-fil-markets/docs/storageclient.mmd.png new file mode 100644 index 0000000000000000000000000000000000000000..95be3a02c0de811690c36c73070a6e514eb85aff GIT binary patch literal 360921 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

    CX~Ei0L!g_Kt&# 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 zF*p*~=7gDATr}qw6a-ts;1l&%{){%j8z8y4ClientEventOpenClientEventFundingInitiatedClientEventEnsureFundsFailedClientEventEnsureFundsFailedClientEventFundsEnsuredClientEventFundsEnsuredClientEventWriteProposalFailedClientEventReadResponseFailedClientEventResponseVerificationFailedClientEventInitiateDataTransferClientEventUnexpectedDealStateClientEventDataTransferFailedClientEventDataTransferFailedClientEventDataTransferInitiatedClientEventDataTransferCompleteClientEventDataTransferCompleteClientEventWaitForDealStateClientEventResponseDealDidNotMatchClientEventDealRejectedClientEventDealAcceptedClientEventDealPublishFailedClientEventDealPublishedClientEventDealActivationFailedClientEventDealActivatedClientEventDealSlashedClientEventDealExpiredClientEventDealCompletionFailedClientEventFailedStorageDealUnknownStorageDealProposalAcceptedOn entry runs ValidateDealPublishedStorageDealSealingOn entry runs VerifyDealActivatedStorageDealActiveOn entry runs WaitForDealCompletionStorageDealExpiredStorageDealSlashedStorageDealFailingOn entry runs FailDealStorageDealFundsEnsuredOn entry runs ProposeDealStorageDealCheckForAcceptanceOn entry runs CheckForDealAcceptanceStorageDealStartDataTransferOn entry runs InitiateDataTransferStorageDealTransferringStorageDealEnsureClientFundsOn entry runs EnsureClientFundsStorageDealClientFundingOn entry runs WaitForFundingStorageDealErrorThe following events are not shown cause they can trigger from any state.ClientEventStreamCloseError - transitions state to StorageDealErrorClientEventRestart - does not transition state \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd b/vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd new file mode 100644 index 0000000000..16a2c599ca --- /dev/null +++ b/vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd @@ -0,0 +1,82 @@ +stateDiagram-v2 + state "StorageDealUnknown" as 0 + state "StorageDealStaged" as 4 + state "StorageDealSealing" as 5 + state "" as 6 + state "StorageDealActive" as 7 + state "StorageDealExpired" as 8 + state "StorageDealSlashed" as 9 + state "StorageDealRejecting" as 10 + state "StorageDealFailing" as 11 + state "StorageDealValidating" as 14 + state "StorageDealAcceptWait" as 15 + state "StorageDealTransferring" as 17 + state "StorageDealWaitingForData" as 18 + state "StorageDealVerifyData" as 19 + state "StorageDealEnsureProviderFunds" as 20 + state "StorageDealProviderFunding" as 22 + state "StorageDealPublish" as 24 + state "StorageDealPublishing" as 25 + state "StorageDealError" as 26 + 4 : On entry runs HandoffDeal + 5 : On entry runs VerifyDealActivated + 6 : On entry runs RecordPieceInfo + 7 : On entry runs WaitForDealCompletion + 10 : On entry runs RejectDeal + 11 : On entry runs FailDeal + 14 : On entry runs ValidateDealProposal + 15 : On entry runs DecideOnProposal + 19 : On entry runs VerifyData + 20 : On entry runs EnsureProviderFunds + 22 : On entry runs WaitForFunding + 24 : On entry runs PublishDeal + 25 : On entry runs WaitForPublish + [*] --> 0 + note right of 0 + The following events are not shown cause they can trigger from any state. + + ProviderEventNodeErrored - transitions state to StorageDealFailing + ProviderEventRestart - does not transition state + end note + 0 --> 14 : ProviderEventOpen + 14 --> 10 : ProviderEventDealRejected + 15 --> 10 : ProviderEventDealRejected + 19 --> 10 : ProviderEventDealRejected + 10 --> 11 : ProviderEventRejectionSent + 14 --> 15 : ProviderEventDealDeciding + 15 --> 18 : ProviderEventDataRequested + 17 --> 11 : ProviderEventDataTransferFailed + 18 --> 17 : ProviderEventDataTransferInitiated + 17 --> 19 : ProviderEventDataTransferCompleted + 19 --> 11 : ProviderEventDataVerificationFailed + 18 --> 20 : ProviderEventVerifiedData + 19 --> 20 : ProviderEventVerifiedData + 20 --> 22 : ProviderEventFundingInitiated + 20 --> 24 : ProviderEventFunded + 22 --> 24 : ProviderEventFunded + 24 --> 25 : ProviderEventDealPublishInitiated + 25 --> 11 : ProviderEventDealPublishError + 10 --> 11 : ProviderEventSendResponseFailed + 15 --> 11 : ProviderEventSendResponseFailed + 25 --> 4 : ProviderEventDealPublished + 4 --> 11 : ProviderEventFileStoreErrored + 5 --> 11 : ProviderEventFileStoreErrored + 7 --> 11 : ProviderEventFileStoreErrored + 4 --> 11 : ProviderEventDealHandoffFailed + 4 --> 5 : ProviderEventDealHandedOff + 5 --> 11 : ProviderEventDealActivationFailed + 5 --> 6 : ProviderEventDealActivated + 6 --> 11 : ProviderEventPieceStoreErrored + 6 --> 11 : ProviderEventUnableToLocatePiece + 6 --> 11 : ProviderEventReadMetadataErrored + 6 --> 7 : ProviderEventPieceRecorded + 7 --> 9 : ProviderEventDealSlashed + 7 --> 8 : ProviderEventDealExpired + 7 --> 26 : ProviderEventDealCompletionFailed + 11 --> 26 : ProviderEventFailed + 10 --> 26 : ProviderEventRestart + 14 --> 26 : ProviderEventRestart + 15 --> 26 : ProviderEventRestart + 26 --> [*] + 9 --> [*] + 8 --> [*] diff --git a/vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd.png b/vendor/github.com/filecoin-project/go-fil-markets/docs/storageprovider.mmd.png new file mode 100644 index 0000000000000000000000000000000000000000..e43c1c8b7229af9ef557824db8d73f76d5d0e72c GIT binary patch literal 551481 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

    + {{end}} + + + +
    {{.Msg.From}} -> {{.Msg.To}} ({{ToFil .Msg.Value}} FIL), M{{.Msg.Method}}
    + {{if not .Subcall}}
    Msg CID: {{.Msg.Cid}}
    {{end}} + {{if gt (len .Msg.Params) 0}} +
    {{JsonParams ($code) (.Msg.Method) (.Msg.Params) | html}}
    + {{end}} +
    Took {{.Duration}}, Exit: {{.MsgRct.ExitCode}}{{if gt (len .MsgRct.Return) 0}}, Return{{end}}
    + + {{if gt (len .MsgRct.Return) 0}} +
    {{JsonReturn ($code) (.Msg.Method) (.MsgRct.Return) | html}}
    + {{end}} + + {{if ne .MsgRct.ExitCode 0}} +
    Error:
    {{.Error}}
    + {{end}} + +
    +Gas Trace + + + {{define "virt" -}} + {{- if . -}} + +({{.}}) + {{- end -}} + {{- end}} + + {{define "gasC" -}} + + {{- end}} + + {{range .GasCharges}} + + {{template "gasC" .}} + + + {{end}} + {{with SumGas .GasCharges}} + + {{template "gasC" .}} + + + {{end}} +
    NameTotal/Compute/StorageTime TakenLocation
    {{.TotalGas}}{{template "virt" .TotalVirtualGas }}/{{.ComputeGas}}{{template "virt" .VirtualComputeGas}}/{{.StorageGas}}{{template "virt" .VirtualStorageGas}}
    {{.Name}}{{if .Extra}}:{{.Extra}}{{end}}{{.TimeTaken}} + {{ $fImp := FirstImportant .Location }} + {{ if $fImp }} +
    + {{ $fImp }}
    + {{ $elipOn := false }} + {{ range $index, $ele := .Location -}} + {{- if $index }}
    {{end -}} + {{- if .Show -}} + {{ if $elipOn }} + {{ $elipOn = false }} + + {{end}} + + {{- if .Important }}{{end -}} + {{- . -}} + {{if .Important }}{{end}} + {{else}} + {{ if not $elipOn }} + {{ $elipOn = true }} + + {{end}} +
    + {{end}} +
    Sum{{.TimeTaken}}
    +
    + + + {{if gt (len .Subcalls) 0}} +
    Subcalls:
    + {{$hash := .Hash}} + {{range .Subcalls}} + {{template "message" (Call . true (printf "%s-%s" $hash .Msg.Cid.String))}} + {{end}} + {{end}} +` + +type compStateHTMLIn struct { + TipSet *types.TipSet + Comp *api.ComputeStateOutput +} + +func computeStateHTMLTempl(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(addr address.Address) (cid.Cid, error)) error { + t, err := template.New("compute_state").Funcs(map[string]interface{}{ + "GetCode": getCode, + "GetMethod": getMethod, + "ToFil": toFil, + "JsonParams": jsonParams, + "JsonReturn": jsonReturn, + "IsSlow": isSlow, + "IsVerySlow": isVerySlow, + "IntExit": func(i exitcode.ExitCode) int64 { return int64(i) }, + "SumGas": sumGas, + "CodeStr": codeStr, + "Call": call, + "FirstImportant": func(locs []types.Loc) *types.Loc { + if len(locs) != 0 { + for _, l := range locs { + if l.Important() { + return &l + } + } + return &locs[0] + } + return nil + }, + }).Parse(compStateTemplate) + if err != nil { + return err + } + t, err = t.New("message").Parse(compStateMsg) + if err != nil { + return err + } + + return t.ExecuteTemplate(os.Stdout, "compute_state", &compStateHTMLIn{ + TipSet: ts, + Comp: o, + }) +} + +type callMeta struct { + types.ExecutionTrace + Subcall bool + Hash string +} + +func call(e types.ExecutionTrace, subcall bool, hash string) callMeta { + return callMeta{ + ExecutionTrace: e, + Subcall: subcall, + Hash: hash, + } +} + +func codeStr(c cid.Cid) string { + cmh, err := multihash.Decode(c.Hash()) + if err != nil { + panic(err) + } + return string(cmh.Digest) +} + +func getMethod(code cid.Cid, method abi.MethodNum) string { + return stmgr.MethodsMap[code][method].Name +} + +func toFil(f types.BigInt) types.FIL { + return types.FIL(f) +} + +func isSlow(t time.Duration) bool { + return t > 10*time.Millisecond +} + +func isVerySlow(t time.Duration) bool { + return t > 50*time.Millisecond +} + +func sumGas(changes []*types.GasTrace) types.GasTrace { + var out types.GasTrace + for _, gc := range changes { + out.TotalGas += gc.TotalGas + out.ComputeGas += gc.ComputeGas + out.StorageGas += gc.StorageGas + + out.TotalVirtualGas += gc.TotalVirtualGas + out.VirtualComputeGas += gc.VirtualComputeGas + out.VirtualStorageGas += gc.VirtualStorageGas + } + + return out +} + +func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) { + re := reflect.New(stmgr.MethodsMap[code][method].Params.Elem()) + p := re.Interface().(cbg.CBORUnmarshaler) + if err := p.UnmarshalCBOR(bytes.NewReader(params)); err != nil { + return "", err + } + + b, err := json.MarshalIndent(p, "", " ") + return string(b), err +} + +func jsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { + re := reflect.New(stmgr.MethodsMap[code][method].Ret.Elem()) + p := re.Interface().(cbg.CBORUnmarshaler) + if err := p.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { + return "", err + } + + b, err := json.MarshalIndent(p, "", " ") + return string(b), err +} + +var stateWaitMsgCmd = &cli.Command{ + Name: "wait-msg", + Usage: "Wait for a message to appear on chain", + ArgsUsage: "[messageCid]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "timeout", + Value: "10m", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must specify message cid to wait for") + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + msg, err := cid.Decode(cctx.Args().First()) + if err != nil { + return err + } + + mw, err := api.StateWaitMsg(ctx, msg, build.MessageConfidence) + if err != nil { + return err + } + + m, err := api.ChainGetMessage(ctx, msg) + if err != nil { + return err + } + + fmt.Printf("message was executed in tipset: %s\n", mw.TipSet.Cids()) + fmt.Printf("Exit Code: %d\n", mw.Receipt.ExitCode) + fmt.Printf("Gas Used: %d\n", mw.Receipt.GasUsed) + fmt.Printf("Return: %x\n", mw.Receipt.Return) + if err := printReceiptReturn(ctx, api, m, mw.Receipt); err != nil { + return err + } + + return nil + }, +} + +func printReceiptReturn(ctx context.Context, api api.FullNode, m *types.Message, r types.MessageReceipt) error { + act, err := api.StateGetActor(ctx, m.To, types.EmptyTSK) + if err != nil { + return err + } + + jret, err := jsonReturn(act.Code, m.Method, r.Return) + if err != nil { + return err + } + + fmt.Println(jret) + + return nil +} + +var stateSearchMsgCmd = &cli.Command{ + Name: "search-msg", + Usage: "Search to see whether a message has appeared on chain", + ArgsUsage: "[messageCid]", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must specify message cid to search for") + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + msg, err := cid.Decode(cctx.Args().First()) + if err != nil { + return err + } + + mw, err := api.StateSearchMsg(ctx, msg) + if err != nil { + return err + } + + if mw != nil { + fmt.Printf("message was executed in tipset: %s", mw.TipSet.Cids()) + fmt.Printf("\nExit Code: %d", mw.Receipt.ExitCode) + fmt.Printf("\nGas Used: %d", mw.Receipt.GasUsed) + fmt.Printf("\nReturn: %x", mw.Receipt.Return) + } else { + fmt.Print("message was not found on chain") + } + return nil + }, +} + +var stateCallCmd = &cli.Command{ + Name: "call", + Usage: "Invoke a method on an actor locally", + ArgsUsage: "[toAddress methodId (optional)]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "", + Value: builtin.SystemActorAddr.String(), + }, + &cli.StringFlag{ + Name: "value", + Usage: "specify value field for invocation", + Value: "0", + }, + &cli.StringFlag{ + Name: "ret", + Usage: "specify how to parse output (auto, raw, addr, big)", + Value: "auto", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 2 { + return fmt.Errorf("must specify at least actor and method to invoke") + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + toa, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return fmt.Errorf("given 'to' address %q was invalid: %w", cctx.Args().First(), err) + } + + froma, err := address.NewFromString(cctx.String("from")) + if err != nil { + return fmt.Errorf("given 'from' address %q was invalid: %w", cctx.String("from"), err) + } + + ts, err := LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + + method, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64) + if err != nil { + return fmt.Errorf("must pass method as a number") + } + + value, err := types.ParseFIL(cctx.String("value")) + if err != nil { + return fmt.Errorf("failed to parse 'value': %s", err) + } + + act, err := api.StateGetActor(ctx, toa, ts.Key()) + if err != nil { + return fmt.Errorf("failed to lookup target actor: %s", err) + } + + params, err := parseParamsForMethod(act.Code, method, cctx.Args().Slice()[2:]) + if err != nil { + return fmt.Errorf("failed to parse params: %s", err) + } + + ret, err := api.StateCall(ctx, &types.Message{ + From: froma, + To: toa, + Value: types.BigInt(value), + GasLimit: 10000000000, + GasPrice: types.NewInt(0), + Method: abi.MethodNum(method), + Params: params, + }, ts.Key()) + if err != nil { + return fmt.Errorf("state call failed: %s", err) + } + + if ret.MsgRct.ExitCode != 0 { + return fmt.Errorf("invocation failed (exit: %d): %s", ret.MsgRct.ExitCode, ret.Error) + } + + s, err := formatOutput(cctx.String("ret"), ret.MsgRct.Return) + if err != nil { + return fmt.Errorf("failed to format output: %s", err) + } + + fmt.Printf("return: %s\n", s) + + return nil + }, +} + +func formatOutput(t string, val []byte) (string, error) { + switch t { + case "raw", "hex": + return fmt.Sprintf("%x", val), nil + case "address", "addr", "a": + a, err := address.NewFromBytes(val) + if err != nil { + return "", err + } + return a.String(), nil + case "big", "int", "bigint": + bi := types.BigFromBytes(val) + return bi.String(), nil + case "fil": + bi := types.FIL(types.BigFromBytes(val)) + return bi.String(), nil + case "pid", "peerid", "peer": + pid, err := peer.IDFromBytes(val) + if err != nil { + return "", err + } + + return pid.Pretty(), nil + case "auto": + if len(val) == 0 { + return "", nil + } + + a, err := address.NewFromBytes(val) + if err == nil { + return "address: " + a.String(), nil + } + + pid, err := peer.IDFromBytes(val) + if err == nil { + return "peerID: " + pid.Pretty(), nil + } + + bi := types.BigFromBytes(val) + return "bigint: " + bi.String(), nil + default: + return "", fmt.Errorf("unrecognized output type: %q", t) + } +} + +func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, error) { + if len(args) == 0 { + return nil, nil + } + + var f interface{} + switch act { + case builtin.StorageMarketActorCodeID: + f = market.Actor{}.Exports()[method] + case builtin.StorageMinerActorCodeID: + f = miner2.Actor{}.Exports()[method] + case builtin.StoragePowerActorCodeID: + f = power.Actor{}.Exports()[method] + case builtin.MultisigActorCodeID: + f = multisig.Actor{}.Exports()[method] + case builtin.PaymentChannelActorCodeID: + f = paych.Actor{}.Exports()[method] + default: + return nil, fmt.Errorf("the lazy devs didnt add support for that actor to this call yet") + } + + rf := reflect.TypeOf(f) + if rf.NumIn() != 3 { + return nil, fmt.Errorf("expected referenced method to have three arguments") + } + + paramObj := rf.In(2).Elem() + if paramObj.NumField() != len(args) { + return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField()) + } + + p := reflect.New(paramObj) + for i := 0; i < len(args); i++ { + switch paramObj.Field(i).Type { + case reflect.TypeOf(address.Address{}): + a, err := address.NewFromString(args[i]) + if err != nil { + return nil, fmt.Errorf("failed to parse address: %s", err) + } + p.Elem().Field(i).Set(reflect.ValueOf(a)) + case reflect.TypeOf(uint64(0)): + val, err := strconv.ParseUint(args[i], 10, 64) + if err != nil { + return nil, err + } + p.Elem().Field(i).Set(reflect.ValueOf(val)) + case reflect.TypeOf(peer.ID("")): + pid, err := peer.IDB58Decode(args[i]) + if err != nil { + return nil, fmt.Errorf("failed to parse peer ID: %s", err) + } + p.Elem().Field(i).Set(reflect.ValueOf(pid)) + default: + return nil, fmt.Errorf("unsupported type for call (TODO): %s", paramObj.Field(i).Type) + } + } + + m := p.Interface().(cbg.CBORMarshaler) + buf := new(bytes.Buffer) + if err := m.MarshalCBOR(buf); err != nil { + return nil, fmt.Errorf("failed to marshal param object: %s", err) + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/cli/sync.go b/vendor/github.com/filecoin-project/lotus/cli/sync.go new file mode 100644 index 0000000000..fbb69a8703 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cli/sync.go @@ -0,0 +1,201 @@ +package cli + +import ( + "context" + "fmt" + "time" + + "github.com/filecoin-project/specs-actors/actors/abi" + cid "github.com/ipfs/go-cid" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain" +) + +var syncCmd = &cli.Command{ + Name: "sync", + Usage: "Inspect or interact with the chain syncer", + Subcommands: []*cli.Command{ + syncStatusCmd, + syncWaitCmd, + syncMarkBadCmd, + syncCheckBadCmd, + }, +} + +var syncStatusCmd = &cli.Command{ + Name: "status", + Usage: "check sync status", + Action: func(cctx *cli.Context) error { + apic, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + state, err := apic.SyncState(ctx) + if err != nil { + return err + } + + fmt.Println("sync status:") + for i, ss := range state.ActiveSyncs { + fmt.Printf("worker %d:\n", i) + var base, target []cid.Cid + var heightDiff int64 + var theight abi.ChainEpoch + if ss.Base != nil { + base = ss.Base.Cids() + heightDiff = int64(ss.Base.Height()) + } + if ss.Target != nil { + target = ss.Target.Cids() + heightDiff = int64(ss.Target.Height()) - heightDiff + theight = ss.Target.Height() + } else { + heightDiff = 0 + } + fmt.Printf("\tBase:\t%s\n", base) + fmt.Printf("\tTarget:\t%s (%d)\n", target, theight) + fmt.Printf("\tHeight diff:\t%d\n", heightDiff) + fmt.Printf("\tStage: %s\n", chain.SyncStageString(ss.Stage)) + fmt.Printf("\tHeight: %d\n", ss.Height) + if ss.End.IsZero() { + if !ss.Start.IsZero() { + fmt.Printf("\tElapsed: %s\n", time.Since(ss.Start)) + } + } else { + fmt.Printf("\tElapsed: %s\n", ss.End.Sub(ss.Start)) + } + if ss.Stage == api.StageSyncErrored { + fmt.Printf("\tError: %s\n", ss.Message) + } + } + return nil + }, +} + +var syncWaitCmd = &cli.Command{ + Name: "wait", + Usage: "Wait for sync to be complete", + Action: func(cctx *cli.Context) error { + napi, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + return SyncWait(ctx, napi) + }, +} + +var syncMarkBadCmd = &cli.Command{ + Name: "mark-bad", + Usage: "Mark the given block as bad, will prevent syncing to a chain that contains it", + ArgsUsage: "[blockCid]", + Action: func(cctx *cli.Context) error { + napi, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("must specify block cid to mark") + } + + bcid, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to decode input as a cid: %s", err) + } + + return napi.SyncMarkBad(ctx, bcid) + }, +} + +var syncCheckBadCmd = &cli.Command{ + Name: "check-bad", + Usage: "check if the given block was marked bad, and for what reason", + ArgsUsage: "[blockCid]", + Action: func(cctx *cli.Context) error { + napi, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("must specify block cid to check") + } + + bcid, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to decode input as a cid: %s", err) + } + + reason, err := napi.SyncCheckBad(ctx, bcid) + if err != nil { + return err + } + + if reason == "" { + fmt.Println("block was not marked as bad") + return nil + } + + fmt.Println(reason) + return nil + }, +} + +func SyncWait(ctx context.Context, napi api.FullNode) error { + for { + state, err := napi.SyncState(ctx) + if err != nil { + return err + } + + head, err := napi.ChainHead(ctx) + if err != nil { + return err + } + + working := 0 + for i, ss := range state.ActiveSyncs { + switch ss.Stage { + case api.StageSyncComplete: + default: + working = i + case api.StageIdle: + // not complete, not actively working + } + } + + ss := state.ActiveSyncs[working] + + var target []cid.Cid + if ss.Target != nil { + target = ss.Target.Cids() + } + + fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height) + + if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) { + fmt.Println("\nDone!") + return nil + } + + select { + case <-ctx.Done(): + fmt.Println("\nExit by user") + return nil + case <-time.After(1 * time.Second): + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cli/version.go b/vendor/github.com/filecoin-project/lotus/cli/version.go new file mode 100644 index 0000000000..d257f5ba9c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cli/version.go @@ -0,0 +1,32 @@ +package cli + +import ( + "fmt" + + "github.com/urfave/cli/v2" +) + +var versionCmd = &cli.Command{ + Name: "version", + Usage: "Print version", + Action: func(cctx *cli.Context) error { + api, closer, err := GetAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + // TODO: print more useful things + + v, err := api.Version(ctx) + if err != nil { + return err + } + fmt.Println("Daemon: ", v) + + fmt.Print("Local: ") + cli.VersionPrinter(cctx) + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cli/wait.go b/vendor/github.com/filecoin-project/lotus/cli/wait.go new file mode 100644 index 0000000000..ca8cdce3f5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cli/wait.go @@ -0,0 +1,34 @@ +package cli + +import ( + "fmt" + "time" + + "github.com/urfave/cli/v2" +) + +var waitApiCmd = &cli.Command{ + Name: "wait-api", + Usage: "Wait for lotus api to come online", + Action: func(cctx *cli.Context) error { + for i := 0; i < 30; i++ { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + fmt.Printf("Not online yet... (%s)\n", err) + time.Sleep(time.Second) + continue + } + defer closer() + + ctx := ReqContext(cctx) + + _, err = api.ID(ctx) + if err != nil { + return err + } + + return nil + } + return fmt.Errorf("timed out waiting for api to come online") + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cli/wallet.go b/vendor/github.com/filecoin-project/lotus/cli/wallet.go new file mode 100644 index 0000000000..22234ca5a9 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cli/wallet.go @@ -0,0 +1,408 @@ +package cli + +import ( + "bufio" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/filecoin-project/go-address" + types "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/specs-actors/actors/crypto" + "golang.org/x/xerrors" + + "github.com/urfave/cli/v2" +) + +var walletCmd = &cli.Command{ + Name: "wallet", + Usage: "Manage wallet", + Subcommands: []*cli.Command{ + walletNew, + walletList, + walletBalance, + walletExport, + walletImport, + walletGetDefault, + walletSetDefault, + walletSign, + walletVerify, + walletDelete, + }, +} + +var walletNew = &cli.Command{ + Name: "new", + Usage: "Generate a new key of the given type", + ArgsUsage: "[bls|secp256k1 (default secp256k1)]", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + t := cctx.Args().First() + if t == "" { + t = "secp256k1" + } + + nk, err := api.WalletNew(ctx, wallet.ActSigType(t)) + if err != nil { + return err + } + + fmt.Println(nk.String()) + + return nil + }, +} + +var walletList = &cli.Command{ + Name: "list", + Usage: "List wallet address", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + addrs, err := api.WalletList(ctx) + if err != nil { + return err + } + + for _, addr := range addrs { + fmt.Println(addr.String()) + } + return nil + }, +} + +var walletBalance = &cli.Command{ + Name: "balance", + Usage: "Get account balance", + ArgsUsage: "[address]", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + var addr address.Address + if cctx.Args().First() != "" { + addr, err = address.NewFromString(cctx.Args().First()) + } else { + addr, err = api.WalletDefaultAddress(ctx) + } + if err != nil { + return err + } + + balance, err := api.WalletBalance(ctx, addr) + if err != nil { + return err + } + + if balance.Equals(types.NewInt(0)) { + fmt.Printf("%s (warning: may display 0 if chain sync in progress)\n", types.FIL(balance)) + } else { + fmt.Printf("%s\n", types.FIL(balance)) + } + + return nil + }, +} + +var walletGetDefault = &cli.Command{ + Name: "default", + Usage: "Get default wallet address", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + addr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + + fmt.Printf("%s\n", addr.String()) + return nil + }, +} + +var walletSetDefault = &cli.Command{ + Name: "set-default", + Usage: "Set default wallet address", + ArgsUsage: "[address]", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("must pass address to set as default") + } + + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + return api.WalletSetDefault(ctx, addr) + }, +} + +var walletExport = &cli.Command{ + Name: "export", + Usage: "export keys", + ArgsUsage: "[address]", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("must specify key to export") + } + + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + ki, err := api.WalletExport(ctx, addr) + if err != nil { + return err + } + + b, err := json.Marshal(ki) + if err != nil { + return err + } + + fmt.Println(hex.EncodeToString(b)) + return nil + }, +} + +var walletImport = &cli.Command{ + Name: "import", + Usage: "import keys", + ArgsUsage: "[ (optional, will read from stdin if omitted)]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "format", + Usage: "specify input format for key", + Value: "hex-lotus", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + var inpdata []byte + if !cctx.Args().Present() || cctx.Args().First() == "-" { + reader := bufio.NewReader(os.Stdin) + fmt.Print("Enter private key: ") + indata, err := reader.ReadBytes('\n') + if err != nil { + return err + } + inpdata = indata + + } else { + fdata, err := ioutil.ReadFile(cctx.Args().First()) + if err != nil { + return err + } + inpdata = fdata + } + + var ki types.KeyInfo + switch cctx.String("format") { + case "hex-lotus": + data, err := hex.DecodeString(strings.TrimSpace(string(inpdata))) + if err != nil { + return err + } + + if err := json.Unmarshal(data, &ki); err != nil { + return err + } + case "json-lotus": + if err := json.Unmarshal(inpdata, &ki); err != nil { + return err + } + case "gfc-json": + var f struct { + KeyInfo []struct { + PrivateKey []byte + SigType int + } + } + if err := json.Unmarshal(inpdata, &f); err != nil { + return xerrors.Errorf("failed to parse go-filecoin key: %s", err) + } + + gk := f.KeyInfo[0] + ki.PrivateKey = gk.PrivateKey + switch gk.SigType { + case 1: + ki.Type = wallet.KTSecp256k1 + case 2: + ki.Type = wallet.KTBLS + default: + return fmt.Errorf("unrecognized key type: %d", gk.SigType) + } + default: + return fmt.Errorf("unrecognized format: %s", cctx.String("format")) + } + + addr, err := api.WalletImport(ctx, &ki) + if err != nil { + return err + } + + fmt.Printf("imported key %s successfully!\n", addr) + return nil + }, +} + +var walletSign = &cli.Command{ + Name: "sign", + Usage: "sign a message", + ArgsUsage: " ", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() || cctx.NArg() != 2 { + return fmt.Errorf("must specify signing address and message to sign") + } + + addr, err := address.NewFromString(cctx.Args().First()) + + if err != nil { + return err + } + + msg, err := hex.DecodeString(cctx.Args().Get(1)) + + if err != nil { + return err + } + + sig, err := api.WalletSign(ctx, addr, msg) + + if err != nil { + return err + } + + sigBytes := append([]byte{byte(sig.Type)}, sig.Data...) + + fmt.Println(hex.EncodeToString(sigBytes)) + return nil + }, +} + +var walletVerify = &cli.Command{ + Name: "verify", + Usage: "verify the signature of a message", + ArgsUsage: " ", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() || cctx.NArg() != 3 { + return fmt.Errorf("must specify signing address, message, and signature to verify") + } + + addr, err := address.NewFromString(cctx.Args().First()) + + if err != nil { + return err + } + + msg, err := hex.DecodeString(cctx.Args().Get(1)) + + if err != nil { + return err + } + + sigBytes, err := hex.DecodeString(cctx.Args().Get(2)) + + if err != nil { + return err + } + + var sig crypto.Signature + if err := sig.UnmarshalBinary(sigBytes); err != nil { + return err + } + + if api.WalletVerify(ctx, addr, msg, &sig) { + fmt.Println("valid") + return nil + } else { + fmt.Println("invalid") + return NewCliError("CLI Verify called with invalid signature") + } + }, +} + +var walletDelete = &cli.Command{ + Name: "delete", + Usage: "Delete an account from the wallet", + ArgsUsage: "
    ", + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() || cctx.NArg() != 1 { + return fmt.Errorf("must specify address to delete") + } + + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + return api.WalletDelete(ctx, addr) + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/chain-noise/main.go b/vendor/github.com/filecoin-project/lotus/cmd/chain-noise/main.go new file mode 100644 index 0000000000..a1e92ee962 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/chain-noise/main.go @@ -0,0 +1,94 @@ +package main + +import ( + "context" + "fmt" + "math/rand" + "os" + "time" + + "github.com/filecoin-project/specs-actors/actors/crypto" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + + "github.com/urfave/cli/v2" +) + +func main() { + app := &cli.App{ + Name: "chain-noise", + Usage: "Generate some spam transactions in the network", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + }, + Commands: []*cli.Command{runCmd}, + } + + if err := app.Run(os.Args); err != nil { + fmt.Println("Error: ", err) + os.Exit(1) + } +} + +var runCmd = &cli.Command{ + Name: "run", + Action: func(cctx *cli.Context) error { + addr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + return sendSmallFundsTxs(ctx, api, addr, 5) + }, +} + +func sendSmallFundsTxs(ctx context.Context, api api.FullNode, from address.Address, rate int) error { + var sendSet []address.Address + for i := 0; i < 20; i++ { + naddr, err := api.WalletNew(ctx, crypto.SigTypeSecp256k1) + if err != nil { + return err + } + + sendSet = append(sendSet, naddr) + } + + tick := time.NewTicker(time.Second / time.Duration(rate)) + for { + select { + case <-tick.C: + msg := &types.Message{ + From: from, + To: sendSet[rand.Intn(20)], + Value: types.NewInt(1), + GasLimit: 100000, + GasPrice: types.NewInt(0), + } + + smsg, err := api.MpoolPushMessage(ctx, msg) + if err != nil { + return err + } + fmt.Println("Message sent: ", smsg.Cid()) + case <-ctx.Done(): + return nil + } + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/import.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/import.go new file mode 100644 index 0000000000..6d5f7f8ff4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/import.go @@ -0,0 +1,623 @@ +package main + +import ( + "bufio" + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "math" + "net/http" + _ "net/http/pprof" + "os" + "runtime" + "runtime/pprof" + "sort" + "time" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/secp" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/specs-actors/actors/abi" + "golang.org/x/xerrors" + + "github.com/ipfs/go-datastore" + badger "github.com/ipfs/go-ds-badger2" + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/urfave/cli/v2" +) + +type TipSetExec struct { + TipSet types.TipSetKey + Trace []*api.InvocResult + Duration time.Duration +} + +var importBenchCmd = &cli.Command{ + Name: "import", + Usage: "benchmark chain import and validation", + Subcommands: []*cli.Command{ + importAnalyzeCmd, + }, + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "height", + Usage: "halt validation after given height", + }, + &cli.IntFlag{ + Name: "batch-seal-verify-threads", + Usage: "set the parallelism factor for batch seal verification", + Value: runtime.NumCPU(), + }, + }, + Action: func(cctx *cli.Context) error { + vm.BatchSealVerifyParallelism = cctx.Int("batch-seal-verify-threads") + if !cctx.Args().Present() { + fmt.Println("must pass car file of chain to benchmark importing") + return nil + } + + cfi, err := os.Open(cctx.Args().First()) + if err != nil { + return err + } + defer cfi.Close() //nolint:errcheck // read only file + + tdir, err := ioutil.TempDir("", "lotus-import-bench") + if err != nil { + return err + } + + bds, err := badger.NewDatastore(tdir, nil) + if err != nil { + return err + } + bs := blockstore.NewBlockstore(bds) + cbs, err := blockstore.CachedBlockstore(context.TODO(), bs, blockstore.DefaultCacheOpts()) + if err != nil { + return err + } + bs = cbs + ds := datastore.NewMapDatastore() + cs := store.NewChainStore(bs, ds, vm.Syscalls(ffiwrapper.ProofVerifier)) + stm := stmgr.NewStateManager(cs) + + prof, err := os.Create("import-bench.prof") + if err != nil { + return err + } + defer prof.Close() //nolint:errcheck + + if err := pprof.StartCPUProfile(prof); err != nil { + return err + } + + head, err := cs.Import(cfi) + if err != nil { + return err + } + + if h := cctx.Int64("height"); h != 0 { + tsh, err := cs.GetTipsetByHeight(context.TODO(), abi.ChainEpoch(h), head, true) + if err != nil { + return err + } + head = tsh + } + + ts := head + tschain := []*types.TipSet{ts} + for ts.Height() != 0 { + next, err := cs.LoadTipSet(ts.Parents()) + if err != nil { + return err + } + + tschain = append(tschain, next) + ts = next + } + + ibj, err := os.Create("import-bench.json") + if err != nil { + return err + } + defer ibj.Close() //nolint:errcheck + + enc := json.NewEncoder(ibj) + + var lastTse *TipSetExec + + lastState := tschain[len(tschain)-1].ParentState() + for i := len(tschain) - 2; i >= 0; i-- { + cur := tschain[i] + log.Infof("computing state (height: %d, ts=%s)", cur.Height(), cur.Cids()) + if cur.ParentState() != lastState { + lastTrace := lastTse.Trace + d, err := json.MarshalIndent(lastTrace, "", " ") + if err != nil { + panic(err) + } + fmt.Println("TRACE") + fmt.Println(string(d)) + return xerrors.Errorf("tipset chain had state mismatch at height %d (%s != %s)", cur.Height(), cur.ParentState(), lastState) + } + start := time.Now() + st, trace, err := stm.ExecutionTrace(context.TODO(), cur) + if err != nil { + return err + } + stripCallers(trace) + + lastTse = &TipSetExec{ + TipSet: cur.Key(), + Trace: trace, + Duration: time.Since(start), + } + lastState = st + if err := enc.Encode(lastTse); err != nil { + return xerrors.Errorf("failed to write out tipsetexec: %w", err) + } + } + + pprof.StopCPUProfile() + + return nil + + }, +} + +func walkExecutionTrace(et *types.ExecutionTrace) { + for _, gc := range et.GasCharges { + gc.Callers = nil + } + for _, sub := range et.Subcalls { + walkExecutionTrace(&sub) //nolint:scopelint,gosec + } +} + +func stripCallers(trace []*api.InvocResult) { + for _, t := range trace { + walkExecutionTrace(&t.ExecutionTrace) + } +} + +type Invocation struct { + TipSet types.TipSetKey + Invoc *api.InvocResult +} + +const GasPerNs = 10 + +func countGasCosts(et *types.ExecutionTrace) (int64, int64) { + var cgas, vgas int64 + + for _, gc := range et.GasCharges { + cgas += gc.ComputeGas + vgas += gc.VirtualComputeGas + } + + for _, sub := range et.Subcalls { + c, v := countGasCosts(&sub) + cgas += c + vgas += v + } + + return cgas, vgas +} + +func compStats(vals []float64) (float64, float64) { + var sum float64 + + for _, v := range vals { + sum += v + } + + av := sum / float64(len(vals)) + + var varsum float64 + for _, v := range vals { + delta := av - v + varsum += delta * delta + } + + return av, math.Sqrt(varsum / float64(len(vals))) +} + +type stats struct { + timeTaken meanVar + gasRatio meanVar + + extraCovar *covar +} + +type covar struct { + meanX float64 + meanY float64 + c float64 + n float64 + m2x float64 + m2y float64 +} + +func (cov1 *covar) Covariance() float64 { + return cov1.c / (cov1.n - 1) +} + +func (cov1 *covar) VarianceX() float64 { + return cov1.m2x / (cov1.n - 1) +} + +func (v1 *covar) StddevX() float64 { + return math.Sqrt(v1.VarianceX()) +} + +func (cov1 *covar) VarianceY() float64 { + return cov1.m2y / (cov1.n - 1) +} + +func (v1 *covar) StddevY() float64 { + return math.Sqrt(v1.VarianceY()) +} + +func (cov1 *covar) AddPoint(x, y float64) { + cov1.n += 1 + + dx := x - cov1.meanX + cov1.meanX += dx / cov1.n + dx2 := x - cov1.meanX + cov1.m2x += dx * dx2 + + dy := y - cov1.meanY + cov1.meanY += dy / cov1.n + dy2 := y - cov1.meanY + cov1.m2y += dy * dy2 + + cov1.c += dx * dy +} + +func (cov1 *covar) Combine(cov2 *covar) { + if cov1.n == 0 { + *cov1 = *cov2 + return + } + if cov2.n == 0 { + return + } + + if cov1.n == 1 { + cpy := *cov2 + cpy.AddPoint(cov2.meanX, cov2.meanY) + *cov1 = cpy + return + } + if cov2.n == 1 { + cov1.AddPoint(cov2.meanX, cov2.meanY) + } + + out := covar{} + out.n = cov1.n + cov2.n + + dx := cov1.meanX - cov2.meanX + out.meanX = cov1.meanX - dx*cov2.n/out.n + out.m2x = cov1.m2x + cov2.m2x + dx*dx*cov1.n*cov2.n/out.n + + dy := cov1.meanY - cov2.meanY + out.meanY = cov1.meanY - dy*cov2.n/out.n + out.m2y = cov1.m2y + cov2.m2y + dy*dy*cov1.n*cov2.n/out.n + + out.c = cov1.c + cov2.c + dx*dy*cov1.n*cov2.n/out.n + *cov1 = out +} + +func (cov1 *covar) A() float64 { + return cov1.Covariance() / cov1.VarianceX() +} +func (cov1 *covar) B() float64 { + return cov1.meanY - cov1.meanX*cov1.A() +} +func (cov1 *covar) Correl() float64 { + return cov1.Covariance() / cov1.StddevX() / cov1.StddevY() +} + +type meanVar struct { + n float64 + mean float64 + m2 float64 +} + +func (v1 *meanVar) AddPoint(value float64) { + // based on https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm + v1.n += 1 + delta := value - v1.mean + v1.mean += delta / v1.n + delta2 := value - v1.mean + v1.m2 += delta * delta2 +} + +func (v1 *meanVar) Variance() float64 { + return v1.m2 / (v1.n - 1) +} +func (v1 *meanVar) Mean() float64 { + return v1.mean +} +func (v1 *meanVar) Stddev() float64 { + return math.Sqrt(v1.Variance()) +} + +func (v1 *meanVar) Combine(v2 *meanVar) { + if v1.n == 0 { + *v1 = *v2 + return + } + if v2.n == 0 { + return + } + if v1.n == 1 { + cpy := *v2 + cpy.AddPoint(v1.mean) + *v1 = cpy + return + } + if v2.n == 1 { + v1.AddPoint(v2.mean) + return + } + + newCount := v1.n + v2.n + delta := v2.mean - v1.mean + meanDelta := delta * v2.n / newCount + m2 := v1.m2 + v2.m2 + delta*meanDelta*v1.n + v1.n = newCount + v1.mean += meanDelta + v1.m2 = m2 +} + +func getExtras(ex interface{}) (*string, *float64) { + if t, ok := ex.(string); ok { + return &t, nil + } + if size, ok := ex.(float64); ok { + return nil, &size + } + if exMap, ok := ex.(map[string]interface{}); ok { + t, tok := exMap["type"].(string) + size, sok := exMap["size"].(float64) + if tok && sok { + return &t, &size + } + if tok { + return &t, nil + } + if sok { + return nil, &size + } + return nil, nil + } + return nil, nil +} + +func tallyGasCharges(charges map[string]*stats, et types.ExecutionTrace) { + for i, gc := range et.GasCharges { + name := gc.Name + if name == "OnIpldGetStart" { + continue + } + tt := float64(gc.TimeTaken.Nanoseconds()) + if name == "OnIpldGet" { + prev := et.GasCharges[i-1] + if prev.Name != "OnIpldGetStart" { + log.Warn("OnIpldGet without OnIpldGetStart") + } + tt += float64(prev.TimeTaken.Nanoseconds()) + } + eType, eSize := getExtras(gc.Extra) + if eType != nil { + name += "-" + *eType + } + compGas := gc.VirtualComputeGas + if compGas == 0 { + compGas = 1 + } + s := charges[name] + if s == nil { + s = new(stats) + charges[name] = s + } + + if eSize != nil { + if s.extraCovar == nil { + s.extraCovar = &covar{} + } + s.extraCovar.AddPoint(*eSize, tt) + } + + s.timeTaken.AddPoint(tt) + + ratio := tt / float64(compGas) * GasPerNs + s.gasRatio.AddPoint(ratio) + } + for _, sub := range et.Subcalls { + tallyGasCharges(charges, sub) + } +} + +var importAnalyzeCmd = &cli.Command{ + Name: "analyze", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + fmt.Println("must pass bench file to analyze") + return nil + } + + go func() { + http.ListenAndServe("localhost:6060", nil) + }() + + fi, err := os.Open(cctx.Args().First()) + if err != nil { + return err + } + + const nWorkers = 16 + jsonIn := make(chan []byte, 2*nWorkers) + type result struct { + totalTime time.Duration + chargeStats map[string]*stats + expensiveInvocs []Invocation + } + + results := make(chan result, nWorkers) + + for i := 0; i < nWorkers; i++ { + go func() { + chargeStats := make(map[string]*stats) + var totalTime time.Duration + const invocsKeep = 32 + var expensiveInvocs = make([]Invocation, 0, 8*invocsKeep) + var leastExpensiveInvoc = time.Duration(0) + + for { + b, ok := <-jsonIn + if !ok { + results <- result{ + totalTime: totalTime, + chargeStats: chargeStats, + expensiveInvocs: expensiveInvocs, + } + return + } + + var tse TipSetExec + err := json.Unmarshal(b, &tse) + if err != nil { + log.Warnf("error unmarshaling tipset: %+v", err) + continue + } + + totalTime += tse.Duration + for _, inv := range tse.Trace { + if inv.Duration > leastExpensiveInvoc { + expensiveInvocs = append(expensiveInvocs, Invocation{ + TipSet: tse.TipSet, + Invoc: inv, + }) + } + + tallyGasCharges(chargeStats, inv.ExecutionTrace) + } + if len(expensiveInvocs) > 4*invocsKeep { + sort.Slice(expensiveInvocs, func(i, j int) bool { + return expensiveInvocs[i].Invoc.Duration > expensiveInvocs[j].Invoc.Duration + }) + leastExpensiveInvoc = expensiveInvocs[len(expensiveInvocs)-1].Invoc.Duration + n := 30 + if len(expensiveInvocs) < n { + n = len(expensiveInvocs) + } + expensiveInvocs = expensiveInvocs[:n] + } + } + }() + } + + var totalTipsets int64 + reader := bufio.NewReader(fi) + for { + b, err := reader.ReadBytes('\n') + if err != nil && err != io.EOF { + if e, ok := err.(*json.SyntaxError); ok { + log.Warnf("syntax error at byte offset %d", e.Offset) + } + return err + } + totalTipsets++ + jsonIn <- b + fmt.Fprintf(os.Stderr, "\rProcessed %d tipsets", totalTipsets) + if err == io.EOF { + break + } + } + close(jsonIn) + fmt.Fprintf(os.Stderr, "\n") + fmt.Fprintf(os.Stderr, "Collecting results\n") + + var invocs []Invocation + var totalTime time.Duration + var keys []string + var charges = make(map[string]*stats) + for i := 0; i < nWorkers; i++ { + fmt.Fprintf(os.Stderr, "\rProcessing results from worker %d/%d", i+1, nWorkers) + res := <-results + invocs = append(invocs, res.expensiveInvocs...) + for k, v := range res.chargeStats { + s := charges[k] + if s == nil { + s = new(stats) + charges[k] = s + } + s.timeTaken.Combine(&v.timeTaken) + s.gasRatio.Combine(&v.gasRatio) + + if v.extraCovar != nil { + if s.extraCovar == nil { + s.extraCovar = &covar{} + } + s.extraCovar.Combine(v.extraCovar) + } + } + totalTime += res.totalTime + } + + fmt.Fprintf(os.Stderr, "\nCollecting gas keys\n") + for k := range charges { + keys = append(keys, k) + } + + fmt.Println("Gas Price Deltas") + sort.Strings(keys) + for _, k := range keys { + s := charges[k] + fmt.Printf("%s: incr by %.4f~%.4f; tt %.4f~%.4f\n", k, s.gasRatio.Mean(), s.gasRatio.Stddev(), + s.timeTaken.Mean(), s.timeTaken.Stddev()) + if s.extraCovar != nil { + fmt.Printf("\t correll: %.2f, tt = %.2f * extra + %.2f\n", s.extraCovar.Correl(), + s.extraCovar.A(), s.extraCovar.B()) + fmt.Printf("\t covar: %.2f, extra: %.2f~%.2f, tt2: %.2f~%.2f, count %.0f\n", + s.extraCovar.Covariance(), s.extraCovar.meanX, s.extraCovar.StddevX(), + s.extraCovar.meanY, s.extraCovar.StddevY(), s.extraCovar.n) + } + } + + sort.Slice(invocs, func(i, j int) bool { + return invocs[i].Invoc.Duration > invocs[j].Invoc.Duration + }) + + fmt.Println("Total time: ", totalTime) + fmt.Println("Average time per epoch: ", totalTime/time.Duration(totalTipsets)) + if actorExec, ok := charges["OnActorExec"]; ok { + timeInActors := actorExec.timeTaken.Mean() * actorExec.timeTaken.n + fmt.Printf("Avarage time per epoch in actors: %s (%.1f%%)\n", time.Duration(timeInActors)/time.Duration(totalTipsets), timeInActors/float64(totalTime)*100) + } + if actorExecDone, ok := charges["OnActorExecDone"]; ok { + timeInActors := actorExecDone.timeTaken.Mean() * actorExecDone.timeTaken.n + fmt.Printf("Avarage time per epoch in OnActorExecDone %s (%.1f%%)\n", time.Duration(timeInActors)/time.Duration(totalTipsets), timeInActors/float64(totalTime)*100) + } + + n := 30 + if len(invocs) < n { + n = len(invocs) + } + fmt.Printf("Top %d most expensive calls:\n", n) + for i := 0; i < n; i++ { + inv := invocs[i].Invoc + fmt.Printf("%s: %s %s %d %s\n", inv.Duration, inv.Msg.From, inv.Msg.To, inv.Msg.Method, invocs[i].TipSet) + } + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/main.go new file mode 100644 index 0000000000..db31ecbb60 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/main.go @@ -0,0 +1,747 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "math/rand" + "os" + "path/filepath" + "time" + + "github.com/docker/go-units" + logging "github.com/ipfs/go-log/v2" + "github.com/minio/blake2b-simd" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + paramfetch "github.com/filecoin-project/go-paramfetch" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/sector-storage/ffiwrapper/basicfs" + "github.com/filecoin-project/sector-storage/stores" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-storage/storage" + + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/genesis" +) + +var log = logging.Logger("lotus-bench") + +type BenchResults struct { + SectorSize abi.SectorSize + + SealingResults []SealingResult + + PostGenerateCandidates time.Duration + PostWinningProofCold time.Duration + PostWinningProofHot time.Duration + VerifyWinningPostCold time.Duration + VerifyWinningPostHot time.Duration + + PostWindowProofCold time.Duration + PostWindowProofHot time.Duration + VerifyWindowPostCold time.Duration + VerifyWindowPostHot time.Duration +} + +type SealingResult struct { + AddPiece time.Duration + PreCommit1 time.Duration + PreCommit2 time.Duration + Commit1 time.Duration + Commit2 time.Duration + Verify time.Duration + Unseal time.Duration +} + +type Commit2In struct { + SectorNum int64 + Phase1Out []byte + SectorSize uint64 +} + +func main() { + logging.SetLogLevel("*", "INFO") + + log.Info("Starting lotus-bench") + + miner.SupportedProofTypes[abi.RegisteredSealProof_StackedDrg2KiBV1] = struct{}{} + + app := &cli.App{ + Name: "lotus-bench", + Usage: "Benchmark performance of lotus on your hardware", + Version: build.UserVersion(), + Commands: []*cli.Command{ + proveCmd, + sealBenchCmd, + importBenchCmd, + }, + } + + if err := app.Run(os.Args); err != nil { + log.Warnf("%+v", err) + return + } +} + +var sealBenchCmd = &cli.Command{ + Name: "sealing", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "storage-dir", + Value: "~/.lotus-bench", + Usage: "Path to the storage directory that will store sectors long term", + }, + &cli.StringFlag{ + Name: "sector-size", + Value: "512MiB", + Usage: "size of the sectors in bytes, i.e. 32GiB", + }, + &cli.BoolFlag{ + Name: "no-gpu", + Usage: "disable gpu usage for the benchmark run", + }, + &cli.StringFlag{ + Name: "miner-addr", + Usage: "pass miner address (only necessary if using existing sectorbuilder)", + Value: "t01000", + }, + &cli.StringFlag{ + Name: "benchmark-existing-sectorbuilder", + Usage: "pass a directory to run post timings on an existing sectorbuilder", + }, + &cli.BoolFlag{ + Name: "json-out", + Usage: "output results in json format", + }, + &cli.BoolFlag{ + Name: "skip-commit2", + Usage: "skip the commit2 (snark) portion of the benchmark", + }, + &cli.BoolFlag{ + Name: "skip-unseal", + Usage: "skip the unseal portion of the benchmark", + }, + &cli.StringFlag{ + Name: "save-commit2-input", + Usage: "Save commit2 input to a file", + }, + &cli.IntFlag{ + Name: "num-sectors", + Value: 1, + }, + &cli.IntFlag{ + Name: "parallel", + Value: 1, + }, + }, + Action: func(c *cli.Context) error { + if c.Bool("no-gpu") { + err := os.Setenv("BELLMAN_NO_GPU", "1") + if err != nil { + return xerrors.Errorf("setting no-gpu flag: %w", err) + } + } + + robench := c.String("benchmark-existing-sectorbuilder") + + var sbdir string + + if robench == "" { + sdir, err := homedir.Expand(c.String("storage-dir")) + if err != nil { + return err + } + + err = os.MkdirAll(sdir, 0775) //nolint:gosec + if err != nil { + return xerrors.Errorf("creating sectorbuilder dir: %w", err) + } + + tsdir, err := ioutil.TempDir(sdir, "bench") + if err != nil { + return err + } + defer func() { + if err := os.RemoveAll(tsdir); err != nil { + log.Warn("remove all: ", err) + } + }() + + // TODO: pretty sure this isnt even needed? + if err := os.MkdirAll(tsdir, 0775); err != nil { + return err + } + + sbdir = tsdir + } else { + exp, err := homedir.Expand(robench) + if err != nil { + return err + } + sbdir = exp + } + + // miner address + maddr, err := address.NewFromString(c.String("miner-addr")) + if err != nil { + return err + } + amid, err := address.IDFromAddress(maddr) + if err != nil { + return err + } + mid := abi.ActorID(amid) + + // sector size + sectorSizeInt, err := units.RAMInBytes(c.String("sector-size")) + if err != nil { + return err + } + sectorSize := abi.SectorSize(sectorSizeInt) + + spt, err := ffiwrapper.SealProofTypeFromSectorSize(sectorSize) + if err != nil { + return err + } + + cfg := &ffiwrapper.Config{ + SealProofType: spt, + } + + // Only fetch parameters if actually needed + if !c.Bool("skip-commit2") { + if err := paramfetch.GetParams(lcli.ReqContext(c), build.ParametersJSON(), uint64(sectorSize)); err != nil { + return xerrors.Errorf("getting params: %w", err) + } + } + + sbfs := &basicfs.Provider{ + Root: sbdir, + } + + sb, err := ffiwrapper.New(sbfs, cfg) + if err != nil { + return err + } + + var sealTimings []SealingResult + var sealedSectors []abi.SectorInfo + + if robench == "" { + var err error + parCfg := ParCfg{ + PreCommit1: c.Int("parallel"), + PreCommit2: 1, + Commit: 1, + } + sealTimings, sealedSectors, err = runSeals(sb, sbfs, c.Int("num-sectors"), parCfg, mid, sectorSize, []byte(c.String("ticket-preimage")), c.String("save-commit2-input"), c.Bool("skip-commit2"), c.Bool("skip-unseal")) + if err != nil { + return xerrors.Errorf("failed to run seals: %w", err) + } + } + + beforePost := time.Now() + + var challenge [32]byte + rand.Read(challenge[:]) + + if robench != "" { + // TODO: implement sbfs.List() and use that for all cases (preexisting sectorbuilder or not) + + // TODO: this assumes we only ever benchmark a preseal + // sectorbuilder directory... we need a better way to handle + // this in other cases + + fdata, err := ioutil.ReadFile(filepath.Join(sbdir, "pre-seal-"+maddr.String()+".json")) + if err != nil { + return err + } + + var genmm map[string]genesis.Miner + if err := json.Unmarshal(fdata, &genmm); err != nil { + return err + } + + genm, ok := genmm[maddr.String()] + if !ok { + return xerrors.Errorf("preseal file didnt have expected miner in it") + } + + for _, s := range genm.Sectors { + sealedSectors = append(sealedSectors, abi.SectorInfo{ + SealedCID: s.CommR, + SectorNumber: s.SectorID, + SealProof: s.ProofType, + }) + } + } + + bo := BenchResults{ + SectorSize: sectorSize, + SealingResults: sealTimings, + } + + if !c.Bool("skip-commit2") { + log.Info("generating winning post candidates") + wipt, err := spt.RegisteredWinningPoStProof() + if err != nil { + return err + } + + fcandidates, err := ffiwrapper.ProofVerifier.GenerateWinningPoStSectorChallenge(context.TODO(), wipt, mid, challenge[:], uint64(len(sealedSectors))) + if err != nil { + return err + } + + candidates := make([]abi.SectorInfo, len(fcandidates)) + for i, fcandidate := range fcandidates { + candidates[i] = sealedSectors[fcandidate] + } + + gencandidates := time.Now() + + log.Info("computing winning post snark (cold)") + proof1, err := sb.GenerateWinningPoSt(context.TODO(), mid, candidates, challenge[:]) + if err != nil { + return err + } + + winningpost1 := time.Now() + + log.Info("computing winning post snark (hot)") + proof2, err := sb.GenerateWinningPoSt(context.TODO(), mid, candidates, challenge[:]) + if err != nil { + return err + } + + winnningpost2 := time.Now() + + pvi1 := abi.WinningPoStVerifyInfo{ + Randomness: abi.PoStRandomness(challenge[:]), + Proofs: proof1, + ChallengedSectors: candidates, + Prover: mid, + } + ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(context.TODO(), pvi1) + if err != nil { + return err + } + if !ok { + log.Error("post verification failed") + } + + verifyWinningPost1 := time.Now() + + pvi2 := abi.WinningPoStVerifyInfo{ + Randomness: abi.PoStRandomness(challenge[:]), + Proofs: proof2, + ChallengedSectors: candidates, + Prover: mid, + } + + ok, err = ffiwrapper.ProofVerifier.VerifyWinningPoSt(context.TODO(), pvi2) + if err != nil { + return err + } + if !ok { + log.Error("post verification failed") + } + verifyWinningPost2 := time.Now() + + log.Info("computing window post snark (cold)") + wproof1, _, err := sb.GenerateWindowPoSt(context.TODO(), mid, sealedSectors, challenge[:]) + if err != nil { + return err + } + + windowpost1 := time.Now() + + log.Info("computing window post snark (hot)") + wproof2, _, err := sb.GenerateWindowPoSt(context.TODO(), mid, sealedSectors, challenge[:]) + if err != nil { + return err + } + + windowpost2 := time.Now() + + wpvi1 := abi.WindowPoStVerifyInfo{ + Randomness: challenge[:], + Proofs: wproof1, + ChallengedSectors: sealedSectors, + Prover: mid, + } + ok, err = ffiwrapper.ProofVerifier.VerifyWindowPoSt(context.TODO(), wpvi1) + if err != nil { + return err + } + if !ok { + log.Error("post verification failed") + } + + verifyWindowpost1 := time.Now() + + wpvi2 := abi.WindowPoStVerifyInfo{ + Randomness: challenge[:], + Proofs: wproof2, + ChallengedSectors: sealedSectors, + Prover: mid, + } + ok, err = ffiwrapper.ProofVerifier.VerifyWindowPoSt(context.TODO(), wpvi2) + if err != nil { + return err + } + if !ok { + log.Error("post verification failed") + } + + verifyWindowpost2 := time.Now() + + bo.PostGenerateCandidates = gencandidates.Sub(beforePost) + bo.PostWinningProofCold = winningpost1.Sub(gencandidates) + bo.PostWinningProofHot = winnningpost2.Sub(winningpost1) + bo.VerifyWinningPostCold = verifyWinningPost1.Sub(winnningpost2) + bo.VerifyWinningPostHot = verifyWinningPost2.Sub(verifyWinningPost1) + + bo.PostWindowProofCold = windowpost1.Sub(verifyWinningPost2) + bo.PostWindowProofHot = windowpost2.Sub(windowpost1) + bo.VerifyWindowPostCold = verifyWindowpost1.Sub(windowpost2) + bo.VerifyWindowPostHot = verifyWindowpost2.Sub(verifyWindowpost1) + } + + if c.Bool("json-out") { + data, err := json.MarshalIndent(bo, "", " ") + if err != nil { + return err + } + + fmt.Println(string(data)) + } else { + fmt.Printf("----\nresults (v27) (%d)\n", sectorSize) + if robench == "" { + fmt.Printf("seal: addPiece: %s (%s)\n", bo.SealingResults[0].AddPiece, bps(bo.SectorSize, bo.SealingResults[0].AddPiece)) // TODO: average across multiple sealings + fmt.Printf("seal: preCommit phase 1: %s (%s)\n", bo.SealingResults[0].PreCommit1, bps(bo.SectorSize, bo.SealingResults[0].PreCommit1)) + fmt.Printf("seal: preCommit phase 2: %s (%s)\n", bo.SealingResults[0].PreCommit2, bps(bo.SectorSize, bo.SealingResults[0].PreCommit2)) + fmt.Printf("seal: commit phase 1: %s (%s)\n", bo.SealingResults[0].Commit1, bps(bo.SectorSize, bo.SealingResults[0].Commit1)) + fmt.Printf("seal: commit phase 2: %s (%s)\n", bo.SealingResults[0].Commit2, bps(bo.SectorSize, bo.SealingResults[0].Commit2)) + fmt.Printf("seal: verify: %s\n", bo.SealingResults[0].Verify) + if !c.Bool("skip-unseal") { + fmt.Printf("unseal: %s (%s)\n", bo.SealingResults[0].Unseal, bps(bo.SectorSize, bo.SealingResults[0].Unseal)) + } + fmt.Println("") + } + if !c.Bool("skip-commit2") { + fmt.Printf("generate candidates: %s (%s)\n", bo.PostGenerateCandidates, bps(bo.SectorSize*abi.SectorSize(len(bo.SealingResults)), bo.PostGenerateCandidates)) + fmt.Printf("compute winning post proof (cold): %s\n", bo.PostWinningProofCold) + fmt.Printf("compute winning post proof (hot): %s\n", bo.PostWinningProofHot) + fmt.Printf("verify winning post proof (cold): %s\n", bo.VerifyWinningPostCold) + fmt.Printf("verify winning post proof (hot): %s\n\n", bo.VerifyWinningPostHot) + + fmt.Printf("compute window post proof (cold): %s\n", bo.PostWindowProofCold) + fmt.Printf("compute window post proof (hot): %s\n", bo.PostWindowProofHot) + fmt.Printf("verify window post proof (cold): %s\n", bo.VerifyWindowPostCold) + fmt.Printf("verify window post proof (hot): %s\n", bo.VerifyWindowPostHot) + } + } + return nil + }, +} + +type ParCfg struct { + PreCommit1 int + PreCommit2 int + Commit int +} + +func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []abi.SectorInfo, error) { + var pieces []abi.PieceInfo + sealTimings := make([]SealingResult, numSectors) + sealedSectors := make([]abi.SectorInfo, numSectors) + + preCommit2Sema := make(chan struct{}, par.PreCommit2) + commitSema := make(chan struct{}, par.Commit) + + if numSectors%par.PreCommit1 != 0 { + return nil, nil, fmt.Errorf("parallelism factor must cleanly divide numSectors") + } + + for i := abi.SectorNumber(1); i <= abi.SectorNumber(numSectors); i++ { + sid := abi.SectorID{ + Miner: mid, + Number: i, + } + + start := time.Now() + log.Infof("[%d] Writing piece into sector...", i) + + r := rand.New(rand.NewSource(100 + int64(i))) + + pi, err := sb.AddPiece(context.TODO(), sid, nil, abi.PaddedPieceSize(sectorSize).Unpadded(), r) + if err != nil { + return nil, nil, err + } + + pieces = append(pieces, pi) + + sealTimings[i-1].AddPiece = time.Since(start) + } + + sectorsPerWorker := numSectors / par.PreCommit1 + + errs := make(chan error, par.PreCommit1) + for wid := 0; wid < par.PreCommit1; wid++ { + go func(worker int) { + sealerr := func() error { + start := 1 + (worker * sectorsPerWorker) + end := start + sectorsPerWorker + for i := abi.SectorNumber(start); i < abi.SectorNumber(end); i++ { + ix := int(i - 1) + sid := abi.SectorID{ + Miner: mid, + Number: i, + } + + start := time.Now() + + trand := blake2b.Sum256(ticketPreimage) + ticket := abi.SealRandomness(trand[:]) + + log.Infof("[%d] Running replication(1)...", i) + pieces := []abi.PieceInfo{pieces[ix]} + pc1o, err := sb.SealPreCommit1(context.TODO(), sid, ticket, pieces) + if err != nil { + return xerrors.Errorf("commit: %w", err) + } + + precommit1 := time.Now() + + preCommit2Sema <- struct{}{} + pc2Start := time.Now() + log.Infof("[%d] Running replication(2)...", i) + cids, err := sb.SealPreCommit2(context.TODO(), sid, pc1o) + if err != nil { + return xerrors.Errorf("commit: %w", err) + } + + precommit2 := time.Now() + <-preCommit2Sema + + sealedSectors[ix] = abi.SectorInfo{ + SealProof: sb.SealProofType(), + SectorNumber: i, + SealedCID: cids.Sealed, + } + + seed := lapi.SealSeed{ + Epoch: 101, + Value: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 255}, + } + + commitSema <- struct{}{} + commitStart := time.Now() + log.Infof("[%d] Generating PoRep for sector (1)", i) + c1o, err := sb.SealCommit1(context.TODO(), sid, ticket, seed.Value, pieces, cids) + if err != nil { + return err + } + + sealcommit1 := time.Now() + + log.Infof("[%d] Generating PoRep for sector (2)", i) + + if saveC2inp != "" { + c2in := Commit2In{ + SectorNum: int64(i), + Phase1Out: c1o, + SectorSize: uint64(sectorSize), + } + + b, err := json.Marshal(&c2in) + if err != nil { + return err + } + + if err := ioutil.WriteFile(saveC2inp, b, 0664); err != nil { + log.Warnf("%+v", err) + } + } + + var proof storage.Proof + if !skipc2 { + proof, err = sb.SealCommit2(context.TODO(), sid, c1o) + if err != nil { + return err + } + } + + sealcommit2 := time.Now() + <-commitSema + + if !skipc2 { + svi := abi.SealVerifyInfo{ + SectorID: abi.SectorID{Miner: mid, Number: i}, + SealedCID: cids.Sealed, + SealProof: sb.SealProofType(), + Proof: proof, + DealIDs: nil, + Randomness: ticket, + InteractiveRandomness: seed.Value, + UnsealedCID: cids.Unsealed, + } + + ok, err := ffiwrapper.ProofVerifier.VerifySeal(svi) + if err != nil { + return err + } + if !ok { + return xerrors.Errorf("porep proof for sector %d was invalid", i) + } + } + + verifySeal := time.Now() + + if !skipunseal { + log.Infof("[%d] Unsealing sector", i) + { + p, done, err := sbfs.AcquireSector(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, stores.FTUnsealed, stores.FTNone, true) + if err != nil { + return xerrors.Errorf("acquire unsealed sector for removing: %w", err) + } + done() + + if err := os.Remove(p.Unsealed); err != nil { + return xerrors.Errorf("removing unsealed sector: %w", err) + } + } + + err := sb.UnsealPiece(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, 0, abi.PaddedPieceSize(sectorSize).Unpadded(), ticket, cids.Unsealed) + if err != nil { + return err + } + } + unseal := time.Now() + + sealTimings[ix].PreCommit1 = precommit1.Sub(start) + sealTimings[ix].PreCommit2 = precommit2.Sub(pc2Start) + sealTimings[ix].Commit1 = sealcommit1.Sub(commitStart) + sealTimings[ix].Commit2 = sealcommit2.Sub(sealcommit1) + sealTimings[ix].Verify = verifySeal.Sub(sealcommit2) + sealTimings[ix].Unseal = unseal.Sub(verifySeal) + } + return nil + }() + if sealerr != nil { + errs <- sealerr + return + } + errs <- nil + }(wid) + } + + for i := 0; i < par.PreCommit1; i++ { + err := <-errs + if err != nil { + return nil, nil, err + } + } + + return sealTimings, sealedSectors, nil +} + +var proveCmd = &cli.Command{ + Name: "prove", + Usage: "Benchmark a proof computation", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "no-gpu", + Usage: "disable gpu usage for the benchmark run", + }, + &cli.StringFlag{ + Name: "miner-addr", + Usage: "pass miner address (only necessary if using existing sectorbuilder)", + Value: "t01000", + }, + }, + Action: func(c *cli.Context) error { + if c.Bool("no-gpu") { + err := os.Setenv("BELLMAN_NO_GPU", "1") + if err != nil { + return xerrors.Errorf("setting no-gpu flag: %w", err) + } + } + + if !c.Args().Present() { + return xerrors.Errorf("Usage: lotus-bench prove [input.json]") + } + + inb, err := ioutil.ReadFile(c.Args().First()) + if err != nil { + return xerrors.Errorf("reading input file: %w", err) + } + + var c2in Commit2In + if err := json.Unmarshal(inb, &c2in); err != nil { + return xerrors.Errorf("unmarshalling input file: %w", err) + } + + if err := paramfetch.GetParams(lcli.ReqContext(c), build.ParametersJSON(), c2in.SectorSize); err != nil { + return xerrors.Errorf("getting params: %w", err) + } + + maddr, err := address.NewFromString(c.String("miner-addr")) + if err != nil { + return err + } + mid, err := address.IDFromAddress(maddr) + if err != nil { + return err + } + + spt, err := ffiwrapper.SealProofTypeFromSectorSize(abi.SectorSize(c2in.SectorSize)) + if err != nil { + return err + } + + cfg := &ffiwrapper.Config{ + SealProofType: spt, + } + + sb, err := ffiwrapper.New(nil, cfg) + if err != nil { + return err + } + + start := time.Now() + + proof, err := sb.SealCommit2(context.TODO(), abi.SectorID{Miner: abi.ActorID(mid), Number: abi.SectorNumber(c2in.SectorNum)}, c2in.Phase1Out) + if err != nil { + return err + } + + sealCommit2 := time.Now() + + fmt.Printf("proof: %x\n", proof) + + fmt.Printf("----\nresults (v27) (%d)\n", c2in.SectorSize) + dur := sealCommit2.Sub(start) + + fmt.Printf("seal: commit phase 2: %s (%s)\n", dur, bps(abi.SectorSize(c2in.SectorSize), dur)) + return nil + }, +} + +func bps(data abi.SectorSize, d time.Duration) string { + bdata := new(big.Int).SetUint64(uint64(data)) + bdata = bdata.Mul(bdata, big.NewInt(time.Second.Nanoseconds())) + bps := bdata.Div(bdata, big.NewInt(d.Nanoseconds())) + return types.SizeStr(types.BigInt{bps}) + "/s" +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/stats_test.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/stats_test.go new file mode 100644 index 0000000000..16caf3f7e8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-bench/stats_test.go @@ -0,0 +1,47 @@ +package main + +import ( + "math/rand" + "testing" +) + +func TestMeanVar(t *testing.T) { + N := 16 + ss := make([]*meanVar, N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < N; i++ { + ss[i] = &meanVar{} + maxJ := rng.Intn(1000) + for j := 0; j < maxJ; j++ { + ss[i].AddPoint(rng.NormFloat64()*5 + 500) + } + t.Logf("mean: %f, stddev: %f, count %f", ss[i].mean, ss[i].Stddev(), ss[i].n) + } + out := &meanVar{} + for i := 0; i < N; i++ { + out.Combine(ss[i]) + t.Logf("combine: mean: %f, stddev: %f", out.mean, out.Stddev()) + } +} + +func TestCovar(t *testing.T) { + N := 16 + ss := make([]*covar, N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < N; i++ { + ss[i] = &covar{} + maxJ := rng.Intn(1000) + 500 + for j := 0; j < maxJ; j++ { + x := rng.NormFloat64()*5 + 500 + ss[i].AddPoint(x, x*2-1000) + } + t.Logf("corell: %f, y = %f*x+%f @%.0f", ss[i].Correl(), ss[i].A(), ss[i].B(), ss[i].n) + t.Logf("\txVar: %f yVar: %f covar: %f", ss[i].StddevX(), ss[i].StddevY(), ss[i].Covariance()) + } + out := &covar{} + for i := 0; i < N; i++ { + out.Combine(ss[i]) + t.Logf("combine: corell: %f, y = %f*x+%f", out.Correl(), out.A(), out.B()) + t.Logf("\txVar: %f yVar: %f covar: %f", out.StddevX(), out.StddevY(), out.Covariance()) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/blockssub.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/blockssub.go new file mode 100644 index 0000000000..c569f18856 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/blockssub.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" + + aapi "github.com/filecoin-project/lotus/api" +) + +func subBlocks(ctx context.Context, api aapi.FullNode, st *storage) { + sub, err := api.SyncIncomingBlocks(ctx) + if err != nil { + log.Error(err) + return + } + + for bh := range sub { + err := st.storeHeaders(map[cid.Cid]*types.BlockHeader{ + bh.Cid(): bh, + }, false) + if err != nil { + log.Errorf("%+v", err) + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/dot.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/dot.go new file mode 100644 index 0000000000..87dab62ad0 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/dot.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + "hash/crc32" + "strconv" + + "github.com/ipfs/go-cid" + "github.com/urfave/cli/v2" +) + +var dotCmd = &cli.Command{ + Name: "dot", + Usage: "generate dot graphs", + ArgsUsage: " ", + Action: func(cctx *cli.Context) error { + st, err := openStorage(cctx.String("db")) + if err != nil { + return err + } + + minH, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32) + if err != nil { + return err + } + tosee, err := strconv.ParseInt(cctx.Args().Get(1), 10, 32) + if err != nil { + return err + } + maxH := minH + tosee + + res, err := st.db.Query(`select block, parent, b.miner, b.height, p.height from block_parents + inner join blocks b on block_parents.block = b.cid + inner join blocks p on block_parents.parent = p.cid +where b.height > $1 and b.height < $2`, minH, maxH) + + if err != nil { + return err + } + + fmt.Println("digraph D {") + + hl := st.hasList() + + for res.Next() { + var block, parent, miner string + var height, ph uint64 + if err := res.Scan(&block, &parent, &miner, &height, &ph); err != nil { + return err + } + + bc, err := cid.Parse(block) + if err != nil { + return err + } + + _, has := hl[bc] + + col := crc32.Checksum([]byte(miner), crc32.MakeTable(crc32.Castagnoli))&0xc0c0c0c0 + 0x30303030 + + hasstr := "" + if !has { + //col = 0xffffffff + hasstr = " UNSYNCED" + } + + nulls := height - ph - 1 + for i := uint64(0); i < nulls; i++ { + name := block + "NP" + fmt.Sprint(i) + + fmt.Printf("%s [label = \"NULL:%d\", fillcolor = \"#ffddff\", style=filled, forcelabels=true]\n%s -> %s\n", + name, height-nulls+i, name, parent) + + parent = name + } + + fmt.Printf("%s [label = \"%s:%d%s\", fillcolor = \"#%06x\", style=filled, forcelabels=true]\n%s -> %s\n", block, miner, height, hasstr, col, block, parent) + } + if res.Err() != nil { + return res.Err() + } + + fmt.Println("}") + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/main.go new file mode 100644 index 0000000000..b5ceb73482 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/main.go @@ -0,0 +1,112 @@ +package main + +import ( + "fmt" + "net/http" + _ "net/http/pprof" + "os" + + logging "github.com/ipfs/go-log/v2" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/build" + lcli "github.com/filecoin-project/lotus/cli" +) + +var log = logging.Logger("chainwatch") + +func main() { + _ = logging.SetLogLevel("*", "INFO") + if err := logging.SetLogLevel("rpc", "error"); err != nil { + panic(err) + } + + log.Info("Starting chainwatch") + + local := []*cli.Command{ + runCmd, + dotCmd, + } + + app := &cli.App{ + Name: "lotus-chainwatch", + Usage: "Devnet token distribution utility", + Version: build.UserVersion(), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + &cli.StringFlag{ + Name: "db", + EnvVars: []string{"LOTUS_DB"}, + Value: "", + }, + }, + + Commands: local, + } + + if err := app.Run(os.Args); err != nil { + log.Warnf("%+v", err) + return + } +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "Start lotus chainwatch", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "front", + Value: "127.0.0.1:8418", + }, + &cli.IntFlag{ + Name: "max-batch", + Value: 1000, + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + v, err := api.Version(ctx) + if err != nil { + return err + } + + log.Infof("Remote version: %s", v.Version) + + maxBatch := cctx.Int("max-batch") + + st, err := openStorage(cctx.String("db")) + if err != nil { + return err + } + defer st.close() //nolint:errcheck + + runSyncer(ctx, api, st, maxBatch) + + h, err := newHandler(api, st) + if err != nil { + return xerrors.Errorf("handler setup: %w", err) + } + + http.Handle("/", h) + + fmt.Printf("Open http://%s\n", cctx.String("front")) + + go func() { + <-ctx.Done() + os.Exit(0) + }() + + return http.ListenAndServe(cctx.String("front"), nil) + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/mpool.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/mpool.go new file mode 100644 index 0000000000..74ffa87712 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/mpool.go @@ -0,0 +1,60 @@ +package main + +import ( + "context" + "time" + + "github.com/ipfs/go-cid" + + aapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +func subMpool(ctx context.Context, api aapi.FullNode, st *storage) { + sub, err := api.MpoolSub(ctx) + if err != nil { + return + } + + for { + var updates []aapi.MpoolUpdate + + select { + case update := <-sub: + updates = append(updates, update) + case <-ctx.Done(): + return + } + + loop: + for { + time.Sleep(10 * time.Millisecond) + select { + case update := <-sub: + updates = append(updates, update) + default: + break loop + } + } + + msgs := map[cid.Cid]*types.Message{} + for _, v := range updates { + if v.Type != aapi.MpoolAdd { + continue + } + + msgs[v.Message.Message.Cid()] = &v.Message.Message + } + + log.Debugf("Processing %d mpool updates", len(msgs)) + + err := st.storeMessages(msgs) + if err != nil { + log.Error(err) + } + + if err := st.storeMpoolInclusions(updates); err != nil { + log.Error(err) + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/block.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/block.html new file mode 100644 index 0000000000..9d247b88b6 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/block.html @@ -0,0 +1,61 @@ + + + + Lotus ChainWatch + + + +{{$cid := param "cid"}} + +
    +
    +
    + Lotus ChainWatch - Wallets +
    +
    +
    +
    +
    Miner: {{index (strings "blocks" "miner" "cid=$1" $cid) 0}}
    +
    Parents:
    +
    + {{range strings "block_parents" "parent" "block=$1" $cid}} + {{$parent := .}} + {{. | substr 54 62}} + {{end}} +
    +
    Messages:
    + + {{range strings "block_messages" "message" "block=$1" $cid}} + {{$msg := .}} + + + + + + + {{$rec := qstrs `select r.exit, r.gas_used from messages + inner join block_messages bm on messages.cid = bm.message + inner join blocks b on bm.block = b.cid + inner join block_parents bp on b.cid = bp.parent + inner join blocks chd on bp.block = chd.cid + inner join receipts r on messages.cid = r.msg and chd.parentStateRoot = r.state + where messages.cid=$1 and b.cid=$2` 2 $msg $cid}} + + + + {{end}} +
    {{$msg | substr 54 62}} + {{$from := qstr "select \"from\" from messages where cid=$1" $msg}} + {{$nonce := qstr "select nonce from messages where cid=$1" $msg}} + {{$from}} (N:{{$nonce}}) + -> + {{$to := qstr "select \"to\" from messages where cid=$1" $msg}} + {{$to}} + + Method:{{qstr "select method from messages where cid=$1" $msg}} + exit:{{index $rec 0}}gasUsed:{{index $rec 1}}
    +
    +
    +
    + + \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/blocks.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/blocks.html new file mode 100644 index 0000000000..296d0d4609 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/blocks.html @@ -0,0 +1,43 @@ + + + + Lotus ChainWatch + + + +{{$start := param "start" | parseInt}} + +
    +
    +
    + Lotus ChainWatch - Wallets +
    +
    +
    +
    + + {{range pageDown $start 50}} + + + + + + {{end}} +
    + {{$h := .}} + {{$h}}; + + {{qstr `select count(distinct block_messages.message) from block_messages + inner join blocks b on block_messages.block = b.cid + where b.height = $1` $h}} Msgs + + {{range strings "blocks" "cid" "height = $1" $h}} + {{. | substr 54 62}} + {{end}} +
    + Next 50 +
    +
    +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/index.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/index.html new file mode 100644 index 0000000000..315ba57051 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/index.html @@ -0,0 +1,37 @@ + + + + Lotus ChainWatch + + + +
    +
    +
    + Lotus ChainWatch +
    +
    +
    +
    + {{countCol "actors" "id"}} Actors; + {{countCol "miner_heads" "addr"}} Miners; + {{netPower "slashed_at = 0" | sizeStr}} Power + ({{netPower "" | sizeStr}} Total; + {{netPower "slashed_at > 0" | sizeStr}} Slashed) +
    +
    + {{count "messages"}} Messages; {{count "actors"}} state changes +
    +
    + {{count "id_address_map" "id != address"}} Keys; + E% FIL in wallets; F% FIL in miners; M% in market; %G Other actors; %H FIL it treasury +
    +
    + {{$maxH := queryNum "select max(height) from blocks inner join blocks_synced bs on blocks.cid = bs.cid"}} + + {{count "blocks"}} Blocks; Current Height: {{$maxH}}; +
    +
    +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/key.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/key.html new file mode 100644 index 0000000000..3c16e1f27b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/key.html @@ -0,0 +1,40 @@ + + + + Lotus ChainWatch + + + +{{$wallet := param "w"}} + +
    +
    +
    + Lotus ChainWatch - Wallet {{$wallet}} +
    +
    +
    +
    + Balance: {{queryNum "select balance from actors inner join id_address_map m on m.address = $1 where actors.id = m.id order by nonce desc limit 1" $wallet }} +
    +
    + Messages: + + + {{ range messages "\"from\" = $1 or \"to\" = $1" $wallet}} + + {{ if eq .From.String $wallet }} + + {{else}} + + {{end}} + + + + {{end}} +
    DirPeerNonceValueBlockMpool Wait
    To{{.To.String}}From{{.From.String}}{{.Nonce}}{{.Value}}
    +
    +
    +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/keys.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/keys.html new file mode 100644 index 0000000000..1ad72fafef --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/keys.html @@ -0,0 +1,28 @@ + + + + Lotus ChainWatch + + + +
    +
    +
    + Lotus ChainWatch - Wallets +
    +
    +
    +
    + {{range strings "id_address_map" "address" "address != id"}} + {{$addr := .}} +
    + {{$addr}} + {{qstr "select count(distinct cid) from messages where \"from\"=$1" $addr}} outmsgs; + {{qstr "select count(distinct cid) from messages where \"to\"=$1" $addr}} inmsgs +
    + {{end}} +
    +
    +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/main.css b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/main.css new file mode 100644 index 0000000000..cc9da2f35c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/site/main.css @@ -0,0 +1,66 @@ +body { + font-family: 'monospace'; + background: #1f1f1f; + color: #f0f0f0; + padding: 0; + margin: 0; +} + +b { + color: #aff; +} + +.Index { + width: 100vw; + height: 100vh; + background: #1a1a1a; + color: #f0f0f0; + font-family: monospace; + overflow: auto; + + display: grid; + grid-template-columns: auto 80vw auto; + grid-template-rows: 3em auto auto auto; + grid-template-areas: + "header header header header" + ". . . ." + ". main main ." + ". main main ." + ". main main ." + ". main main ." + ". main main ." + ". . . ."; +} + +.Index-header { + background: #2a2a2a; + grid-area: header; +} + +.Index-Index-header > div { + padding-left: 0.7em; + padding-top: 0.7em; +} + +.Index-nodes { + grid-area: main; + background: #2a2a2a; +} + +.Index-node { + margin: 5px; + padding: 15px; + background: #1f1f1f; +} + +a:link { + color: #50f020; +} + +a:visited { + color: #50f020; +} + +a:hover { + color: #30a00a; +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/storage.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/storage.go new file mode 100644 index 0000000000..e68c586b55 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/storage.go @@ -0,0 +1,1278 @@ +package main + +import ( + "context" + "database/sql" + "fmt" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/libp2p/go-libp2p-core/peer" + "sync" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + miner_spec "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/ipfs/go-cid" + _ "github.com/lib/pq" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +type storage struct { + db *sql.DB + + headerLk sync.Mutex + + // stateful miner data + minerSectors map[cid.Cid]struct{} +} + +func openStorage(dbSource string) (*storage, error) { + db, err := sql.Open("postgres", dbSource) + if err != nil { + return nil, err + } + + db.SetMaxOpenConns(1350) + + ms := make(map[cid.Cid]struct{}) + ms[cid.Undef] = struct{}{} + + st := &storage{db: db, minerSectors: ms} + + return st, st.setup() +} + +func (st *storage) setup() error { + tx, err := st.db.Begin() + if err != nil { + return err + } + _, err = tx.Exec(` +create table if not exists block_cids +( + cid text not null + constraint block_cids_pk + primary key +); + +create unique index if not exists block_cids_cid_uindex + on block_cids (cid); + +create table if not exists blocks_synced +( + cid text not null + constraint blocks_synced_pk + primary key + constraint blocks_block_cids_cid_fk + references block_cids (cid), + add_ts int not null +); + +create unique index if not exists blocks_synced_cid_uindex + on blocks_synced (cid); + +create table if not exists block_parents +( + block text not null + constraint blocks_block_cids_cid_fk + references block_cids (cid), + parent text not null +); + +create unique index if not exists block_parents_block_parent_uindex + on block_parents (block, parent); + +create table if not exists drand_entries +( + round bigint not null + constraint drand_entries_pk + primary key, + data bytea not null +); +create unique index if not exists drand_entries_round_uindex + on drand_entries (round); + +create table if not exists block_drand_entries +( + round bigint not null + constraint block_drand_entries_drand_entries_round_fk + references drand_entries (round), + block text not null + constraint blocks_block_cids_cid_fk + references block_cids (cid) +); +create unique index if not exists block_drand_entries_round_uindex + on block_drand_entries (round, block); + +create table if not exists blocks +( + cid text not null + constraint blocks_pk + primary key + constraint blocks_block_cids_cid_fk + references block_cids (cid), + parentWeight numeric not null, + parentStateRoot text not null, + height bigint not null, + miner text not null, + timestamp bigint not null, + ticket bytea not null, + eprof bytea, + forksig bigint not null +); + +create unique index if not exists block_cid_uindex + on blocks (cid); + +create materialized view if not exists state_heights + as select distinct height, parentstateroot from blocks; + +create index if not exists state_heights_index + on state_heights (height); + +create index if not exists state_heights_height_index + on state_heights (parentstateroot); + +create table if not exists id_address_map +( + id text not null, + address text not null, + constraint id_address_map_pk + primary key (id, address) +); + +create unique index if not exists id_address_map_id_uindex + on id_address_map (id); + +create unique index if not exists id_address_map_address_uindex + on id_address_map (address); + +create table if not exists actors + ( + id text not null + constraint id_address_map_actors_id_fk + references id_address_map (id), + code text not null, + head text not null, + nonce int not null, + balance text not null, + stateroot text + ); + +create index if not exists actors_id_index + on actors (id); + +create index if not exists id_address_map_address_index + on id_address_map (address); + +create index if not exists id_address_map_id_index + on id_address_map (id); + +create or replace function actor_tips(epoch bigint) + returns table (id text, + code text, + head text, + nonce int, + balance text, + stateroot text, + height bigint, + parentstateroot text) as +$body$ + select distinct on (id) * from actors + inner join state_heights sh on sh.parentstateroot = stateroot + where height < $1 + order by id, height desc; +$body$ language sql; + +create table if not exists actor_states +( + head text not null, + code text not null, + state json not null +); + +create unique index if not exists actor_states_head_code_uindex + on actor_states (head, code); + +create index if not exists actor_states_head_index + on actor_states (head); + +create index if not exists actor_states_code_head_index + on actor_states (head, code); + +create table if not exists messages +( + cid text not null + constraint messages_pk + primary key, + "from" text not null, + "to" text not null, + nonce bigint not null, + value text not null, + gasprice bigint not null, + gaslimit bigint not null, + method bigint, + params bytea +); + +create unique index if not exists messages_cid_uindex + on messages (cid); + +create index if not exists messages_from_index + on messages ("from"); + +create index if not exists messages_to_index + on messages ("to"); + +create table if not exists block_messages +( + block text not null + constraint blocks_block_cids_cid_fk + references block_cids (cid), + message text not null, + constraint block_messages_pk + primary key (block, message) +); + +create table if not exists mpool_messages +( + msg text not null + constraint mpool_messages_pk + primary key + constraint mpool_messages_messages_cid_fk + references messages, + add_ts int not null +); + +create unique index if not exists mpool_messages_msg_uindex + on mpool_messages (msg); + +create table if not exists receipts +( + msg text not null, + state text not null, + idx int not null, + exit int not null, + gas_used int not null, + return bytea, + constraint receipts_pk + primary key (msg, state) +); + +create index if not exists receipts_msg_state_index + on receipts (msg, state); + +create table if not exists miner_sectors +( + miner_id text not null, + sector_id bigint not null, + + activation_epoch bigint not null, + expiration_epoch bigint not null, + termination_epoch bigint, + + deal_weight text not null, + verified_deal_weight text not null, + seal_cid text not null, + seal_rand_epoch bigint not null, + constraint miner_sectors_pk + primary key (miner_id, sector_id) +); + +create index if not exists miner_sectors_miner_sectorid_index + on miner_sectors (miner_id, sector_id); + +create table if not exists miner_info +( + miner_id text not null, + owner_addr text not null, + worker_addr text not null, + peer_id text, + sector_size text not null, + + precommit_deposits text not null, + locked_funds text not null, + next_deadline_process_faults bigint not null, + constraint miner_info_pk + primary key (miner_id) +); + +/* used to tell when a miners sectors (proven-not-yet-expired) changed if the miner_sectors_cid's are different a new sector was added or removed (terminated/expired) */ +create table if not exists miner_sectors_heads +( + miner_id text not null, + miner_sectors_cid text not null, + + state_root text not null, + + constraint miner_sectors_heads_pk + primary key (miner_id,miner_sectors_cid) + +); + +/* +create or replace function miner_tips(epoch bigint) + returns table (head text, + addr text, + stateroot text, + sectorset text, + setsize decimal, + provingset text, + provingsize decimal, + owner text, + worker text, + peerid text, + sectorsize bigint, + power decimal, + active bool, + ppe bigint, + slashed_at bigint, + height bigint, + parentstateroot text) as + $body$ + select distinct on (addr) * from miner_heads + inner join state_heights sh on sh.parentstateroot = stateroot + where height < $1 + order by addr, height desc; + $body$ language sql; + +create table if not exists deals +( + id int not null, + pieceRef text not null, + pieceSize bigint not null, + client text not null, + provider text not null, + start decimal not null, + end decimal not null, + epochPrice decimal not null, + collateral decimal not null, + constraint deals_pk + primary key (id) +); + +create index if not exists deals_client_index + on deals (client); + +create unique index if not exists deals_id_uindex + on deals (id); + +create index if not exists deals_pieceRef_index + on deals (pieceRef); + +create index if not exists deals_provider_index + on deals (provider); + +create table if not exists deal_activations +( + deal bigint not null + constraint deal_activations_deals_id_fk + references deals, + activation_epoch bigint not null, + constraint deal_activations_pk + primary key (deal) +); + +create index if not exists deal_activations_activation_epoch_index + on deal_activations (activation_epoch); + +create unique index if not exists deal_activations_deal_uindex + on deal_activations (deal); +*/ + +`) + if err != nil { + return err + } + return tx.Commit() +} + +func (st *storage) hasList() map[cid.Cid]struct{} { + rws, err := st.db.Query(`select cid FROM blocks_synced`) + if err != nil { + log.Error(err) + return map[cid.Cid]struct{}{} + } + out := map[cid.Cid]struct{}{} + + for rws.Next() { + var c string + if err := rws.Scan(&c); err != nil { + log.Error(err) + continue + } + + ci, err := cid.Parse(c) + if err != nil { + log.Error(err) + continue + } + + out[ci] = struct{}{} + } + + return out +} + +func (st *storage) storeActors(actors map[address.Address]map[types.Actor]actorInfo) error { + // Basic + tx, err := st.db.Begin() + if err != nil { + return err + } + if _, err := tx.Exec(` + create temp table a (like actors excluding constraints) on commit drop; + `); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy a (id, code, head, nonce, balance, stateroot) from stdin `) + if err != nil { + return err + } + + for addr, acts := range actors { + for act, st := range acts { + if _, err := stmt.Exec(addr.String(), act.Code.String(), act.Head.String(), act.Nonce, act.Balance.String(), st.stateroot.String()); err != nil { + return err + } + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into actors select * from a on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + if err := tx.Commit(); err != nil { + return err + } + + // States + tx, err = st.db.Begin() + if err != nil { + return err + } + if _, err := tx.Exec(` + create temp table a (like actor_states excluding constraints) on commit drop; + `); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err = tx.Prepare(`copy a (head, code, state) from stdin `) + if err != nil { + return err + } + + for _, acts := range actors { + for act, st := range acts { + if _, err := stmt.Exec(act.Head.String(), act.Code.String(), st.state); err != nil { + return err + } + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into actor_states select * from a on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + if err := tx.Commit(); err != nil { + return err + } + + return nil +} + +type storeSectorsAPI interface { + StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) +} + +func (st *storage) storeSectors(minerTips map[types.TipSetKey][]*minerStateInfo, sectorApi storeSectorsAPI) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(`create temp table ms (like miner_sectors excluding constraints) on commit drop;`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy ms (miner_id, sector_id, activation_epoch, expiration_epoch, deal_weight, verified_deal_weight, seal_cid, seal_rand_epoch) from STDIN`) + if err != nil { + return err + } + + for tipset, miners := range minerTips { + for _, miner := range miners { + sectors, err := sectorApi.StateMinerSectors(context.TODO(), miner.addr, nil, true, tipset) + if err != nil { + log.Debugw("Failed to load sectors", "tipset", tipset.String(), "miner", miner.addr.String(), "error", err) + } + + for _, sector := range sectors { + if _, err := stmt.Exec( + miner.addr.String(), + uint64(sector.ID), + int64(sector.Info.ActivationEpoch), + int64(sector.Info.Info.Expiration), + sector.Info.DealWeight.String(), + sector.Info.VerifiedDealWeight.String(), + sector.Info.Info.SealedCID.String(), + int64(sector.Info.Info.SealRandEpoch), + ); err != nil { + return err + } + } + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into miner_sectors select * from ms on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + return tx.Commit() +} + +func (st *storage) storeMiners(minerTips map[types.TipSetKey][]*minerStateInfo) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(`create temp table mi (like miner_info excluding constraints) on commit drop;`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy mi (miner_id, owner_addr, worker_addr, peer_id, sector_size, precommit_deposits, locked_funds, next_deadline_process_faults) from STDIN`) + if err != nil { + return err + } + for ts, miners := range minerTips { + for _, miner := range miners { + var pid string + if len(miner.info.PeerId) != 0 { + peerid, err := peer.IDFromBytes(miner.info.PeerId) + if err != nil { + // this should "never happen", but if it does we should still store info about the miner. + log.Warnw("failed to decode peerID", "peerID (bytes)", miner.info.PeerId, "miner", miner.addr, "tipset", ts.String()) + } else { + pid = peerid.String() + } + } + if _, err := stmt.Exec( + miner.addr.String(), + miner.info.Owner.String(), + miner.info.Worker.String(), + pid, + miner.info.SectorSize.ShortString(), + miner.state.PreCommitDeposits.String(), + miner.state.LockedFunds.String(), + miner.state.NextDeadlineToProcessFaults, + ); err != nil { + log.Errorw("failed to store miner state", "state", miner.state, "info", miner.info, "error", err) + return err + } + + } + } + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into miner_info select * from mi on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + return tx.Commit() +} + +type minerSectorUpdate struct { + minerState *minerStateInfo + tskey types.TipSetKey + oldSector cid.Cid +} + +func (st *storage) storeMinerSectorsHeads(minerTips map[types.TipSetKey][]*minerStateInfo, api api.FullNode) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(`create temp table msh (like miner_sectors_heads excluding constraints) on commit drop;`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy msh (miner_id, miner_sectors_cid, state_root) from STDIN`) + if err != nil { + return err + } + + var updateMiners []*minerSectorUpdate + for tsk, miners := range minerTips { + for _, miner := range miners { + sectorCID, err := st.getLatestMinerSectorCID(context.TODO(), miner.addr) + if err != nil { + panic(err) + } + if sectorCID == cid.Undef { + continue + } + if _, found := st.minerSectors[sectorCID]; !found { + // schedule miner table update + updateMiners = append(updateMiners, &minerSectorUpdate{ + minerState: miner, + tskey: tsk, + oldSector: sectorCID, + }) + } + st.minerSectors[sectorCID] = struct{}{} + log.Debugw("got sector CID", "miner", miner.addr, "cid", sectorCID.String()) + if _, err := stmt.Exec( + miner.addr.String(), + miner.state.Sectors.String(), + miner.stateroot.String(), + ); err != nil { + log.Errorw("failed to store miners sectors head", "state", miner.state, "info", miner.info, "error", err) + return err + } + + } + } + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into miner_sectors_heads select * from msh on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + if err := tx.Commit(); err != nil { + return err + } + return st.updateMinerSectors(updateMiners, api) +} + +type deletedSector struct { + deletedSector miner_spec.SectorOnChainInfo + miner address.Address + tskey types.TipSetKey +} + +func (st *storage) updateMinerSectors(miners []*minerSectorUpdate, api api.FullNode) error { + log.Info("updating miners constant sector table") + var deletedSectors []*deletedSector + for _, miner := range miners { + s := &apiIpldStore{context.TODO(), api} + newSectors, err := adt.AsArray(s, miner.minerState.state.Sectors) + if err != nil { + log.Warnw("new sectors as array", "error", err, "cid", miner.minerState.state.Sectors) + return err + } + + oldSectors, err := adt.AsArray(s, miner.oldSector) + if err != nil { + log.Warnw("old sectors as array", "error", err, "cid", miner.oldSector.String()) + return err + } + + var oldSecInfo miner_spec.SectorOnChainInfo + var newSecInfo miner_spec.SectorOnChainInfo + // if we cannot find an old sector in the new list then it was removed. + if err := oldSectors.ForEach(&oldSecInfo, func(i int64) error { + found, err := newSectors.Get(uint64(oldSecInfo.Info.SectorNumber), &newSecInfo) + if err != nil { + log.Warnw("new sectors get", "error", err) + return err + } + if !found { + log.Infow("MINER DELETED SECTOR", "miner", miner.minerState.addr.String(), "sector", oldSecInfo.Info.SectorNumber, "tipset", miner.tskey.String()) + deletedSectors = append(deletedSectors, &deletedSector{ + deletedSector: oldSecInfo, + miner: miner.minerState.addr, + tskey: miner.tskey, + }) + } + return nil + }); err != nil { + log.Warnw("old sectors foreach", "error", err) + return err + } + if len(deletedSectors) > 0 { + log.Infow("Calculated updates", "miner", miner.minerState.addr, "deleted sectors", len(deletedSectors)) + } + } + // now we have all the sectors that were removed, update the database + tx, err := st.db.Begin() + if err != nil { + return err + } + stmt, err := tx.Prepare(`UPDATE miner_sectors SET termination_epoch=$1 WHERE miner_id=$2 AND sector_id=$3`) + if err != nil { + return err + } + for _, ds := range deletedSectors { + ts, err := api.ChainGetTipSet(context.TODO(), ds.tskey) + if err != nil { + log.Warnw("get tipset", "error", err) + return err + } + // TODO validate this shits right + if ts.Height() >= ds.deletedSector.Info.Expiration { + // means it expired, do nothing + log.Infow("expired sector", "miner", ds.miner.String(), "sector", ds.deletedSector.Info.SectorNumber) + continue + } + log.Infow("terminated sector", "miner", ds.miner.String(), "sector", ds.deletedSector.Info.SectorNumber) + // means it was terminated. + if _, err := stmt.Exec(int64(ts.Height()), ds.miner.String(), int64(ds.deletedSector.Info.SectorNumber)); err != nil { + return err + } + } + + if err := stmt.Close(); err != nil { + return err + } + defer log.Info("update miner sectors complete") + return tx.Commit() +} + +func (st *storage) storeHeaders(bhs map[cid.Cid]*types.BlockHeader, sync bool) error { + st.headerLk.Lock() + defer st.headerLk.Unlock() + + tx, err := st.db.Begin() + if err != nil { + return xerrors.Errorf("begin: %w", err) + } + + if _, err := tx.Exec(` + +create temp table bc (like block_cids excluding constraints) on commit drop; +create temp table de (like drand_entries excluding constraints) on commit drop; +create temp table bde (like block_drand_entries excluding constraints) on commit drop; +create temp table tbp (like block_parents excluding constraints) on commit drop; +create temp table bs (like blocks_synced excluding constraints) on commit drop; +create temp table b (like blocks excluding constraints) on commit drop; + + +`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + { + stmt, err := tx.Prepare(`copy bc (cid) from STDIN`) + if err != nil { + return err + } + + for _, bh := range bhs { + if _, err := stmt.Exec(bh.Cid().String()); err != nil { + log.Error(err) + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into block_cids select * from bc on conflict do nothing `); err != nil { + return xerrors.Errorf("drand entries put: %w", err) + } + } + + { + stmt, err := tx.Prepare(`copy de (round, data) from STDIN`) + if err != nil { + return err + } + + for _, bh := range bhs { + for _, ent := range bh.BeaconEntries { + if _, err := stmt.Exec(ent.Round, ent.Data); err != nil { + log.Error(err) + } + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into drand_entries select * from de on conflict do nothing `); err != nil { + return xerrors.Errorf("drand entries put: %w", err) + } + } + + { + stmt, err := tx.Prepare(`copy bde (round, block) from STDIN`) + if err != nil { + return err + } + + for _, bh := range bhs { + for _, ent := range bh.BeaconEntries { + if _, err := stmt.Exec(ent.Round, bh.Cid().String()); err != nil { + log.Error(err) + } + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into block_drand_entries select * from bde on conflict do nothing `); err != nil { + return xerrors.Errorf("block drand entries put: %w", err) + } + } + + { + stmt, err := tx.Prepare(`copy tbp (block, parent) from STDIN`) + if err != nil { + return err + } + + for _, bh := range bhs { + for _, parent := range bh.Parents { + if _, err := stmt.Exec(bh.Cid().String(), parent.String()); err != nil { + log.Error(err) + } + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into block_parents select * from tbp on conflict do nothing `); err != nil { + return xerrors.Errorf("parent put: %w", err) + } + } + + if sync { + now := time.Now().Unix() + + stmt, err := tx.Prepare(`copy bs (cid, add_ts) from stdin `) + if err != nil { + return err + } + + for _, bh := range bhs { + if _, err := stmt.Exec(bh.Cid().String(), now); err != nil { + log.Error(err) + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into blocks_synced select * from bs on conflict do nothing `); err != nil { + return xerrors.Errorf("syncd put: %w", err) + } + } + + stmt2, err := tx.Prepare(`copy b (cid, parentWeight, parentStateRoot, height, miner, "timestamp", ticket, eprof, forksig) from stdin`) + if err != nil { + return err + } + + for _, bh := range bhs { + var eprof interface{} + if bh.ElectionProof != nil { + eprof = bh.ElectionProof.VRFProof + } + + if bh.Ticket == nil { + log.Warnf("got a block with nil ticket") + + bh.Ticket = &types.Ticket{ + VRFProof: []byte{}, + } + } + + if _, err := stmt2.Exec( + bh.Cid().String(), + bh.ParentWeight.String(), + bh.ParentStateRoot.String(), + bh.Height, + bh.Miner.String(), + bh.Timestamp, + bh.Ticket.VRFProof, + eprof, + bh.ForkSignaling); err != nil { + log.Error(err) + } + } + + if err := stmt2.Close(); err != nil { + return xerrors.Errorf("s2 close: %w", err) + } + + if _, err := tx.Exec(`insert into blocks select * from b on conflict do nothing `); err != nil { + return xerrors.Errorf("blk put: %w", err) + } + + return tx.Commit() +} + +func (st *storage) storeMessages(msgs map[cid.Cid]*types.Message) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(` + +create temp table msgs (like messages excluding constraints) on commit drop; + + +`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy msgs (cid, "from", "to", nonce, "value", gasprice, gaslimit, method, params) from stdin `) + if err != nil { + return err + } + + for c, m := range msgs { + if _, err := stmt.Exec( + c.String(), + m.From.String(), + m.To.String(), + m.Nonce, + m.Value.String(), + m.GasPrice.String(), + m.GasLimit, + m.Method, + m.Params, + ); err != nil { + return err + } + } + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into messages select * from msgs on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + return tx.Commit() +} + +func (st *storage) storeReceipts(recs map[mrec]*types.MessageReceipt) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(` + +create temp table recs (like receipts excluding constraints) on commit drop; + + +`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy recs (msg, state, idx, exit, gas_used, return) from stdin `) + if err != nil { + return err + } + + for c, m := range recs { + if _, err := stmt.Exec( + c.msg.String(), + c.state.String(), + c.idx, + m.ExitCode, + m.GasUsed, + m.Return, + ); err != nil { + return err + } + } + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into receipts select * from recs on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + return tx.Commit() +} + +func (st *storage) storeAddressMap(addrs map[address.Address]address.Address) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(` + +create temp table iam (like id_address_map excluding constraints) on commit drop; + + +`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy iam (id, address) from STDIN `) + if err != nil { + return err + } + + for a, i := range addrs { + if i == address.Undef { + continue + } + if _, err := stmt.Exec( + i.String(), + a.String(), + ); err != nil { + return err + } + } + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into id_address_map select * from iam on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + return tx.Commit() +} + +func (st *storage) storeMsgInclusions(incls map[cid.Cid][]cid.Cid) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(` + +create temp table mi (like block_messages excluding constraints) on commit drop; + + +`); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy mi (block, message) from STDIN `) + if err != nil { + return err + } + + for b, msgs := range incls { + for _, msg := range msgs { + if _, err := stmt.Exec( + b.String(), + msg.String(), + ); err != nil { + return err + } + } + } + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into block_messages select * from mi on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + return tx.Commit() +} + +func (st *storage) storeMpoolInclusions(msgs []api.MpoolUpdate) error { + tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(` + create temp table mi (like mpool_messages excluding constraints) on commit drop; + `); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy mi (msg, add_ts) from stdin `) + if err != nil { + return err + } + + for _, msg := range msgs { + if msg.Type != api.MpoolAdd { + continue + } + + if _, err := stmt.Exec( + msg.Message.Message.Cid().String(), + time.Now().Unix(), + ); err != nil { + return err + } + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into mpool_messages select * from mi on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + return tx.Commit() +} + +func (st *storage) storeDeals(deals map[string]api.MarketDeal) error { + /*tx, err := st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(` + create temp table d (like deals excluding constraints) on commit drop; + `); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err := tx.Prepare(`copy d (id, pieceref, piecesize, client, "provider", "start", "end", epochprice, collateral) from stdin `) + if err != nil { + return err + } + + var bloat uint64 + + for id, deal := range deals { + if len(deal.Proposal.PieceCID.String()) > 100 { + bloat += uint64(len(deal.Proposal.PieceCID.String())) + continue + } + if _, err := stmt.Exec( + id, + deal.Proposal.PieceCID.String(), + deal.Proposal.PieceSize, + deal.Proposal.Client.String(), + deal.Proposal.Provider.String(), + fmt.Sprint(deal.Proposal.StartEpoch), + fmt.Sprint(deal.Proposal.EndEpoch), + deal.Proposal.StoragePricePerEpoch.String(), + deal.Proposal.ProviderCollateral.String(), + ); err != nil { + return err + } + } + if bloat > 0 { + log.Warnf("deal PieceRefs had %d bytes of garbage", bloat) + } + + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into deals select * from d on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + if err := tx.Commit(); err != nil { + return err + } + + // Activations + + tx, err = st.db.Begin() + if err != nil { + return err + } + + if _, err := tx.Exec(` + create temp table d (like deal_activations excluding constraints) on commit drop; + `); err != nil { + return xerrors.Errorf("prep temp: %w", err) + } + + stmt, err = tx.Prepare(`copy d (deal, activation_epoch) from stdin `) + if err != nil { + return err + } + + for id, deal := range deals { + if deal.State.SectorStartEpoch <= 0 { + continue + } + if _, err := stmt.Exec( + id, + deal.State.SectorStartEpoch, + ); err != nil { + return err + } + } + if err := stmt.Close(); err != nil { + return err + } + + if _, err := tx.Exec(`insert into deal_activations select * from d on conflict do nothing `); err != nil { + return xerrors.Errorf("actor put: %w", err) + } + + if err := tx.Commit(); err != nil { + return err + } + */ + return nil +} + +func (st *storage) refreshViews() error { + if _, err := st.db.Exec(`refresh materialized view state_heights`); err != nil { + return err + } + + return nil +} + +func (st *storage) close() error { + return st.db.Close() +} + +func (st *storage) getLatestMinerSectorCID(ctx context.Context, miner address.Address) (cid.Cid, error) { + queryStr := fmt.Sprintf(` +SELECT miner_sectors_cid +FROM miner_sectors_heads +LEFT JOIN blocks ON miner_sectors_heads.state_root = blocks.parentstateroot +WHERE miner_id = '%s' +ORDER BY blocks.height DESC +LIMIT 1; +`, + miner.String()) + + var cidstr string + err := st.db.QueryRowContext(ctx, queryStr).Scan(&cidstr) + switch { + case err == sql.ErrNoRows: + log.Warnf("no miner with miner_id: %s in table", miner) + return cid.Undef, nil + case err != nil: + return cid.Undef, err + default: + return cid.Decode(cidstr) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/sync.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/sync.go new file mode 100644 index 0000000000..59e77e4a07 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/sync.go @@ -0,0 +1,596 @@ +package main + +import ( + "bytes" + "container/list" + "context" + "encoding/json" + "fmt" + "math" + "sync" + "time" + + "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/util/adt" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + parmap "github.com/filecoin-project/lotus/lib/parmap" +) + +func runSyncer(ctx context.Context, api api.FullNode, st *storage, maxBatch int) { + notifs, err := api.ChainNotify(ctx) + if err != nil { + panic(err) + } + go func() { + for notif := range notifs { + for _, change := range notif { + switch change.Type { + case store.HCCurrent: + fallthrough + case store.HCApply: + syncHead(ctx, api, st, change.Val, maxBatch) + case store.HCRevert: + log.Warnf("revert todo") + } + + if change.Type == store.HCCurrent { + go subMpool(ctx, api, st) + go subBlocks(ctx, api, st) + } + } + } + }() +} + +type minerStateInfo struct { + // common + addr address.Address + act types.Actor + stateroot cid.Cid + + // miner specific + state miner.State + info miner.MinerInfo + + // tracked by power actor + rawPower big.Int + qalPower big.Int + ssize uint64 + psize uint64 +} + +type actorInfo struct { + stateroot cid.Cid + tsKey types.TipSetKey + state string +} + +func syncHead(ctx context.Context, api api.FullNode, st *storage, headTs *types.TipSet, maxBatch int) { + var alk sync.Mutex + + log.Infof("Getting synced block list") + + hazlist := st.hasList() + + log.Infof("Getting headers / actors") + + // global list of all blocks that need to be synced + allToSync := map[cid.Cid]*types.BlockHeader{} + // a stack + toVisit := list.New() + + for _, header := range headTs.Blocks() { + toVisit.PushBack(header) + } + + // TODO consider making a db query to check where syncing left off at in the case of a restart and avoid reprocessing + // those entries, or write value to file on shutdown + // walk the entire chain starting from headTS + for toVisit.Len() > 0 { + bh := toVisit.Remove(toVisit.Back()).(*types.BlockHeader) + _, has := hazlist[bh.Cid()] + if _, seen := allToSync[bh.Cid()]; seen || has { + continue + } + + allToSync[bh.Cid()] = bh + if len(allToSync)%500 == 10 { + log.Debugf("to visit: (%d) %s @%d", len(allToSync), bh.Cid(), bh.Height) + } + + if len(bh.Parents) == 0 { + continue + } + + pts, err := api.ChainGetTipSet(ctx, types.NewTipSetKey(bh.Parents...)) + if err != nil { + log.Error(err) + continue + } + + for _, header := range pts.Blocks() { + toVisit.PushBack(header) + } + } + + // Main worker loop, this loop runs until all tipse from headTS to genesis have been processed. + for len(allToSync) > 0 { + // first map is addresses -> common actors states (head, code, balance, nonce) + // second map common actor states -> chain state (tipset, stateroot) & unique actor state (deserialization of their head CID) represented as json. + actors := map[address.Address]map[types.Actor]actorInfo{} + + // map of actor public key address to ID address + addressToID := map[address.Address]address.Address{} + minH := abi.ChainEpoch(math.MaxInt64) + + // find the blockheader with the lowest height + for _, header := range allToSync { + if header.Height < minH { + minH = header.Height + } + } + + // toSync maps block cids to their headers and contains all block headers that will be synced in this batch + // `maxBatch` is a tunable parameter to control how many blocks we sync per iteration. + toSync := map[cid.Cid]*types.BlockHeader{} + for c, header := range allToSync { + if header.Height < minH+abi.ChainEpoch(maxBatch) { + toSync[c] = header + addressToID[header.Miner] = address.Undef + } + } + // remove everything we are syncing this round from the global list of blocks to sync + for c := range toSync { + delete(allToSync, c) + } + + log.Infow("Starting Sync", "height", minH, "numBlocks", len(toSync), "maxBatch", maxBatch) + + // map of addresses to changed actors + var changes map[string]types.Actor + // collect all actor state that has changes between block headers + paDone := 0 + parmap.Par(50, parmap.MapArr(toSync), func(bh *types.BlockHeader) { + paDone++ + if paDone%100 == 0 { + log.Infof("pa: %d %d%%", paDone, (paDone*100)/len(toSync)) + } + + if len(bh.Parents) == 0 { // genesis case + genesisTs, _ := types.NewTipSet([]*types.BlockHeader{bh}) + aadrs, err := api.StateListActors(ctx, genesisTs.Key()) + if err != nil { + log.Error(err) + return + } + + // TODO suspicious there is not a lot to be gained by doing this in parallel since the genesis state + // is unlikely to contain a lot of actors, why not for loop here? + parmap.Par(50, aadrs, func(addr address.Address) { + act, err := api.StateGetActor(ctx, addr, genesisTs.Key()) + if err != nil { + log.Error(err) + return + } + + ast, err := api.StateReadState(ctx, addr, genesisTs.Key()) + if err != nil { + log.Error(err) + return + } + state, err := json.Marshal(ast.State) + if err != nil { + log.Error(err) + return + } + + alk.Lock() + _, ok := actors[addr] + if !ok { + actors[addr] = map[types.Actor]actorInfo{} + } + actors[addr][*act] = actorInfo{ + stateroot: bh.ParentStateRoot, + tsKey: genesisTs.Key(), + state: string(state), + } + addressToID[addr] = address.Undef + alk.Unlock() + }) + + return + } + + pts, err := api.ChainGetTipSet(ctx, types.NewTipSetKey(bh.Parents...)) + if err != nil { + log.Error(err) + return + } + + // TODO Does this return actors that have been deleted between states? + // collect all actors that had state changes between the blockheader parent-state and its grandparent-state. + changes, err = api.StateChangedActors(ctx, pts.ParentState(), bh.ParentStateRoot) + if err != nil { + log.Error(err) + return + } + + // record the state of all actors that have changed + for a, act := range changes { + act := act + + addr, err := address.NewFromString(a) + if err != nil { + log.Error(err) + return + } + + ast, err := api.StateReadState(ctx, addr, pts.Key()) + + if err != nil { + log.Error(err) + return + } + + state, err := json.Marshal(ast.State) + if err != nil { + log.Error(err) + return + } + + alk.Lock() + _, ok := actors[addr] + if !ok { + actors[addr] = map[types.Actor]actorInfo{} + } + // a change occurred for the actor with address `addr` and state `act` at tipset `pts`. + actors[addr][act] = actorInfo{ + stateroot: bh.ParentStateRoot, + state: string(state), + tsKey: pts.Key(), + } + addressToID[addr] = address.Undef + alk.Unlock() + } + }) + + // map of tipset to all miners that had a head-change at that tipset. + minerTips := make(map[types.TipSetKey][]*minerStateInfo, len(changes)) + // heads we've seen, im being paranoid + headsSeen := make(map[cid.Cid]struct{}, len(actors)) + + log.Infof("Getting messages") + + msgs, incls := fetchMessages(ctx, api, toSync) + + log.Infof("Resolving addresses") + + for _, message := range msgs { + addressToID[message.To] = address.Undef + addressToID[message.From] = address.Undef + } + + parmap.Par(50, parmap.KMapArr(addressToID), func(addr address.Address) { + // FIXME: cannot use EmptyTSK here since actorID's can change during reorgs, need to use the corresponding tipset. + // TODO: figure out a way to get the corresponding tipset... + raddr, err := api.StateLookupID(ctx, addr, types.EmptyTSK) + if err != nil { + log.Warn(err) + return + } + alk.Lock() + addressToID[addr] = raddr + alk.Unlock() + }) + + log.Infof("Getting miner info") + + minerChanges := 0 + for addr, m := range actors { + for actor, c := range m { + if actor.Code != builtin.StorageMinerActorCodeID { + continue + } + + // only want miner actors with head change events + if _, found := headsSeen[actor.Head]; found { + continue + } + minerChanges++ + + minerTips[c.tsKey] = append(minerTips[c.tsKey], &minerStateInfo{ + addr: addr, + act: actor, + stateroot: c.stateroot, + + state: miner.State{}, + info: miner.MinerInfo{}, + + rawPower: big.Zero(), + qalPower: big.Zero(), + }) + + headsSeen[actor.Head] = struct{}{} + } + } + + minerProcessingStartedAt := time.Now() + log.Infow("Processing miners", "numTips", len(minerTips), "numMinerChanges", minerChanges) + // extract the power actor state at each tipset, loop over all miners that changed at said tipset and extract their + // claims from the power actor state. This ensures we only fetch the power actors state once for each tipset. + parmap.Par(50, parmap.KVMapArr(minerTips), func(it func() (types.TipSetKey, []*minerStateInfo)) { + tsKey, minerInfo := it() + + // get the power actors claims map + mp, err := getPowerActorClaimsMap(ctx, api, tsKey) + if err != nil { + log.Error(err) + return + } + // Get miner raw and quality power + for _, mi := range minerInfo { + var claim power.Claim + // get miner claim from power actors claim map and store if found, else the miner had no claim at + // this tipset + found, err := mp.Get(adt.AddrKey(mi.addr), &claim) + if err != nil { + log.Error(err) + } + if found { + mi.qalPower = claim.QualityAdjPower + mi.rawPower = claim.RawBytePower + } + + // Get the miner state info + astb, err := api.ChainReadObj(ctx, mi.act.Head) + if err != nil { + log.Error(err) + return + } + if err := mi.state.UnmarshalCBOR(bytes.NewReader(astb)); err != nil { + log.Error(err) + return + } + mi.info = mi.state.Info + } + + // TODO Get the Sector Count + // FIXME this is returning a lot of "address not found" errors, which is strange given that StateChangedActors + // retruns all actors that had a state change at tipset `k.tsKey`, maybe its returning deleted miners too?? + /* + sszs, err := api.StateMinerSectorCount(ctx, k.addr, k.tsKey) + if err != nil { + info.psize = 0 + info.ssize = 0 + } else { + info.psize = sszs.Pset + info.ssize = sszs.Sset + } + */ + }) + log.Infow("Completed Miner Processing", "duration", time.Since(minerProcessingStartedAt).String(), "processed", minerChanges) + + log.Info("Getting receipts") + + receipts := fetchParentReceipts(ctx, api, toSync) + + log.Info("Storing headers") + + if err := st.storeHeaders(toSync, true); err != nil { + log.Errorf("%+v", err) + return + } + + log.Info("Storing address mapping") + + if err := st.storeAddressMap(addressToID); err != nil { + log.Error(err) + return + } + + log.Info("Storing actors") + + if err := st.storeActors(actors); err != nil { + log.Error(err) + return + } + + log.Info("Storing miners") + if err := st.storeMiners(minerTips); err != nil { + log.Error(err) + return + } + + log.Info("Storing miner sectors") + sectorStart := time.Now() + if err := st.storeSectors(minerTips, api); err != nil { + log.Error(err) + return + } + log.Infow("Finished storing miner sectors", "duration", time.Since(sectorStart).String()) + + log.Info("Storing miner sectors heads") + if err := st.storeMinerSectorsHeads(minerTips, api); err != nil { + log.Error(err) + return + } + + log.Infof("Storing messages") + + if err := st.storeMessages(msgs); err != nil { + log.Error(err) + return + } + + log.Info("Storing message inclusions") + + if err := st.storeMsgInclusions(incls); err != nil { + log.Error(err) + return + } + + log.Infof("Storing parent receipts") + + if err := st.storeReceipts(receipts); err != nil { + log.Error(err) + return + } + log.Infof("Sync stage done") + } + + log.Infof("Get deals") + + // TODO: incremental, gather expired + deals, err := api.StateMarketDeals(ctx, headTs.Key()) + if err != nil { + log.Error(err) + return + } + + log.Infof("Store deals") + + if err := st.storeDeals(deals); err != nil { + log.Error(err) + return + } + + log.Infof("Refresh views") + + if err := st.refreshViews(); err != nil { + log.Error(err) + return + } + + log.Infof("Sync done") +} + +func fetchMessages(ctx context.Context, api api.FullNode, toSync map[cid.Cid]*types.BlockHeader) (map[cid.Cid]*types.Message, map[cid.Cid][]cid.Cid) { + var lk sync.Mutex + messages := map[cid.Cid]*types.Message{} + inclusions := map[cid.Cid][]cid.Cid{} // block -> msgs + + parmap.Par(50, parmap.MapArr(toSync), func(header *types.BlockHeader) { + msgs, err := api.ChainGetBlockMessages(ctx, header.Cid()) + if err != nil { + log.Error(err) + return + } + + vmm := make([]*types.Message, 0, len(msgs.Cids)) + for _, m := range msgs.BlsMessages { + vmm = append(vmm, m) + } + + for _, m := range msgs.SecpkMessages { + vmm = append(vmm, &m.Message) + } + + lk.Lock() + for _, message := range vmm { + messages[message.Cid()] = message + inclusions[header.Cid()] = append(inclusions[header.Cid()], message.Cid()) + } + lk.Unlock() + }) + + return messages, inclusions +} + +type mrec struct { + msg cid.Cid + state cid.Cid + idx int +} + +func fetchParentReceipts(ctx context.Context, api api.FullNode, toSync map[cid.Cid]*types.BlockHeader) map[mrec]*types.MessageReceipt { + var lk sync.Mutex + out := map[mrec]*types.MessageReceipt{} + + parmap.Par(50, parmap.MapArr(toSync), func(header *types.BlockHeader) { + recs, err := api.ChainGetParentReceipts(ctx, header.Cid()) + if err != nil { + log.Error(err) + return + } + msgs, err := api.ChainGetParentMessages(ctx, header.Cid()) + if err != nil { + log.Error(err) + return + } + + lk.Lock() + for i, r := range recs { + out[mrec{ + msg: msgs[i].Cid, + state: header.ParentStateRoot, + idx: i, + }] = r + } + lk.Unlock() + }) + + return out +} + +// load the power actor state clam as an adt.Map at the tipset `ts`. +func getPowerActorClaimsMap(ctx context.Context, api api.FullNode, ts types.TipSetKey) (*adt.Map, error) { + powerActor, err := api.StateGetActor(ctx, builtin.StoragePowerActorAddr, ts) + if err != nil { + return nil, err + } + + powerRaw, err := api.ChainReadObj(ctx, powerActor.Head) + if err != nil { + return nil, err + } + + var powerActorState power.State + if err := powerActorState.UnmarshalCBOR(bytes.NewReader(powerRaw)); err != nil { + return nil, fmt.Errorf("failed to unmarshal power actor state: %w", err) + } + + s := &apiIpldStore{ctx, api} + return adt.AsMap(s, powerActorState.Claims) +} + +// require for AMT and HAMT access +// TODO extract this to a common location in lotus and reuse the code +type apiIpldStore struct { + ctx context.Context + api api.FullNode +} + +func (ht *apiIpldStore) Context() context.Context { + return ht.ctx +} + +func (ht *apiIpldStore) Get(ctx context.Context, c cid.Cid, out interface{}) error { + raw, err := ht.api.ChainReadObj(ctx, c) + if err != nil { + return err + } + + cu, ok := out.(cbg.CBORUnmarshaler) + if ok { + if err := cu.UnmarshalCBOR(bytes.NewReader(raw)); err != nil { + return err + } + return nil + } + return fmt.Errorf("Object does not implement CBORUnmarshaler: %T", out) +} + +func (ht *apiIpldStore) Put(ctx context.Context, v interface{}) (cid.Cid, error) { + return cid.Undef, fmt.Errorf("Put is not implemented on apiIpldStore") +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/templates.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/templates.go new file mode 100644 index 0000000000..67534f1e91 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-chainwatch/templates.go @@ -0,0 +1,350 @@ +package main + +import ( + "fmt" + "html/template" + "net/http" + "os" + "path/filepath" + "strconv" + + rice "github.com/GeertJohan/go.rice" + "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/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" +) + +type handler struct { + api api.FullNode + st *storage + site *rice.Box + assets http.Handler + + templates map[string]*template.Template +} + +func newHandler(api api.FullNode, st *storage) (*handler, error) { + h := &handler{ + api: api, + st: st, + site: rice.MustFindBox("site"), + + templates: map[string]*template.Template{}, + } + h.assets = http.FileServer(h.site.HTTPBox()) + + funcs := template.FuncMap{ + "count": h.count, + "countCol": h.countCol, + "sum": h.sum, + "netPower": h.netPower, + "queryNum": h.queryNum, + "sizeStr": sizeStr, + "strings": h.strings, + "qstr": h.qstr, + "qstrs": h.qstrs, + "messages": h.messages, + + "pageDown": pageDown, + "parseInt": func(s string) (int, error) { i, e := strconv.ParseInt(s, 10, 64); return int(i), e }, + "substr": func(i, j int, s string) string { return s[i:j] }, + "sub": func(a, b int) int { return a - b }, // TODO: really not builtin? + + "param": func(string) string { return "" }, // replaced in request handler + } + + base := template.New("") + + base.Funcs(funcs) + + return h, h.site.Walk("", func(path string, info os.FileInfo, err error) error { + if filepath.Ext(path) != ".html" { + return nil + } + if err != nil { + return err + } + log.Info(path) + + h.templates["/"+path], err = base.New(path).Parse(h.site.MustString(path)) + return err + }) +} + +func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h, err := newHandler(h.api, h.st) // for faster dev + if err != nil { + log.Error(err) + return + } + + p := r.URL.Path + if p == "/" { + p = "/index.html" + } + + t, ok := h.templates[p] + if !ok { + h.assets.ServeHTTP(w, r) + return + } + + t, err = t.Clone() + if err != nil { + log.Error(err) + return + } + + t.Funcs(map[string]interface{}{ + "param": r.FormValue, + }) + + if err := t.Execute(w, nil); err != nil { + log.Errorf("%+v", err) + return + } + + log.Info(r.URL.Path) +} + +// Template funcs + +func (h *handler) count(table string, filters ...string) (int, error) { + // explicitly not caring about sql injection too much, this doesn't take user input + + filts := "" + if len(filters) > 0 { + filts = " where " + for _, filter := range filters { + filts += filter + " and " + } + filts = filts[:len(filts)-5] + } + + var c int + err := h.st.db.QueryRow("select count(1) from " + table + filts).Scan(&c) + if err != nil { + return 0, err + } + + return c, nil +} + +func (h *handler) countCol(table string, col string, filters ...string) (int, error) { + // explicitly not caring about sql injection too much, this doesn't take user input + + filts := "" + if len(filters) > 0 { + filts = " where " + for _, filter := range filters { + filts += filter + " and " + } + filts = filts[:len(filts)-5] + } + + var c int + err := h.st.db.QueryRow("select count(distinct " + col + ") from " + table + filts).Scan(&c) + if err != nil { + return 0, err + } + + return c, nil +} + +func (h *handler) sum(table string, col string) (types.BigInt, error) { + return h.queryNum("select sum(cast(" + col + " as bigint)) from " + table) +} + +func (h *handler) netPower(slashFilt string) (types.BigInt, error) { + if slashFilt != "" { + slashFilt = " where " + slashFilt + } + return h.queryNum(`select sum(power) from (select distinct on (addr) power, slashed_at from miner_heads + inner join blocks b on miner_heads.stateroot = b.parentStateRoot +order by addr, height desc) as p` + slashFilt) +} + +func (h *handler) queryNum(q string, p ...interface{}) (types.BigInt, error) { + // explicitly not caring about sql injection too much, this doesn't take user input + + var c string + err := h.st.db.QueryRow(q, p...).Scan(&c) + if err != nil { + log.Error("qnum ", q, p, err) + return types.NewInt(0), err + } + + i := types.NewInt(0) + _, ok := i.SetString(c, 10) + if !ok { + return types.NewInt(0), xerrors.New("num parse error: " + c) + } + return i, nil +} + +var units = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"} + +func sizeStr(size types.BigInt) string { + size = types.BigMul(size, types.NewInt(100)) + i := 0 + for types.BigCmp(size, types.NewInt(102400)) >= 0 && i < len(units)-1 { + size = types.BigDiv(size, types.NewInt(1024)) + i++ + } + return fmt.Sprintf("%s.%s %s", types.BigDiv(size, types.NewInt(100)), types.BigMod(size, types.NewInt(100)), units[i]) +} + +func (h *handler) strings(table string, col string, filter string, args ...interface{}) (out []string, err error) { + if len(filter) > 0 { + filter = " where " + filter + } + log.Info("strings qstr ", "select "+col+" from "+table+filter, args) + rws, err := h.st.db.Query("select "+col+" from "+table+filter, args...) + if err != nil { + return nil, err + } + for rws.Next() { + var r string + if err := rws.Scan(&r); err != nil { + return nil, err + } + out = append(out, r) + } + + return +} + +func (h *handler) qstr(q string, p ...interface{}) (string, error) { + // explicitly not caring about sql injection too much, this doesn't take user input + + r, err := h.qstrs(q, 1, p...) + if err != nil { + return "", err + } + return r[0], nil +} + +func (h *handler) qstrs(q string, n int, p ...interface{}) ([]string, error) { + // explicitly not caring about sql injection too much, this doesn't take user input + + c := make([]string, n) + ia := make([]interface{}, n) + for i := range c { + ia[i] = &c[i] + } + err := h.st.db.QueryRow(q, p...).Scan(ia...) + if err != nil { + log.Error("qnum ", q, p, err) + return nil, err + } + + return c, nil +} + +type sbig types.BigInt + +func (bi *sbig) Scan(value interface{}) error { + switch value := value.(type) { + case string: + i, ok := big.NewInt(0).SetString(value, 10) + if !ok { + if value == "" { + return nil + } + return xerrors.Errorf("failed to parse bigint string: '%s'", value) + } + + bi.Int = i + + return nil + case int64: + bi.Int = big.NewInt(value).Int + return nil + default: + return xerrors.Errorf("non-string types unsupported: %T", value) + } +} + +type Message struct { + To address.Address + From address.Address + + Nonce uint64 + + Value sbig + + GasPrice sbig + GasLimit int64 + + Method abi.MethodNum + Params []byte +} + +func (h *handler) messages(filter string, args ...interface{}) (out []types.Message, err error) { + if len(filter) > 0 { + filter = " where " + filter + } + + log.Info("select * from messages " + filter) + + rws, err := h.st.db.Query("select * from messages "+filter, args...) + if err != nil { + return nil, err + } + for rws.Next() { + var r Message + var cs string + + if err := rws.Scan( + &cs, + &r.From, + &r.To, + &r.Nonce, + &r.Value, + &r.GasPrice, + &r.GasLimit, + &r.Method, + &r.Params, + ); err != nil { + return nil, err + } + + c, err := cid.Parse(cs) + if err != nil { + return nil, err + } + tr := types.Message{ + To: r.To, + From: r.From, + Nonce: r.Nonce, + Value: types.BigInt(r.Value), + GasPrice: types.BigInt(r.GasPrice), + GasLimit: r.GasLimit, + Method: r.Method, + Params: r.Params, + } + if c != tr.Cid() { + log.Warn("msg cid doesn't match") + } + + out = append(out, tr) + } + + return +} + +func pageDown(base, n int) []int { + out := make([]int, n) + for i := range out { + out[i] = base - i + } + + return out +} + +var _ http.Handler = &handler{} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/main.go new file mode 100644 index 0000000000..9743f209f8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/main.go @@ -0,0 +1,454 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "html/template" + "io" + "io/ioutil" + "net" + "net/http" + "os" + "sort" + "strconv" + "time" + + rice "github.com/GeertJohan/go.rice" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" +) + +var log = logging.Logger("main") + +var sendPerRequest, _ = types.ParseFIL("50") + +var supportedSectors struct { + SectorSizes []struct { + Name string + Value uint64 + Default bool + } +} + +func init() { + for supportedSector, _ := range miner.SupportedProofTypes { + sectorSize, err := supportedSector.SectorSize() + if err != nil { + panic(err) + } + + supportedSectors.SectorSizes = append(supportedSectors.SectorSizes, struct { + Name string + Value uint64 + Default bool + }{ + Name: sectorSize.ShortString(), + Value: uint64(sectorSize), + Default: false, + }) + + } + + sort.Slice(supportedSectors.SectorSizes[:], func(i, j int) bool { + return supportedSectors.SectorSizes[i].Value < supportedSectors.SectorSizes[j].Value + }) + + supportedSectors.SectorSizes[0].Default = true +} + +func main() { + logging.SetLogLevel("*", "INFO") + + log.Info("Starting fountain") + + local := []*cli.Command{ + runCmd, + } + + app := &cli.App{ + Name: "lotus-fountain", + Usage: "Devnet token distribution utility", + Version: build.UserVersion(), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + }, + + Commands: local, + } + + if err := app.Run(os.Args); err != nil { + log.Warn(err) + return + } +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "Start lotus fountain", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "front", + Value: "127.0.0.1:7777", + }, + &cli.StringFlag{ + Name: "from", + }, + }, + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + v, err := nodeApi.Version(ctx) + if err != nil { + return err + } + + log.Info("Remote version: %s", v.Version) + + from, err := address.NewFromString(cctx.String("from")) + if err != nil { + return xerrors.Errorf("parsing source address (provide correct --from flag!): %w", err) + } + + defaultMinerPeer, err := peer.Decode("12D3KooWJpBNhwgvoZ15EB1JwRTRpxgM9D2fwq6eEktrJJG74aP6") + if err != nil { + return err + } + + h := &handler{ + ctx: ctx, + api: nodeApi, + from: from, + limiter: NewLimiter(LimiterConfig{ + TotalRate: time.Second, + TotalBurst: 256, + IPRate: time.Minute, + IPBurst: 5, + WalletRate: 15 * time.Minute, + WalletBurst: 2, + }), + minerLimiter: NewLimiter(LimiterConfig{ + TotalRate: time.Second, + TotalBurst: 256, + IPRate: 10 * time.Minute, + IPBurst: 2, + WalletRate: 1 * time.Hour, + WalletBurst: 2, + }), + defaultMinerPeer: defaultMinerPeer, + } + + http.Handle("/", http.FileServer(rice.MustFindBox("site").HTTPBox())) + http.HandleFunc("/miner.html", h.minerhtml) + http.HandleFunc("/send", h.send) + http.HandleFunc("/mkminer", h.mkminer) + http.HandleFunc("/msgwait", h.msgwait) + http.HandleFunc("/msgwaitaddr", h.msgwaitaddr) + + fmt.Printf("Open http://%s\n", cctx.String("front")) + + go func() { + <-ctx.Done() + os.Exit(0) + }() + + return http.ListenAndServe(cctx.String("front"), nil) + }, +} + +type handler struct { + ctx context.Context + api api.FullNode + + from address.Address + + limiter *Limiter + minerLimiter *Limiter + + defaultMinerPeer peer.ID +} + +func (h *handler) minerhtml(w http.ResponseWriter, r *http.Request) { + f, err := rice.MustFindBox("site").Open("_miner.html") + if err != nil { + w.WriteHeader(500) + _, _ = w.Write([]byte(err.Error())) + return + } + + tmpl, err := ioutil.ReadAll(f) + if err != nil { + w.WriteHeader(500) + _, _ = w.Write([]byte(err.Error())) + return + } + + var executedTmpl bytes.Buffer + + t, err := template.New("miner.html").Parse(string(tmpl)) + if err := t.Execute(&executedTmpl, supportedSectors); err != nil { + w.WriteHeader(500) + _, _ = w.Write([]byte(err.Error())) + return + } + + if _, err := io.Copy(w, &executedTmpl); err != nil { + log.Errorf("failed to write template to string %s", err) + } + + return +} + +func (h *handler) send(w http.ResponseWriter, r *http.Request) { + to, err := address.NewFromString(r.FormValue("address")) + if err != nil { + w.WriteHeader(400) + _, _ = w.Write([]byte(err.Error())) + return + } + + // Limit based on wallet address + limiter := h.limiter.GetWalletLimiter(to.String()) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests)+": wallet limit", http.StatusTooManyRequests) + return + } + + // Limit based on IP + + reqIP := r.Header.Get("X-Real-IP") + if reqIP == "" { + h, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + log.Errorf("could not get ip from: %s, err: %s", r.RemoteAddr, err) + } + reqIP = h + } + if i := net.ParseIP(reqIP); i != nil && i.IsLoopback() { + log.Errorf("rate limiting localhost: %s", reqIP) + } + + limiter = h.limiter.GetIPLimiter(reqIP) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests)+": IP limit", http.StatusTooManyRequests) + return + } + + // General limiter to allow throttling all messages that can make it into the mpool + if !h.limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests)+": global limit", http.StatusTooManyRequests) + return + } + + smsg, err := h.api.MpoolPushMessage(h.ctx, &types.Message{ + Value: types.BigInt(sendPerRequest), + From: h.from, + To: to, + + GasPrice: types.NewInt(0), + GasLimit: 10000, + }) + if err != nil { + w.WriteHeader(400) + _, _ = w.Write([]byte(err.Error())) + return + } + + _, _ = w.Write([]byte(smsg.Cid().String())) +} + +func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) { + owner, err := address.NewFromString(r.FormValue("address")) + if err != nil { + w.WriteHeader(400) + _, _ = w.Write([]byte(err.Error())) + return + } + + if owner.Protocol() != address.BLS { + w.WriteHeader(400) + _, _ = w.Write([]byte("Miner address must use BLS. A BLS address starts with the prefix 't3'.")) + _, _ = w.Write([]byte("Please create a BLS address by running \"lotus wallet new bls\" while connected to a Lotus node.")) + return + } + + ssize, err := strconv.ParseInt(r.FormValue("sectorSize"), 10, 64) + if err != nil { + return + } + + log.Infof("%s: create actor start", owner) + + // Limit based on wallet address + limiter := h.minerLimiter.GetWalletLimiter(owner.String()) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests)+": wallet limit", http.StatusTooManyRequests) + return + } + + // Limit based on IP + reqIP := r.Header.Get("X-Real-IP") + if reqIP == "" { + h, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + log.Errorf("could not get ip from: %s, err: %s", r.RemoteAddr, err) + } + reqIP = h + } + limiter = h.minerLimiter.GetIPLimiter(reqIP) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests)+": IP limit", http.StatusTooManyRequests) + return + } + + // General limiter owner allow throttling all messages that can make it into the mpool + if !h.minerLimiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests)+": global limit", http.StatusTooManyRequests) + return + } + + collateral, err := h.api.StatePledgeCollateral(r.Context(), types.EmptyTSK) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + smsg, err := h.api.MpoolPushMessage(h.ctx, &types.Message{ + Value: types.BigInt(sendPerRequest), + From: h.from, + To: owner, + + GasPrice: types.NewInt(0), + GasLimit: 10000, + }) + if err != nil { + w.WriteHeader(400) + w.Write([]byte("pushfunds: " + err.Error())) + return + } + log.Infof("%s: push funds %s", owner, smsg.Cid()) + + spt, err := ffiwrapper.SealProofTypeFromSectorSize(abi.SectorSize(ssize)) + if err != nil { + w.WriteHeader(400) + w.Write([]byte("sealprooftype: " + err.Error())) + return + } + + params, err := actors.SerializeParams(&power.CreateMinerParams{ + Owner: owner, + Worker: owner, + SealProofType: spt, + Peer: abi.PeerID(h.defaultMinerPeer), + }) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + createStorageMinerMsg := &types.Message{ + To: builtin.StoragePowerActorAddr, + From: h.from, + Value: types.BigAdd(collateral, types.BigDiv(collateral, types.NewInt(100))), + + Method: builtin.MethodsPower.CreateMiner, + Params: params, + + GasLimit: 10000000, + GasPrice: types.NewInt(0), + } + + signed, err := h.api.MpoolPushMessage(r.Context(), createStorageMinerMsg) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + log.Infof("%s: create miner msg: %s", owner, signed.Cid()) + + http.Redirect(w, r, fmt.Sprintf("/wait.html?f=%s&m=%s&o=%s", signed.Cid(), smsg.Cid(), owner), 303) +} + +func (h *handler) msgwait(w http.ResponseWriter, r *http.Request) { + c, err := cid.Parse(r.FormValue("cid")) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + if mw.Receipt.ExitCode != 0 { + w.WriteHeader(400) + w.Write([]byte(xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode).Error())) + return + } + w.WriteHeader(200) +} + +func (h *handler) msgwaitaddr(w http.ResponseWriter, r *http.Request) { + c, err := cid.Parse(r.FormValue("cid")) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + if mw.Receipt.ExitCode != 0 { + w.WriteHeader(400) + w.Write([]byte(xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode).Error())) + return + } + w.WriteHeader(200) + + var ma power.CreateMinerReturn + if err := ma.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { + log.Errorf("%w", err) + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + fmt.Fprintf(w, "{\"addr\": \"%s\"}", ma.IDAddress) +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter.go new file mode 100644 index 0000000000..eb7215780e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter.go @@ -0,0 +1,94 @@ +package main + +import ( + "sync" + "time" + + "golang.org/x/time/rate" +) + +type Limiter struct { + control *rate.Limiter + + ips map[string]*rate.Limiter + wallets map[string]*rate.Limiter + mu *sync.RWMutex + + config LimiterConfig +} + +type LimiterConfig struct { + TotalRate time.Duration + TotalBurst int + + IPRate time.Duration + IPBurst int + + WalletRate time.Duration + WalletBurst int +} + +func NewLimiter(c LimiterConfig) *Limiter { + return &Limiter{ + control: rate.NewLimiter(rate.Every(c.TotalRate), c.TotalBurst), + mu: &sync.RWMutex{}, + ips: make(map[string]*rate.Limiter), + wallets: make(map[string]*rate.Limiter), + + config: c, + } +} + +func (i *Limiter) Allow() bool { + return i.control.Allow() +} + +func (i *Limiter) AddIPLimiter(ip string) *rate.Limiter { + i.mu.Lock() + defer i.mu.Unlock() + + limiter := rate.NewLimiter(rate.Every(i.config.IPRate), i.config.IPBurst) + + i.ips[ip] = limiter + + return limiter +} + +func (i *Limiter) GetIPLimiter(ip string) *rate.Limiter { + i.mu.Lock() + limiter, exists := i.ips[ip] + + if !exists { + i.mu.Unlock() + return i.AddIPLimiter(ip) + } + + i.mu.Unlock() + + return limiter +} + +func (i *Limiter) AddWalletLimiter(addr string) *rate.Limiter { + i.mu.Lock() + defer i.mu.Unlock() + + limiter := rate.NewLimiter(rate.Every(i.config.WalletRate), i.config.WalletBurst) + + i.wallets[addr] = limiter + + return limiter +} + +func (i *Limiter) GetWalletLimiter(wallet string) *rate.Limiter { + i.mu.Lock() + limiter, exists := i.wallets[wallet] + + if !exists { + i.mu.Unlock() + return i.AddWalletLimiter(wallet) + } + + i.mu.Unlock() + + return limiter +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter_test.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter_test.go new file mode 100644 index 0000000000..03590de500 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/rate_limiter_test.go @@ -0,0 +1,38 @@ +package main + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestRateLimit(t *testing.T) { + limiter := NewLimiter(LimiterConfig{ + TotalRate: time.Second, + TotalBurst: 20, + IPRate: time.Second, + IPBurst: 1, + WalletRate: time.Second, + WalletBurst: 1, + }) + + for i := 0; i < 20; i++ { + assert.True(t, limiter.Allow()) + } + + assert.False(t, limiter.Allow()) + + time.Sleep(time.Second) + assert.True(t, limiter.Allow()) + + assert.True(t, limiter.GetIPLimiter("127.0.0.1").Allow()) + assert.False(t, limiter.GetIPLimiter("127.0.0.1").Allow()) + time.Sleep(time.Second) + assert.True(t, limiter.GetIPLimiter("127.0.0.1").Allow()) + + assert.True(t, limiter.GetWalletLimiter("abc123").Allow()) + assert.False(t, limiter.GetWalletLimiter("abc123").Allow()) + time.Sleep(time.Second) + assert.True(t, limiter.GetWalletLimiter("abc123").Allow()) +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/_miner.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/_miner.html new file mode 100644 index 0000000000..d83f90d727 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/_miner.html @@ -0,0 +1,51 @@ + + + + Creating Storage Miner - Lotus Fountain + + + +
    +
    +
    + [CREATING STORAGE MINER] +
    +
    +
    + Enter owner/worker address: + + + +
    +
    + +
    + When creating storage miner, DO NOT REFRESH THE PAGE, wait for it to load. This can take more than 5min. +
    +
    + If you don't have an owner/worker address, you can create it by following these instructions. +
    +
    + +
    + + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/funds.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/funds.html new file mode 100644 index 0000000000..cd26032f3a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/funds.html @@ -0,0 +1,29 @@ + + + + Sending Funds - Lotus Fountain + + + +
    +
    +
    + [SENDING FUNDS] +
    +
    +
    + Enter destination address: + + +
    +
    +
    + +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/index.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/index.html new file mode 100644 index 0000000000..85226e4c0b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/index.html @@ -0,0 +1,27 @@ + + + + Lotus Fountain + + + +
    +
    +
    + [LOTUS DEVNET FAUCET] +
    + + +
    + +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/main.css b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/main.css new file mode 100644 index 0000000000..bcdb24c2e8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/main.css @@ -0,0 +1,56 @@ +body { + font-family: 'monospace'; + background: #1f1f1f; + color: #f0f0f0; + padding: 0; + margin: 0; +} + +.Index { + width: 100vw; + height: 100vh; + background: #1a1a1a; + color: #f0f0f0; + font-family: monospace; + + display: grid; + grid-template-columns: auto 40vw auto; + grid-template-rows: auto auto auto 3em; + grid-template-areas: + ". . . ." + ". main main ." + ". . . ." + "footer footer footer footer"; +} +.Index-footer { + background: #2a2a2a; + grid-area: footer; +} + +.Index-footer > div { + padding-left: 0.7em; + padding-top: 0.7em; +} + +.Index-nodes { + grid-area: main; + background: #2a2a2a; +} + +.Index-node { + margin: 5px; + padding: 15px; + background: #1f1f1f; +} + +a:link { + color: #50f020; +} + +a:visited { + color: #50f020; +} + +a:hover { + color: #30a00a; +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/wait.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/wait.html new file mode 100644 index 0000000000..ea2d64236b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-fountain/site/wait.html @@ -0,0 +1,69 @@ + + + + Creating Storage Miner (wait) - Lotus Fountain + + + +
    +
    +
    + [CREATING STORAGE MINER] +
    +
    + Gas Funds:    - WAIT +
    +
    + Miner Actor:  - WAIT +
    + + +
    + +
    + + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main.go new file mode 100644 index 0000000000..e8a32a7194 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main.go @@ -0,0 +1,265 @@ +package main + +import ( + "context" + "errors" + "os" + "os/signal" + "syscall" + "time" + + cid "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-jsonrpc" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +type CidWindow [][]cid.Cid + +var log = logging.Logger("lotus-health") + +func main() { + logging.SetLogLevel("*", "INFO") + + log.Info("Starting health agent") + + local := []*cli.Command{ + watchHeadCmd, + } + + app := &cli.App{ + Name: "lotus-health", + Usage: "Tools for monitoring lotus daemon health", + Version: build.UserVersion(), + Commands: local, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + }, + } + + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + return + } +} + +var watchHeadCmd = &cli.Command{ + Name: "watch-head", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "threshold", + Value: 3, + Usage: "number of times head remains unchanged before failing health check", + }, + &cli.IntFlag{ + Name: "interval", + Value: int(build.BlockDelaySecs), + Usage: "interval in seconds between chain head checks", + }, + &cli.StringFlag{ + Name: "systemd-unit", + Value: "lotus-daemon.service", + Usage: "systemd unit name to restart on health check failure", + }, + &cli.IntFlag{ + Name: "api-timeout", + // TODO: this default value seems spurious. + Value: int(build.BlockDelaySecs), + Usage: "timeout between API retries", + }, + &cli.IntFlag{ + Name: "api-retries", + Value: 8, + Usage: "number of API retry attempts", + }, + }, + Action: func(c *cli.Context) error { + var headCheckWindow CidWindow + threshold := c.Int("threshold") + interval := time.Duration(c.Int("interval")) * time.Second + name := c.String("systemd-unit") + apiRetries := c.Int("api-retries") + apiTimeout := time.Duration(c.Int("api-timeout")) * time.Second + + nCh := make(chan interface{}, 1) + sCh := make(chan os.Signal, 1) + signal.Notify(sCh, os.Interrupt, syscall.SIGTERM) + + api, closer, err := getFullNodeAPI(c, apiRetries, apiTimeout) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(c) + + go func() { + for { + log.Info("Waiting for sync to complete") + if err := waitForSyncComplete(ctx, api, apiRetries, apiTimeout); err != nil { + nCh <- err + return + } + headCheckWindow, err = updateWindow(ctx, api, headCheckWindow, threshold, apiRetries, apiTimeout) + if err != nil { + log.Warn("Failed to connect to API. Restarting systemd service") + nCh <- nil + return + } + ok := checkWindow(headCheckWindow, threshold) + if !ok { + log.Warn("Chain head has not updated. Restarting systemd service") + nCh <- nil + break + } + log.Info("Chain head is healthy") + time.Sleep(interval) + } + return + }() + + restart, err := notifyHandler(name, nCh, sCh) + if err != nil { + return err + } + if restart != "done" { + return errors.New("Systemd unit failed to restart:" + restart) + } + log.Info("Restarting health agent") + // Exit health agent and let supervisor restart health agent + // Restarting lotus systemd unit kills api connection + os.Exit(130) + return nil + }, +} + +/* + * reads channel of slices of Cids + * compares slices of Cids when len is greater or equal to `t` - threshold + * if all slices are equal, head has not updated and returns false + */ +func checkWindow(window CidWindow, t int) bool { + var dup int + windowLen := len(window) + if windowLen >= t { + cidWindow: + for i := range window { + next := windowLen - 1 - i + // if array length is different, head is changing + if next >= 1 && len(window[next]) != len(window[next-1]) { + break cidWindow + } + // if cids are different, head is changing + for j := range window[next] { + if next >= 1 && window[next][j] != window[next-1][j] { + break cidWindow + } + } + if i < (t - 1) { + dup++ + } + } + + if dup == (t - 1) { + return false + } + } + return true +} + +/* + * returns a slice of slices of Cids + * len of slice <= `t` - threshold + */ +func updateWindow(ctx context.Context, a api.FullNode, w CidWindow, t int, r int, to time.Duration) (CidWindow, error) { + head, err := getHead(ctx, a, r, to) + if err != nil { + return nil, err + } + window := appendCIDsToWindow(w, head.Cids(), t) + return window, err +} + +/* + * get chain head from API + * retries if API no available + * returns tipset + */ +func getHead(ctx context.Context, a api.FullNode, r int, t time.Duration) (*types.TipSet, error) { + for i := 0; i < r; i++ { + head, err := a.ChainHead(ctx) + if err != nil && i == (r-1) { + return nil, err + } + if err != nil { + log.Warnf("Call to API failed. Retrying in %.0fs", t.Seconds()) + time.Sleep(t) + continue + } + return head, err + } + return nil, nil +} + +/* + * appends slice of Cids to window slice + * keeps a fixed window slice size, dropping older slices + * returns new window + */ +func appendCIDsToWindow(w CidWindow, c []cid.Cid, t int) CidWindow { + offset := len(w) - t + 1 + if offset >= 0 { + return append(w[offset:], c) + } + return append(w, c) +} + +/* + * wait for node to sync + */ +func waitForSyncComplete(ctx context.Context, a api.FullNode, r int, t time.Duration) error { + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(3 * time.Second): + head, err := getHead(ctx, a, r, t) + if err != nil { + return err + } + + if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) { + return nil + } + } + } +} + +/* + * A thin wrapper around lotus cli GetFullNodeAPI + * Adds retry logic + */ +func getFullNodeAPI(ctx *cli.Context, r int, t time.Duration) (api.FullNode, jsonrpc.ClientCloser, error) { + for i := 0; i < r; i++ { + api, closer, err := lcli.GetFullNodeAPI(ctx) + if err != nil && i == (r-1) { + return nil, nil, err + } + if err != nil { + log.Warnf("API connection failed. Retrying in %.0fs", t.Seconds()) + time.Sleep(t) + continue + } + return api, closer, err + } + return nil, nil, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main_test.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main_test.go new file mode 100644 index 0000000000..346376167b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/main_test.go @@ -0,0 +1,166 @@ +package main + +import ( + "testing" + + cid "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" + "github.com/stretchr/testify/assert" +) + +func TestAppendCIDsToWindow(t *testing.T) { + assert := assert.New(t) + var window CidWindow + threshold := 3 + cid0 := makeCID("0") + cid1 := makeCID("1") + cid2 := makeCID("2") + cid3 := makeCID("3") + window = appendCIDsToWindow(window, []cid.Cid{cid0}, threshold) + window = appendCIDsToWindow(window, []cid.Cid{cid1}, threshold) + window = appendCIDsToWindow(window, []cid.Cid{cid2}, threshold) + window = appendCIDsToWindow(window, []cid.Cid{cid3}, threshold) + assert.Len(window, 3) + assert.Equal(window[0][0], cid1) + assert.Equal(window[1][0], cid2) + assert.Equal(window[2][0], cid3) +} + +func TestCheckWindow(t *testing.T) { + assert := assert.New(t) + threshold := 3 + + var healthyHeadCheckWindow CidWindow + healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{ + makeCID("abcd"), + }, threshold) + healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + }, threshold) + healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + }, threshold) + ok := checkWindow(healthyHeadCheckWindow, threshold) + assert.True(ok) + + var healthyHeadCheckWindow1 CidWindow + healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + }, threshold) + healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + makeCID("abcd"), + }, threshold) + healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{ + makeCID("abcd"), + }, threshold) + ok = checkWindow(healthyHeadCheckWindow1, threshold) + assert.True(ok) + + var healthyHeadCheckWindow2 CidWindow + healthyHeadCheckWindow2 = appendCIDsToWindow(healthyHeadCheckWindow2, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + }, threshold) + healthyHeadCheckWindow2 = appendCIDsToWindow(healthyHeadCheckWindow2, []cid.Cid{ + makeCID("abcd"), + }, threshold) + ok = checkWindow(healthyHeadCheckWindow2, threshold) + assert.True(ok) + + var healthyHeadCheckWindow3 CidWindow + healthyHeadCheckWindow3 = appendCIDsToWindow(healthyHeadCheckWindow3, []cid.Cid{ + makeCID("abcd"), + }, threshold) + healthyHeadCheckWindow3 = appendCIDsToWindow(healthyHeadCheckWindow3, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + }, threshold) + ok = checkWindow(healthyHeadCheckWindow3, threshold) + assert.True(ok) + + var healthyHeadCheckWindow4 CidWindow + healthyHeadCheckWindow4 = appendCIDsToWindow(healthyHeadCheckWindow4, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + }, threshold) + ok = checkWindow(healthyHeadCheckWindow4, threshold) + assert.True(ok) + + var healthyHeadCheckWindow5 CidWindow + healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + makeCID("bbff"), + }, 5) + healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{ + makeCID("bbcd"), + makeCID("bbfe"), + }, 5) + healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{ + makeCID("abcd"), + }, 5) + healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{ + makeCID("cbcd"), + makeCID("cbfe"), + }, 5) + healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{ + makeCID("cbcd"), + makeCID("cbfe"), + }, 5) + ok = checkWindow(healthyHeadCheckWindow5, threshold) + assert.True(ok) + + var unhealthyHeadCheckWindow CidWindow + unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{ + makeCID("abcd"), + makeCID("fbcd"), + }, threshold) + unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{ + makeCID("abcd"), + makeCID("fbcd"), + }, threshold) + unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{ + makeCID("abcd"), + makeCID("fbcd"), + }, threshold) + ok = checkWindow(unhealthyHeadCheckWindow, threshold) + assert.False(ok) + + var unhealthyHeadCheckWindow1 CidWindow + unhealthyHeadCheckWindow1 = appendCIDsToWindow(unhealthyHeadCheckWindow1, []cid.Cid{ + makeCID("abcd"), + makeCID("fbcd"), + }, threshold) + unhealthyHeadCheckWindow1 = appendCIDsToWindow(unhealthyHeadCheckWindow1, []cid.Cid{ + makeCID("abcd"), + makeCID("fbcd"), + }, threshold) + ok = checkWindow(unhealthyHeadCheckWindow1, threshold) + assert.True(ok) + + var unhealthyHeadCheckWindow2 CidWindow + unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{ + makeCID("abcd"), + }, threshold) + unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{ + makeCID("abcd"), + }, threshold) + unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{ + makeCID("abcd"), + }, threshold) + ok = checkWindow(unhealthyHeadCheckWindow2, threshold) + assert.False(ok) +} + +func makeCID(s string) cid.Cid { + h1, err := mh.Sum([]byte(s), mh.SHA2_256, -1) + if err != nil { + log.Fatal(err) + } + return cid.NewCidV1(0x55, h1) +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/notify.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/notify.go new file mode 100644 index 0000000000..031f0fe2f2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-health/notify.go @@ -0,0 +1,31 @@ +package main + +import ( + "os" + + "github.com/coreos/go-systemd/v22/dbus" +) + +func notifyHandler(n string, ch chan interface{}, sCh chan os.Signal) (string, error) { + select { + // alerts to restart systemd unit + case <-ch: + statusCh := make(chan string, 1) + c, err := dbus.New() + if err != nil { + return "", err + } + _, err = c.TryRestartUnit(n, "fail", statusCh) + if err != nil { + return "", err + } + select { + case result := <-statusCh: + return result, nil + } + // SIGTERM + case <-sCh: + os.Exit(1) + return "", nil + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/main.go new file mode 100644 index 0000000000..ff45687f87 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/main.go @@ -0,0 +1,371 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net" + "net/http" + "os" + "path/filepath" + "syscall" + "time" + + "github.com/google/uuid" + "github.com/gorilla/mux" + logging "github.com/ipfs/go-log/v2" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-jsonrpc/auth" + paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/sector-storage/ffiwrapper" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/build" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/lotuslog" + "github.com/filecoin-project/lotus/node/repo" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/sector-storage/sealtasks" + "github.com/filecoin-project/sector-storage/stores" +) + +var log = logging.Logger("main") + +const FlagStorageRepo = "workerrepo" + +func main() { + lotuslog.SetupLogLevels() + + log.Info("Starting lotus worker") + + local := []*cli.Command{ + runCmd, + } + + app := &cli.App{ + Name: "lotus-seal-worker", + Usage: "Remote storage miner worker", + Version: build.UserVersion(), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: FlagStorageRepo, + EnvVars: []string{"WORKER_PATH"}, + Value: "~/.lotusworker", // TODO: Consider XDG_DATA_HOME + }, + &cli.StringFlag{ + Name: "storagerepo", + EnvVars: []string{"LOTUS_STORAGE_PATH"}, + Value: "~/.lotusstorage", // TODO: Consider XDG_DATA_HOME + }, + &cli.BoolFlag{ + Name: "enable-gpu-proving", + Usage: "enable use of GPU for mining operations", + Value: true, + }, + }, + + Commands: local, + } + app.Setup() + app.Metadata["repoType"] = repo.Worker + + if err := app.Run(os.Args); err != nil { + log.Warnf("%+v", err) + return + } +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "Start lotus worker", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "address", + Usage: "Locally reachable address", + }, + &cli.BoolFlag{ + Name: "no-local-storage", + Usage: "don't use storageminer repo for sector storage", + }, + &cli.BoolFlag{ + Name: "precommit1", + Usage: "enable precommit1 (32G sectors: 1 core, 128GiB Memory)", + Value: true, + }, + &cli.BoolFlag{ + Name: "precommit2", + Usage: "enable precommit2 (32G sectors: all cores, 96GiB Memory)", + Value: true, + }, + &cli.BoolFlag{ + Name: "commit", + Usage: "enable commit (32G sectors: all cores or GPUs, 128GiB Memory + 64GiB swap)", + Value: true, + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Bool("enable-gpu-proving") { + if err := os.Setenv("BELLMAN_NO_GPU", "true"); err != nil { + return xerrors.Errorf("could not set no-gpu env: %+v", err) + } + } + + if cctx.String("address") == "" { + return xerrors.Errorf("--address flag is required") + } + + // Connect to storage-miner + var nodeApi api.StorageMiner + var closer func() + var err error + for { + nodeApi, closer, err = lcli.GetStorageMinerAPI(cctx) + if err == nil { + break + } + fmt.Printf("\r\x1b[0KConnecting to miner API... (%s)", err) + time.Sleep(time.Second) + continue + } + + defer closer() + ctx := lcli.ReqContext(cctx) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + v, err := nodeApi.Version(ctx) + if err != nil { + return err + } + if v.APIVersion != build.APIVersion { + return xerrors.Errorf("lotus-storage-miner API version doesn't match: local: ", api.Version{APIVersion: build.APIVersion}) + } + log.Infof("Remote version %s", v) + + watchMinerConn(ctx, cctx, nodeApi) + + // Check params + + act, err := nodeApi.ActorAddress(ctx) + if err != nil { + return err + } + ssize, err := nodeApi.ActorSectorSize(ctx, act) + if err != nil { + return err + } + + if cctx.Bool("commit") { + if err := paramfetch.GetParams(ctx, build.ParametersJSON(), uint64(ssize)); err != nil { + return xerrors.Errorf("get params: %w", err) + } + } + + var taskTypes []sealtasks.TaskType + + taskTypes = append(taskTypes, sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize) + + if cctx.Bool("precommit1") { + taskTypes = append(taskTypes, sealtasks.TTPreCommit1) + } + if cctx.Bool("precommit2") { + taskTypes = append(taskTypes, sealtasks.TTPreCommit2) + } + if cctx.Bool("commit") { + taskTypes = append(taskTypes, sealtasks.TTCommit2) + } + + if len(taskTypes) == 0 { + return xerrors.Errorf("no task types specified") + } + + // Open repo + + repoPath := cctx.String(FlagStorageRepo) + r, err := repo.NewFS(repoPath) + if err != nil { + return err + } + + ok, err := r.Exists() + if err != nil { + return err + } + if !ok { + if err := r.Init(repo.Worker); err != nil { + return err + } + + lr, err := r.Lock(repo.Worker) + if err != nil { + return err + } + + var localPaths []stores.LocalPath + + if !cctx.Bool("no-local-storage") { + b, err := json.MarshalIndent(&stores.LocalStorageMeta{ + ID: stores.ID(uuid.New().String()), + Weight: 10, + CanSeal: true, + CanStore: false, + }, "", " ") + if err != nil { + return xerrors.Errorf("marshaling storage config: %w", err) + } + + if err := ioutil.WriteFile(filepath.Join(lr.Path(), "sectorstore.json"), b, 0644); err != nil { + return xerrors.Errorf("persisting storage metadata (%s): %w", filepath.Join(lr.Path(), "sectorstore.json"), err) + } + + localPaths = append(localPaths, stores.LocalPath{ + Path: lr.Path(), + }) + } + + if err := lr.SetStorage(func(sc *stores.StorageConfig) { + sc.StoragePaths = append(sc.StoragePaths, localPaths...) + }); err != nil { + return xerrors.Errorf("set storage config: %w", err) + } + + { + // init datastore for r.Exists + _, err := lr.Datastore("/") + if err != nil { + return err + } + } + if err := lr.Close(); err != nil { + return xerrors.Errorf("close repo: %w", err) + } + } + + lr, err := r.Lock(repo.Worker) + if err != nil { + return err + } + + log.Info("Opening local storage; connecting to master") + + localStore, err := stores.NewLocal(ctx, lr, nodeApi, []string{"http://" + cctx.String("address") + "/remote"}) + if err != nil { + return err + } + + // Setup remote sector store + spt, err := ffiwrapper.SealProofTypeFromSectorSize(ssize) + if err != nil { + return xerrors.Errorf("getting proof type: %w", err) + } + + sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner) + if err != nil { + return xerrors.Errorf("could not get api info: %w", err) + } + + remote := stores.NewRemote(localStore, nodeApi, sminfo.AuthHeader()) + + // Create / expose the worker + + workerApi := &worker{ + LocalWorker: sectorstorage.NewLocalWorker(sectorstorage.WorkerConfig{ + SealProof: spt, + TaskTypes: taskTypes, + }, remote, localStore, nodeApi), + } + + mux := mux.NewRouter() + + log.Info("Setting up control endpoint at " + cctx.String("address")) + + rpcServer := jsonrpc.NewServer() + rpcServer.Register("Filecoin", apistruct.PermissionedWorkerAPI(workerApi)) + + mux.Handle("/rpc/v0", rpcServer) + mux.PathPrefix("/remote").HandlerFunc((&stores.FetchHandler{Local: localStore}).ServeHTTP) + mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof + + ah := &auth.Handler{ + Verify: nodeApi.AuthVerify, + Next: mux.ServeHTTP, + } + + srv := &http.Server{ + Handler: ah, + BaseContext: func(listener net.Listener) context.Context { + return ctx + }, + } + + go func() { + <-ctx.Done() + log.Warn("Shutting down...") + if err := srv.Shutdown(context.TODO()); err != nil { + log.Errorf("shutting down RPC server failed: %s", err) + } + log.Warn("Graceful shutdown successful") + }() + + nl, err := net.Listen("tcp", cctx.String("address")) + if err != nil { + return err + } + + log.Info("Waiting for tasks") + + go func() { + if err := nodeApi.WorkerConnect(ctx, "ws://"+cctx.String("address")+"/rpc/v0"); err != nil { + log.Errorf("Registering worker failed: %+v", err) + cancel() + return + } + }() + + return srv.Serve(nl) + }, +} + +func watchMinerConn(ctx context.Context, cctx *cli.Context, nodeApi api.StorageMiner) { + go func() { + closing, err := nodeApi.Closing(ctx) + if err != nil { + log.Errorf("failed to get remote closing channel: %+v", err) + } + + select { + case <-closing: + case <-ctx.Done(): + } + + if ctx.Err() != nil { + return // graceful shutdown + } + + log.Warnf("Connection with miner node lost, restarting") + + exe, err := os.Executable() + if err != nil { + log.Errorf("getting executable for auto-restart: %+v", err) + } + + log.Sync() + + // TODO: there are probably cleaner/more graceful ways to restart, + // but this is good enough for now (FSM can recover from the mess this creates) + if err := syscall.Exec(exe, []string{exe, "run", + fmt.Sprintf("--address=%s", cctx.String("address")), + fmt.Sprintf("--no-local-storage=%t", cctx.Bool("no-local-storage")), + fmt.Sprintf("--precommit1=%t", cctx.Bool("precommit1")), + fmt.Sprintf("--precommit2=%t", cctx.Bool("precommit2")), + fmt.Sprintf("--commit=%t", cctx.Bool("commit")), + }, os.Environ()); err != nil { + fmt.Println(err) + } + }() +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/rpc.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/rpc.go new file mode 100644 index 0000000000..1046056be2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seal-worker/rpc.go @@ -0,0 +1,20 @@ +package main + +import ( + "context" + + "github.com/filecoin-project/specs-storage/storage" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/sector-storage" +) + +type worker struct { + *sectorstorage.LocalWorker +} + +func (w *worker) Version(context.Context) (build.Version, error) { + return build.APIVersion, nil +} + +var _ storage.Sealer = &worker{} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/genesis.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/genesis.go new file mode 100644 index 0000000000..d439e2ed5a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/genesis.go @@ -0,0 +1,143 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + + "github.com/google/uuid" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi/big" + + "github.com/filecoin-project/lotus/build" + genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" + "github.com/filecoin-project/lotus/genesis" +) + +var genesisCmd = &cli.Command{ + Name: "genesis", + Description: "manipulate lotus genesis template", + Subcommands: []*cli.Command{ + genesisNewCmd, + genesisAddMinerCmd, + }, +} + +var genesisNewCmd = &cli.Command{ + Name: "new", + Description: "create new genesis template", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "network-name", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return xerrors.New("seed genesis new [genesis.json]") + } + + out := genesis.Template{ + Accounts: []genesis.Actor{}, + Miners: []genesis.Miner{}, + NetworkName: cctx.String("network-name"), + } + if out.NetworkName == "" { + out.NetworkName = "localnet-" + uuid.New().String() + } + + genb, err := json.MarshalIndent(&out, "", " ") + if err != nil { + return err + } + + genf, err := homedir.Expand(cctx.Args().First()) + if err != nil { + return err + } + + if err := ioutil.WriteFile(genf, genb, 0644); err != nil { + return err + } + + return nil + }, +} + +var genesisAddMinerCmd = &cli.Command{ + Name: "add-miner", + Description: "add genesis miner", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 2 { + return xerrors.New("seed genesis add-miner [genesis.json] [preseal.json]") + } + + genf, err := homedir.Expand(cctx.Args().First()) + if err != nil { + return err + } + + var template genesis.Template + genb, err := ioutil.ReadFile(genf) + if err != nil { + return xerrors.Errorf("read genesis template: %w", err) + } + + if err := json.Unmarshal(genb, &template); err != nil { + return xerrors.Errorf("unmarshal genesis template: %w", err) + } + + minf, err := homedir.Expand(cctx.Args().Get(1)) + if err != nil { + return xerrors.Errorf("expand preseal file path: %w", err) + } + miners := map[string]genesis.Miner{} + minb, err := ioutil.ReadFile(minf) + if err != nil { + return xerrors.Errorf("read preseal file: %w", err) + } + if err := json.Unmarshal(minb, &miners); err != nil { + return xerrors.Errorf("unmarshal miner info: %w", err) + } + + for mn, miner := range miners { + log.Infof("Adding miner %s to genesis template", mn) + { + id := uint64(genesis2.MinerStart) + uint64(len(template.Miners)) + maddr, err := address.NewFromString(mn) + if err != nil { + return xerrors.Errorf("parsing miner address: %w", err) + } + mid, err := address.IDFromAddress(maddr) + if err != nil { + return xerrors.Errorf("getting miner id from address: %w", err) + } + if mid != id { + return xerrors.Errorf("tried to set miner t0%d as t0%d", mid, id) + } + } + + template.Miners = append(template.Miners, miner) + log.Infof("Giving %s some initial balance", miner.Owner) + template.Accounts = append(template.Accounts, genesis.Actor{ + Type: genesis.TAccount, + Balance: big.Mul(big.NewInt(50_000_000), big.NewInt(int64(build.FilecoinPrecision))), + Meta: (&genesis.AccountMeta{Owner: miner.Owner}).ActorMeta(), + }) + } + + genb, err = json.MarshalIndent(&template, "", " ") + if err != nil { + return err + } + + if err := ioutil.WriteFile(genf, genb, 0644); err != nil { + return err + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/main.go new file mode 100644 index 0000000000..cf0f166d92 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/main.go @@ -0,0 +1,195 @@ +package main + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "os" + + "github.com/docker/go-units" + "github.com/filecoin-project/sector-storage/ffiwrapper" + + logging "github.com/ipfs/go-log/v2" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + + "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/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" + "github.com/filecoin-project/lotus/genesis" +) + +var log = logging.Logger("lotus-seed") + +func main() { + logging.SetLogLevel("*", "INFO") + + local := []*cli.Command{ + genesisCmd, + + preSealCmd, + aggregateManifestsCmd, + } + + app := &cli.App{ + Name: "lotus-seed", + Usage: "Seal sectors for genesis miner", + Version: build.UserVersion(), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "sector-dir", + Value: "~/.genesis-sectors", + }, + }, + + Commands: local, + } + + if err := app.Run(os.Args); err != nil { + log.Warn(err) + os.Exit(1) + } +} + +var preSealCmd = &cli.Command{ + Name: "pre-seal", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "miner-addr", + Value: "t01000", + Usage: "specify the future address of your miner", + }, + &cli.StringFlag{ + Name: "sector-size", + Value: "2KiB", + Usage: "specify size of sectors to pre-seal", + }, + &cli.StringFlag{ + Name: "ticket-preimage", + Value: "lotus is fire", + Usage: "set the ticket preimage for sealing randomness", + }, + &cli.IntFlag{ + Name: "num-sectors", + Value: 1, + Usage: "select number of sectors to pre-seal", + }, + &cli.Uint64Flag{ + Name: "sector-offset", + Value: 0, + Usage: "how many sector ids to skip when starting to seal", + }, + &cli.StringFlag{ + Name: "key", + Value: "", + Usage: "(optional) Key to use for signing / owner/worker addresses", + }, + &cli.BoolFlag{ + Name: "fake-sectors", + Value: false, + }, + }, + Action: func(c *cli.Context) error { + sdir := c.String("sector-dir") + sbroot, err := homedir.Expand(sdir) + if err != nil { + return err + } + + maddr, err := address.NewFromString(c.String("miner-addr")) + if err != nil { + return err + } + + var k *types.KeyInfo + if c.String("key") != "" { + k = new(types.KeyInfo) + kh, err := ioutil.ReadFile(c.String("key")) + if err != nil { + return err + } + kb, err := hex.DecodeString(string(kh)) + if err := json.Unmarshal(kb, k); err != nil { + return err + } + } + + sectorSizeInt, err := units.RAMInBytes(c.String("sector-size")) + if err != nil { + return err + } + sectorSize := abi.SectorSize(sectorSizeInt) + + rp, err := ffiwrapper.SealProofTypeFromSectorSize(sectorSize) + if err != nil { + return err + } + + gm, key, err := seed.PreSeal(maddr, rp, abi.SectorNumber(c.Uint64("sector-offset")), c.Int("num-sectors"), sbroot, []byte(c.String("ticket-preimage")), k, c.Bool("fake-sectors")) + if err != nil { + return err + } + + return seed.WriteGenesisMiner(maddr, sbroot, gm, key) + }, +} + +var aggregateManifestsCmd = &cli.Command{ + Name: "aggregate-manifests", + Usage: "aggregate a set of preseal manifests into a single file", + Action: func(cctx *cli.Context) error { + var inputs []map[string]genesis.Miner + for _, infi := range cctx.Args().Slice() { + fi, err := os.Open(infi) + if err != nil { + return err + } + var val map[string]genesis.Miner + if err := json.NewDecoder(fi).Decode(&val); err != nil { + return err + } + + inputs = append(inputs, val) + } + + output := make(map[string]genesis.Miner) + for _, in := range inputs { + for maddr, val := range in { + if gm, ok := output[maddr]; ok { + output[maddr] = mergeGenMiners(gm, val) + } else { + output[maddr] = val + } + } + } + + blob, err := json.MarshalIndent(output, "", " ") + if err != nil { + return err + } + + fmt.Println(string(blob)) + return nil + }, +} + +func mergeGenMiners(a, b genesis.Miner) genesis.Miner { + if a.SectorSize != b.SectorSize { + panic("sector sizes mismatch") + } + + return genesis.Miner{ + Owner: a.Owner, + Worker: a.Worker, + PeerId: a.PeerId, + MarketBalance: big.Zero(), + PowerBalance: big.Zero(), + SectorSize: a.SectorSize, + Sectors: append(a.Sectors, b.Sectors...), + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/seed/seed.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/seed/seed.go new file mode 100644 index 0000000000..beba39ae1f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-seed/seed/seed.go @@ -0,0 +1,271 @@ +package seed + +import ( + "context" + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/google/uuid" + logging "github.com/ipfs/go-log/v2" + ic "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/minio/blake2b-simd" + "golang.org/x/xerrors" + + ffi "github.com/filecoin-project/filecoin-ffi" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/sector-storage/zerocomm" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/crypto" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/genesis" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/sector-storage/ffiwrapper/basicfs" + "github.com/filecoin-project/sector-storage/stores" +) + +var log = logging.Logger("preseal") + +func PreSeal(maddr address.Address, spt abi.RegisteredSealProof, offset abi.SectorNumber, sectors int, sbroot string, preimage []byte, key *types.KeyInfo, fakeSectors bool) (*genesis.Miner, *types.KeyInfo, error) { + mid, err := address.IDFromAddress(maddr) + if err != nil { + return nil, nil, err + } + + cfg := &ffiwrapper.Config{ + SealProofType: spt, + } + + if err := os.MkdirAll(sbroot, 0775); err != nil { //nolint:gosec + return nil, nil, err + } + + next := offset + + sbfs := &basicfs.Provider{ + Root: sbroot, + } + + sb, err := ffiwrapper.New(sbfs, cfg) + if err != nil { + return nil, nil, err + } + + ssize, err := spt.SectorSize() + if err != nil { + return nil, nil, err + } + + var sealedSectors []*genesis.PreSeal + for i := 0; i < sectors; i++ { + sid := abi.SectorID{Miner: abi.ActorID(mid), Number: next} + next++ + + var preseal *genesis.PreSeal + if !fakeSectors { + preseal, err = presealSector(sb, sbfs, sid, spt, ssize, preimage) + if err != nil { + return nil, nil, err + } + } else { + preseal, err = presealSectorFake(sbfs, sid, spt, ssize) + if err != nil { + return nil, nil, err + } + } + + sealedSectors = append(sealedSectors, preseal) + } + + var minerAddr *wallet.Key + if key != nil { + minerAddr, err = wallet.NewKey(*key) + if err != nil { + return nil, nil, err + } + } else { + minerAddr, err = wallet.GenerateKey(crypto.SigTypeBLS) + if err != nil { + return nil, nil, err + } + } + + var pid peer.ID + { + log.Warn("PeerID not specified, generating dummy") + p, _, err := ic.GenerateEd25519Key(rand.Reader) + if err != nil { + return nil, nil, err + } + + pid, err = peer.IDFromPrivateKey(p) + if err != nil { + return nil, nil, err + } + } + + miner := &genesis.Miner{ + Owner: minerAddr.Address, + Worker: minerAddr.Address, + MarketBalance: big.Zero(), + PowerBalance: big.Zero(), + SectorSize: ssize, + Sectors: sealedSectors, + PeerId: pid, + } + + if err := createDeals(miner, minerAddr, maddr, ssize); err != nil { + return nil, nil, xerrors.Errorf("creating deals: %w", err) + } + + { + b, err := json.MarshalIndent(&stores.LocalStorageMeta{ + ID: stores.ID(uuid.New().String()), + Weight: 0, // read-only + CanSeal: false, + CanStore: false, + }, "", " ") + if err != nil { + return nil, nil, xerrors.Errorf("marshaling storage config: %w", err) + } + + if err := ioutil.WriteFile(filepath.Join(sbroot, "sectorstore.json"), b, 0644); err != nil { + return nil, nil, xerrors.Errorf("persisting storage metadata (%s): %w", filepath.Join(sbroot, "storage.json"), err) + } + } + + return miner, &minerAddr.KeyInfo, nil +} + +func presealSector(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, sid abi.SectorID, spt abi.RegisteredSealProof, ssize abi.SectorSize, preimage []byte) (*genesis.PreSeal, error) { + pi, err := sb.AddPiece(context.TODO(), sid, nil, abi.PaddedPieceSize(ssize).Unpadded(), rand.Reader) + if err != nil { + return nil, err + } + + trand := blake2b.Sum256(preimage) + ticket := abi.SealRandomness(trand[:]) + + fmt.Printf("sector-id: %d, piece info: %v\n", sid, pi) + + in2, err := sb.SealPreCommit1(context.TODO(), sid, ticket, []abi.PieceInfo{pi}) + if err != nil { + return nil, xerrors.Errorf("commit: %w", err) + } + + cids, err := sb.SealPreCommit2(context.TODO(), sid, in2) + if err != nil { + return nil, xerrors.Errorf("commit: %w", err) + } + + if err := sb.FinalizeSector(context.TODO(), sid, nil); err != nil { + return nil, xerrors.Errorf("trim cache: %w", err) + } + + if err := cleanupUnsealed(sbfs, sid); err != nil { + return nil, xerrors.Errorf("remove unsealed file: %w", err) + } + + log.Warn("PreCommitOutput: ", sid, cids.Sealed, cids.Unsealed) + + return &genesis.PreSeal{ + CommR: cids.Sealed, + CommD: cids.Unsealed, + SectorID: sid.Number, + ProofType: spt, + }, nil +} + +func presealSectorFake(sbfs *basicfs.Provider, sid abi.SectorID, spt abi.RegisteredSealProof, ssize abi.SectorSize) (*genesis.PreSeal, error) { + paths, done, err := sbfs.AcquireSector(context.TODO(), sid, 0, stores.FTSealed|stores.FTCache, true) + if err != nil { + return nil, xerrors.Errorf("acquire unsealed sector: %w", err) + } + defer done() + + if err := os.Mkdir(paths.Cache, 0755); err != nil { + return nil, xerrors.Errorf("mkdir cache: %w", err) + } + + commr, err := ffi.FauxRep(spt, paths.Cache, paths.Sealed) + if err != nil { + return nil, xerrors.Errorf("fauxrep: %w", err) + } + + return &genesis.PreSeal{ + CommR: commr, + CommD: zerocomm.ZeroPieceCommitment(abi.PaddedPieceSize(ssize).Unpadded()), + SectorID: sid.Number, + ProofType: spt, + }, nil +} + +func cleanupUnsealed(sbfs *basicfs.Provider, sid abi.SectorID) error { + paths, done, err := sbfs.AcquireSector(context.TODO(), sid, stores.FTUnsealed, stores.FTNone, stores.PathSealing) + if err != nil { + return err + } + defer done() + + return os.Remove(paths.Unsealed) +} + +func WriteGenesisMiner(maddr address.Address, sbroot string, gm *genesis.Miner, key *types.KeyInfo) error { + output := map[string]genesis.Miner{ + maddr.String(): *gm, + } + + out, err := json.MarshalIndent(output, "", " ") + if err != nil { + return err + } + + log.Infof("Writing preseal manifest to %s", filepath.Join(sbroot, "pre-seal-"+maddr.String()+".json")) + + if err := ioutil.WriteFile(filepath.Join(sbroot, "pre-seal-"+maddr.String()+".json"), out, 0664); err != nil { + return err + } + + if key != nil { + b, err := json.Marshal(key) + if err != nil { + return err + } + + // TODO: allow providing key + if err := ioutil.WriteFile(filepath.Join(sbroot, "pre-seal-"+maddr.String()+".key"), []byte(hex.EncodeToString(b)), 0664); err != nil { + return err + } + } + + return nil +} + +func createDeals(m *genesis.Miner, k *wallet.Key, maddr address.Address, ssize abi.SectorSize) error { + for _, sector := range m.Sectors { + proposal := &market.DealProposal{ + PieceCID: sector.CommD, + PieceSize: abi.PaddedPieceSize(ssize), + Client: k.Address, + Provider: maddr, + StartEpoch: 0, + EndEpoch: 9001, + StoragePricePerEpoch: big.Zero(), + ProviderCollateral: big.Zero(), + ClientCollateral: big.Zero(), + } + + sector.Deal = *proposal + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base16.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base16.go new file mode 100644 index 0000000000..adfdfeddba --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base16.go @@ -0,0 +1,52 @@ +package main + +import ( + "encoding/hex" + "fmt" + "io" + "io/ioutil" + "os" + "strings" + + "github.com/urfave/cli/v2" +) + +var base16Cmd = &cli.Command{ + Name: "base16", + Description: "standard hex", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "decode", + Value: false, + Usage: "Decode the value", + }, + }, + Action: func(cctx *cli.Context) error { + var input io.Reader + + if cctx.Args().Len() == 0 { + input = os.Stdin + } else { + input = strings.NewReader(cctx.Args().First()) + } + + bytes, err := ioutil.ReadAll(input) + if err != nil { + return nil + } + + if cctx.Bool("decode") { + decoded, err := hex.DecodeString(strings.TrimSpace(string(bytes))) + if err != nil { + return err + } + + fmt.Println(string(decoded)) + } else { + encoded := hex.EncodeToString(bytes) + fmt.Println(encoded) + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base32.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base32.go new file mode 100644 index 0000000000..cd30a21465 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/base32.go @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "strings" + + "github.com/urfave/cli/v2" + + "github.com/multiformats/go-base32" +) + +var base32Cmd = &cli.Command{ + Name: "base32", + Description: "multiformats base32", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "decode", + Value: false, + Usage: "Decode the multiformats base32", + }, + }, + Action: func(cctx *cli.Context) error { + var input io.Reader + + if cctx.Args().Len() == 0 { + input = os.Stdin + } else { + input = strings.NewReader(cctx.Args().First()) + } + + bytes, err := ioutil.ReadAll(input) + if err != nil { + return nil + } + + if cctx.Bool("decode") { + decoded, err := base32.RawStdEncoding.DecodeString(strings.TrimSpace(string(bytes))) + if err != nil { + return err + } + + fmt.Println(string(decoded)) + } else { + encoded := base32.RawStdEncoding.EncodeToString(bytes) + fmt.Println(encoded) + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bigint.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bigint.go new file mode 100644 index 0000000000..e087a341a5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bigint.go @@ -0,0 +1,47 @@ +package main + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/urfave/cli/v2" +) + +var bigIntParseCmd = &cli.Command{ + Name: "bigint", + Description: "parse encoded big ints", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Action: func(cctx *cli.Context) error { + val := cctx.Args().Get(0) + + var dec []byte + switch cctx.String("enc") { + case "base64": + d, err := base64.StdEncoding.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding base64 value: %w", err) + } + dec = d + case "hex": + d, err := hex.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding hex value: %w", err) + } + dec = d + default: + return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc")) + } + + iv := types.BigFromBytes(dec) + fmt.Println(iv.String()) + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bitfield.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bitfield.go new file mode 100644 index 0000000000..79ce214eee --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/bitfield.go @@ -0,0 +1,245 @@ +package main + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + "io/ioutil" + "os" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-bitfield" + rlepluslazy "github.com/filecoin-project/go-bitfield/rle" +) + +var bitFieldCmd = &cli.Command{ + Name: "bitfield", + Description: "analyze bitfields", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Subcommands: []*cli.Command{ + bitFieldRunsCmd, + bitFieldStatCmd, + bitFieldDecodeCmd, + }, +} + +var bitFieldRunsCmd = &cli.Command{ + Name: "runs", + Description: "print bit runs in a bitfield", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Action: func(cctx *cli.Context) error { + var val string + if cctx.Args().Present() { + val = cctx.Args().Get(0) + } else { + b, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return err + } + val = string(b) + } + + var dec []byte + switch cctx.String("enc") { + case "base64": + d, err := base64.StdEncoding.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding base64 value: %w", err) + } + dec = d + case "hex": + d, err := hex.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding hex value: %w", err) + } + dec = d + default: + return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc")) + } + + rle, err := rlepluslazy.FromBuf(dec) + if err != nil { + return xerrors.Errorf("opening rle: %w", err) + } + + rit, err := rle.RunIterator() + if err != nil { + return xerrors.Errorf("getting run iterator: %w", err) + } + var idx uint64 + for rit.HasNext() { + r, err := rit.NextRun() + if err != nil { + return xerrors.Errorf("next run: %w", err) + } + if !r.Valid() { + fmt.Print("!INVALID ") + } + s := "TRUE " + if !r.Val { + s = "FALSE" + } + + fmt.Printf("@%d %s * %d\n", idx, s, r.Len) + + idx += r.Len + } + + return nil + }, +} + +var bitFieldStatCmd = &cli.Command{ + Name: "stat", + Description: "print bitfield stats", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Action: func(cctx *cli.Context) error { + var val string + if cctx.Args().Present() { + val = cctx.Args().Get(0) + } else { + b, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return err + } + val = string(b) + } + + var dec []byte + switch cctx.String("enc") { + case "base64": + d, err := base64.StdEncoding.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding base64 value: %w", err) + } + dec = d + case "hex": + d, err := hex.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding hex value: %w", err) + } + dec = d + default: + return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc")) + } + + rle, err := rlepluslazy.FromBuf(dec) + if err != nil { + return xerrors.Errorf("opening rle: %w", err) + } + + rit, err := rle.RunIterator() + if err != nil { + return xerrors.Errorf("getting run iterator: %w", err) + } + + fmt.Printf("Raw length: %d bits (%d bytes)\n", len(dec)*8, len(dec)) + + var ones, zeros, oneRuns, zeroRuns, invalid uint64 + + for rit.HasNext() { + r, err := rit.NextRun() + if err != nil { + return xerrors.Errorf("next run: %w", err) + } + if !r.Valid() { + invalid++ + } + if r.Val { + ones += r.Len + oneRuns++ + } else { + zeros += r.Len + zeroRuns++ + } + } + + if _, err := rle.Count(); err != nil { // check overflows + fmt.Println("Error: ", err) + } + + fmt.Printf("Decoded length: %d bits\n", ones+zeros) + fmt.Printf("\tOnes: %d\n", ones) + fmt.Printf("\tZeros: %d\n", zeros) + fmt.Printf("Runs: %d\n", oneRuns+zeroRuns) + fmt.Printf("\tOne Runs: %d\n", oneRuns) + fmt.Printf("\tZero Runs: %d\n", zeroRuns) + fmt.Printf("Invalid runs: %d\n", invalid) + return nil + }, +} + +var bitFieldDecodeCmd = &cli.Command{ + Name: "decode", + Description: "decode bitfield and print all numbers in it", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "enc", + Value: "base64", + Usage: "specify input encoding to parse", + }, + }, + Action: func(cctx *cli.Context) error { + var val string + if cctx.Args().Present() { + val = cctx.Args().Get(0) + } else { + b, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return err + } + val = string(b) + } + + var dec []byte + switch cctx.String("enc") { + case "base64": + d, err := base64.StdEncoding.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding base64 value: %w", err) + } + dec = d + case "hex": + d, err := hex.DecodeString(val) + if err != nil { + return fmt.Errorf("decoding hex value: %w", err) + } + dec = d + default: + return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc")) + } + + rle, err := bitfield.NewFromBytes(dec) + if err != nil { + return xerrors.Errorf("failed to parse bitfield: %w", err) + } + + vals, err := rle.All(100000000000) + if err != nil { + return xerrors.Errorf("getting all items: %w", err) + } + fmt.Println(vals) + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/commp.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/commp.go new file mode 100644 index 0000000000..9b0cab75df --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/commp.go @@ -0,0 +1,27 @@ +package main + +import ( + "encoding/hex" + "fmt" + + commcid "github.com/filecoin-project/go-fil-commcid" + "github.com/urfave/cli/v2" +) + +var commpToCidCmd = &cli.Command{ + Name: "commp-to-cid", + Description: "Convert a raw commP to a piece-Cid", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must specify commP to convert") + } + + dec, err := hex.DecodeString(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to decode input as hex string: %w", err) + } + + fmt.Println(commcid.PieceCommitmentV1ToCID(dec)) + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/import-car.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/import-car.go new file mode 100644 index 0000000000..e54089df08 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/import-car.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "io" + "os" + + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/ipld/go-car" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/node/repo" +) + +var importCarCmd = &cli.Command{ + Name: "import-car", + Description: "Import a car file into node chain blockstore", + Action: func(cctx *cli.Context) error { + r, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return xerrors.Errorf("opening fs repo: %w", err) + } + + exists, err := r.Exists() + if err != nil { + return err + } + if !exists { + return xerrors.Errorf("lotus repo doesn't exist") + } + + lr, err := r.Lock(repo.FullNode) + if err != nil { + return err + } + defer lr.Close() //nolint:errcheck + + cf := cctx.Args().Get(0) + f, err := os.OpenFile(cf, os.O_RDONLY, 0664) + if err != nil { + return xerrors.Errorf("opening the car file: %w", err) + } + + ds, err := lr.Datastore("/chain") + if err != nil { + return err + } + + bs := blockstore.NewBlockstore(ds) + bs = blockstore.NewIdStore(bs) + + cr, err := car.NewCarReader(f) + if err != nil { + return err + } + + for { + blk, err := cr.Next() + switch err { + case io.EOF: + if err := f.Close(); err != nil { + return err + } + fmt.Println() + return ds.Close() + default: + fmt.Println() + return err + case nil: + fmt.Printf("\r%s", blk.Cid()) + if err := bs.Put(blk); err != nil { + return xerrors.Errorf("put %s: %w", blk.Cid(), err) + } + } + } + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/keyinfo.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/keyinfo.go new file mode 100644 index 0000000000..028ead4131 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/keyinfo.go @@ -0,0 +1,365 @@ +package main + +import ( + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "strings" + "text/template" + + "github.com/urfave/cli/v2" + + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/node/modules/lp2p" + "github.com/filecoin-project/lotus/node/repo" + + _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/secp" +) + +var validTypes = []string{wallet.KTBLS, wallet.KTSecp256k1, lp2p.KTLibp2pHost} + +type keyInfoOutput struct { + Type string + Address string + PublicKey string +} + +var keyinfoCmd = &cli.Command{ + Name: "keyinfo", + Usage: "work with lotus keyinfo files (wallets and libp2p host keys)", + Description: `The subcommands of keyinfo provide helpful tools for working with keyinfo files without + having to run the lotus daemon.`, + Subcommands: []*cli.Command{ + keyinfoNewCmd, + keyinfoInfoCmd, + keyinfoImportCmd, + }, +} + +var keyinfoImportCmd = &cli.Command{ + Name: "import", + Usage: "import a keyinfo file into a lotus repository", + Description: `The import command provides a way to import keyfiles into a lotus repository + without running the daemon. + + Note: The LOTUS_PATH directory must be created. This command will not create this directory for you. + + Examples + + env LOTUS_PATH=/var/lib/lotus lotus-shed keyinfo import libp2p-host.keyinfo`, + Action: func(cctx *cli.Context) error { + flagRepo := cctx.String("repo") + + var input io.Reader + if cctx.Args().Len() == 0 { + input = os.Stdin + } else { + var err error + input, err = os.Open(cctx.Args().First()) + if err != nil { + return err + } + } + + encoded, err := ioutil.ReadAll(input) + if err != nil { + return err + } + + decoded, err := hex.DecodeString(strings.TrimSpace(string(encoded))) + if err != nil { + return err + } + + var keyInfo types.KeyInfo + if err := json.Unmarshal(decoded, &keyInfo); err != nil { + return err + } + + fsrepo, err := repo.NewFS(flagRepo) + if err != nil { + return err + } + + lkrepo, err := fsrepo.Lock(repo.FullNode) + if err != nil { + return err + } + + defer lkrepo.Close() + + keystore, err := lkrepo.KeyStore() + if err != nil { + return err + } + + switch keyInfo.Type { + case lp2p.KTLibp2pHost: + if err := keystore.Put(lp2p.KLibp2pHost, keyInfo); err != nil { + return err + } + + sk, err := crypto.UnmarshalPrivateKey(keyInfo.PrivateKey) + if err != nil { + return err + } + + peerid, err := peer.IDFromPrivateKey(sk) + if err != nil { + return err + } + + fmt.Printf("%s\n", peerid.String()) + + break + case wallet.KTSecp256k1, wallet.KTBLS: + w, err := wallet.NewWallet(keystore) + if err != nil { + return err + } + + addr, err := w.Import(&keyInfo) + if err != nil { + return err + } + + fmt.Printf("%s\n", addr.String()) + } + + return nil + }, +} + +var keyinfoInfoCmd = &cli.Command{ + Name: "info", + Usage: "print information about a keyinfo file", + Description: `The info command prints additional information about a key which can't easily + be retrieved by inspecting the file itself. + + The 'format' flag takes a golang text/template template as its value. + + The following fields can be retrived through this command + Type + Address + PublicKey + + The PublicKey value will be printed base64 encoded using golangs StdEncoding + + Examples + + Retreive the address of a lotus wallet + lotus-shed keyinfo info --format '{{ .Address }}' wallet.keyinfo + `, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "format", + Value: "{{ .Type }} {{ .Address }}", + Usage: "specify which output columns to print", + }, + }, + Action: func(cctx *cli.Context) error { + format := cctx.String("format") + + var input io.Reader + if cctx.Args().Len() == 0 { + input = os.Stdin + } else { + var err error + input, err = os.Open(cctx.Args().First()) + if err != nil { + return err + } + } + + encoded, err := ioutil.ReadAll(input) + if err != nil { + return err + } + + decoded, err := hex.DecodeString(strings.TrimSpace(string(encoded))) + if err != nil { + return err + } + + var keyInfo types.KeyInfo + if err := json.Unmarshal(decoded, &keyInfo); err != nil { + return err + } + + var kio keyInfoOutput + + switch keyInfo.Type { + case lp2p.KTLibp2pHost: + kio.Type = keyInfo.Type + + sk, err := crypto.UnmarshalPrivateKey(keyInfo.PrivateKey) + if err != nil { + return err + } + + pk := sk.GetPublic() + + peerid, err := peer.IDFromPrivateKey(sk) + if err != nil { + return err + } + + pkBytes, err := pk.Raw() + if err != nil { + return err + } + + kio.Address = peerid.String() + kio.PublicKey = base64.StdEncoding.EncodeToString(pkBytes) + + break + case wallet.KTSecp256k1, wallet.KTBLS: + kio.Type = keyInfo.Type + + key, err := wallet.NewKey(keyInfo) + if err != nil { + return err + } + + kio.Address = key.Address.String() + kio.PublicKey = base64.StdEncoding.EncodeToString(key.PublicKey) + } + + tmpl, err := template.New("output").Parse(format) + if err != nil { + return err + } + + return tmpl.Execute(os.Stdout, kio) + }, +} + +var keyinfoNewCmd = &cli.Command{ + Name: "new", + Usage: "create a new keyinfo file of the provided type", + ArgsUsage: "[bls|secp256k1|libp2p-host]", + Description: `Keyinfo files are base16 encoded json structures containing a type + string value, and a base64 encoded private key. + + Both the bls and secp256k1 keyfiles can be imported into a running lotus daemon using + the 'lotus wallet import' command. Or imported to a non-running / unitialized repo using + the 'lotus-shed keyinfo import' command. Libp2p host keys can only be imported using lotus-shed + as lotus itself does not provide this functionality at the moment.`, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Value: "-.keyinfo", + Usage: "output file formt", + }, + &cli.BoolFlag{ + Name: "silent", + Value: false, + Usage: "do not print the address to stdout", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("please specify a type to generate") + } + + keyType := cctx.Args().First() + flagOutput := cctx.String("output") + + if i := SliceIndex(len(validTypes), func(i int) bool { + if keyType == validTypes[i] { + return true + } + return false + }); i == -1 { + return fmt.Errorf("invalid key type argument provided '%s'", keyType) + } + + keystore := wallet.NewMemKeyStore() + + var keyAddr string + var keyInfo types.KeyInfo + + switch keyType { + case lp2p.KTLibp2pHost: + sk, err := lp2p.PrivKey(keystore) + if err != nil { + return err + } + + ki, err := keystore.Get(lp2p.KLibp2pHost) + if err != nil { + return err + } + + peerid, err := peer.IDFromPrivateKey(sk) + if err != nil { + return err + } + + keyAddr = peerid.String() + keyInfo = ki + + break + case wallet.KTSecp256k1, wallet.KTBLS: + key, err := wallet.GenerateKey(wallet.ActSigType(keyType)) + if err != nil { + return err + } + + keyAddr = key.Address.String() + keyInfo = key.KeyInfo + + break + } + + filename := flagOutput + filename = strings.ReplaceAll(filename, "", keyAddr) + filename = strings.ReplaceAll(filename, "", keyType) + + file, err := os.Create(filename) + if err != nil { + return err + } + + defer func() { + if err := file.Close(); err != nil { + log.Warnf("failed to close output file: %w", err) + } + }() + + bytes, err := json.Marshal(keyInfo) + if err != nil { + return err + } + + encoded := hex.EncodeToString(bytes) + if _, err := file.Write([]byte(encoded)); err != nil { + return err + } + + if !cctx.Bool("silent") { + fmt.Println(keyAddr) + } + + return nil + }, +} + +func SliceIndex(length int, fn func(i int) bool) int { + for i := 0; i < length; i++ { + if fn(i) { + return i + } + } + + return -1 +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/main.go new file mode 100644 index 0000000000..c37b93a421 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "os" + + logging "github.com/ipfs/go-log/v2" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/build" +) + +var log = logging.Logger("lotus-shed") + +func main() { + logging.SetLogLevel("*", "INFO") + + local := []*cli.Command{ + base32Cmd, + base16Cmd, + bitFieldCmd, + keyinfoCmd, + noncefix, + bigIntParseCmd, + staterootStatsCmd, + importCarCmd, + commpToCidCmd, + fetchParamCmd, + proofsCmd, + verifRegCmd, + } + + app := &cli.App{ + Name: "lotus-shed", + Usage: "A place for all the lotus tools", + Version: build.BuildVersion, + Commands: local, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + }, + } + + if err := app.Run(os.Args); err != nil { + log.Warnf("%+v", err) + os.Exit(1) + return + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/nonce-fix.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/nonce-fix.go new file mode 100644 index 0000000000..4fb30300ab --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/nonce-fix.go @@ -0,0 +1,109 @@ +package main + +import ( + "fmt" + "math" + + "github.com/filecoin-project/go-address" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var noncefix = &cli.Command{ + Name: "noncefix", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + &cli.Uint64Flag{ + Name: "start", + }, + &cli.Uint64Flag{ + Name: "end", + }, + &cli.StringFlag{ + Name: "addr", + }, + &cli.BoolFlag{ + Name: "auto", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + addr, err := address.NewFromString(cctx.String("addr")) + if err != nil { + return err + } + + start := cctx.Uint64("start") + end := cctx.Uint64("end") + if end == 0 { + end = math.MaxUint64 + } + + if cctx.Bool("auto") { + a, err := api.StateGetActor(ctx, addr, types.EmptyTSK) + if err != nil { + return err + } + start = a.Nonce + + msgs, err := api.MpoolPending(ctx, types.EmptyTSK) + if err != nil { + return err + } + + for _, msg := range msgs { + if msg.Message.From != addr { + continue + } + if msg.Message.Nonce < start { + continue // past + } + if msg.Message.Nonce < end { + end = msg.Message.Nonce + } + } + + } + if end == math.MaxUint64 { + fmt.Println("No nonce gap found or no --end flag specified") + return nil + } + fmt.Printf("Creating %d filler messages (%d ~ %d)\n", end-start, start, end) + + for i := start; i < end; i++ { + msg := &types.Message{ + From: addr, + To: addr, + Value: types.NewInt(1), + GasLimit: 10000, + GasPrice: types.NewInt(1), + Nonce: i, + } + smsg, err := api.WalletSignMessage(ctx, addr, msg) + if err != nil { + return err + } + + _, err = api.MpoolPush(ctx, smsg) + if err != nil { + return err + } + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/params.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/params.go new file mode 100644 index 0000000000..3f7e7b6fb7 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/params.go @@ -0,0 +1,35 @@ +package main + +import ( + "github.com/docker/go-units" + paramfetch "github.com/filecoin-project/go-paramfetch" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/build" +) + +var fetchParamCmd = &cli.Command{ + Name: "fetch-params", + Usage: "Fetch proving parameters", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "proving-params", + Usage: "download params used creating proofs for given size, i.e. 32GiB", + }, + }, + Action: func(cctx *cli.Context) error { + sectorSizeInt, err := units.RAMInBytes(cctx.String("proving-params")) + if err != nil { + return err + } + sectorSize := uint64(sectorSizeInt) + err = paramfetch.GetParams(lcli.ReqContext(cctx), build.ParametersJSON(), sectorSize) + if err != nil { + return xerrors.Errorf("fetching proof parameters: %w", err) + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/proofs.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/proofs.go new file mode 100644 index 0000000000..f18dc93fb1 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/proofs.go @@ -0,0 +1,108 @@ +package main + +import ( + "encoding/hex" + "fmt" + + "github.com/urfave/cli/v2" + + ffi "github.com/filecoin-project/filecoin-ffi" + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/ipfs/go-cid" +) + +var proofsCmd = &cli.Command{ + Name: "proofs", + Subcommands: []*cli.Command{ + verifySealProofCmd, + }, +} + +var verifySealProofCmd = &cli.Command{ + Name: "verify-seal", + ArgsUsage: " ", + Description: "Verify a seal proof with manual inputs", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "ticket", + }, + &cli.StringFlag{ + Name: "proof-rand", + }, + &cli.StringFlag{ + Name: "miner", + }, + &cli.Uint64Flag{ + Name: "sector-id", + }, + &cli.Int64Flag{ + Name: "proof-type", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 3 { + return fmt.Errorf("must specify commR, commD, and proof to verify") + } + + commr, err := cid.Decode(cctx.Args().Get(0)) + if err != nil { + return err + } + + commd, err := cid.Decode(cctx.Args().Get(1)) + if err != nil { + return err + } + + proof, err := hex.DecodeString(cctx.Args().Get(2)) + if err != nil { + return fmt.Errorf("failed to decode hex proof input: %w", err) + } + + maddr, err := address.NewFromString(cctx.String("miner")) + if err != nil { + return err + } + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return err + } + + ticket, err := hex.DecodeString(cctx.String("ticket")) + if err != nil { + return err + } + + proofRand, err := hex.DecodeString(cctx.String("proof-rand")) + if err != nil { + return err + } + + snum := abi.SectorNumber(cctx.Uint64("sector-id")) + + ok, err := ffi.VerifySeal(abi.SealVerifyInfo{ + SectorID: abi.SectorID{ + Miner: abi.ActorID(mid), + Number: snum, + }, + SealedCID: commr, + SealProof: abi.RegisteredSealProof(cctx.Int64("proof-type")), + Proof: proof, + DealIDs: nil, + Randomness: abi.SealRandomness(ticket), + InteractiveRandomness: abi.InteractiveSealRandomness(proofRand), + UnsealedCID: commd, + }) + if err != nil { + return err + } + if !ok { + return fmt.Errorf("invalid proof") + } + + fmt.Println("proof valid!") + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/stateroot-stats.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/stateroot-stats.go new file mode 100644 index 0000000000..0546e53150 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/stateroot-stats.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + + "github.com/urfave/cli/v2" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var staterootStatsCmd = &cli.Command{ + Name: "stateroot-stats", + Description: "Walk down the chain and collect stats-obj changes between tipsets", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "tipset", + Usage: "specify tipset to start from", + }, + &cli.IntFlag{ + Name: "count", + Usage: "number of tipsets to count back", + Value: 30, + }, + &cli.BoolFlag{ + Name: "diff", + Usage: "compare tipset with previous", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + ts, err := lcli.LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + + if ts == nil { + ts, err = api.ChainHead(ctx) + if err != nil { + return err + } + } + + fn := func(ts *types.TipSet) (cid.Cid, []cid.Cid) { + blk := ts.Blocks()[0] + strt := blk.ParentStateRoot + cids := blk.Parents + + return strt, cids + } + + count := cctx.Int("count") + diff := cctx.Bool("diff") + + fmt.Printf("Height\tSize\tLinks\tObj\tBase\n") + for i := 0; i < count; i++ { + if ts.Height() == 0 { + return nil + } + strt, cids := fn(ts) + + k := types.NewTipSetKey(cids...) + ts, err = api.ChainGetTipSet(ctx, k) + if err != nil { + return err + } + + pstrt, _ := fn(ts) + + if !diff { + pstrt = cid.Undef + } + + stats, err := api.ChainStatObj(ctx, strt, pstrt) + if err != nil { + return err + } + + fmt.Printf("%d\t%d\t%d\t%s\t%s\n", ts.Height(), stats.Size, stats.Links, strt, pstrt) + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/verifreg.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/verifreg.go new file mode 100644 index 0000000000..a448fcaf96 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-shed/verifreg.go @@ -0,0 +1,378 @@ +package main + +import ( + "bytes" + "fmt" + "github.com/filecoin-project/lotus/build" + + "github.com/filecoin-project/go-address" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + + "github.com/filecoin-project/lotus/api/apibstore" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + "github.com/ipfs/go-hamt-ipld" + cbor "github.com/ipfs/go-ipld-cbor" + + cbg "github.com/whyrusleeping/cbor-gen" +) + +var verifRegCmd = &cli.Command{ + Name: "verifreg", + Usage: "Interact with the verified registry actor", + Flags: []cli.Flag{}, + Subcommands: []*cli.Command{ + verifRegAddVerifierCmd, + verifRegVerifyClientCmd, + verifRegListVerifiersCmd, + verifRegListClientsCmd, + verifRegCheckClientCmd, + verifRegCheckVerifierCmd, + }, +} + +var verifRegAddVerifierCmd = &cli.Command{ + Name: "add-verifier", + Usage: "make a given account a verifier", + Action: func(cctx *cli.Context) error { + fromk, err := address.NewFromString("t3qfoulel6fy6gn3hjmbhpdpf6fs5aqjb5fkurhtwvgssizq4jey5nw4ptq5up6h7jk7frdvvobv52qzmgjinq") + if err != nil { + return err + } + + if cctx.Args().Len() != 2 { + return fmt.Errorf("must specify two arguments: address and allowance") + } + + target, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + allowance, err := types.BigFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + params, err := actors.SerializeParams(&verifreg.AddVerifierParams{Address: target, Allowance: allowance}) + if err != nil { + return err + } + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + msg := &types.Message{ + To: builtin.VerifiedRegistryActorAddr, + From: fromk, + Method: builtin.MethodsVerifiedRegistry.AddVerifier, + GasPrice: types.NewInt(1), + GasLimit: 300000, + Params: params, + } + + smsg, err := api.MpoolPushMessage(ctx, msg) + if err != nil { + return err + } + + fmt.Printf("message sent, now waiting on cid: %s\n", smsg.Cid()) + + mwait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return err + } + + if mwait.Receipt.ExitCode != 0 { + return fmt.Errorf("failed to add verifier: %d", mwait.Receipt.ExitCode) + } + + return nil + + }, +} + +var verifRegVerifyClientCmd = &cli.Command{ + Name: "verify-client", + Usage: "make a given account a verified client", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "specify your verifier address to send the message from", + }, + }, + Action: func(cctx *cli.Context) error { + froms := cctx.String("from") + if froms == "" { + return fmt.Errorf("must specify from address with --from") + } + + fromk, err := address.NewFromString(froms) + if err != nil { + return err + } + + if cctx.Args().Len() != 2 { + return fmt.Errorf("must specify two arguments: address and allowance") + } + + target, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + allowance, err := types.BigFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + params, err := actors.SerializeParams(&verifreg.AddVerifiedClientParams{Address: target, Allowance: allowance}) + if err != nil { + return err + } + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + msg := &types.Message{ + To: builtin.VerifiedRegistryActorAddr, + From: fromk, + Method: builtin.MethodsVerifiedRegistry.AddVerifiedClient, + GasPrice: types.NewInt(1), + GasLimit: 300000, + Params: params, + } + + smsg, err := api.MpoolPushMessage(ctx, msg) + if err != nil { + return err + } + + fmt.Printf("message sent, now waiting on cid: %s\n", smsg.Cid()) + + mwait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return err + } + + if mwait.Receipt.ExitCode != 0 { + return fmt.Errorf("failed to add verified client: %d", mwait.Receipt.ExitCode) + } + + return nil + }, +} + +var verifRegListVerifiersCmd = &cli.Command{ + Name: "list-verifiers", + Usage: "list all verifiers", + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + act, err := api.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + if err != nil { + return err + } + + apibs := apibstore.NewAPIBlockstore(api) + cst := cbor.NewCborStore(apibs) + + var st verifreg.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + return err + } + + vh, err := hamt.LoadNode(ctx, cst, st.Verifiers) + if err != nil { + return err + } + + if err := vh.ForEach(ctx, func(k string, val interface{}) error { + addr, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + + var dcap verifreg.DataCap + + if err := dcap.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { + return err + } + + fmt.Printf("%s: %s\n", addr, dcap) + + return nil + }); err != nil { + return err + } + + return nil + }, +} + +var verifRegListClientsCmd = &cli.Command{ + Name: "list-clients", + Usage: "list all verified clients", + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + act, err := api.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + if err != nil { + return err + } + + apibs := apibstore.NewAPIBlockstore(api) + cst := cbor.NewCborStore(apibs) + + var st verifreg.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + return err + } + + vh, err := hamt.LoadNode(ctx, cst, st.VerifiedClients) + if err != nil { + return err + } + + if err := vh.ForEach(ctx, func(k string, val interface{}) error { + addr, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + + var dcap verifreg.DataCap + + if err := dcap.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { + return err + } + + fmt.Printf("%s: %s\n", addr, dcap) + + return nil + }); err != nil { + return err + } + + return nil + }, +} + +var verifRegCheckClientCmd = &cli.Command{ + Name: "check-client", + Usage: "check verified client remaining bytes", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must specify client address to check") + } + + caddr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + act, err := api.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + if err != nil { + return err + } + + apibs := apibstore.NewAPIBlockstore(api) + cst := cbor.NewCborStore(apibs) + + var st verifreg.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + return err + } + + vh, err := hamt.LoadNode(ctx, cst, st.VerifiedClients) + if err != nil { + return err + } + + var dcap verifreg.DataCap + if err := vh.Find(ctx, string(caddr.Bytes()), &dcap); err != nil { + return err + } + + fmt.Println(dcap) + + return nil + }, +} + +var verifRegCheckVerifierCmd = &cli.Command{ + Name: "check-verifier", + Usage: "check verifiers remaining bytes", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must specify verifier address to check") + } + + vaddr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + act, err := api.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + if err != nil { + return err + } + + apibs := apibstore.NewAPIBlockstore(api) + cst := cbor.NewCborStore(apibs) + + var st verifreg.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + return err + } + + vh, err := hamt.LoadNode(ctx, cst, st.Verifiers) + if err != nil { + return err + } + + var dcap verifreg.DataCap + if err := vh.Find(ctx, string(vaddr.Bytes()), &dcap); err != nil { + return err + } + + fmt.Println(dcap) + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/README.md b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/README.md new file mode 100644 index 0000000000..04220aa3bd --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/README.md @@ -0,0 +1,39 @@ +# lotus-stats + +`lotus-stats` is a small tool to push chain information into influxdb + +## Setup + +Influx configuration can be configured through env variables. + +``` +INFLUX_ADDR="http://localhost:8086" +INFLUX_USER="" +INFLUX_PASS="" +``` + +## Usage + +lotus-stats will be default look in `~/.lotus` to connect to a running daemon and resume collecting stats from last record block height. + +For other usage see `./lotus-stats --help` + +``` +go build -o lotus-stats *.go +. env.stats && ./lotus-stats +``` + + +## Development + +Start grafana and influxdb containers and import the dashboard to grafana. +The url of the imported dashboard will be returned. + +If the script doesn't work, you can manually setup the datasource and import the dashboard. + +``` +docker-compose up -d +./setup.bash +``` + +The default username and password for grafana are both `admin`. diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/chain.dashboard.json b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/chain.dashboard.json new file mode 100644 index 0000000000..5ff7654d01 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/chain.dashboard.json @@ -0,0 +1,2533 @@ +{ + "__inputs": [ + { + "name": "DS_INFLUXDB", + "label": "InfluxDB", + "description": "", + "type": "datasource", + "pluginId": "influxdb", + "pluginName": "InfluxDB" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "6.5.0-pre" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "influxdb", + "name": "InfluxDB", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "decimals": 2, + "fill": 3, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "hideTimeOverride": false, + "id": 38, + "interval": "", + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_miner", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "miner" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "chain.election", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT count(\"value\") FROM \"chain.election\" WHERE $timeFilter -10m GROUP BY time($__interval), \"miner\" fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "count" + }, + { + "params": [ + "20" + ], + "type": "moving_average" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Blocks Won", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "decimals": null, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 9 + }, + "id": 22, + "interval": "", + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/.*/", + "color": "rgb(31, 120, 193)" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "groupBy": [], + "measurement": "chain.power", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": "4h", + "timeRegions": [], + "timeShift": null, + "title": "Total Power", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 9 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": 0 + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [], + "measurement": "chain.blocktime", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT difference(mean(\"value\")) FROM \"chain.blocktime\" WHERE $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "difference" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Avg Blocktime", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 9 + }, + "id": 42, + "interval": "", + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": 0 + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT sum(\"value\") FROM \"chain.miner_power\" WHERE $timeFilter GROUP BY time(45s)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Network Storage", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 9 + }, + "id": 6, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": 0 + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + } + ], + "measurement": "chain.election", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Blocks In Tipset", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorPostfix": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 13 + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [], + "measurement": "chain.height", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Block Height", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 13 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": 0 + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [], + "measurement": "chain.blocktime", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "difference" + } + ] + ], + "tags": [] + } + ], + "thresholds": "30,90", + "timeFrom": null, + "timeShift": null, + "title": "Last Blocktime", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 13 + }, + "id": 32, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "chain.message_gasprice", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Avg Gas Price", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "decbytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 13 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "chain.message_size", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Avg Message Size", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 13 + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": 0 + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "chain.blockheader_size", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "1024,2048", + "timeFrom": null, + "timeShift": null, + "title": "Avg Blockheader Size", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 13 + }, + "id": 10, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "pluginVersion": "6.4.2", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": 0 + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "chain.message_count", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"value\" FROM \"chain.message_count\" WHERE $timeFilter ", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Avg Messages in Tipset", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "decimals": 0, + "format": "dateTimeFromNow", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 16 + }, + "id": 16, + "interval": "", + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [], + "measurement": "chain.blocktime", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [ + "*1000" + ], + "type": "math" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Head Updated", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 3, + "w": 16, + "x": 4, + "y": 16 + }, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Null Blocks", + "yaxis": 2 + }, + { + "alias": "Block Time", + "color": "rgb(31, 120, 193)" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Block Time", + "groupBy": [], + "measurement": "chain.blocktime", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT difference(\"value\") FROM \"chain.blocktime\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "difference" + } + ] + ], + "tags": [] + }, + { + "alias": "Null Blocks", + "groupBy": [], + "measurement": "chain.height", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "difference" + }, + { + "params": [ + "-1" + ], + "type": "math" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Tipsets", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": "Time between tipsets", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": "Number of Null blocks", + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "${DS_INFLUXDB}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 16 + }, + "id": 30, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "FIL", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true, + "ymax": null, + "ymin": null + }, + "tableColumn": "", + "targets": [ + { + "groupBy": [], + "measurement": "chain.pledge_collateral", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Pledge Collateral", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "${DS_INFLUXDB}", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 4, + "x": 0, + "y": 19 + }, + "id": 28, + "options": {}, + "pageSize": null, + "showHeader": true, + "sort": { + "col": 1, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "power", + "thresholds": [], + "type": "number", + "unit": "bytes" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "groupBy": [], + "measurement": "chain.miner_power", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT top(\"value\", \"miner\", 20) as \"power\" FROM \"chain.miner_power\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Top Power Table", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "fill": 5, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 4, + "y": 19 + }, + "id": 40, + "interval": "", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": true, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_miner", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "miner" + ], + "type": "tag" + }, + { + "params": [ + "previous" + ], + "type": "fill" + } + ], + "limit": "", + "measurement": "chain.miner_power", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"chain.miner_power\" WHERE $timeFilter GROUP BY time($__interval), \"miner\" fill(previous)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [ + "\"miner\",20" + ], + "type": "top" + } + ] + ], + "slimit": "", + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Top Miner Power", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "bytes", + "label": "Power", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "${DS_INFLUXDB}", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 8, + "x": 16, + "y": 19 + }, + "id": 18, + "options": {}, + "pageSize": null, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Height", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "mappingType": 1, + "pattern": "chain.height", + "preserveFormat": false, + "sanitize": false, + "type": "string" + }, + { + "alias": "Tipset", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "chain.height.tipset", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "mappingType": 1, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "groupBy": [], + "measurement": "chain.height", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"value\", \"tipset\" FROM \"chain.height\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Chain Table", + "transform": "timeseries_to_columns", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 4, + "y": 27 + }, + "id": 24, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/.*/", + "color": "rgb(31, 120, 193)" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "previous" + ], + "type": "fill" + } + ], + "measurement": "chain.pledge_collateral", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pledge Collateral", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "FIL", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "cacheTimeout": null, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 4, + "y": 33 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "previous" + ], + "type": "fill" + } + ], + "measurement": "chain.miner_power", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT count(\"value\") FROM \"chain.miner_power\" WHERE $timeFilter GROUP BY time($__interval)", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "count" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Miners on Chain", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 34, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Adr $tag_actor | Md $tag_method", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "actor" + ], + "type": "tag" + }, + { + "params": [ + "method" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "chain.message_count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Actor Messages Method", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB}", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 36, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "avg", + "sortDesc": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Adr $tag_actor | Md $tag_method | Ex $tag_exitcode", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "method" + ], + "type": "tag" + }, + { + "params": [ + "exitcode" + ], + "type": "tag" + }, + { + "params": [ + "actor" + ], + "type": "tag" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "chain.message_count", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT sum(\"value\") FROM \"chain.message_count\" WHERE $timeFilter GROUP BY time($__interval), \"method\", \"exitcode\", \"actor\" fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "count" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Actor Messages Method With Exitcode", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "45s", + "schemaVersion": 20, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "45s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Chain", + "uid": "z6FtI92Zz", + "version": 9 +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/docker-compose.yml b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/docker-compose.yml new file mode 100644 index 0000000000..03d573b94a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3' + +services: + influxdb: + image: influxdb:latest + container_name: influxdb + environment: + - INFLUXDB_DB=lotus + ports: + - "8086:8086" + volumes: + - influxdb:/var/lib/influxdb + + grafana: + image: grafana/grafana:latest + container_name: grafana + ports: + - "3000:3000" + links: + - influxdb + volumes: + - grafana:/var/lib/grafana + +volumes: + influxdb: + grafana: diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/env.stats b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/env.stats new file mode 100644 index 0000000000..a76e7554aa --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/env.stats @@ -0,0 +1,3 @@ +export INFLUX_ADDR="http://localhost:8086" +export INFLUX_USER="" +export INFLUX_PASS="" diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/main.go new file mode 100644 index 0000000000..ddc33b7ac4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "context" + "flag" + "os" + + "github.com/filecoin-project/lotus/tools/stats" + logging "github.com/ipfs/go-log/v2" +) + +var log = logging.Logger("stats") + +const ( + influxAddrEnvVar = "INFLUX_ADDR" + influxUserEnvVar = "INFLUX_USER" + influxPassEnvVar = "INFLUX_PASS" +) + +func main() { + var repo string = "~/.lotus" + var database string = "lotus" + var reset bool = false + var nosync bool = false + var height int64 = 0 + var headlag int = 3 + + flag.StringVar(&repo, "repo", repo, "lotus repo path") + flag.StringVar(&database, "database", database, "influx database") + flag.Int64Var(&height, "height", height, "block height to start syncing from (0 will resume)") + flag.IntVar(&headlag, "head-lag", headlag, "number of head events to hold to protect against small reorgs") + flag.BoolVar(&reset, "reset", reset, "truncate database before starting stats gathering") + flag.BoolVar(&nosync, "nosync", nosync, "skip waiting for sync") + + flag.Parse() + + ctx := context.Background() + + influx, err := stats.InfluxClient(os.Getenv(influxAddrEnvVar), os.Getenv(influxUserEnvVar), os.Getenv(influxPassEnvVar)) + if err != nil { + log.Fatal(err) + } + + if reset { + if err := stats.ResetDatabase(influx, database); err != nil { + log.Fatal(err) + } + } + + if !reset && height == 0 { + h, err := stats.GetLastRecordedHeight(influx, database) + if err != nil { + log.Info(err) + } + + height = h + } + + api, closer, err := stats.GetFullNodeAPI(repo) + if err != nil { + log.Fatal(err) + } + defer closer() + + if !nosync { + if err := stats.WaitForSyncComplete(ctx, api); err != nil { + log.Fatal(err) + } + } + + stats.Collect(ctx, api, influx, database, height, headlag) +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/setup.bash b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/setup.bash new file mode 100755 index 0000000000..e2812b93a6 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-stats/setup.bash @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +GRAFANA_HOST="localhost:3000" + +curl -s -XPOST http://admin:admin@$GRAFANA_HOST/api/datasources -H 'Content-Type: text/json' --data-binary @- > /dev/null << EOF +{ + "name":"InfluxDB", + "type":"influxdb", + "database":"lotus", + "url": "http://influxdb:8086", + "basicAuth":false, + "access": "proxy" +} +EOF + +curl -s -XPOST http://admin:admin@$GRAFANA_HOST/api/dashboards/import -H 'Content-Type: text/json' --data-binary @- << EOF | jq -r "\"http://$GRAFANA_HOST\" + .importedUrl" +{ + "dashboard": $(cat ./chain.dashboard.json), + "overwrite": true, + "inputs": [ + { + "name": "DS_INFLUXDB", + "pluginId": "influxdb", + "type": "datasource", + "value": "InfluxDB" + } + ] +} +EOF diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/actor.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/actor.go new file mode 100644 index 0000000000..44eb7a0e4a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/actor.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + + ma "github.com/multiformats/go-multiaddr" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var actorCmd = &cli.Command{ + Name: "actor", + Usage: "manipulate the miner actor", + Subcommands: []*cli.Command{ + actorSetAddrsCmd, + }, +} + +var actorSetAddrsCmd = &cli.Command{ + Name: "set-addrs", + Usage: "set addresses that your miner can be publically dialed on", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "gas-limit", + Usage: "set gas limit", + Value: 100000, + }, + }, + Action: func(cctx *cli.Context) error { + nodeAPI, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + var addrs []abi.Multiaddrs + for _, a := range cctx.Args().Slice() { + maddr, err := ma.NewMultiaddr(a) + if err != nil { + return fmt.Errorf("failed to parse %q as a multiaddr: %w", a, err) + } + + addrs = append(addrs, maddr.Bytes()) + } + + maddr, err := nodeAPI.ActorAddress(ctx) + if err != nil { + return err + } + + minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + params, err := actors.SerializeParams(&miner.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) + if err != nil { + return err + } + + gasLimit := cctx.Int64("gas-limit") + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + To: maddr, + From: minfo.Worker, + Value: types.NewInt(0), + GasPrice: types.NewInt(1), + GasLimit: gasLimit, + Method: 18, + Params: params, + }) + if err != nil { + return err + } + + fmt.Printf("Requested multiaddrs change in message %s\n", smsg.Cid()) + return nil + + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/info.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/info.go new file mode 100644 index 0000000000..4e54252bcd --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/info.go @@ -0,0 +1,250 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "sort" + "time" + + "github.com/fatih/color" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + sealing "github.com/filecoin-project/storage-fsm" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var infoCmd = &cli.Command{ + Name: "info", + Usage: "Print storage miner info", + Flags: []cli.Flag{ + &cli.BoolFlag{Name: "color"}, + }, + Action: func(cctx *cli.Context) error { + color.NoColor = !cctx.Bool("color") + + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := nodeApi.ActorAddress(ctx) + if err != nil { + return err + } + + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + var mas miner.State + { + rmas, err := api.ChainReadObj(ctx, mact.Head) + if err != nil { + return err + } + if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { + return err + } + } + + fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) + + // Sector size + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + fmt.Printf("Sector Size: %s\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize)))) + + pow, err := api.StateMinerPower(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + rpercI := types.BigDiv(types.BigMul(pow.MinerPower.RawBytePower, types.NewInt(1000000)), pow.TotalPower.RawBytePower) + qpercI := types.BigDiv(types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(1000000)), pow.TotalPower.QualityAdjPower) + + fmt.Printf("Byte Power: %s / %s (%0.4f%%)\n", + color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)), + types.SizeStr(pow.TotalPower.RawBytePower), + float64(rpercI.Int64())/10000) + + fmt.Printf("Actual Power: %s / %s (%0.4f%%)\n", + color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)), + types.DeciStr(pow.TotalPower.QualityAdjPower), + float64(qpercI.Int64())/10000) + + secCounts, err := api.StateMinerSectorCount(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + faults, err := api.StateMinerFaults(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + nfaults, err := faults.Count() + if err != nil { + return xerrors.Errorf("counting faults: %w", err) + } + + fmt.Printf("\tCommitted: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Sset), types.NewInt(uint64(mi.SectorSize))))) + if nfaults == 0 { + fmt.Printf("\tProving: %s\n", types.SizeStr(types.BigMul(types.NewInt(secCounts.Pset), types.NewInt(uint64(mi.SectorSize))))) + } else { + var faultyPercentage float64 + if secCounts.Sset != 0 { + faultyPercentage = float64(10000*nfaults/secCounts.Sset) / 100. + } + fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n", + types.SizeStr(types.BigMul(types.NewInt(secCounts.Pset), types.NewInt(uint64(mi.SectorSize)))), + types.SizeStr(types.BigMul(types.NewInt(nfaults), types.NewInt(uint64(mi.SectorSize)))), + faultyPercentage) + } + + if pow.MinerPower.RawBytePower.LessThan(power.ConsensusMinerMinPower) { + fmt.Print("Below minimum power threshold, no blocks will be won") + } else { + expWinChance := float64(types.BigMul(qpercI, types.NewInt(build.BlocksPerEpoch)).Int64()) / 1000000 + if expWinChance > 0 { + if expWinChance > 1 { + expWinChance = 1 + } + winRate := time.Duration(float64(time.Second*time.Duration(build.BlockDelaySecs)) / expWinChance) + winPerDay := float64(time.Hour*24) / float64(winRate) + + fmt.Print("Expected block win rate: ") + color.Blue("%.4f/day (every %s)", winPerDay, winRate.Truncate(time.Second)) + } + } + + fmt.Println() + + fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance))) + fmt.Printf("\tPreCommit: %s\n", types.FIL(mas.PreCommitDeposits)) + fmt.Printf("\tLocked: %s\n", types.FIL(mas.LockedFunds)) + color.Green("\tAvailable: %s", types.FIL(types.BigSub(mact.Balance, types.BigAdd(mas.LockedFunds, mas.PreCommitDeposits)))) + wb, err := api.WalletBalance(ctx, mi.Worker) + if err != nil { + return xerrors.Errorf("getting worker balance: %w", err) + } + color.Cyan("Worker Balance: %s", types.FIL(wb)) + + mb, err := api.StateMarketBalance(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting market balance: %w", err) + } + fmt.Printf("Market (Escrow): %s\n", types.FIL(mb.Escrow)) + fmt.Printf("Market (Locked): %s\n", types.FIL(mb.Locked)) + + fmt.Println() + + fmt.Println("Sectors:") + err = sectorsInfo(ctx, nodeApi) + if err != nil { + return err + } + + // TODO: grab actr state / info + // * Sealed sectors (count / bytes) + // * Power + return nil + }, +} + +type stateMeta struct { + i int + col color.Attribute + state sealing.SectorState +} + +var stateOrder = map[sealing.SectorState]stateMeta{} +var stateList = []stateMeta{ + {col: 39, state: "Total"}, + {col: color.FgGreen, state: sealing.Proving}, + + {col: color.FgRed, state: sealing.UndefinedSectorState}, + {col: color.FgYellow, state: sealing.Empty}, + {col: color.FgYellow, state: sealing.Packing}, + {col: color.FgYellow, state: sealing.PreCommit1}, + {col: color.FgYellow, state: sealing.PreCommit2}, + {col: color.FgYellow, state: sealing.PreCommitting}, + {col: color.FgYellow, state: sealing.PreCommitWait}, + {col: color.FgYellow, state: sealing.WaitSeed}, + {col: color.FgYellow, state: sealing.Committing}, + {col: color.FgYellow, state: sealing.CommitWait}, + {col: color.FgYellow, state: sealing.FinalizeSector}, + + {col: color.FgRed, state: sealing.FailedUnrecoverable}, + {col: color.FgRed, state: sealing.SealPreCommit1Failed}, + {col: color.FgRed, state: sealing.SealPreCommit2Failed}, + {col: color.FgRed, state: sealing.PreCommitFailed}, + {col: color.FgRed, state: sealing.ComputeProofFailed}, + {col: color.FgRed, state: sealing.CommitFailed}, + {col: color.FgRed, state: sealing.PackingFailed}, + {col: color.FgRed, state: sealing.FinalizeFailed}, + {col: color.FgRed, state: sealing.Faulty}, + {col: color.FgRed, state: sealing.FaultReported}, + {col: color.FgRed, state: sealing.FaultedFinal}, +} + +func init() { + for i, state := range stateList { + stateOrder[state.state] = stateMeta{ + i: i, + col: state.col, + } + } +} + +func sectorsInfo(ctx context.Context, napi api.StorageMiner) error { + sectors, err := napi.SectorsList(ctx) + if err != nil { + return err + } + + buckets := map[sealing.SectorState]int{ + "Total": len(sectors), + } + for _, s := range sectors { + st, err := napi.SectorsStatus(ctx, s) + if err != nil { + return err + } + + buckets[sealing.SectorState(st.State)]++ + } + + var sorted []stateMeta + for state, i := range buckets { + sorted = append(sorted, stateMeta{i: i, state: state}) + } + + sort.Slice(sorted, func(i, j int) bool { + return stateOrder[sorted[i].state].i < stateOrder[sorted[j].state].i + }) + + for _, s := range sorted { + _, _ = color.New(stateOrder[s.state].col).Printf("\t%s: %d\n", s.state, s.i) + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/init.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/init.go new file mode 100644 index 0000000000..14972c69a0 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/init.go @@ -0,0 +1,669 @@ +package main + +import ( + "bytes" + "context" + "crypto/rand" + "encoding/binary" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + + "github.com/docker/go-units" + "github.com/google/uuid" + "github.com/ipfs/go-datastore" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + cborutil "github.com/filecoin-project/go-cbor-util" + paramfetch "github.com/filecoin-project/go-paramfetch" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/sector-storage/stores" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + crypto2 "github.com/filecoin-project/specs-actors/actors/crypto" + + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/genesis" + "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/storage" + sealing "github.com/filecoin-project/storage-fsm" +) + +var initCmd = &cli.Command{ + Name: "init", + Usage: "Initialize a lotus storage miner repo", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "actor", + Usage: "specify the address of an already created miner actor", + }, + &cli.BoolFlag{ + Name: "genesis-miner", + Usage: "enable genesis mining (DON'T USE ON BOOTSTRAPPED NETWORK)", + Hidden: true, + }, + &cli.BoolFlag{ + Name: "create-worker-key", + Usage: "create separate worker key", + }, + &cli.StringFlag{ + Name: "worker", + Aliases: []string{"w"}, + Usage: "worker key to use (overrides --create-worker-key)", + }, + &cli.StringFlag{ + Name: "owner", + Aliases: []string{"o"}, + Usage: "owner key to use", + }, + &cli.StringFlag{ + Name: "sector-size", + Usage: "specify sector size to use", + Value: units.BytesSize(float64(build.DefaultSectorSize())), + }, + &cli.StringSliceFlag{ + Name: "pre-sealed-sectors", + Usage: "specify set of presealed sectors for starting as a genesis miner", + }, + &cli.StringFlag{ + Name: "pre-sealed-metadata", + Usage: "specify the metadata file for the presealed sectors", + }, + &cli.BoolFlag{ + Name: "nosync", + Usage: "don't check full-node sync status", + }, + &cli.BoolFlag{ + Name: "symlink-imported-sectors", + Usage: "attempt to symlink to presealed sectors instead of copying them into place", + }, + &cli.BoolFlag{ + Name: "no-local-storage", + Usage: "don't use storageminer repo for sector storage", + }, + &cli.StringFlag{ + Name: "gas-price", + Usage: "set gas price for initialization messages in AttoFIL", + Value: "0", + }, + }, + Action: func(cctx *cli.Context) error { + log.Info("Initializing lotus storage miner") + + sectorSizeInt, err := units.RAMInBytes(cctx.String("sector-size")) + if err != nil { + return err + } + ssize := abi.SectorSize(sectorSizeInt) + + gasPrice, err := types.BigFromString(cctx.String("gas-price")) + if err != nil { + return xerrors.Errorf("failed to parse gas-price flag: %s", err) + } + + symlink := cctx.Bool("symlink-imported-sectors") + if symlink { + log.Info("will attempt to symlink to imported sectors") + } + + ctx := lcli.ReqContext(cctx) + + log.Info("Checking proof parameters") + + if err := paramfetch.GetParams(ctx, build.ParametersJSON(), uint64(ssize)); err != nil { + return xerrors.Errorf("fetching proof parameters: %w", err) + } + + log.Info("Trying to connect to full node RPC") + + api, closer, err := lcli.GetFullNodeAPI(cctx) // TODO: consider storing full node address in config + if err != nil { + return err + } + defer closer() + + log.Info("Checking full node sync status") + + if !cctx.Bool("genesis-miner") && !cctx.Bool("nosync") { + if err := lcli.SyncWait(ctx, api); err != nil { + return xerrors.Errorf("sync wait: %w", err) + } + } + + log.Info("Checking if repo exists") + + repoPath := cctx.String(FlagStorageRepo) + r, err := repo.NewFS(repoPath) + if err != nil { + return err + } + + ok, err := r.Exists() + if err != nil { + return err + } + if ok { + return xerrors.Errorf("repo at '%s' is already initialized", cctx.String(FlagStorageRepo)) + } + + log.Info("Checking full node version") + + v, err := api.Version(ctx) + if err != nil { + return err + } + + if !v.APIVersion.EqMajorMinor(build.APIVersion) { + return xerrors.Errorf("Remote API version didn't match (local %s, remote %s)", build.APIVersion, v.APIVersion) + } + + log.Info("Initializing repo") + + if err := r.Init(repo.StorageMiner); err != nil { + return err + } + + { + lr, err := r.Lock(repo.StorageMiner) + if err != nil { + return err + } + + var localPaths []stores.LocalPath + + if pssb := cctx.StringSlice("pre-sealed-sectors"); len(pssb) != 0 { + log.Infof("Setting up storage config with presealed sectors: %v", pssb) + + for _, psp := range pssb { + psp, err := homedir.Expand(psp) + if err != nil { + return err + } + localPaths = append(localPaths, stores.LocalPath{ + Path: psp, + }) + } + } + + if !cctx.Bool("no-local-storage") { + b, err := json.MarshalIndent(&stores.LocalStorageMeta{ + ID: stores.ID(uuid.New().String()), + Weight: 10, + CanSeal: true, + CanStore: true, + }, "", " ") + if err != nil { + return xerrors.Errorf("marshaling storage config: %w", err) + } + + if err := ioutil.WriteFile(filepath.Join(lr.Path(), "sectorstore.json"), b, 0644); err != nil { + return xerrors.Errorf("persisting storage metadata (%s): %w", filepath.Join(lr.Path(), "sectorstore.json"), err) + } + + localPaths = append(localPaths, stores.LocalPath{ + Path: lr.Path(), + }) + } + + if err := lr.SetStorage(func(sc *stores.StorageConfig) { + sc.StoragePaths = append(sc.StoragePaths, localPaths...) + }); err != nil { + return xerrors.Errorf("set storage config: %w", err) + } + + if err := lr.Close(); err != nil { + return err + } + } + + if err := storageMinerInit(ctx, cctx, api, r, ssize, gasPrice); err != nil { + log.Errorf("Failed to initialize lotus-storage-miner: %+v", err) + path, err := homedir.Expand(repoPath) + if err != nil { + return err + } + log.Infof("Cleaning up %s after attempt...", path) + if err := os.RemoveAll(path); err != nil { + log.Errorf("Failed to clean up failed storage repo: %s", err) + } + return xerrors.Errorf("Storage-miner init failed") + } + + // TODO: Point to setting storage price, maybe do it interactively or something + log.Info("Storage miner successfully created, you can now start it with 'lotus-storage-miner run'") + + return nil + }, +} + +func migratePreSealMeta(ctx context.Context, api lapi.FullNode, metadata string, maddr address.Address, mds dtypes.MetadataDS) error { + metadata, err := homedir.Expand(metadata) + if err != nil { + return xerrors.Errorf("expanding preseal dir: %w", err) + } + + b, err := ioutil.ReadFile(metadata) + if err != nil { + return xerrors.Errorf("reading preseal metadata: %w", err) + } + + psm := map[string]genesis.Miner{} + if err := json.Unmarshal(b, &psm); err != nil { + return xerrors.Errorf("unmarshaling preseal metadata: %w", err) + } + + meta, ok := psm[maddr.String()] + if !ok { + return xerrors.Errorf("preseal file didn't contain metadata for miner %s", maddr) + } + + maxSectorID := abi.SectorNumber(0) + for _, sector := range meta.Sectors { + sectorKey := datastore.NewKey(sealing.SectorStorePrefix).ChildString(fmt.Sprint(sector.SectorID)) + + dealID, err := findMarketDealID(ctx, api, sector.Deal) + if err != nil { + return xerrors.Errorf("finding storage deal for pre-sealed sector %d: %w", sector.SectorID, err) + } + commD := sector.CommD + commR := sector.CommR + + info := &sealing.SectorInfo{ + State: sealing.Proving, + SectorNumber: sector.SectorID, + Pieces: []sealing.Piece{ + { + Piece: abi.PieceInfo{ + Size: abi.PaddedPieceSize(meta.SectorSize), + PieceCID: commD, + }, + DealInfo: &sealing.DealInfo{ + DealID: dealID, + DealSchedule: sealing.DealSchedule{ + StartEpoch: sector.Deal.StartEpoch, + EndEpoch: sector.Deal.EndEpoch, + }, + }, + }, + }, + CommD: &commD, + CommR: &commR, + Proof: nil, + TicketValue: abi.SealRandomness{}, + TicketEpoch: 0, + PreCommitMessage: nil, + SeedValue: abi.InteractiveSealRandomness{}, + SeedEpoch: 0, + CommitMessage: nil, + } + + b, err := cborutil.Dump(info) + if err != nil { + return err + } + + if err := mds.Put(sectorKey, b); err != nil { + return err + } + + if sector.SectorID > maxSectorID { + maxSectorID = sector.SectorID + } + + /* // TODO: Import deals into market + pnd, err := cborutil.AsIpld(sector.Deal) + if err != nil { + return err + } + + dealKey := datastore.NewKey(deals.ProviderDsPrefix).ChildString(pnd.Cid().String()) + + deal := &deals.MinerDeal{ + MinerDeal: storagemarket.MinerDeal{ + ClientDealProposal: sector.Deal, + ProposalCid: pnd.Cid(), + State: storagemarket.StorageDealActive, + Ref: &storagemarket.DataRef{Root: proposalCid}, // TODO: This is super wrong, but there + // are no params for CommP CIDs, we can't recover unixfs cid easily, + // and this isn't even used after the deal enters Complete state + DealID: dealID, + }, + } + + b, err = cborutil.Dump(deal) + if err != nil { + return err + } + + if err := mds.Put(dealKey, b); err != nil { + return err + }*/ + } + + log.Infof("Setting next sector ID to %d", maxSectorID+1) + + buf := make([]byte, binary.MaxVarintLen64) + size := binary.PutUvarint(buf, uint64(maxSectorID+1)) + return mds.Put(datastore.NewKey(modules.StorageCounterDSPrefix), buf[:size]) +} + +func findMarketDealID(ctx context.Context, api lapi.FullNode, deal market.DealProposal) (abi.DealID, error) { + // TODO: find a better way + // (this is only used by genesis miners) + + deals, err := api.StateMarketDeals(ctx, types.EmptyTSK) + if err != nil { + return 0, xerrors.Errorf("getting market deals: %w", err) + } + + for k, v := range deals { + if v.Proposal.PieceCID.Equals(deal.PieceCID) { + id, err := strconv.ParseUint(k, 10, 64) + return abi.DealID(id), err + } + } + + return 0, xerrors.New("deal not found") +} + +func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode, r repo.Repo, ssize abi.SectorSize, gasPrice types.BigInt) error { + lr, err := r.Lock(repo.StorageMiner) + if err != nil { + return err + } + defer lr.Close() //nolint:errcheck + + log.Info("Initializing libp2p identity") + + p2pSk, err := makeHostKey(lr) + if err != nil { + return xerrors.Errorf("make host key: %w", err) + } + + peerid, err := peer.IDFromPrivateKey(p2pSk) + if err != nil { + return xerrors.Errorf("peer ID from private key: %w", err) + } + + mds, err := lr.Datastore("/metadata") + if err != nil { + return err + } + + var addr address.Address + if act := cctx.String("actor"); act != "" { + a, err := address.NewFromString(act) + if err != nil { + return xerrors.Errorf("failed parsing actor flag value (%q): %w", act, err) + } + + if cctx.Bool("genesis-miner") { + if err := mds.Put(datastore.NewKey("miner-address"), a.Bytes()); err != nil { + return err + } + + spt, err := ffiwrapper.SealProofTypeFromSectorSize(ssize) + if err != nil { + return err + } + + mid, err := address.IDFromAddress(a) + if err != nil { + return xerrors.Errorf("getting id address: %w", err) + } + + sa, err := modules.StorageAuth(ctx, api) + if err != nil { + return err + } + + smgr, err := sectorstorage.New(ctx, lr, stores.NewIndex(), &ffiwrapper.Config{ + SealProofType: spt, + }, sectorstorage.SealerConfig{true, true, true, true}, nil, sa) + if err != nil { + return err + } + epp, err := storage.NewWinningPoStProver(api, smgr, ffiwrapper.ProofVerifier, dtypes.MinerID(mid)) + if err != nil { + return err + } + + m := miner.NewMiner(api, epp, a) + { + if err := m.Start(ctx); err != nil { + return xerrors.Errorf("failed to start up genesis miner: %w", err) + } + + cerr := configureStorageMiner(ctx, api, a, peerid, gasPrice) + + if err := m.Stop(ctx); err != nil { + log.Error("failed to shut down storage miner: ", err) + } + + if cerr != nil { + return xerrors.Errorf("failed to configure storage miner: %w", cerr) + } + } + + if pssb := cctx.String("pre-sealed-metadata"); pssb != "" { + pssb, err := homedir.Expand(pssb) + if err != nil { + return err + } + + log.Infof("Importing pre-sealed sector metadata for %s", a) + + if err := migratePreSealMeta(ctx, api, pssb, a, mds); err != nil { + return xerrors.Errorf("migrating presealed sector metadata: %w", err) + } + } + + return nil + } + + if pssb := cctx.String("pre-sealed-metadata"); pssb != "" { + pssb, err := homedir.Expand(pssb) + if err != nil { + return err + } + + log.Infof("Importing pre-sealed sector metadata for %s", a) + + if err := migratePreSealMeta(ctx, api, pssb, a, mds); err != nil { + return xerrors.Errorf("migrating presealed sector metadata: %w", err) + } + } + + if err := configureStorageMiner(ctx, api, a, peerid, gasPrice); err != nil { + return xerrors.Errorf("failed to configure storage miner: %w", err) + } + + addr = a + } else { + a, err := createStorageMiner(ctx, api, peerid, gasPrice, cctx) + if err != nil { + return xerrors.Errorf("creating miner failed: %w", err) + } + + addr = a + } + + log.Infof("Created new storage miner: %s", addr) + if err := mds.Put(datastore.NewKey("miner-address"), addr.Bytes()); err != nil { + return err + } + + return nil +} + +func makeHostKey(lr repo.LockedRepo) (crypto.PrivKey, error) { + pk, _, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + return nil, err + } + + ks, err := lr.KeyStore() + if err != nil { + return nil, err + } + + kbytes, err := pk.Bytes() + if err != nil { + return nil, err + } + + if err := ks.Put("libp2p-host", types.KeyInfo{ + Type: "libp2p-host", + PrivateKey: kbytes, + }); err != nil { + return nil, err + } + + return pk, nil +} + +func configureStorageMiner(ctx context.Context, api lapi.FullNode, addr address.Address, peerid peer.ID, gasPrice types.BigInt) error { + mi, err := api.StateMinerInfo(ctx, addr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getWorkerAddr returned bad address: %w", err) + } + + enc, err := actors.SerializeParams(&miner2.ChangePeerIDParams{NewID: abi.PeerID(peerid)}) + if err != nil { + return err + } + + msg := &types.Message{ + To: addr, + From: mi.Worker, + Method: builtin.MethodsMiner.ChangePeerID, + Params: enc, + Value: types.NewInt(0), + GasPrice: gasPrice, + GasLimit: 99999999, + } + + smsg, err := api.MpoolPushMessage(ctx, msg) + if err != nil { + return err + } + + log.Info("Waiting for message: ", smsg.Cid()) + ret, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return err + } + + if ret.Receipt.ExitCode != 0 { + return xerrors.Errorf("update peer id message failed with exit code %d", ret.Receipt.ExitCode) + } + + return nil +} + +func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID, gasPrice types.BigInt, cctx *cli.Context) (address.Address, error) { + log.Info("Creating StorageMarket.CreateStorageMiner message") + + var err error + var owner address.Address + if cctx.String("owner") != "" { + owner, err = address.NewFromString(cctx.String("owner")) + } else { + owner, err = api.WalletDefaultAddress(ctx) + } + if err != nil { + return address.Undef, err + } + + ssize, err := units.RAMInBytes(cctx.String("sector-size")) + if err != nil { + return address.Undef, fmt.Errorf("failed to parse sector size: %w", err) + } + + worker := owner + if cctx.String("worker") != "" { + worker, err = address.NewFromString(cctx.String("worker")) + } else if cctx.Bool("create-worker-key") { // TODO: Do we need to force this if owner is Secpk? + worker, err = api.WalletNew(ctx, crypto2.SigTypeBLS) + } + // TODO: Transfer some initial funds to worker + if err != nil { + return address.Undef, err + } + + collateral, err := api.StatePledgeCollateral(ctx, types.EmptyTSK) + if err != nil { + return address.Undef, err + } + + spt, err := ffiwrapper.SealProofTypeFromSectorSize(abi.SectorSize(ssize)) + if err != nil { + return address.Undef, err + } + + params, err := actors.SerializeParams(&power.CreateMinerParams{ + Owner: owner, + Worker: worker, + SealProofType: spt, + Peer: abi.PeerID(peerid), + }) + if err != nil { + return address.Undef, err + } + + createStorageMinerMsg := &types.Message{ + To: builtin.StoragePowerActorAddr, + From: owner, + Value: types.BigAdd(collateral, types.BigDiv(collateral, types.NewInt(100))), + + Method: builtin.MethodsPower.CreateMiner, + Params: params, + + GasLimit: 10000000, + GasPrice: gasPrice, + } + + signed, err := api.MpoolPushMessage(ctx, createStorageMinerMsg) + if err != nil { + return address.Undef, err + } + + log.Infof("Pushed StorageMarket.CreateStorageMiner, %s to Mpool", signed.Cid()) + log.Infof("Waiting for confirmation") + + mw, err := api.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence) + if err != nil { + return address.Undef, err + } + + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode) + } + + var retval power.CreateMinerReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { + return address.Undef, err + } + + log.Infof("New storage miners address is: %s (%s)", retval.IDAddress, retval.RobustAddress) + return retval.IDAddress, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/main.go new file mode 100644 index 0000000000..62efe9370f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/main.go @@ -0,0 +1,87 @@ +package main + +import ( + "os" + + logging "github.com/ipfs/go-log/v2" + "github.com/urfave/cli/v2" + "go.opencensus.io/trace" + + "github.com/filecoin-project/lotus/build" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/lotuslog" + "github.com/filecoin-project/lotus/lib/tracing" + "github.com/filecoin-project/lotus/node/repo" +) + +var log = logging.Logger("main") + +const FlagStorageRepo = "storagerepo" + +func main() { + lotuslog.SetupLogLevels() + + local := []*cli.Command{ + actorCmd, + storageDealsCmd, + retrievalDealsCmd, + infoCmd, + initCmd, + rewardsCmd, + runCmd, + stopCmd, + sectorsCmd, + storageCmd, + workersCmd, + provingCmd, + } + jaeger := tracing.SetupJaegerTracing("lotus") + defer func() { + if jaeger != nil { + jaeger.Flush() + } + }() + + for _, cmd := range local { + cmd := cmd + originBefore := cmd.Before + cmd.Before = func(cctx *cli.Context) error { + trace.UnregisterExporter(jaeger) + jaeger = tracing.SetupJaegerTracing("lotus/" + cmd.Name) + + if originBefore != nil { + return originBefore(cctx) + } + return nil + } + } + + app := &cli.App{ + Name: "lotus-storage-miner", + Usage: "Filecoin decentralized storage network storage miner", + Version: build.UserVersion(), + EnableBashCompletion: true, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + &cli.StringFlag{ + Name: FlagStorageRepo, + EnvVars: []string{"LOTUS_STORAGE_PATH"}, + Value: "~/.lotusstorage", // TODO: Consider XDG_DATA_HOME + }, + }, + + Commands: append(local, lcli.CommonCommands...), + } + app.Setup() + app.Metadata["repoType"] = repo.StorageMiner + + if err := app.Run(os.Args); err != nil { + log.Warnf("%+v", err) + os.Exit(1) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/market.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/market.go new file mode 100644 index 0000000000..4a82d51625 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/market.go @@ -0,0 +1,449 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + "path/filepath" + "text/tabwriter" + "time" + + "github.com/docker/go-units" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-cidutil/cidenc" + "github.com/multiformats/go-multibase" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/specs-actors/actors/abi" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var CidBaseFlag = cli.StringFlag{ + Name: "cid-base", + Hidden: true, + Value: "base32", + Usage: "Multibase encoding used for version 1 CIDs in output.", + DefaultText: "base32", +} + +// GetCidEncoder returns an encoder using the `cid-base` flag if provided, or +// the default (Base32) encoder if not. +func GetCidEncoder(cctx *cli.Context) (cidenc.Encoder, error) { + val := cctx.String("cid-base") + + e := cidenc.Encoder{Base: multibase.MustNewEncoder(multibase.Base32)} + + if val != "" { + var err error + e.Base, err = multibase.EncoderByName(val) + if err != nil { + return e, err + } + } + + return e, nil +} + +var storageDealSelectionCmd = &cli.Command{ + Name: "selection", + Usage: "Configure acceptance criteria for storage deal proposals", + Subcommands: []*cli.Command{ + storageDealSelectionShowCmd, + storageDealSelectionResetCmd, + storageDealSelectionRejectCmd, + }, +} + +var storageDealSelectionShowCmd = &cli.Command{ + Name: "list", + Usage: "List storage deal proposal selection criteria", + Action: func(cctx *cli.Context) error { + smapi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + onlineOk, err := smapi.DealsConsiderOnlineStorageDeals(lcli.DaemonContext(cctx)) + if err != nil { + return err + } + + offlineOk, err := smapi.DealsConsiderOfflineStorageDeals(lcli.DaemonContext(cctx)) + if err != nil { + return err + } + + fmt.Printf("considering online storage deals: %t\n", onlineOk) + fmt.Printf("considering offline storage deals: %t\n", offlineOk) + + return nil + }, +} + +var storageDealSelectionResetCmd = &cli.Command{ + Name: "reset", + Usage: "Reset storage deal proposal selection criteria to default values", + Action: func(cctx *cli.Context) error { + smapi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + err = smapi.DealsSetConsiderOnlineStorageDeals(lcli.DaemonContext(cctx), true) + if err != nil { + return err + } + + err = smapi.DealsSetConsiderOfflineStorageDeals(lcli.DaemonContext(cctx), true) + if err != nil { + return err + } + + return nil + }, +} + +var storageDealSelectionRejectCmd = &cli.Command{ + Name: "reject", + Usage: "Configure criteria which necessitate automatic rejection", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "online", + }, + &cli.BoolFlag{ + Name: "offline", + }, + }, + Action: func(cctx *cli.Context) error { + smapi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + if cctx.Bool("online") { + err = smapi.DealsSetConsiderOnlineStorageDeals(lcli.DaemonContext(cctx), false) + if err != nil { + return err + } + } + + if cctx.Bool("offline") { + err = smapi.DealsSetConsiderOfflineStorageDeals(lcli.DaemonContext(cctx), false) + if err != nil { + return err + } + } + + return nil + }, +} + +var setAskCmd = &cli.Command{ + Name: "set-ask", + Usage: "Configure the miner's ask", + Flags: []cli.Flag{ + &cli.Uint64Flag{ + Name: "price", + Usage: "Set the price of the ask (specified as FIL / GiB / Epoch) to `PRICE`", + Required: true, + }, + &cli.StringFlag{ + Name: "duration", + Usage: "Set duration of ask (a quantity of time after which the ask expires) `DURATION`", + DefaultText: "720h0m0s", + Value: "720h0m0s", + }, + &cli.StringFlag{ + Name: "min-piece-size", + Usage: "Set minimum piece size (w/bit-padding, in bytes) in ask to `SIZE`", + DefaultText: "256B", + Value: "256B", + }, + &cli.StringFlag{ + Name: "max-piece-size", + Usage: "Set maximum piece size (w/bit-padding, in bytes) in ask to `SIZE`", + DefaultText: "miner sector size", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := lcli.DaemonContext(cctx) + + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + pri := types.NewInt(cctx.Uint64("price")) + + dur, err := time.ParseDuration(cctx.String("duration")) + if err != nil { + return xerrors.Errorf("cannot parse duration: %w", err) + } + + qty := dur.Seconds() / float64(build.BlockDelaySecs) + + min, err := units.RAMInBytes(cctx.String("min-piece-size")) + if err != nil { + return xerrors.Errorf("cannot parse min-piece-size to quantity of bytes: %w", err) + } + + if min < 256 { + return xerrors.New("minimum piece size (w/bit-padding) is 256B") + } + + max, err := units.RAMInBytes(cctx.String("max-piece-size")) + if err != nil { + return xerrors.Errorf("cannot parse max-piece-size to quantity of bytes: %w", err) + } + + maddr, err := api.ActorAddress(ctx) + if err != nil { + return err + } + + ssize, err := api.ActorSectorSize(ctx, maddr) + if err != nil { + return err + } + + smax := int64(ssize) + + if max == 0 { + max = smax + } + + if max > smax { + return xerrors.Errorf("max piece size (w/bit-padding) %s cannot exceed miner sector size %s", types.SizeStr(types.NewInt(uint64(max))), types.SizeStr(types.NewInt(uint64(smax)))) + } + + return api.MarketSetAsk(ctx, pri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max)) + }, +} + +var getAskCmd = &cli.Command{ + Name: "get-ask", + Usage: "Print the miner's ask", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + ctx := lcli.DaemonContext(cctx) + + fnapi, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + smapi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + sask, err := smapi.MarketGetAsk(ctx) + if err != nil { + return err + } + + var ask *storagemarket.StorageAsk + if sask != nil && sask.Ask != nil { + ask = sask.Ask + } + + w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) + fmt.Fprintf(w, "Price per GiB / Epoch\tMin. Piece Size (w/bit-padding)\tMax. Piece Size (w/bit-padding)\tExpiry (Epoch)\tExpiry (Appx. Rem. Time)\tSeq. No.\n") + if ask == nil { + fmt.Fprintf(w, "\n") + + return w.Flush() + } + + head, err := fnapi.ChainHead(ctx) + if err != nil { + return err + } + + dlt := ask.Expiry - head.Height() + rem := "" + if dlt > 0 { + rem = (time.Second * time.Duration(int64(dlt)*int64(build.BlockDelaySecs))).String() + } + + fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo) + + return w.Flush() + }, +} + +var storageDealsCmd = &cli.Command{ + Name: "storage-deals", + Usage: "Manage storage deals and related configuration", + Subcommands: []*cli.Command{ + dealsImportDataCmd, + dealsListCmd, + storageDealSelectionCmd, + setAskCmd, + getAskCmd, + setBlocklistCmd, + getBlocklistCmd, + resetBlocklistCmd, + }, +} + +var dealsImportDataCmd = &cli.Command{ + Name: "import-data", + Usage: "Manually import data for a deal", + ArgsUsage: " ", + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := lcli.DaemonContext(cctx) + + if cctx.Args().Len() < 2 { + return fmt.Errorf("must specify proposal CID and file path") + } + + propCid, err := cid.Decode(cctx.Args().Get(0)) + if err != nil { + return err + } + + fpath := cctx.Args().Get(1) + + return api.DealsImportData(ctx, propCid, fpath) + + }, +} + +var dealsListCmd = &cli.Command{ + Name: "list", + Usage: "List all deals for this miner", + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := lcli.DaemonContext(cctx) + + deals, err := api.MarketListIncompleteDeals(ctx) + if err != nil { + return err + } + + data, err := json.MarshalIndent(deals, "", " ") + if err != nil { + return err + } + + fmt.Println(string(data)) + return nil + }, +} + +var getBlocklistCmd = &cli.Command{ + Name: "get-blocklist", + Usage: "List the contents of the storage miner's piece CID blocklist", + Flags: []cli.Flag{ + &CidBaseFlag, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + blocklist, err := api.DealsPieceCidBlocklist(lcli.DaemonContext(cctx)) + if err != nil { + return err + } + + encoder, err := GetCidEncoder(cctx) + if err != nil { + return err + } + + for idx := range blocklist { + fmt.Println(encoder.Encode(blocklist[idx])) + } + + return nil + }, +} + +var setBlocklistCmd = &cli.Command{ + Name: "set-blocklist", + Usage: "Set the storage miner's list of blocklisted piece CIDs", + ArgsUsage: "[ (optional, will read from stdin if omitted)]", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + scanner := bufio.NewScanner(os.Stdin) + if cctx.Args().Present() && cctx.Args().First() != "-" { + absPath, err := filepath.Abs(cctx.Args().First()) + if err != nil { + return err + } + + file, err := os.Open(absPath) + if err != nil { + log.Fatal(err) + } + defer file.Close() //nolint:errcheck + + scanner = bufio.NewScanner(file) + } + + var blocklist []cid.Cid + for scanner.Scan() { + decoded, err := cid.Decode(scanner.Text()) + if err != nil { + return err + } + + blocklist = append(blocklist, decoded) + } + + err = scanner.Err() + if err != nil { + return err + } + + return api.DealsSetPieceCidBlocklist(lcli.DaemonContext(cctx), blocklist) + }, +} + +var resetBlocklistCmd = &cli.Command{ + Name: "reset-blocklist", + Usage: "Remove all entries from the storage miner's piece CID blocklist", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + return api.DealsSetPieceCidBlocklist(lcli.DaemonContext(cctx), []cid.Cid{}) + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/proving.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/proving.go new file mode 100644 index 0000000000..4b10b5b0e5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/proving.go @@ -0,0 +1,328 @@ +package main + +import ( + "bytes" + "fmt" + "os" + "text/tabwriter" + "time" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-bitfield" + rlepluslazy "github.com/filecoin-project/go-bitfield/rle" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var provingCmd = &cli.Command{ + Name: "proving", + Usage: "View proving information", + Subcommands: []*cli.Command{ + provingInfoCmd, + provingDeadlinesCmd, + provingFaultsCmd, + }, +} + +var provingFaultsCmd = &cli.Command{ + Name: "faults", + Usage: "View the currently known proving faulty sectors information", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := nodeApi.ActorAddress(ctx) + if err != nil { + return xerrors.Errorf("getting actor address: %w", err) + } + + var mas miner.State + { + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + rmas, err := api.ChainReadObj(ctx, mact.Head) + if err != nil { + return err + } + if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { + return err + } + } + faults, err := mas.Faults.All(100000000000) + if err != nil { + return err + } + if len(faults) == 0 { + fmt.Println("no faulty sectors") + return nil + } + head, err := api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + deadlines, err := api.StateMinerDeadlines(ctx, maddr, head.Key()) + if err != nil { + return xerrors.Errorf("getting miner deadlines: %w", err) + } + tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) + _, _ = fmt.Fprintln(tw, "deadline\tsectors") + for deadline, sectors := range deadlines.Due { + intersectSectors, _ := bitfield.IntersectBitField(sectors, mas.Faults) + if intersectSectors != nil { + allSectors, _ := intersectSectors.All(100000000000) + for _, num := range allSectors { + _, _ = fmt.Fprintf(tw, "%d\t%d\n", deadline, num) + } + } + + } + return tw.Flush() + }, +} + +var provingInfoCmd = &cli.Command{ + Name: "info", + Usage: "View current state information", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := nodeApi.ActorAddress(ctx) + if err != nil { + return xerrors.Errorf("getting actor address: %w", err) + } + + head, err := api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + + cd, err := api.StateMinerProvingDeadline(ctx, maddr, head.Key()) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + deadlines, err := api.StateMinerDeadlines(ctx, maddr, head.Key()) + if err != nil { + return xerrors.Errorf("getting miner deadlines: %w", err) + } + + curDeadlineSectors, err := deadlines.Due[cd.Index].Count() + if err != nil { + return xerrors.Errorf("counting deadline sectors: %w", err) + } + + var mas miner.State + { + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + rmas, err := api.ChainReadObj(ctx, mact.Head) + if err != nil { + return err + } + if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { + return err + } + } + + newSectors, err := mas.NewSectors.Count() + if err != nil { + return err + } + + faults, err := mas.Faults.Count() + if err != nil { + return err + } + + recoveries, err := mas.Recoveries.Count() + if err != nil { + return err + } + + var provenSectors uint64 + for _, d := range deadlines.Due { + c, err := d.Count() + if err != nil { + return err + } + provenSectors += c + } + + var faultPerc float64 + if provenSectors > 0 { + faultPerc = float64(faults*10000/provenSectors) / 100 + } + + fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch) + fmt.Printf("Chain Period: %d\n", cd.CurrentEpoch/miner.WPoStProvingPeriod) + fmt.Printf("Chain Period Start: %s\n", epochTime(cd.CurrentEpoch, (cd.CurrentEpoch/miner.WPoStProvingPeriod)*miner.WPoStProvingPeriod)) + fmt.Printf("Chain Period End: %s\n\n", epochTime(cd.CurrentEpoch, (cd.CurrentEpoch/miner.WPoStProvingPeriod+1)*miner.WPoStProvingPeriod)) + + fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%miner.WPoStProvingPeriod) + fmt.Printf("Proving Period Start: %s\n", epochTime(cd.CurrentEpoch, cd.PeriodStart)) + fmt.Printf("Next Period Start: %s\n\n", epochTime(cd.CurrentEpoch, cd.PeriodStart+miner.WPoStProvingPeriod)) + + fmt.Printf("Faults: %d (%.2f%%)\n", faults, faultPerc) + fmt.Printf("Recovering: %d\n", recoveries) + fmt.Printf("New Sectors: %d\n\n", newSectors) + + fmt.Printf("Deadline Index: %d\n", cd.Index) + fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors) + fmt.Printf("Deadline Open: %s\n", epochTime(cd.CurrentEpoch, cd.Open)) + fmt.Printf("Deadline Close: %s\n", epochTime(cd.CurrentEpoch, cd.Close)) + fmt.Printf("Deadline Challenge: %s\n", epochTime(cd.CurrentEpoch, cd.Challenge)) + fmt.Printf("Deadline FaultCutoff: %s\n", epochTime(cd.CurrentEpoch, cd.FaultCutoff)) + return nil + }, +} + +func epochTime(curr, e abi.ChainEpoch) string { + switch { + case curr > e: + return fmt.Sprintf("%d (%s ago)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(curr-e))) + case curr == e: + return fmt.Sprintf("%d (now)", e) + case curr < e: + return fmt.Sprintf("%d (in %s)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(e-curr))) + } + + panic("math broke") +} + +var provingDeadlinesCmd = &cli.Command{ + Name: "deadlines", + Usage: "View the current proving period deadlines information", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := nodeApi.ActorAddress(ctx) + if err != nil { + return xerrors.Errorf("getting actor address: %w", err) + } + + deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + var mas miner.State + { + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + rmas, err := api.ChainReadObj(ctx, mact.Head) + if err != nil { + return err + } + if err := mas.UnmarshalCBOR(bytes.NewReader(rmas)); err != nil { + return err + } + } + + tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) + _, _ = fmt.Fprintln(tw, "deadline\tsectors\tpartitions\tproven") + + for i, field := range deadlines.Due { + c, err := field.Count() + if err != nil { + return err + } + + firstPartition, sectorCount, err := miner.PartitionsForDeadline(deadlines, mas.Info.WindowPoStPartitionSectors, uint64(i)) + if err != nil { + return err + } + + partitionCount := (sectorCount + mas.Info.WindowPoStPartitionSectors - 1) / mas.Info.WindowPoStPartitionSectors + + var provenPartitions uint64 + { + var maskRuns []rlepluslazy.Run + if firstPartition > 0 { + maskRuns = append(maskRuns, rlepluslazy.Run{ + Val: false, + Len: firstPartition, + }) + } + maskRuns = append(maskRuns, rlepluslazy.Run{ + Val: true, + Len: partitionCount, + }) + + ppbm, err := bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{Runs: maskRuns}) + if err != nil { + return err + } + + pp, err := bitfield.IntersectBitField(ppbm, mas.PostSubmissions) + if err != nil { + return err + } + + provenPartitions, err = pp.Count() + if err != nil { + return err + } + } + + var cur string + if di.Index == uint64(i) { + cur += "\t(current)" + } + _, _ = fmt.Fprintf(tw, "%d\t%d\t%d\t%d%s\n", i, c, partitionCount, provenPartitions, cur) + } + + return tw.Flush() + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/retrieval-deals.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/retrieval-deals.go new file mode 100644 index 0000000000..942e30dff2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/retrieval-deals.go @@ -0,0 +1,113 @@ +package main + +import ( + "fmt" + + lcli "github.com/filecoin-project/lotus/cli" + "github.com/urfave/cli/v2" +) + +var retrievalDealsCmd = &cli.Command{ + Name: "retrieval-deals", + Usage: "Manage retrieval deals and related configuration", + Subcommands: []*cli.Command{ + retrievalDealSelectionCmd, + }, +} + +var retrievalDealSelectionCmd = &cli.Command{ + Name: "selection", + Usage: "Configure acceptance criteria for retrieval deal proposals", + Subcommands: []*cli.Command{ + retrievalDealSelectionShowCmd, + retrievalDealSelectionResetCmd, + retrievalDealSelectionRejectCmd, + }, +} + +var retrievalDealSelectionShowCmd = &cli.Command{ + Name: "list", + Usage: "List retrieval deal proposal selection criteria", + Action: func(cctx *cli.Context) error { + smapi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + onlineOk, err := smapi.DealsConsiderOnlineRetrievalDeals(lcli.DaemonContext(cctx)) + if err != nil { + return err + } + + offlineOk, err := smapi.DealsConsiderOfflineRetrievalDeals(lcli.DaemonContext(cctx)) + if err != nil { + return err + } + + fmt.Printf("considering online retrieval deals: %t\n", onlineOk) + fmt.Printf("considering offline retrieval deals: %t\n", offlineOk) + + return nil + }, +} + +var retrievalDealSelectionResetCmd = &cli.Command{ + Name: "reset", + Usage: "Reset retrieval deal proposal selection criteria to default values", + Action: func(cctx *cli.Context) error { + smapi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + err = smapi.DealsSetConsiderOnlineRetrievalDeals(lcli.DaemonContext(cctx), true) + if err != nil { + return err + } + + err = smapi.DealsSetConsiderOfflineRetrievalDeals(lcli.DaemonContext(cctx), true) + if err != nil { + return err + } + + return nil + }, +} + +var retrievalDealSelectionRejectCmd = &cli.Command{ + Name: "reject", + Usage: "Configure criteria which necessitate automatic rejection", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "online", + }, + &cli.BoolFlag{ + Name: "offline", + }, + }, + Action: func(cctx *cli.Context) error { + smapi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + if cctx.Bool("online") { + err = smapi.DealsSetConsiderOnlineRetrievalDeals(lcli.DaemonContext(cctx), false) + if err != nil { + return err + } + } + + if cctx.Bool("offline") { + err = smapi.DealsSetConsiderOfflineRetrievalDeals(lcli.DaemonContext(cctx), false) + if err != nil { + return err + } + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/rewards.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/rewards.go new file mode 100644 index 0000000000..4152880aee --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/rewards.go @@ -0,0 +1,88 @@ +package main + +import ( + "fmt" + + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" +) + +var rewardsCmd = &cli.Command{ + Name: "rewards", + Subcommands: []*cli.Command{ + rewardsRedeemCmd, + }, +} + +var rewardsRedeemCmd = &cli.Command{ + Name: "redeem", + Usage: "Redeem block rewards", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "gas-limit", + Usage: "set gas limit", + Value: 100000, + }, + }, + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := nodeApi.ActorAddress(ctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + params, err := actors.SerializeParams(&miner.WithdrawBalanceParams{ + mact.Balance, // Default to attempting to withdraw all the extra funds in the miner actor + }) + if err != nil { + return err + } + + gasLimit := cctx.Int64("gas-limit") + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + To: maddr, + From: mi.Owner, + Value: types.NewInt(0), + GasPrice: types.NewInt(1), + GasLimit: gasLimit, + Method: builtin.MethodsMiner.WithdrawBalance, + Params: params, + }) + if err != nil { + return err + } + + fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid()) + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/run.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/run.go new file mode 100644 index 0000000000..29634d17d4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/run.go @@ -0,0 +1,180 @@ +package main + +import ( + "context" + "net/http" + _ "net/http/pprof" + "os" + "os/signal" + "syscall" + + mux "github.com/gorilla/mux" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr-net" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-jsonrpc/auth" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/build" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/ulimit" + "github.com/filecoin-project/lotus/node" + "github.com/filecoin-project/lotus/node/impl" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/repo" +) + +var runCmd = &cli.Command{ + Name: "run", + Usage: "Start a lotus storage miner process", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "api", + Usage: "2345", + }, + &cli.BoolFlag{ + Name: "enable-gpu-proving", + Usage: "enable use of GPU for mining operations", + Value: true, + }, + &cli.BoolFlag{ + Name: "nosync", + Usage: "don't check full-node sync status", + }, + &cli.BoolFlag{ + Name: "manage-fdlimit", + Usage: "manage open file limit", + Value: true, + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Bool("enable-gpu-proving") { + os.Setenv("BELLMAN_NO_GPU", "true") + } + + nodeApi, ncloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer ncloser() + ctx := lcli.DaemonContext(cctx) + + v, err := nodeApi.Version(ctx) + if err != nil { + return err + } + + if cctx.Bool("manage-fdlimit") { + if _, _, err := ulimit.ManageFdLimit(); err != nil { + log.Errorf("setting file descriptor limit: %s", err) + } + } + + if v.APIVersion != build.APIVersion { + return xerrors.Errorf("lotus-daemon API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion}) + } + + log.Info("Checking full node sync status") + + if !cctx.Bool("nosync") { + if err := lcli.SyncWait(ctx, nodeApi); err != nil { + return xerrors.Errorf("sync wait: %w", err) + } + } + + storageRepoPath := cctx.String(FlagStorageRepo) + r, err := repo.NewFS(storageRepoPath) + if err != nil { + return err + } + + ok, err := r.Exists() + if err != nil { + return err + } + if !ok { + return xerrors.Errorf("repo at '%s' is not initialized, run 'lotus-storage-miner init' to set it up", storageRepoPath) + } + + shutdownChan := make(chan struct{}) + + var minerapi api.StorageMiner + stop, err := node.New(ctx, + node.StorageMiner(&minerapi), + node.Override(new(dtypes.ShutdownChan), shutdownChan), + node.Online(), + node.Repo(r), + + node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") }, + node.Override(new(dtypes.APIEndpoint), func() (dtypes.APIEndpoint, error) { + return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("api")) + })), + node.Override(new(api.FullNode), nodeApi), + ) + if err != nil { + return err + } + + endpoint, err := r.APIEndpoint() + if err != nil { + return err + } + + // Bootstrap with full node + remoteAddrs, err := nodeApi.NetAddrsListen(ctx) + if err != nil { + return err + } + + if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil { + return err + } + + log.Infof("Remote version %s", v) + + lst, err := manet.Listen(endpoint) + if err != nil { + return xerrors.Errorf("could not listen: %w", err) + } + + mux := mux.NewRouter() + + rpcServer := jsonrpc.NewServer() + rpcServer.Register("Filecoin", apistruct.PermissionedStorMinerAPI(minerapi)) + + mux.Handle("/rpc/v0", rpcServer) + mux.PathPrefix("/remote").HandlerFunc(minerapi.(*impl.StorageMinerAPI).ServeRemote) + mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof + + ah := &auth.Handler{ + Verify: minerapi.AuthVerify, + Next: mux.ServeHTTP, + } + + srv := &http.Server{Handler: ah} + + sigChan := make(chan os.Signal, 2) + go func() { + select { + case <-sigChan: + case <-shutdownChan: + } + + log.Warn("Shutting down...") + if err := stop(context.TODO()); err != nil { + log.Errorf("graceful shutting down failed: %s", err) + } + if err := srv.Shutdown(context.TODO()); err != nil { + log.Errorf("shutting down RPC server failed: %s", err) + } + log.Warn("Graceful shutdown successful") + }() + signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) + + return srv.Serve(manet.NetListener(lst)) + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/sectors.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/sectors.go new file mode 100644 index 0000000000..0dfce2f38b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/sectors.go @@ -0,0 +1,283 @@ +package main + +import ( + "fmt" + "os" + "sort" + "strconv" + "text/tabwriter" + "time" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/specs-actors/actors/abi" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var sectorsCmd = &cli.Command{ + Name: "sectors", + Usage: "interact with sector store", + Subcommands: []*cli.Command{ + sectorsStatusCmd, + sectorsListCmd, + sectorsRefsCmd, + sectorsUpdateCmd, + sectorsPledgeCmd, + sectorsRemoveCmd, + }, +} + +var sectorsPledgeCmd = &cli.Command{ + Name: "pledge", + Usage: "store random data in a sector", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + return nodeApi.PledgeSector(ctx) + }, +} + +var sectorsStatusCmd = &cli.Command{ + Name: "status", + Usage: "Get the seal status of a sector by its number", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "log", + Usage: "display event log", + }, + }, + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("must specify sector number to get status of") + } + + id, err := strconv.ParseUint(cctx.Args().First(), 10, 64) + if err != nil { + return err + } + + status, err := nodeApi.SectorsStatus(ctx, abi.SectorNumber(id)) + if err != nil { + return err + } + + fmt.Printf("SectorID:\t%d\n", status.SectorID) + fmt.Printf("Status:\t%s\n", status.State) + fmt.Printf("CommD:\t\t%x\n", status.CommD) + fmt.Printf("CommR:\t\t%x\n", status.CommR) + fmt.Printf("Ticket:\t\t%x\n", status.Ticket.Value) + fmt.Printf("TicketH:\t\t%d\n", status.Ticket.Epoch) + fmt.Printf("Seed:\t\t%x\n", status.Seed.Value) + fmt.Printf("SeedH:\t\t%d\n", status.Seed.Epoch) + fmt.Printf("Proof:\t\t%x\n", status.Proof) + fmt.Printf("Deals:\t\t%v\n", status.Deals) + fmt.Printf("Retries:\t\t%d\n", status.Retries) + if status.LastErr != "" { + fmt.Printf("Last Error:\t\t%s\n", status.LastErr) + } + + if cctx.Bool("log") { + fmt.Printf("--------\nEvent Log:\n") + + for i, l := range status.Log { + fmt.Printf("%d.\t%s:\t[%s]\t%s\n", i, time.Unix(int64(l.Timestamp), 0), l.Kind, l.Message) + if l.Trace != "" { + fmt.Printf("\t%s\n", l.Trace) + } + } + } + return nil + }, +} + +var sectorsListCmd = &cli.Command{ + Name: "list", + Usage: "List sectors", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + fullApi, closer2, err := lcli.GetFullNodeAPI(cctx) // TODO: consider storing full node address in config + if err != nil { + return err + } + defer closer2() + + ctx := lcli.ReqContext(cctx) + + list, err := nodeApi.SectorsList(ctx) + if err != nil { + return err + } + + maddr, err := nodeApi.ActorAddress(ctx) + if err != nil { + return err + } + + pset, err := fullApi.StateMinerProvingSet(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + provingIDs := make(map[abi.SectorNumber]struct{}, len(pset)) + for _, info := range pset { + provingIDs[info.ID] = struct{}{} + } + + sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, true, types.EmptyTSK) + if err != nil { + return err + } + commitedIDs := make(map[abi.SectorNumber]struct{}, len(pset)) + for _, info := range sset { + commitedIDs[info.ID] = struct{}{} + } + + sort.Slice(list, func(i, j int) bool { + return list[i] < list[j] + }) + + w := tabwriter.NewWriter(os.Stdout, 8, 4, 1, ' ', 0) + + for _, s := range list { + st, err := nodeApi.SectorsStatus(ctx, s) + if err != nil { + fmt.Fprintf(w, "%d:\tError: %s\n", s, err) + continue + } + + _, inSSet := commitedIDs[s] + _, inPSet := provingIDs[s] + + fmt.Fprintf(w, "%d: %s\tsSet: %s\tpSet: %s\ttktH: %d\tseedH: %d\tdeals: %v\n", + s, + st.State, + yesno(inSSet), + yesno(inPSet), + st.Ticket.Epoch, + st.Seed.Epoch, + st.Deals, + ) + } + + return w.Flush() + }, +} + +var sectorsRefsCmd = &cli.Command{ + Name: "refs", + Usage: "List References to sectors", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + refs, err := nodeApi.SectorsRefs(ctx) + if err != nil { + return err + } + + for name, refs := range refs { + fmt.Printf("Block %s:\n", name) + for _, ref := range refs { + fmt.Printf("\t%d+%d %d bytes\n", ref.SectorID, ref.Offset, ref.Size) + } + } + return nil + }, +} + +var sectorsRemoveCmd = &cli.Command{ + Name: "remove", + Usage: "Forcefully remove a sector (WARNING: This means losing power and collateral for the removed sector)", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "pass this flag if you know what you are doing", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Bool("really-do-it") { + return xerrors.Errorf("this is a command for advanced users, only use it if you are sure of what you are doing") + } + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + if cctx.Args().Len() != 1 { + return xerrors.Errorf("must pass sector number") + } + + id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) + if err != nil { + return xerrors.Errorf("could not parse sector number: %w", err) + } + + return nodeApi.SectorRemove(ctx, abi.SectorNumber(id)) + }, +} + +var sectorsUpdateCmd = &cli.Command{ + Name: "update-state", + Usage: "ADVANCED: manually update the state of a sector, this may aid in error recovery", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "pass this flag if you know what you are doing", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Bool("really-do-it") { + return xerrors.Errorf("this is a command for advanced users, only use it if you are sure of what you are doing") + } + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + if cctx.Args().Len() < 2 { + return xerrors.Errorf("must pass sector number and new state") + } + + id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) + if err != nil { + return xerrors.Errorf("could not parse sector number: %w", err) + } + + return nodeApi.SectorsUpdate(ctx, abi.SectorNumber(id), api.SectorState(cctx.Args().Get(1))) + }, +} + +func yesno(b bool) string { + if b { + return "YES" + } + return "NO" +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/stop.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/stop.go new file mode 100644 index 0000000000..0cc10b73c8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/stop.go @@ -0,0 +1,29 @@ +package main + +import ( + _ "net/http/pprof" + + "github.com/urfave/cli/v2" + + lcli "github.com/filecoin-project/lotus/cli" +) + +var stopCmd = &cli.Command{ + Name: "stop", + Usage: "Stop a running lotus storage miner", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetAPI(cctx) + if err != nil { + return err + } + defer closer() + + err = api.Shutdown(lcli.ReqContext(cctx)) + if err != nil { + return err + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/storage.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/storage.go new file mode 100644 index 0000000000..4ab46fdaed --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/storage.go @@ -0,0 +1,382 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "time" + + "github.com/fatih/color" + "github.com/google/uuid" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/sector-storage/stores" +) + +const metaFile = "sectorstore.json" + +var storageCmd = &cli.Command{ + Name: "storage", + Usage: "manage sector storage", + Subcommands: []*cli.Command{ + storageAttachCmd, + storageListCmd, + storageFindCmd, + }, +} + +var storageAttachCmd = &cli.Command{ + Name: "attach", + Usage: "attach local storage path", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "init", + Usage: "initialize the path first", + }, + &cli.Uint64Flag{ + Name: "weight", + Usage: "(for init) path weight", + Value: 10, + }, + &cli.BoolFlag{ + Name: "seal", + Usage: "(for init) use path for sealing", + }, + &cli.BoolFlag{ + Name: "store", + Usage: "(for init) use path for long-term storage", + }, + }, + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + if !cctx.Args().Present() { + return xerrors.Errorf("must specify storage path to attach") + } + + p, err := homedir.Expand(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("expanding path: %w", err) + } + + if cctx.Bool("init") { + if err := os.MkdirAll(p, 0755); err != nil { + if !os.IsExist(err) { + return err + } + } + + _, err := os.Stat(filepath.Join(p, metaFile)) + if !os.IsNotExist(err) { + if err == nil { + return xerrors.Errorf("path is already initialized") + } + return err + } + + cfg := &stores.LocalStorageMeta{ + ID: stores.ID(uuid.New().String()), + Weight: cctx.Uint64("weight"), + CanSeal: cctx.Bool("seal"), + CanStore: cctx.Bool("store"), + } + + if !(cfg.CanStore || cfg.CanSeal) { + return xerrors.Errorf("must specify at least one of --store of --seal") + } + + b, err := json.MarshalIndent(cfg, "", " ") + if err != nil { + return xerrors.Errorf("marshaling storage config: %w", err) + } + + if err := ioutil.WriteFile(filepath.Join(p, metaFile), b, 0644); err != nil { + return xerrors.Errorf("persisting storage metadata (%s): %w", filepath.Join(p, metaFile), err) + } + } + + return nodeApi.StorageAddLocal(ctx, p) + }, +} + +var storageListCmd = &cli.Command{ + Name: "list", + Usage: "list local storage paths", + Flags: []cli.Flag{ + &cli.BoolFlag{Name: "color"}, + }, + Action: func(cctx *cli.Context) error { + color.NoColor = !cctx.Bool("color") + + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + st, err := nodeApi.StorageList(ctx) + if err != nil { + return err + } + + local, err := nodeApi.StorageLocal(ctx) + if err != nil { + return err + } + + type fsInfo struct { + stores.ID + sectors []stores.Decl + stat stores.FsStat + } + + sorted := make([]fsInfo, 0, len(st)) + for id, decls := range st { + st, err := nodeApi.StorageStat(ctx, id) + if err != nil { + sorted = append(sorted, fsInfo{ID: id, sectors: decls}) + continue + } + + sorted = append(sorted, fsInfo{id, decls, st}) + } + + sort.Slice(sorted, func(i, j int) bool { + if sorted[i].stat.Capacity != sorted[j].stat.Capacity { + return sorted[i].stat.Capacity > sorted[j].stat.Capacity + } + return sorted[i].ID < sorted[j].ID + }) + + for _, s := range sorted { + + var cnt [3]int + for _, decl := range s.sectors { + for i := range cnt { + if decl.SectorFileType&(1< 98: + percCol = color.FgRed + case usedPercent > 90: + percCol = color.FgYellow + } + + var barCols = uint64(50) + set := (st.Capacity - st.Available) * barCols / st.Capacity + bar := strings.Repeat("|", int(set)) + strings.Repeat(" ", int(barCols-set)) + + fmt.Printf("\t[%s] %s/%s %s\n", color.New(percCol).Sprint(bar), + types.SizeStr(types.NewInt(st.Capacity-st.Available)), + types.SizeStr(types.NewInt(st.Capacity)), + color.New(percCol).Sprintf("%d%%", usedPercent)) + fmt.Printf("\t%s; %s; %s\n", + color.YellowString("Unsealed: %d", cnt[0]), + color.GreenString("Sealed: %d", cnt[1]), + color.BlueString("Caches: %d", cnt[2])) + + si, err := nodeApi.StorageInfo(ctx, s.ID) + if err != nil { + return err + } + + fmt.Print("\t") + if si.CanSeal || si.CanStore { + fmt.Printf("Weight: %d; Use: ", si.Weight) + if si.CanSeal { + fmt.Print(color.MagentaString("Seal ")) + } + if si.CanStore { + fmt.Print(color.CyanString("Store")) + } + fmt.Println("") + } else { + fmt.Print(color.HiYellowString("Use: ReadOnly")) + } + + if localPath, ok := local[s.ID]; ok { + fmt.Printf("\tLocal: %s\n", color.GreenString(localPath)) + } + for i, l := range si.URLs { + var rtt string + if _, ok := local[s.ID]; !ok && i == 0 { + rtt = " (latency: " + ping.Truncate(time.Microsecond*100).String() + ")" + } + + fmt.Printf("\tURL: %s%s\n", l, rtt) // TODO; try pinging maybe?? print latency? + } + fmt.Println() + } + + return nil + }, +} + +type storedSector struct { + id stores.ID + store stores.SectorStorageInfo + + unsealed, sealed, cache bool +} + +var storageFindCmd = &cli.Command{ + Name: "find", + Usage: "find sector in the storage system", + ArgsUsage: "[sector number]", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + ma, err := nodeApi.ActorAddress(ctx) + if err != nil { + return err + } + + mid, err := address.IDFromAddress(ma) + if err != nil { + return err + } + + if !cctx.Args().Present() { + return xerrors.New("Usage: lotus-storage-miner storage find [sector number]") + } + + snum, err := strconv.ParseUint(cctx.Args().First(), 10, 64) + if err != nil { + return err + } + + sid := abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(snum), + } + + u, err := nodeApi.StorageFindSector(ctx, sid, stores.FTUnsealed, false) + if err != nil { + return xerrors.Errorf("finding unsealed: %w", err) + } + + s, err := nodeApi.StorageFindSector(ctx, sid, stores.FTSealed, false) + if err != nil { + return xerrors.Errorf("finding sealed: %w", err) + } + + c, err := nodeApi.StorageFindSector(ctx, sid, stores.FTCache, false) + if err != nil { + return xerrors.Errorf("finding cache: %w", err) + } + + byId := map[stores.ID]*storedSector{} + for _, info := range u { + sts, ok := byId[info.ID] + if !ok { + sts = &storedSector{ + id: info.ID, + store: info, + } + byId[info.ID] = sts + } + sts.unsealed = true + } + for _, info := range s { + sts, ok := byId[info.ID] + if !ok { + sts = &storedSector{ + id: info.ID, + store: info, + } + byId[info.ID] = sts + } + sts.sealed = true + } + for _, info := range c { + sts, ok := byId[info.ID] + if !ok { + sts = &storedSector{ + id: info.ID, + store: info, + } + byId[info.ID] = sts + } + sts.cache = true + } + + local, err := nodeApi.StorageLocal(ctx) + if err != nil { + return err + } + + var out []*storedSector + for _, sector := range byId { + out = append(out, sector) + } + sort.Slice(out, func(i, j int) bool { + return out[i].id < out[j].id + }) + + for _, info := range out { + var types string + if info.unsealed { + types += "Unsealed, " + } + if info.sealed { + types += "Sealed, " + } + if info.cache { + types += "Cache, " + } + + fmt.Printf("In %s (%s)\n", info.id, types[:len(types)-2]) + fmt.Printf("\tSealing: %t; Storage: %t\n", info.store.CanSeal, info.store.CanSeal) + if localPath, ok := local[info.id]; ok { + fmt.Printf("\tLocal (%s)\n", localPath) + } else { + fmt.Printf("\tRemote\n") + } + for _, l := range info.store.URLs { + fmt.Printf("\tURL: %s\n", l) + } + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/workers.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/workers.go new file mode 100644 index 0000000000..009d2fb90e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-storage-miner/workers.go @@ -0,0 +1,108 @@ +package main + +import ( + "fmt" + "sort" + "strings" + + "github.com/fatih/color" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/sector-storage/storiface" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +var workersCmd = &cli.Command{ + Name: "workers", + Usage: "interact with workers", + Subcommands: []*cli.Command{ + workersListCmd, + }, +} + +var workersListCmd = &cli.Command{ + Name: "list", + Usage: "list workers", + Flags: []cli.Flag{ + &cli.BoolFlag{Name: "color"}, + }, + Action: func(cctx *cli.Context) error { + color.NoColor = !cctx.Bool("color") + + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := lcli.ReqContext(cctx) + + stats, err := nodeApi.WorkerStats(ctx) + if err != nil { + return err + } + + type sortableStat struct { + id uint64 + storiface.WorkerStats + } + + st := make([]sortableStat, 0, len(stats)) + for id, stat := range stats { + st = append(st, sortableStat{id, stat}) + } + + sort.Slice(st, func(i, j int) bool { + return st[i].id < st[j].id + }) + + for _, stat := range st { + gpuUse := "not " + gpuCol := color.FgBlue + if stat.GpuUsed { + gpuCol = color.FgGreen + gpuUse = "" + } + + fmt.Printf("Worker %d, host %s\n", stat.id, color.MagentaString(stat.Info.Hostname)) + + var barCols = uint64(64) + cpuBars := int(stat.CpuUse * barCols / stat.Info.Resources.CPUs) + cpuBar := strings.Repeat("|", cpuBars) + strings.Repeat(" ", int(barCols)-cpuBars) + + fmt.Printf("\tCPU: [%s] %d core(s) in use\n", color.GreenString(cpuBar), stat.CpuUse) + + ramBarsRes := int(stat.Info.Resources.MemReserved * barCols / stat.Info.Resources.MemPhysical) + ramBarsUsed := int(stat.MemUsedMin * barCols / stat.Info.Resources.MemPhysical) + ramBar := color.YellowString(strings.Repeat("|", ramBarsRes)) + + color.GreenString(strings.Repeat("|", ramBarsUsed)) + + strings.Repeat(" ", int(barCols)-ramBarsUsed-ramBarsRes) + + vmem := stat.Info.Resources.MemPhysical + stat.Info.Resources.MemSwap + + vmemBarsRes := int(stat.Info.Resources.MemReserved * barCols / vmem) + vmemBarsUsed := int(stat.MemUsedMax * barCols / vmem) + vmemBar := color.YellowString(strings.Repeat("|", vmemBarsRes)) + + color.GreenString(strings.Repeat("|", vmemBarsUsed)) + + strings.Repeat(" ", int(barCols)-vmemBarsUsed-vmemBarsRes) + + fmt.Printf("\tRAM: [%s] %d%% %s/%s\n", ramBar, + (stat.Info.Resources.MemReserved+stat.MemUsedMin)*100/stat.Info.Resources.MemPhysical, + types.SizeStr(types.NewInt(stat.Info.Resources.MemReserved+stat.MemUsedMin)), + types.SizeStr(types.NewInt(stat.Info.Resources.MemPhysical))) + + fmt.Printf("\tVMEM: [%s] %d%% %s/%s\n", vmemBar, + (stat.Info.Resources.MemReserved+stat.MemUsedMax)*100/vmem, + types.SizeStr(types.NewInt(stat.Info.Resources.MemReserved+stat.MemUsedMax)), + types.SizeStr(types.NewInt(vmem))) + + for _, gpu := range stat.Info.Resources.GPUs { + fmt.Printf("\tGPU: %s\n", color.New(gpuCol).Sprintf("%s, %sused", gpu, gpuUse)) + } + } + + return nil + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/main.go new file mode 100644 index 0000000000..58ed36478c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/main.go @@ -0,0 +1,134 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + rice "github.com/GeertJohan/go.rice" + "github.com/gorilla/websocket" + "github.com/ipfs/go-datastore" + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/ipld/go-car" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-core/peer" + pubsub "github.com/libp2p/go-libp2p-pubsub" + + "github.com/filecoin-project/lotus/build" +) + +var topic = "/fil/headnotifs/" + +func init() { + genBytes := build.MaybeGenesis() + if len(genBytes) == 0 { + topic = "" + return + } + + bs := blockstore.NewBlockstore(datastore.NewMapDatastore()) + + c, err := car.LoadCar(bs, bytes.NewReader(genBytes)) + if err != nil { + panic(err) + } + if len(c.Roots) != 1 { + panic("expected genesis file to have one root") + } + + fmt.Printf("Genesis CID: %s\n", c.Roots[0]) + topic = topic + c.Roots[0].String() +} + +var upgrader = websocket.Upgrader{ + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func main() { + if topic == "" { + fmt.Println("FATAL: No genesis found") + return + } + + ctx := context.Background() + + host, err := libp2p.New( + ctx, + libp2p.Defaults, + ) + if err != nil { + panic(err) + } + ps, err := pubsub.NewGossipSub(ctx, host) + if err != nil { + panic(err) + } + + pi, err := build.BuiltinBootstrap() + if err != nil { + panic(err) + } + + if err := host.Connect(ctx, pi[0]); err != nil { + panic(err) + } + + http.HandleFunc("/sub", handler(ps)) + http.Handle("/", http.FileServer(rice.MustFindBox("townhall/build").HTTPBox())) + + fmt.Println("listening on http://localhost:2975") + + if err := http.ListenAndServe("0.0.0.0:2975", nil); err != nil { + panic(err) + } +} + +type update struct { + From peer.ID + Update json.RawMessage + Time uint64 +} + +func handler(ps *pubsub.PubSub) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + if r.Header.Get("Sec-WebSocket-Protocol") != "" { + w.Header().Set("Sec-WebSocket-Protocol", r.Header.Get("Sec-WebSocket-Protocol")) + } + + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return + } + + sub, err := ps.Subscribe(topic) + if err != nil { + return + } + + fmt.Println("new conn") + + for { + msg, err := sub.Next(r.Context()) + if err != nil { + return + } + + //fmt.Println(msg) + + if err := conn.WriteJSON(update{ + From: peer.ID(msg.From), + Update: msg.Data, + Time: uint64(time.Now().UnixNano() / 1000_000), + }); err != nil { + return + } + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/.gitignore b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/.gitignore new file mode 100644 index 0000000000..4d29575de8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/package.json b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/package.json new file mode 100644 index 0000000000..5a8167622f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/package.json @@ -0,0 +1,31 @@ +{ + "name": "townhall", + "version": "0.1.0", + "private": true, + "dependencies": { + "react": "^16.10.2", + "react-dom": "^16.10.2", + "react-scripts": "3.2.0" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/index.html b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/index.html new file mode 100644 index 0000000000..38af105973 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/index.html @@ -0,0 +1,13 @@ + + + + + + + Lotus TownHall + + + +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/robots.txt b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/robots.txt new file mode 100644 index 0000000000..01b0f9a107 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.css b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.css new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.css @@ -0,0 +1 @@ + diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.js b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.js new file mode 100644 index 0000000000..2f216f5da9 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.js @@ -0,0 +1,87 @@ +import React from 'react'; +import './App.css'; + +function colForH(besth, height) { + const diff = besth - height + if(diff === 0) return '#6f6' + if(diff === 1) return '#df4' + if(diff < 4) return '#ff0' + if(diff < 10) return '#f60' + return '#f00' +} + +function colLag(lag) { + if(lag < 100) return '#6f6' + if(lag < 400) return '#df4' + if(lag < 1000) return '#ff0' + if(lag < 4000) return '#f60' + return '#f00' +} + +function lagCol(lag, good) { + return + {lag} + ms + +} + +class App extends React.Component { + constructor(props) { + super(props); + + let ws = new WebSocket("ws://" + window.location.host + "/sub") + //let ws = new WebSocket("ws://127.0.0.1:2975/sub") + + ws.onmessage = (ev) => { + console.log(ev) + let update = JSON.parse(ev.data) + + update.Update.Weight = Number(update.Update.Weight) + + let wdiff = update.Update.Weight - (this.state[update.From] || {Weight: update.Update.Weight}).Weight + wdiff = {wdiff} + + let utDiff = update.Time - (this.state[update.From] || {utime: update.Time}).utime + utDiff = {utDiff}ms + + this.setState( prev => ({ + ...prev, [update.From]: {...update.Update, utime: update.Time, wdiff: wdiff, utDiff: utDiff}, + })) + } + + ws.onclose = () => { + this.setState({disconnected: true}) + } + + this.state = {} + } + + render() { + if(this.state.disconnected) { + return Error: disconnected + } + + let besth = Object.keys(this.state).map(k => this.state[k]).reduce((p, n) => p > n.Height ? p : n.Height, -1) + let bestw = Object.keys(this.state).map(k => this.state[k]).reduce((p, n) => p > n.Weight ? p : n.Weight, -1) + + return + + {Object.keys(this.state).map(k => [k, this.state[k]]).map(([k, v]) => { + let mnrs = v.Blocks.map(b => ) + let l = [ + , + , + , + , + , + ...mnrs, + ] + + l = {l} + return l + }) + } +
    PeerIDNicknameLagWeight(best, prev)HeightBlocks
     m:{b.Miner}({lagCol(v.Time ? v.Time - (b.Timestamp*1000) : v.utime - (b.Timestamp*1000), v.Time)}){k}{v.NodeName}{v.Time ? lagCol(v.utime - v.Time, true) : ""}(Δ{v.utDiff}){v.Weight}({bestw - v.Weight}, {v.wdiff}){v.Height}({besth - v.Height})
    + } +} +export default App; diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.test.js b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.test.js new file mode 100644 index 0000000000..a754b201bf --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.css b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.css new file mode 100644 index 0000000000..fb0d9d10ef --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.css @@ -0,0 +1,6 @@ +body { + margin: 0; + font-family: monospace; + background: #1f1f1f; + color: #f0f0f0; +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.js b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.js new file mode 100644 index 0000000000..395b74997b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus-townhall/townhall/src/index.js @@ -0,0 +1,6 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon.go new file mode 100644 index 0000000000..bb17c0d87f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon.go @@ -0,0 +1,360 @@ +// +build !nodaemon + +package main + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "runtime/pprof" + "strings" + + "github.com/filecoin-project/lotus/chain/types" + + paramfetch "github.com/filecoin-project/go-paramfetch" + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/mitchellh/go-homedir" + "github.com/multiformats/go-multiaddr" + "github.com/urfave/cli/v2" + "go.opencensus.io/plugin/runmetrics" + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/vm" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/peermgr" + "github.com/filecoin-project/lotus/lib/ulimit" + "github.com/filecoin-project/lotus/metrics" + "github.com/filecoin-project/lotus/node" + "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/testing" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/sector-storage/ffiwrapper" +) + +const ( + makeGenFlag = "lotus-make-genesis" + preTemplateFlag = "genesis-template" +) + +var daemonStopCmd = &cli.Command{ + Name: "stop", + Usage: "Stop a running lotus daemon", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetAPI(cctx) + if err != nil { + return err + } + defer closer() + + err = api.Shutdown(lcli.ReqContext(cctx)) + if err != nil { + return err + } + + return nil + }, +} + +// DaemonCmd is the `go-lotus daemon` command +var DaemonCmd = &cli.Command{ + Name: "daemon", + Usage: "Start a lotus daemon process", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "api", + Value: "1234", + }, + &cli.StringFlag{ + Name: makeGenFlag, + Value: "", + Hidden: true, + }, + &cli.StringFlag{ + Name: preTemplateFlag, + Hidden: true, + }, + &cli.StringFlag{ + Name: "import-key", + Usage: "on first run, import a default key from a given file", + Hidden: true, + }, + &cli.StringFlag{ + Name: "genesis", + Usage: "genesis file to use for first node run", + }, + &cli.BoolFlag{ + Name: "bootstrap", + Value: true, + }, + &cli.StringFlag{ + Name: "import-chain", + Usage: "on first run, load chain from given file", + }, + &cli.BoolFlag{ + Name: "halt-after-import", + Usage: "halt the process after importing chain from file", + }, + &cli.StringFlag{ + Name: "pprof", + Usage: "specify name of file for writing cpu profile to", + }, + &cli.StringFlag{ + Name: "profile", + Usage: "specify type of node", + }, + &cli.BoolFlag{ + Name: "manage-fdlimit", + Usage: "manage open file limit", + Value: true, + }, + }, + Action: func(cctx *cli.Context) error { + err := runmetrics.Enable(runmetrics.RunMetricOptions{ + EnableCPU: true, + EnableMemory: true, + }) + if err != nil { + return xerrors.Errorf("enabling runtime metrics: %w", err) + } + + if cctx.Bool("manage-fdlimit") { + if _, _, err := ulimit.ManageFdLimit(); err != nil { + log.Errorf("setting file descriptor limit: %s", err) + } + } + + if prof := cctx.String("pprof"); prof != "" { + profile, err := os.Create(prof) + if err != nil { + return err + } + + if err := pprof.StartCPUProfile(profile); err != nil { + return err + } + defer pprof.StopCPUProfile() + } + + var isBootstrapper dtypes.Bootstrapper + switch profile := cctx.String("profile"); profile { + case "bootstrapper": + isBootstrapper = true + case "": + // do nothing + default: + return fmt.Errorf("unrecognized profile type: %q", profile) + } + + ctx, _ := tag.New(context.Background(), tag.Insert(metrics.Version, build.BuildVersion), tag.Insert(metrics.Commit, build.CurrentCommit)) + { + dir, err := homedir.Expand(cctx.String("repo")) + if err != nil { + log.Warnw("could not expand repo location", "error", err) + } else { + log.Infof("lotus repo: %s", dir) + } + } + + r, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return xerrors.Errorf("opening fs repo: %w", err) + } + + if err := r.Init(repo.FullNode); err != nil && err != repo.ErrRepoExists { + return xerrors.Errorf("repo init error: %w", err) + } + + if err := paramfetch.GetParams(lcli.ReqContext(cctx), build.ParametersJSON(), 0); err != nil { + return xerrors.Errorf("fetching proof parameters: %w", err) + } + + var genBytes []byte + if cctx.String("genesis") != "" { + genBytes, err = ioutil.ReadFile(cctx.String("genesis")) + if err != nil { + return xerrors.Errorf("reading genesis: %w", err) + } + } else { + genBytes = build.MaybeGenesis() + } + + chainfile := cctx.String("import-chain") + if chainfile != "" { + chainfile, err := homedir.Expand(chainfile) + if err != nil { + return err + } + + if err := ImportChain(r, chainfile); err != nil { + return err + } + if cctx.Bool("halt-after-import") { + fmt.Println("Chain import complete, halting as requested...") + return nil + } + } + + genesis := node.Options() + if len(genBytes) > 0 { + genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genBytes)) + } + if cctx.String(makeGenFlag) != "" { + if cctx.String(preTemplateFlag) == "" { + return xerrors.Errorf("must also pass file with genesis template to `--%s`", preTemplateFlag) + } + genesis = node.Override(new(modules.Genesis), testing.MakeGenesis(cctx.String(makeGenFlag), cctx.String(preTemplateFlag))) + } + + shutdownChan := make(chan struct{}) + + var api api.FullNode + + stop, err := node.New(ctx, + node.FullAPI(&api), + + node.Override(new(dtypes.Bootstrapper), isBootstrapper), + node.Override(new(dtypes.ShutdownChan), shutdownChan), + node.Online(), + node.Repo(r), + + genesis, + + node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") }, + node.Override(node.SetApiEndpointKey, func(lr repo.LockedRepo) error { + apima, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + + cctx.String("api")) + if err != nil { + return err + } + return lr.SetAPIEndpoint(apima) + })), + node.ApplyIf(func(s *node.Settings) bool { return !cctx.Bool("bootstrap") }, + node.Unset(node.RunPeerMgrKey), + node.Unset(new(*peermgr.PeerMgr)), + ), + ) + if err != nil { + return xerrors.Errorf("initializing node: %w", err) + } + + if cctx.String("import-key") != "" { + if err := importKey(ctx, api, cctx.String("import-key")); err != nil { + log.Errorf("importing key failed: %+v", err) + } + } + + // Register all metric views + if err = view.Register( + metrics.DefaultViews..., + ); err != nil { + log.Fatalf("Cannot register the view: %v", err) + } + + // Set the metric to one so it is published to the exporter + stats.Record(ctx, metrics.LotusInfo.M(1)) + + endpoint, err := r.APIEndpoint() + if err != nil { + return xerrors.Errorf("getting api endpoint: %w", err) + } + + // TODO: properly parse api endpoint (or make it a URL) + return serveRPC(api, stop, endpoint, shutdownChan) + }, + Subcommands: []*cli.Command{ + daemonStopCmd, + }, +} + +func importKey(ctx context.Context, api api.FullNode, f string) error { + f, err := homedir.Expand(f) + if err != nil { + return err + } + + hexdata, err := ioutil.ReadFile(f) + if err != nil { + return err + } + + data, err := hex.DecodeString(strings.TrimSpace(string(hexdata))) + if err != nil { + return err + } + + var ki types.KeyInfo + if err := json.Unmarshal(data, &ki); err != nil { + return err + } + + addr, err := api.WalletImport(ctx, &ki) + if err != nil { + return err + } + + if err := api.WalletSetDefault(ctx, addr); err != nil { + return err + } + + log.Info("successfully imported key for %s", addr) + return nil +} + +func ImportChain(r repo.Repo, fname string) error { + fi, err := os.Open(fname) + if err != nil { + return err + } + + lr, err := r.Lock(repo.FullNode) + if err != nil { + return err + } + defer lr.Close() //nolint:errcheck + + ds, err := lr.Datastore("/chain") + if err != nil { + return err + } + + mds, err := lr.Datastore("/metadata") + if err != nil { + return err + } + + bs := blockstore.NewBlockstore(ds) + + cst := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier)) + + log.Info("importing chain from file...") + ts, err := cst.Import(fi) + if err != nil { + return xerrors.Errorf("importing chain failed: %w", err) + } + + stm := stmgr.NewStateManager(cst) + + log.Infof("validating imported chain...") + if err := stm.ValidateChain(context.TODO(), ts); err != nil { + return xerrors.Errorf("chain validation failed: %w", err) + } + + log.Info("accepting %s as new head", ts.Cids()) + if err := cst.SetHead(ts); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon_nodaemon.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon_nodaemon.go new file mode 100644 index 0000000000..a11d92c6c4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus/daemon_nodaemon.go @@ -0,0 +1,24 @@ +// +build nodaemon + +package main + +import ( + "errors" + + "github.com/urfave/cli/v2" +) + +// DaemonCmd is the `go-lotus daemon` command +var DaemonCmd = &cli.Command{ + Name: "daemon", + Usage: "Start a lotus daemon process", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "api", + Value: ":1234", + }, + }, + Action: func(cctx *cli.Context) error { + return errors.New("daemon support not included in this binary") + }, +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus/debug_advance.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus/debug_advance.go new file mode 100644 index 0000000000..2a7d38eab8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus/debug_advance.go @@ -0,0 +1,84 @@ +// +build debug + +package main + +import ( + "github.com/filecoin-project/go-address" + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/specs-actors/actors/crypto" + "golang.org/x/xerrors" + + "github.com/urfave/cli/v2" +) + +func init() { + AdvanceBlockCmd = &cli.Command{ + Name: "advance-block", + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := lcli.ReqContext(cctx) + head, err := api.ChainHead(ctx) + if err != nil { + return err + } + pending, err := api.MpoolPending(ctx, head.Key()) + if err != nil { + return err + } + + msgs, err := miner.SelectMessages(ctx, api.StateGetActor, head, pending) + if err != nil { + return err + } + if len(msgs) > build.BlockMessageLimit { + log.Error("SelectMessages returned too many messages: ", len(msgs)) + msgs = msgs[:build.BlockMessageLimit] + } + + addr, _ := address.NewIDAddress(1000) + var ticket *types.Ticket + { + mi, err := api.StateMinerInfo(ctx, addr, head.Key()) + if err != nil { + return xerrors.Errorf("StateMinerWorker: %w", err) + } + + rand, err := api.ChainGetRandomness(ctx, head.Key(), crypto.DomainSeparationTag_TicketProduction, head.Height(), addr.Bytes()) + if err != nil { + return xerrors.Errorf("failed to get randomness: %w", err) + } + + t, err := gen.ComputeVRF(ctx, api.WalletSign, mi.Worker, rand) + if err != nil { + return xerrors.Errorf("compute vrf failed: %w", err) + } + ticket = &types.Ticket{ + VRFProof: t, + } + + } + // TODO: beacon + + uts := head.MinTimestamp() + uint64(build.BlockDelaySecs) + nheight := head.Height() + 1 + blk, err := api.MinerCreateBlock(ctx, &lapi.BlockTemplate{ + addr, head.Key(), ticket, &types.ElectionProof{}, nil, msgs, nheight, uts, gen.ValidWpostForTesting, + }) + if err != nil { + return xerrors.Errorf("creating block: %w", err) + } + + return api.SyncSubmitBlock(ctx, blk) + }, + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus/main.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus/main.go new file mode 100644 index 0000000000..5376ce02a0 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "context" + "os" + + "github.com/urfave/cli/v2" + "go.opencensus.io/trace" + + "github.com/filecoin-project/lotus/build" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/lotuslog" + "github.com/filecoin-project/lotus/lib/tracing" + "github.com/filecoin-project/lotus/node/repo" +) + +var AdvanceBlockCmd *cli.Command + +func main() { + lotuslog.SetupLogLevels() + + local := []*cli.Command{ + DaemonCmd, + } + if AdvanceBlockCmd != nil { + local = append(local, AdvanceBlockCmd) + } + + jaeger := tracing.SetupJaegerTracing("lotus") + defer func() { + if jaeger != nil { + jaeger.Flush() + } + }() + + for _, cmd := range local { + cmd := cmd + originBefore := cmd.Before + cmd.Before = func(cctx *cli.Context) error { + trace.UnregisterExporter(jaeger) + jaeger = tracing.SetupJaegerTracing("lotus/" + cmd.Name) + + if originBefore != nil { + return originBefore(cctx) + } + return nil + } + } + ctx, span := trace.StartSpan(context.Background(), "/cli") + defer span.End() + + app := &cli.App{ + Name: "lotus", + Usage: "Filecoin decentralized storage network client", + Version: build.UserVersion(), + EnableBashCompletion: true, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + }, + + Commands: append(local, lcli.Commands...), + } + app.Setup() + app.Metadata["traceContext"] = ctx + app.Metadata["repoType"] = repo.FullNode + + if err := app.Run(os.Args); err != nil { + span.SetStatus(trace.Status{ + Code: trace.StatusCodeFailedPrecondition, + Message: err.Error(), + }) + _, ok := err.(*lcli.ErrCmdFailed) + if ok { + log.Debugf("%+v", err) + } else { + log.Warnf("%+v", err) + } + os.Exit(1) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/cmd/lotus/rpc.go b/vendor/github.com/filecoin-project/lotus/cmd/lotus/rpc.go new file mode 100644 index 0000000000..9b942c523e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/cmd/lotus/rpc.go @@ -0,0 +1,111 @@ +package main + +import ( + "context" + "encoding/json" + "net/http" + _ "net/http/pprof" + "os" + "os/signal" + "syscall" + + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr-net" + "golang.org/x/xerrors" + + "contrib.go.opencensus.io/exporter/prometheus" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-jsonrpc/auth" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/node" + "github.com/filecoin-project/lotus/node/impl" +) + +var log = logging.Logger("main") + +func serveRPC(a api.FullNode, stop node.StopFunc, addr multiaddr.Multiaddr, shutdownCh <-chan struct{}) error { + rpcServer := jsonrpc.NewServer() + rpcServer.Register("Filecoin", apistruct.PermissionedFullAPI(a)) + + ah := &auth.Handler{ + Verify: a.AuthVerify, + Next: rpcServer.ServeHTTP, + } + + http.Handle("/rpc/v0", ah) + + importAH := &auth.Handler{ + Verify: a.AuthVerify, + Next: handleImport(a.(*impl.FullNodeAPI)), + } + + http.Handle("/rest/v0/import", importAH) + + exporter, err := prometheus.NewExporter(prometheus.Options{ + Namespace: "lotus", + }) + if err != nil { + log.Fatalf("could not create the prometheus stats exporter: %v", err) + } + + http.Handle("/debug/metrics", exporter) + + lst, err := manet.Listen(addr) + if err != nil { + return xerrors.Errorf("could not listen: %w", err) + } + + srv := &http.Server{Handler: http.DefaultServeMux} + + sigCh := make(chan os.Signal, 2) + go func() { + select { + case <-sigCh: + case <-shutdownCh: + } + + log.Warn("Shutting down...") + if err := srv.Shutdown(context.TODO()); err != nil { + log.Errorf("shutting down RPC server failed: %s", err) + } + if err := stop(context.TODO()); err != nil { + log.Errorf("graceful shutting down failed: %s", err) + } + log.Warn("Graceful shutdown successful") + }() + signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT) + + return srv.Serve(manet.NetListener(lst)) +} + +func handleImport(a *impl.FullNodeAPI) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != "PUT" { + w.WriteHeader(404) + return + } + if !auth.HasPerm(r.Context(), nil, apistruct.PermWrite) { + w.WriteHeader(401) + _ = json.NewEncoder(w).Encode(struct{ Error string }{"unauthorized: missing write permission"}) + return + } + + c, err := a.ClientImportLocal(r.Context(), r.Body) + if err != nil { + w.WriteHeader(500) + _ = json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) + return + } + w.WriteHeader(200) + err = json.NewEncoder(w).Encode(struct{ Cid cid.Cid }{c}) + if err != nil { + log.Errorf("/rest/v0/import: Writing response failed: %+v", err) + return + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/.glossary.json b/vendor/github.com/filecoin-project/lotus/documentation/en/.glossary.json new file mode 100644 index 0000000000..bdc43e319f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/.glossary.json @@ -0,0 +1,146 @@ +{ + "bellman": { + "title": "Bellman", + "value": "Bellman is a rust crate for building zk-SNARK circuits. It provides circuit traits and primitive structures, as well as basic gadget implementations such as booleans and number abstractions." + }, + "nvme": { + "title": "NVMe", + "value": "(non-volatile memory express) is a host controller interface and storage protocol created to accelerate the transfer of data between enterprise and client systems and solid-state drives (SSDs) over a computer's high-speed Peripheral Component Interconnect Express (PCIe) bus." + }, + "multiaddr": { + "title": "Multiaddr", + "value": "Multiaddr is a format for encoding addresses from various well-established network protocols. It is useful to write applications that future-proof their use of addresses, and allow multiple transport protocols and addresses to coexist." + }, + "attofil": { + "title": "attoFIL", + "value": "AttoFIL is a word used to describe 10^-18 FIL. The word atto comes from the Norwegian and Danish term: atten eighteen." + }, + "fil": { + "title": "FIL", + "value": "A ticker symbol is an abbreviation used to uniquely identify Filecoin when it is used in a wallet exchange or a cryptocurrency exchange." + }, + "epost": { + "title": "Election Proof-of-Spacetime", + "value": "Election Proof-of-Spacetime couples the Proof-of-Spacetime process with block production, meaning that in order to produce a block, the miner must produce a valid Proof-of-Spacetime proof (snark output)." + }, + "jwt": { + "title": "JWT", + "value": "JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties." + }, + "json-rpc": { + "title": "JSON-RPC", + "value": "JSON-RPC is a remote procedure call protocol encoded in JSON. It is a very simple protocol (and very similar to XML-RPC), defining only a few data types and commands." + }, + "bls-address": { + "title": "BLS Signature (Address)", + "value": "A Boneh–Lynn–Shacham (BLS) signature is a digital signature scheme that allows a user to determine the authenticity of a signer, and is a commonly used signature scheme in the Filecoin Distributed Storage Network." + }, + "faucet": { + "title": "Filecoin Test Faucet", + "value": "A webpage where you can get free test Filecoin to participate in the Testnet." + }, + "chain": { + "title": "Chain", + "value": "The Filecoin Blockchain is a distributed virtual machine that achieves consensus, processes messages, accounts for storage, and maintains security in the Filecoin Protocol. It is the main interface linking various actors in the Filecoin system." + }, + "miner-power": { + "title": "Miner Power", + "value": "Miner storage in relation to network storage, tracked in the power table." + }, + "sector": { + "title": "Sector", + "value": "A fixed-size block of data of SECTOR_SIZE bytes which generally contains client's data." + }, + "sealing": { + "title": "Sealing", + "value": "A slow encoding process that returns commitments and proofs for data being stored in a sector." + }, + "seal": { + "title": "Seal", + "value": "A slow encoding process that returns commitments and proofs for data being stored in a sector." + }, + "posts": { + "title": "Proof-of-Spacetime(s)", + "value": "Filecoin is a protocol token whose blockchain runs on a novel proof, called Proof-of-Spacetime, where blocks are created by miners that are storing data." + }, + "filecoin-testnet": { + "title": "Filecoin Testnet", + "value": "Until we launch, we are making lots of changes to Lotus. The Testnet is expected to bring a few significant fixes/improvements. During Testnet, you can retrieve test filecoin from our network faucet to use as collateral to start mining. Test filecoin do not have any value – the official filecoin tokens will not be released until Mainnet launch." + }, + "filecoin-decentralized-storage-market": { + "title": "Filecoin Decentralized Storage Market", + "value": "Storage Market subsystem is the data entry point into the network. Storage miners only earn power from data stored in a storage deal and all deals live on the Filecoin network." + }, + "filecoin-proof-parameters": { + "title": "Filecoin Proof Parameters", + "value": "The proving algorithms rely on a large binary parameter file." + }, + "lotus-devnet": { + "title": "DevNet", + "value": "On the DevNets, you can store data as a storage client and also try how Filecoin mining works. The devnets are an important development tool for those who anticipate building applications on top of the Filecoin protocol or storing data on the decentralized storage market. " + }, + "filecoin-distributed-storage-network": { + "title": "Filecoin Distributed Storage Network", + "value": "Filecoin is a distributed storage network based on a blockchain mechanism. Filecoin miners can elect to provide storage capacity for the network, and thereby earn units of the Filecoin cryptocurrency (FIL) by periodically producing cryptographic proofs that certify that they are providing the capacity specified." + }, + "lotus-node": { + "title": "Lotus Node", + "value": "The Lotus Node is full of capabilities. It runs the Blockchain system, makes retrieval deals, does data transfer, supports block producer logic, and syncs and validates the chain." + }, + "block-rewards": { + "title": "Block Reward", + "value": "Over the entire lifetime of the protocol, 1,400,000,000 FIL (TotalIssuance) will be given out to miners. The rate at which the funds are given out is set to halve every six years, smoothly (not a fixed jump like in Bitcoin)." + }, + "block-producer-miner": { + "title": "Miner (Block Producer)", + "value": "The Block Producer Miner's logic. It currently shares an interface and process with the Lotus Node. A Block Producer chooses which messages to include in a block and is rewarded according to each message’s gas price and consumption, forming a market." + }, + "lotus-storage-miner": { + "title": "Storage Miner (lotus-storage-miner)", + "value": "The Storage Miner's logic. It has its own dedicated process. Contributes to the network through Sector commitments and Proofs of Spacetime to prove that it is storing the sectors it has commited to." + }, + "swarm-port": { + "title": "Swarm Port (Libp2p)", + "value": "The LibP2P Swarm manages groups of connections to peers, handles incoming and outgoing streams, and is part of the storage miners implementation. The port value is part of the Host interface." + }, + "daemon": { + "title": "Lotus Daemon", + "value": "A Daemon is a program that runs as a background process. A Daemon in the context of the Filecoin Distributed Storage Network may enable applications to communicate with peers, handle protocols, participate in pubsub, and interact with a distributed hash table (DHT)." + }, + "storage-deal": { + "title": "Storage deal", + "value": "One of the two types of deals in Filecoin markets. Storage deals are recorded on the blockchain and enforced by the protocol." + }, + "retrieval-deal": { + "title": "Retrieval deal", + "value": "One of the two types of deals in Filecoin markets. Retrieval deals are off chain and enabled by micropayment channel by transacting parties." + }, + "deal-cid": { + "title": "Deal CID", + "value": "CID is a format for referencing content in distributed information systems, it is a way to store information so it can be retrieved based on its content, not its location. DealCID specifically is used in storage deals." + }, + "data-cid": { + "title": "Data CID", + "value": "CID is a format for referencing content in distributed information systems, it is a way to store information so it can be retrieved based on its content, not its location. DataCID specifically is used to represent the file that is stored in the Filecoin Distributed Storage Network." + }, + "cid": { + "title": "CID", + "value": "A CID is a self-describing content-addressed identifier. It uses cryptographic hashes to achieve content addressing. It uses several multiformats to achieve flexible self-description, namely multihash for hashes, multicodec for data content types, and multibase to encode the CID itself into strings." + }, + "total-network-power": { + "title": "Total Network Power", + "value": "A reference to all the Power Tables for every subchain, accounting for each Lotus Storage Miner on chain." + }, + "chain-block-height": { + "title": "Chain Block Height", + "value": "Chain block height is defined as the number of blocks in the chain between any given block and the very first block in the blockchain." + }, + "block-height": { + "title": "Block Height", + "value": "Height of the Merkle Tree of a sector. A sector is a contiguous array of bytes that a miner puts together, seals, and performs Proofs of Spacetime on." + }, + "blocktime": { + "title": "Blocktime", + "value": "The time it takes for a Block to propagate to the whole network." + } +} diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/.library.json b/vendor/github.com/filecoin-project/lotus/documentation/en/.library.json new file mode 100644 index 0000000000..545eb4a5bd --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/.library.json @@ -0,0 +1,205 @@ +{ + "posts": [ + { + "title": "Hardware Requirements", + "slug": "en+hardware", + "github": "en/hardware.md", + "value": null, + "posts": [ + { + "title": "Testing Configuration", + "slug": "en+hardware-mining", + "github": "en/hardware-mining.md", + "value": null + } + ] + }, + { + "title": "Setup", + "slug": "en+getting-started", + "github": "en/getting-started.md", + "value": null, + "posts": [ + { + "title": "Arch Linux Installation", + "slug": "en+install-lotus-arch", + "github": "en/install-lotus-arch.md", + "value": null + }, + { + "title": "Ubuntu Installation", + "slug": "en+install-lotus-ubuntu", + "github": "en/install-lotus-ubuntu.md", + "value": null + }, + { + "title": "Fedora Installation", + "slug": "en+install-lotus-fedora", + "github": "en/install-lotus-fedora.md", + "value": null + }, + { + "title": "MacOS Installation", + "slug": "en+install-lotus-macos", + "github": "en/install-lotus-macos.md", + "value": null + }, + { + "title": "Updating Lotus", + "slug": "en+updating-lotus", + "github": "en/updating-lotus.md", + "value": null + }, + { + "title": "Join Testnet", + "slug": "en+join-testnet", + "github": "en/join-testnet.md", + "value": null + }, + { + "title": "Use Lotus with systemd", + "slug": "en+install-systemd-services", + "github": "en/install-systemd-services.md", + "value": null + }, + { + "title": "Setup Troubleshooting", + "slug": "en+setup-troubleshooting", + "github": "en/setup-troubleshooting.md", + "value": null + } + ] + }, + { + "title": "Architecture", + "slug": "en+arch", + "github": "en/architecture.md", + "value": null, + "posts": [] + }, { + "title": "Storage Mining", + "slug": "en+mining", + "github": "en/mining.md", + "value": null, + "posts": [ + { + "title": "Lotus Seal Worker", + "slug": "en+lotus-seal-worker", + "github": "en/mining-lotus-seal-worker.md", + "value": null + }, + { + "title": "Static Ports", + "slug": "en+setting-a-static-port", + "github": "en/setting-a-static-port.md", + "value": null + }, + { + "title": "Mining Troubleshooting", + "slug": "en+mining-troubleshooting", + "github": "en/mining-troubleshooting.md", + "value": null + } + ] + }, + { + "title": "Storing Data", + "slug": "en+storing-data", + "github": "en/storing-data.md", + "value": null, + "posts": [ + { + "title": "Storage Troubleshooting", + "slug": "en+storing-data-troubleshooting", + "github": "en/storing-data-troubleshooting.md", + "value": null + }, + { + "title": "Information for Miners", + "slug": "en+info-for-miners", + "github": "en/miner-deals.md", + "value": null + }, + { + "title": "IPFS Integration", + "slug": "en+ipfs-client-integration", + "github": "en/storing-ipfs-integration.md", + "value": null + } + ] + }, + { + "title": "Retrieving Data", + "slug": "en+retrieving-data", + "github": "en/retrieving-data.md", + "value": null, + "posts": [] + }, + { + "title": "Command Line Interface", + "slug": "en+cli", + "github": "en/cli.md", + "value": null, + "posts": [] + }, + { + "title": "API", + "slug": "en+api", + "github": "en/api.md", + "value": null, + "posts": [ + { + "title": "Remote API Support", + "slug": "en+api-scripting-support", + "github": "en/api-scripting-support.md", + "value": null + }, + { + "title": "API Troubleshooting", + "slug": "en+api-troubleshooting", + "github": "en/api-troubleshooting.md", + "value": null + } + ] + }, + { + "title": "Developer Tools", + "slug": "en+dev-tools", + "github": "en/dev-tools.md", + "value": null, + "posts": [ + { + "title": "Setup Local Devnet", + "slug": "en+setup-local-dev-net", + "github": "en/local-dev-net.md", + "value": null, + "posts": [] + }, + { + "title": "Jaeger Tracing", + "slug": "en+dev-tools-jaeger-tracing", + "github": "en/dev-tools-jaeger-tracing.md", + "value": null, + "posts": [] + } + ] + }, + { + "title": "FAQs", + "slug": "en+faqs", + "github": "en/faqs.md", + "value": null, + "posts": [] + }, + { + "title": "Glossary", + "slug": "en+glossary", + "github": "en/.glossary.json", + "value": null, + "custom": { + "glossary": true + }, + "posts": [] + } + ] +} diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/api-scripting-support.md b/vendor/github.com/filecoin-project/lotus/documentation/en/api-scripting-support.md new file mode 100644 index 0000000000..9d07aa3c8c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/api-scripting-support.md @@ -0,0 +1,25 @@ +# Remote API Support + +You may want to delegate the work **Lotus Storage Miner** or **Lotus Node** performs to other machines. +Here is how to setup the necessary authorization and environment variables. + +## Environment variables + +Environmental variables are variables that are defined for the current shell and are inherited by any child shells or processes. Environmental variables are used to pass information into processes that are spawned from the shell. + +Using the [JWT you generated](https://lotu.sh/en+api#how-do-i-generate-a-token-18865), you can assign it and the **multiaddr** to the appropriate environment variable. + +```sh +# Lotus Node +FULLNODE_API_INFO="JWT_TOKEN:/ip4/127.0.0.1/tcp/1234/http" + +# Lotus Storage Miner +STORAGE_API_INFO="JWT_TOKEN:/ip4/127.0.0.1/tcp/2345/http" +``` + +You can also use `lotus auth api-info --perm admin` to quickly create _API_INFO env vars + +- The **Lotus Node**'s `mutliaddr` is in `~/.lotus/api`. +- The default token is in `~/.lotus/token`. +- The **Lotus Storage Miner**'s `multiaddr` is in `~/.lotusstorage/config`. +- The default token is in `~/.lotusstorage/token`. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/api-troubleshooting.md b/vendor/github.com/filecoin-project/lotus/documentation/en/api-troubleshooting.md new file mode 100644 index 0000000000..0cb3a6800d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/api-troubleshooting.md @@ -0,0 +1,36 @@ +# API Troubleshooting + +## Types: params + +`params` must be an array. If there are no `params` you should still pass an empty array. + +## Types: TipSet + +For methods such as `Filecoin.StateMinerPower`, where the method accepts the argument of the type `TipSet`, you can pass `null` to use the current chain head. + +```sh +curl -X POST \ + -H "Content-Type: application/json" \ + --data '{ "jsonrpc": "2.0", "method": "Filecoin.StateMinerPower", "params": ["t0101", null], "id": 3 }' \ + 'http://127.0.0.1:1234/rpc/v0' +``` + +## Types: Sending a CID + +If you do not serialize the CID as a [JSON IPLD link](https://did-ipid.github.io/ipid-did-method/#txref), you will receive an error. Here is an example of a broken CURL request: + +```sh +curl -X POST \ + -H "Content-Type: application/json" \ + --data '{ "jsonrpc": "2.0", "method":"Filecoin.ClientGetDealInfo", "params": ["bafyreiaxl446wlnu6t6dpq4ivrjf4gda4gvsoi4rr6mpxau7z25xvk5pl4"], "id": 0 }' \ + 'http://127.0.0.1:1234/rpc/v0' +``` + +To fix it, change the `params` property to: + +```sh +curl -X POST \ + -H "Content-Type: application/json" \ + --data '{ "jsonrpc": "2.0", "method":"Filecoin.ClientGetDealInfo", "params": [{"/": "bafyreiaxl446wlnu6t6dpq4ivrjf4gda4gvsoi4rr6mpxau7z25xvk5pl4"}], "id": 0 }' \ + 'http://127.0.0.1:1234/rpc/v0' +``` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/api.md b/vendor/github.com/filecoin-project/lotus/documentation/en/api.md new file mode 100644 index 0000000000..ed42ec3253 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/api.md @@ -0,0 +1,85 @@ +# API + +Here is an early overview of how to make API calls. + +Implementation details for the **JSON-RPC** package are [here](https://github.com/filecoin-project/go-jsonrpc). + +## Overview: How do you modify the config.toml to change the API endpoint? + +API requests are made against `127.0.0.1:1234` unless you modify `.lotus/config.toml`. + +Options: + +- `http://[api:port]/rpc/v0` - HTTP endpoint +- `ws://[api:port]/rpc/v0` - Websocket endpoint +- `PUT http://[api:port]/rest/v0/import` - File import, it requires write permissions. + +## What methods can I use? + +For now, you can look into different files to find methods available to you based on your needs: + +- [Both Lotus node + storage miner APIs](https://github.com/filecoin-project/lotus/blob/master/api/api_common.go) +- [Lotus node API](https://github.com/filecoin-project/lotus/blob/master/api/api_full.go) +- [Storage miner API](https://github.com/filecoin-project/lotus/blob/master/api/api_storage.go) + +The necessary permissions for each are in [api/struct.go](https://github.com/filecoin-project/lotus/blob/master/api/struct.go). + +## How do I make an API request? + +To demonstrate making an API request, we will take the method `ChainHead` from [api/api.go](https://github.com/filecoin-project/lotus/blob/master/api/api_full.go). + +```go +ChainHead(context.Context) (*types.TipSet, error) +``` + +And create a CURL command. In this command, `ChainHead` is included as `{ "method": "Filecoin.ChainHead" }`: + +```sh +curl -X POST \ + -H "Content-Type: application/json" \ + --data '{ "jsonrpc": "2.0", "method": "Filecoin.ChainHead", "params": [], "id": 3 }' \ + 'http://127.0.0.1:1234/rpc/v0' +``` + +If the request requires authorization, add an authorization header: + +```sh +curl -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(cat ~/.lotusstorage/token)" \ + --data '{ "jsonrpc": "2.0", "method": "Filecoin.ChainHead", "params": [], "id": 3 }' \ + 'http://127.0.0.1:1234/rpc/v0' +``` + +> In the future we will add a playground to make it easier to build and experiment with API requests. + +## CURL authorization + +To authorize your request, you will need to include the **JWT** in a HTTP header, for example: + +```sh +-H "Authorization: Bearer $(cat ~/.lotusstorage/token)" +``` + +Admin token is stored in `~/.lotus/token` for the **Lotus Node** or `~/.lotusstorage/token` for the **Lotus Storage Miner**. + +## How do I generate a token? + +To generate a JWT with custom permissions, use this command: + +```sh +# Lotus Node +lotus auth create-token --perm admin + +# Lotus Storage Miner +lotus-storage-miner auth create-token --perm admin +``` + +## What authorization level should I use? + +When viewing [api/apistruct/struct.go](https://github.com/filecoin-project/lotus/blob/master/api/apistruct/struct.go), you will encounter these types: + +- `read` - Read node state, no private data. +- `write` - Write to local store / chain, and `read` permissions. +- `sign` - Use private keys stored in wallet for signing, `read` and `write` permissions. +- `admin` - Manage permissions, `read`, `write`, and `sign` permissions. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/architecture.md b/vendor/github.com/filecoin-project/lotus/documentation/en/architecture.md new file mode 100644 index 0000000000..e4808a877a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/architecture.md @@ -0,0 +1,394 @@ +# Lotus + +Lotus is an implementation of the [Filecoin Distributed Storage Network](https://filecoin.io/). +A Lotus node syncs blockchains that follow the +Filecoin protocol, validating the blocks and state transitions. +The specification for the Filecoin protocol can be found [here](https://filecoin-project.github.io/specs/). + +For information on how to setup and operate a Lotus node, +please follow the instructions [here](https://lotu.sh/en+getting-started). + +# Components + +At a high level, a Lotus node comprises the following components: + +FIXME: No mention of block production here, cross-reference with schomatis's miner doc +- The Syncer, which manages the process of syncing the blockchain +- The State Manager, which can compute the state at any given point in the chain +- The Virtual Machine (VM), which executes messages +- The Repository, where all data is stored +- P2P stuff (FIXME missing libp2p listed under other PL dependencies)? allows hello, blocksync, retrieval, storage +- API / CLI (FIXME missing, in scratchpad) +- Other Filecoin dependencies (specs actors, proofs, storage, etc., FIXME missing) +- Is the Builder worth its own component? +- Other PL dependencies (IPFS, libp2p, IPLD? FIXME, missing) +- External libraries used by Lotus and other deps (FIXME, missing) + +# Preliminaries + +We discuss some key Filecoin concepts here, aiming to explain them by contrasting them with analogous concepts +in other well-known blockchains like Ethereum. We only provide brief descriptions here; elaboration +can be found in the [spec](https://filecoin-project.github.io/specs/). + +### Tipsets + +Unlike in Ethereum, a block can have multiple parents in Filecoin. We thus refer to the parent set of a block, +instead of a single parent. +A [tipset](https://filecoin-project.github.io/specs/#systems__filecoin_blockchain__struct__tipset) +is any set of blocks that share the same parent set. + +There is no concept of "block difficulty" in Filecoin. Instead, +the weight of a tipset is simply the number of blocks in the chain that ends in that tipset. Note that a longer chain +can have less weight than a shorter chain with more blocks per tipset. + +We also allow for "null" tipsets, which include zero blocks. This allows miners to "skip" a round, and build on top +of an imaginary empty tipset if they want to. + +We call the heaviest tipset in a chain the "head" of the chain. + +### Actors and Messages + +An [Actor](https://filecoin-project.github.io/specs/#systems__filecoin_vm__actor) + is analogous to a smart contract in Ethereum. Filecoin does not allow users to define their own +actors, but comes with several [builtin actors](https://github.com/filecoin-project/specs-actors), +which can be thought of as pre-compiled contracts. + +A [Message](https://filecoin-project.github.io/specs/#systems__filecoin_vm__message) +is analogous to transactions in Ethereum. + +# Sync + +Sync refers to the process by which a Lotus node synchronizes to the heaviest chain being advertised by its peers. +At a high-level, Lotus syncs in a manner similar to most other blockchains; a Lotus node listens to the various +chains its peers claim to be at, picks the heaviest one, requests the blocks in the chosen chain, +and validates each block in that chain, running all state transitions along the way. + +The majority of the sync functionality happens in the [`Syncer`](https://github.com/filecoin-project/lotus/blob/master/chain/sync.go), +internally managed by a [`SyncManager`](https://github.com/filecoin-project/lotus/blob/master/chain/sync_manager.go). + +We now discuss the various stages of the sync process. + +## Sync setup + +When a Lotus node connects to a new peer, we exchange the head of our chain +with the new peer through [the `hello` protocol](https://github.com/filecoin-project/lotus/blob/master/node/hello/hello.go). +If the peer's head is heavier than ours, we try to sync to it. Note +that we do NOT update our chain head at this stage. + +## Fetching and Persisting Block Headers + +Note: The API refers to these stages as `StageHeaders` and `StagePersistHeaders`. + +We proceed in the sync process by requesting block headers from the peer, +moving back from their head, until we reach a tipset that we have in common +(such a common tipset must exist, thought it may simply be the genesis block). +The functionality can be found in `Syncer::collectHeaders()`. + +If the common tipset is our head, we treat the sync as a "fast-forward", else we must +drop part of our chain to connect to the peer's head (referred to as "forking"). + +FIXME: This next para might be best replaced with a link to the validation doc +Some of the possible causes of failure in this stage include: + +- The chain is linked to a block that we have previously marked as bad, +and stored in a [`BadBlockCache`](https://github.com/filecoin-project/lotus/blob/master/chain/badtscache.go). +- The beacon entries in a block are inconsistent (FIXME: more details about what is validated here wouldn't be bad). +- Switching to this new chain would involve a chain reorganization beyond the allowed threshold (SPECK-CHECK). + +## Fetching and Validating Blocks + +Note: The API refers to this stage as `StageMessages`. + +Having acquired the headers and found a common tipset, we then move forward, requesting the full blocks, including the messages. + +For each block, we first confirm the syntactic validity of the block (SPECK-CHECK), +which includes the syntactic validity of messages included +in the block. +We then apply the messages, running all the state transitions, and compare the state root we calculate with the provided state root. + + +FIXME: This next para might be best replaced with a link to the validation doc +Some of the possible causes of failure in this stage include: + +- a block is syntactically invalid (including potentially containing syntactically invalid messages) +- the computed state root after applying the block doesn't match the block's state root +- FIXME: Check what's covered by syntactic validity, and add anything important that isn't (like proof validity, future checks, etc.) + +The core functionality can be found in `Syncer::ValidateTipset()`, with `Syncer::checkBlockMessages()` performing +syntactic validation of messages. + +## Setting the head + +Note: The API refers to this stage as `StageSyncComplete`. + +If all validations pass we will now set that head as our heaviest tipset in +[`ChainStore`](https://github.com/filecoin-project/lotus/blob/master/chain/store/store.go). +We already have the full state, since we calculated +it during the sync process. + +FIXME (aayush) I don't fuilly understand the next 2 paragraphs, but it seems important. Confirm and polish. +Relevant issue in IPFS: https://github.com/ipfs/ipfs-docs/issues/264 + +It is important to note at this point that similar to the IPFS architecture of addressing by content and not by location/address (FIXME: check and link to IPFS docs) the "actual" chain stored in the node repo is *relative* to which CID we look for. We always have stored a series of Filecoin blocks pointing to other blocks, each a potential chain in itself by following its parent's reference, and its parent's parent, and so on up to the genesis block. (FIXME: We need a diagram here, one of the Filecoin blog entries might have something similar to what we are describing here.) It only depends on *where* (location) do we start to look for. The *only* address/location reference we hold of the chain, a relative reference, is the `heaviest` pointer. This is reflected by the fact that we don't store it in the `Blockstore` by a fixed, *absolute*, CID that reflects its contents, as this will change each time we sync to a new head (FIXME: link to the immutability IPFS doc that I need to write). + +FIXME: Create a further reading appendix, move this next para to it, along with other +extraneous content +This is one of the few items we store in `Datastore` by key, location, allowing its contents to change on every sync. This is reflected in the `(*ChainStore) writeHead()` function (called by `takeHeaviestTipSet()` above) where we reference the pointer by the explicit `chainHeadKey` address (the string `"head"`, not a hash embedded in a CID), and similarly in `(*ChainStore).Load()` when we start the node and create the `ChainStore`. Compare this to a Filecoin block or message which are immutable, stored in the `Blockstore` by CID, once created they never change. + +## Keeping up with the chain + +A Lotus node also listens for new blocks broadcast by its peers over the `gossipsub` channel (see FIXME for more). +If we have validated such a block's parent tipset, and adding it to our tipset at its height would lead to a heavier +head, then we validate and add this block. The validation described is identical to that invoked during the sync +process (indeed, it's the same codepath). + +# State + +In Filecoin, the chain state at any given point is a collection of data stored under a root CID +encapsulated in the [`StateTree`](https://github.com/filecoin-project/lotus/blob/master/chain/state/statetree.go), +and accessed through the +[`StateManager`](https://github.com/filecoin-project/lotus/blob/master/chain/stmgr/stmgr.go). +The state at the chain's head is thus easily tracked and updated in a state root CID. +(FIXME: Talk about CIDs somewhere, we might want to explain some of the modify/flush/update-root mechanism here.)) + +## Calculating a Tipset State + +Recall that a tipset is a set of blocks that have identical parents (that is, that are built on top of the same tipset). +The genesis tipset comprises the genesis block(s), and has some state corresponding to it. + +The methods `TipSetState()` and `computeTipSetState()` in +[`StateManager`](https://github.com/filecoin-project/lotus/blob/master/chain/stmgr/stmgr.go) + are responsible for computing +the state that results from applying a tipset. This involves applying all the messages included +in the tipset, and performing implicit operations like awarding block rewards. + +Any valid block built on top of a tipset `ts` should have its Parent State Root equal to the result of +calculating the tipset state of `ts`. Note that this means that all blocks in a tipset must have the same Parent +State Root (which is to be expected, since they have the same parent tipset) + +### Preparing to apply a tipset + +When `StateManager::computeTipsetState()` is called with a tipset, `ts`, +it retrieves the parent state root of the blocks in `ts`. It also creates a list of `BlockMessages`, which wraps the BLS +and SecP messages in a block along with the miner that produced the block. + +Control then flows to `StateManager::ApplyBlocks()`, which builds a VM to apply the messages given to it. The VM +is initialized with the parent state root of the blocks in `ts`. We apply the blocks in `ts` in order (see FIXME for +ordering of blocks in a tipset). + +### Applying a block + +For each block, we prepare to apply the ordered messages (first BLS, then SecP). Before applying a message, we check if +we have already applied a message with that CID within the scope of this method. If so, we simply skip that message; +this is how duplicate messages included in the same tipset are skipped (with only the miner of the "first" block to +include the message getting the reward). For the actual process of message application, see FIXME (need an +internal link here), for now we +simply assume that the outcome of the VM applying a message is either an error, or a +[`MessageReceipt`](https://github.com/filecoin-project/lotus/blob/master/chain/types/message_receipt.go) + and some +other information. + +We treat an error from the VM as a showstopper; there is no recovery, and no meaningful state can be computed for `ts`. +Given a successful receipt, we add the rewards and penalties to what the miner has earned so far. Once all the messages +included in a block have been applied (or skipped if they're a duplicate), we use an implicit message to call +the Reward Actor. This awards the miner their reward for having won a block, and also awards / penalizes them based +on the message rewards and penalties we tracked. + +We then proceed to apply the next block in `ts`, using the same VM. This means that the state changes that result +from applying a message are visible when applying all subsequent messages, even if they are included in a different block. + +### Finishing up + +Having applied all the blocks, we send one more implicit message, to the Cron Actor, which handles operations that +must be performed at the end of every epoch (see FIXME for more). The resulting state after calling the Cron Actor +is the computed state of the tipset. + +# Virtual Machine + +The Virtual Machine (VM) is responsible for executing messages. +The [Lotus Virtual Machine](https://github.com/filecoin-project/lotus/blob/master/chain/vm/vm.go) +invokes the appropriate methods in the builtin actors, and provides +a [`Runtime`](https://github.com/filecoin-project/specs-actors/blob/master/actors/runtime/runtime.go) +interface to the [builtin actors](https://github.com/filecoin-project/specs-actors) +that exposes their state, allows them to take certain actions, and meters +their gas usage. The VM also performs balance transfers, creates new account actors as needed, and tracks the gas reward, +penalty, return value, and exit code. + +## Applying a Message + +The primary entrypoint of the VM is the `ApplyMessage()` method. This method should not return an error +unless something goes unrecoverably wrong. + +The first thing this method does is assess if the message provided meets any of the penalty criteria. +If so, a penalty is issued, and the method returns. Next, the entire gas cost of the message is transferred to +a temporary gas holder account. It is from this gas holder that gas will be deducted; if it runs out of gas, the message +fails. Any unused gas in this holder will be refunded to the message's sender at the end of message execution. + +The VM then increments the sender's nonce, takes a snapshot of the state, and invokes `VM::send()`. + +The `send()` method creates a [`Runtime`](https://github.com/filecoin-project/lotus/blob/master/chain/vm/runtime.go) + for the subsequent message execution. +It then transfers the message's value to the recipient, creating a new account actor if needed. + +### Method Invocation + +We use reflection to translate a Filecoin message for the VM to an actual Go function, relying on the VM's +[`invoker`](https://github.com/filecoin-project/lotus/blob/master/chain/vm/invoker.go) structure. +Each actor has its own set of codes defined in `specs-actors/actors/builtin/methods.go`. +The `invoker` structure maps the builtin actors' CIDs + to a list of `invokeFunc` (one per exported method), which each take the `Runtime` (for state manipulation) + and the serialized input parameters. + +FIXME (aayush) Polish this next para. + +The basic layout (without reflection details) of `(*invoker).transform()` is as follows. From each actor registered in `NewInvoker()` we take its `Exports()` methods converting them to `invokeFunc`s. The actual method is wrapped in another function that takes care of decoding the serialized parameters and the runtime, this function is passed to `shimCall()` that will encapsulate the actors code being run inside a `defer` function to `recover()` from panics (we fail in the actors code with panics to unwrap the stack). The return values will then be (CBOR) marshaled and returned to the VM. + +### Returning from the VM + +Once method invocation is complete (including any subcalls), we return to `ApplyMessage()`, which receives +the serialized response and the [`ActorError`](https://github.com/filecoin-project/lotus/blob/master/chain/actors/aerrors/error.go). +The sender will be charged the appropriate amount of gas for the returned response, which gets put into the +[`MessageReceipt`](https://github.com/filecoin-project/lotus/blob/master/chain/types/message_receipt.go). + +The method then refunds any unused gas to the sender, sets up the gas reward for the miner, and +wraps all of this into an `ApplyRet`, which is returned. + +# Building a Lotus node + +When we launch a Lotus node with the command `./lotus daemon` +(see [here](https://github.com/filecoin-project/lotus/blob/master/cmd/lotus/daemon.go) for more), +the node is created through [dependency injection](https://godoc.org/go.uber.org/fx). +This relies on reflection, which makes some of the references hard to follow. +The node sets up all of the subsystems it needs to run, such as the repository, the network connections, thechain sync +service, etc. +This setup is orchestrated through calls to the `node.Override` function. +The structure of each call indicates the type of component it will set up +(many defined in [`node/modules/dtypes/`](https://github.com/filecoin-project/lotus/tree/master/node/modules/dtypes)), +and the function that will provide it. +The dependency is implicit in the argument of the provider function. + +As an example, consider the `modules.ChainStore()` function that provides the +[`ChainStore`](https://github.com/filecoin-project/lotus/blob/master/chain/store/store.go) structure. +It takes as one of its parameters the [`ChainBlockstore`](https://github.com/filecoin-project/lotus/blob/master/node/modules/dtypes/storage.go) +type, which becomes one of its dependencies. +For the node to be built successfully the `ChainBlockstore` will need to be provided before `ChainStore`, a requirement +that is made explicit in another `Override()` call that sets the provider of that type as the `ChainBlockstore()` function. + +## The Repository + +The repo is the directory where all of a node's information is stored. The node is entirely defined by its repo, which +makes it easy to port to another location. This one-to-one relationship means we can speak +of the node as the repo it is associated with, instead of the daemon process that runs from that repo. + +Only one daemon can run be running with an associated repo at a time. +A process signals that it is running a node associated with a particular repo, by creating and acquiring +a `repo.lock`. + +```sh +lsof ~/.lotus/repo.lock +# COMMAND PID +# lotus 52356 +``` +Trying to launch a second daemon hooked to the same repo leads to a `repo is already locked (lotus daemon already running)` +error. + +The `node.Repo()` function (`node/builder.go`) contains most of the dependencies (specified as `Override()` calls) +needed to properly set up the node's repo. We list the most salient ones here. + +### Datastore + +`Datastore` and `ChainBlockstore`: Data related to the node state is saved in the repo's `Datastore`, +an IPFS interface defined [here](https://github.com/ipfs/go-datastore/blob/master/datastore.go). +Lotus creates this interface from a [Badger DB](https://github.com/dgraph-io/badger) in + [`FsRepo`](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go). +Every piece of data is fundamentally a key-value pair in the `datastore` directory of the repo. +There are several abstractions laid on top of it that appear through the code depending on *how* we access it, +but it is important to remember that we're always accessing it from the same place. + +FIXME: Maybe mention the `Batching` interface as the developer will stumble upon it before reaching the `Datastore` one. + +#### Blocks + +FIXME: IPFS blocks vs Filecoin blocks ideally happens before this / here + +The [`Blockstore` interface](`github.com/ipfs/go-ipfs-blockstore/blockstore.go`) structures the key-value pair +into the CID format for the key and the [`Block` interface](`github.com/ipfs/go-block-format/blocks.go`) for the value. +The `Block` value is just a raw string of bytes addressed by its hash, which is included in the CID key. + +`ChainBlockstore` creates a `Blockstore` in the repo under the `/blocks` namespace. +Every key stored there will have the `blocks` prefix so that it does not collide with other stores that use the same repo. + +FIXME: Link to IPFS documentation about DAG, CID, and related, especially we need a diagram that shows how do we wrap each datastore inside the next layer (datastore, batching, block store, gc, etc). + +#### Metadata + +`modules.Datastore()` creates a `dtypes.MetadataDS`, which is an alias for the basic `Datastore` interface. +Metadata is stored here under the `/metadata` prefix. +(FIXME: Explain *what* is metadata in contrast with the block store, namely we store the pointer to the heaviest chain, we might just link to that unwritten section here later.) + +FIXME: Explain the key store related calls (maybe remove, per Schomatis) + +### LockedRepo + +`LockedRepo()`: This method doesn't create or initialize any new structures, but rather registers an + `OnStop` [hook](https://godoc.org/go.uber.org/fx/internal/lifecycle#Hook) + that will close the locked repository associated with it on shutdown. + + +### Repo types / Node types + +FIXME: This section needs to be clarified / corrected...I don't fully understand the config differences (what do they have in common, if anything?) + +At the end of the `Repo()` function we see two mutually exclusive configuration calls based on the `RepoType` (`node/repo/fsrepo.go`). +```Go + ApplyIf(isType(repo.FullNode), ConfigFullNode(c)), + ApplyIf(isType(repo.StorageMiner), ConfigStorageMiner(c)), +``` +As we said, the repo fully identifies the node so a repo type is also a *node* type, in this case a full node or a storage miner. (FIXME: What is the difference between the two, does *full* imply miner?) In this case the `daemon` command will create a `FullNode`, this is specified in the command logic itself in `main.DaemonCmd()`, the `FsRepo` created (and passed to `node.Repo()`) will be initiated with that type (see `(*FsRepo).Init(t RepoType)`). + +## Online + +FIXME: Much of this might need to be subsumed into the p2p section + +The `node.Online()` configuration function (`node/builder.go`) initializes components that involve connecting to, +or interacting with, the Filecoin network. These connections are managed through the libp2p stack (FIXME link to this section when it exists). +We discuss some of the components found in the full node type (that is, included in the `ApplyIf(isType(repo.FullNode),` call). + +#### Chainstore + +`modules.ChainStore()` creates the [`store.ChainStore`](https://github.com/filecoin-project/lotus/blob/master/chain/store/store.go)) +that wraps the stores + previously instantiated in `Repo()`. It is the main point of entry for the node to all chain-related data + (FIXME: this is incorrect, we sometimes access its underlying block store directly, and probably shouldn't). + It also holds the crucial `heaviest` pointer, which indicates the current head of the chain. + + #### ChainExchange and ChainBlockservice +`ChainExchange()` and `ChainBlockservice()` establish a BitSwap connection (FIXME libp2p link) +to exchange chain information in the form of `blocks.Block`s stored in the repo. (See sync section for more details, the Filecoin blocks and messages are backed by these raw IPFS blocks that together form the different structures that define the state of the current/heaviest chain.) + +#### Incoming handlers +`HandleIncomingBlocks()` and `HandleIncomingMessages()` start the services in charge of processing new Filecoin blocks +and messages from the network (see `` for more information about the topics the node is subscribed to, FIXME: should that be part of the libp2p section or should we expand on gossipsub separately?). + +#### Hello +`RunHello()`: starts the services to both send (`(*Service).SayHello()`) and receive (`(*Service).HandleStream()`, `node/hello/hello.go`) +`hello` messages. When nodes establish a new connection with each other, they exchange these messages +to share chain-related information (namely their genesis block and their heaviest tipset). + +#### Syncer +`NewSyncer()` creates the `Syncer` structure and starts the services related to the chain sync process (FIXME link). + +### Ordering the dependencies + +We can establish the dependency relations by looking at the parameters that each function needs and by understanding +the architecture of the node and how the different components relate to each other (the chief purpose of this document). + +As an example, the sync mechanism depends on the node being able to exchange different IPFS blocks with the network, +so as to be able to request the "missing pieces" needed to construct the chain. This dependency is reflected by `NewSyncer()` +having a `blocksync.BlockSync` parameter, which in turn depends on `ChainBlockservice()` and `ChainExchange()`. +The chain exchange service further depends on the chain store to save and retrieve chain data, which is reflected +in `ChainExchange()` having `ChainGCBlockstore` as a parameter (which is just a wrapper around `ChainBlockstore` capable + of garbage collection). + +This block store is the same store underlying the chain store, which is an indirect dependency of `NewSyncer()` (through the `StateManager`). +(FIXME: This last line is flaky, we need to resolve the hierarchy better, we sometimes refer to the chain store and sometimes to its underlying block store. We need a diagram to visualize all the different components just mentioned otherwise it is too hard to follow. We probably even need to skip some of the connections mentioned.) diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/block-validation.md b/vendor/github.com/filecoin-project/lotus/documentation/en/block-validation.md new file mode 100644 index 0000000000..ccd83a9045 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/block-validation.md @@ -0,0 +1,137 @@ +# Incoming block validations + +This document reviews the code flow that takes place inside the full node after receiving a new block from the GossipSub `/fil/blocks` topic and traces all of its protocol-related validation logic. We do not include validation logic *inside* the VM, the analysis stops at `(*VM).Invoke()`. The `V:` tag explicitly signals validations throughout the text. + +## `modules.HandleIncomingBlocks()` + +We subscribe to the `/fil/blocks` PubSub topic to receive external blocks from peers in the network and register a block validator that operates at the PubSub (`libp2p` stack) level, validating each PubSub message containing a Filecoin block header. + +`V:` PubSub message is a valid CBOR `BlockMsg`. + +`V:` Total messages in block are under `BlockMessageLimit`. + +`V:` Aggregate message CIDs, encapsulated in the `MsgMeta` structure, serialize to the `Messages` CID in the block header (`ValidateMsgMeta()`). + +`V:` Miner `Address` in block header is present and corresponds to a public-key address in the current chain state. + +`V:` Block signature (`BlockSig`) is present and belongs to the public-key address retrieved for the miner (`CheckBlockSignature()`). + +## `sub.HandleIncomingBlocks()` + +Assemble a `FullBlock` from the received block header retrieving its Filecoin messages. + +`V:` Block messages CIDs can be retrieved from the network and decode into valid CBOR `Message`/`SignedMessage`. + +## `(*Syncer).InformNewHead()` + +Assemble a `FullTipSet` populated with the single block received earlier. + +`V:` `ValidateMsgMeta()` (already done in the topic validator). + +`V:` Block's `ParentWeight` is greater than the one from the (first block of the) heaviest tipset. + +## `(*Syncer).Sync()` + +`(*Syncer).collectHeaders()`: we retrieve all tipsets from the received block down to our chain. Validation now is expanded to *every* block inside these tipsets. + +`V`: Beacon entires are ordered by their round number. + +`V:` Tipset `Parents` CIDs match the fetched parent tipset through block sync. (This check is not enforced correctly at the moment, see [issue](https://github.com/filecoin-project/lotus/issues/1918).) + +## `(*Syncer).ValidateBlock()` + +This function contains most of the validation logic grouped in separate closures that run asynchronously, this list does not reflect validation order then. + +`V:` Block `Timestamp`: + * Is not bigger than current time plus `AllowableClockDriftSecs`. + * Is not smaller than previous block's `Timestamp` plus `BlockDelay` (including null blocks). + +### Messages + +We check all the messages contained in one block at a time (`(*Syncer).checkBlockMessages()`). + +`V:` The block's `BLSAggregate` matches the aggregate of BLS messages digests and public keys (extracted from the messages `From`). + +`V:` Each `secp256k1` message `Signature` is signed with the public key extracted from the message `From`. + +`V:` Aggregate message CIDs, encapsulated in the `MsgMeta` structure, serialize to the `Messages` CID in block header (similar to `ValidateMsgMeta()` call). + +`V:` For each message, in `ValidForBlockInclusion()`: +* Message fields `Version`, `To`, `From`, `Value`, `GasPrice`, and `GasLimit` are correctly defined. +* Message `GasLimit` is under the message minimum gas cost (derived from chain height and message length). + +`V:` Actor associated with message `From` exists and is an account actor, its `Nonce` matches the message `Nonce`. + +### Miner + +`V:` Miner address is registered in the `Claims` HAMT of the Power actor. + +### Compute parent tipset state + +`V:` Block's `ParentStateRoot` CID matches the state CID computed from the parent tipset. + +`V:` Block's `ParentMessageReceipts` CID matches receipts CID computed from the parent tipset. + +### Winner + +Draw randomness for current epoch with minimum ticket from previous tipset, using `ElectionProofProduction` +domain separation tag. +`V`: `ElectionProof.VRFProof` is computed correctly by checking BLS signature using miner's key. +`V`: Miner is not slashed in `StoragePowerActor`. +`V`: Check if ticket is a winning ticket: +``` +h := blake2b(VRFProof) +lhs := AsInt(h) * totalNetworkPower +rhs := minerPower * 2^256 +if lhs < rhs { return "Winner" } else { return "Not a winner" } +``` + +### Block signature + +`V:` `CheckBlockSignature()` (same signature validation as the one applied to the incoming block). + +### Beacon values check + +`V`: Validate that all `BeaconEntries` are valid. Check that every one of them is a signature of a message: `previousSignature || round` signed using drand's public key. +`V`: All entries between `MaxBeaconRoundForEpoch` down to `prevEntry` (from previous tipset) are included. + +### Verify VRF Ticket chain + +Draw randomness for current epoch with minimum ticket from previous tipset, using `TicketProduction` +domain separation tag. +`V`: `VerifyVRF` using drawn randomness and miner public key. + +### Winning PoSt proof + +Draw randomness for current epoch with `WinningPoSt` domain separation tag. +Get list of sectors challanged in this epoch for this miner, based on the randomness drawn. + +`V`: Use filecoin proofs system to verify that miner prooved access to sealed versions of these sectors. + +## `(*StateManager).TipSetState()` + +Called throughout the validation process for the parent of each tipset being validated. The checks here then do not apply to the received new head itself that started the validation process. + +### `(*StateManager).computeTipSetState()` + +`V:` Every block in the tipset should belong to different a miner. + +### `(*StateManager).ApplyBlocks()` + +We create a new VM with the tipset's `ParentStateRoot` (this is then the parent state of the parent of the tipset currently being validated) on which to apply all messages from all blocks in the tipset. For each message independently we apply the validations listed next. + +### `(*VM).ApplyMessage()` + +`V:` Basic gas and value checks in `checkMessage()`: +* Message `GasLimit` is bigger than zero. +* Message `GasPrice` and `Value` are set. + +`V:` Message storage gas cost is under the message's `GasLimit`. + +`V:` Message's `Nonce` matches nonce in actor retrieved from message's `From`. + +`V:` Message's maximum gas cost (derived from its `GasLimit`, `GasPrice`, and `Value`) is under the balance of the actor retrieved from message's `From`. + +### `(*VM).send()` + +`V:` Message's transfer `Value` is under the balance in actor retrieved from message's `From`. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/cli.md b/vendor/github.com/filecoin-project/lotus/documentation/en/cli.md new file mode 100644 index 0000000000..fd26400d0f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/cli.md @@ -0,0 +1,108 @@ +# Lotus Command Line Interface + +The Command Line Interface (CLI) is a convenient way to interact with +a Lotus node. You can use the CLI to operate your node, +get information about the blockchain, +manage your accounts and transfer funds, +create storage deals, and much more! + +The CLI is intended to be self-documenting, so when in doubt, simply add `--help` +to whatever command you're trying to run! This will also display all of the +input parameters that can be provided to a command. + +We highlight some of the commonly +used features of the CLI below. +All CLI commands should be run from the home directory of the Lotus project. + +## Operating a Lotus node + +### Starting up a node + +```sh +lotus daemon +``` +This command will start up your Lotus node, with its API port open at 1234. +You can pass `--api=` to use a different port. + +### Checking your sync progress + +```sh +lotus sync status +``` +This command will print your current tipset height under `Height`, and the target tipset height +under `Taregt`. + +You can also run `lotus sync wait` to get constant updates on your sync progress. + +### Getting the head tipset + +```sh +lotus chain head +``` + +### Control the logging level + +```sh +lotus log set-level +``` +This command can be used to toggle the logging levels of the different +systems of a Lotus node. In decreasing order +of logging detail, the levels are `debug`, `info`, `warn`, and `error`. + +As an example, +to set the `chain` and `blocksync` to log at the `debug` level, run +`lotus log set-level --system chain --system blocksync debug`. + +To see the various logging system, run `lotus log list`. + +### Find out what version of Lotus you're running + +```sh +lotus version +``` + +## Managing your accounts + +### Listing accounts in your wallet + +```sh +lotus wallet list +``` + +### Creating a new account + +```sh +lotus wallet new bls +``` +This command will create a new BLS account in your wallet; these +addresses start with the prefix `t3`. Running `lotus wallet new secp256k1` +(or just `lotus wallet new`) will create +a new Secp256k1 account, which begins with the prefix `t1`. + +### Getting an account's balance + +```sh +lotus wallet balance
    +``` + +### Transferring funds + +```sh +lotus send --source= +``` +This command will transfer `amount` (in attoFIL) from `source address` to `destination address`. + +### Importing an account into your wallet + +```sh +lotus wallet import +``` +This command will import an account whose private key is saved at the specified file. + +### Exporting an account from your wallet + +```sh +lotus wallet export
    +``` +This command will print out the private key of the specified address +if it is in your wallet. Always be careful with your private key! diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-jaeger-tracing.md b/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-jaeger-tracing.md new file mode 100644 index 0000000000..bbe4d30523 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-jaeger-tracing.md @@ -0,0 +1,26 @@ +# Jaeger Tracing + +Lotus has tracing built into many of its internals. To view the traces, first download [Jaeger](https://www.jaegertracing.io/download/) (Choose the 'all-in-one' binary). Then run it somewhere, start up the lotus daemon, and open up localhost:16686 in your browser. + +## Open Census + +Lotus uses [OpenCensus](https://opencensus.io/) for tracing application flow. This generates spans through the execution of annotated code paths. + +Currently it is set up to use Jaeger, though other tracing backends should be fairly easy to swap in. + +## Running Locally + +To easily run and view tracing locally, first, install jaeger. The easiest way to do this is to [download the binaries](https://www.jaegertracing.io/download/) and then run the `jaeger-all-in-one` binary. This will start up jaeger, listen for spans on `localhost:6831`, and expose a web UI for viewing traces on `http://localhost:16686/`. + +Now, to start sending traces from Lotus to Jaeger, set the environment variable `LOTUS_JAEGER` to `localhost:6831`, and start the `lotus daemon`. + +Now, to view any generated traces, open up `http://localhost:16686/` in your browser. + +## Adding Spans + +To annotate a new codepath with spans, add the following lines to the top of the function you wish to trace: + +```go +ctx, span := trace.StartSpan(ctx, "put function name here") +defer span.End() +``` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-pond-ui.md b/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-pond-ui.md new file mode 100644 index 0000000000..e5c9920730 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools-pond-ui.md @@ -0,0 +1,32 @@ +# Pond UI + +Pond is a graphical testbed for [Lotus](https://docs.lotu.sh). Using it will setup a separate local network which is helpful for debugging. Pond will spin up nodes, connect them in a given topology, start them mining, and observe how they function over time. + +## Build + +```sh +make pond +``` + +## Run + +```sh +./pond run +``` + +Now go to `http://127.0.0.1:2222`. + +## What can I test? + +- The `Spawn Node` button starts a new **Lotus Node** in a new draggable window. +- Click `[Spawn Storage Miner]` to start a **Lotus Storage Miner**. This require's the node's wallet to have funds. +- Click on `[Client]` to open the **Lotus Node**'s client interface and propose a deal with an existing Miner. If successful you'll see a payment channel open up with that Miner. + +Don't leave Pond unattended for more than 10 hours, the web client will eventually consume all available RAM. + +## Troubleshooting + +- Turn it off and on - Start at the top +- `rm -rf ~/.lotus ~/.lotusstorage/`, this command will delete chain sync data, stored wallets, and other configurations so be careful. +- Verify you have the correct versions of dependencies +- If stuck on a bad fork, try `lotus chain sethead --genesis` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools.md b/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools.md new file mode 100644 index 0000000000..60b9b26d40 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/dev-tools.md @@ -0,0 +1,3 @@ +# Developer Tools + +> Running a local network can be a great way to understand how Lotus works and test your setup. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/dev/WIP-arch-complementary-notes.md b/vendor/github.com/filecoin-project/lotus/documentation/en/dev/WIP-arch-complementary-notes.md new file mode 100644 index 0000000000..00bedb56a9 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/dev/WIP-arch-complementary-notes.md @@ -0,0 +1,153 @@ +# Genesis block + +Seems a good way to start exploring the VM state though the instantiation of its different actors like the storage power. + +Explain where do we load the genesis block, the CAR entries, and we set the root of the state. Follow the daemon command option, `chain.LoadGenesis()` saves all the blocks of the CAR file into the store provided by `ChainBlockstore` (this should already be explained in the previous section). The CAR root (MT root?) of those blocks is decoded into the `BlockHeader` that will be the Filecoin (genesis) block of the chain, but most of the information was stored in the raw data (non-Filecoin, what's the correct term?) blocks forwarded directly to the chain, the block header just has a pointer to it. + +`SetGenesis` block with name 0. `(ChainStore).SetGenesis()` stores it there. + +`MakeInitialStateTree` (`chain/gen/genesis/genesis.go`, used to construct the genesis block (`MakeGenesisBlock()`), constructs the state tree (`NewStateTree`) which is just a "pointer" (root node in the HAMT) to the different actors. It will be continuously used in `(*StateTree).SetActor()` an `types.Actor` structure under a certain `Address` (in the HAMT). (How does the `stateSnaps` work? It has no comments.) + +From this point we can follow different setup function like: + +* `SetupInitActor()`: see the `AddressMap`. + +* `SetupStoragePowerActor`: initial (zero) power state of the chain, most important attributes. + +* Account actors in the `template.Accounts`: `SetActor`. + +Which other actor type could be helpful at this point? + +# Basic concepts + +What should be clear at this point either from this document or the spec. + +## Addresses + +## Accounts + +# Sync Topics PubSub + +Gossip sub spec and some introduction. + +# Look at the constructor of a miner + +Follow the `lotus-storage-miner` command to see how a miner is created, from the command to the message to the storage power logic. + +# Directory structure so far, main structures seen, their relation + +List what are the main directories we should be looking at (e.g., `chain/`) and the most important structures (e.g., `StateTree`, `Runtime`, etc.) + +# Tests + +Run a few messages and observe state changes. What is the easiest test that also let's us "interact" with it (modify something and observe the difference). + +### Filecoin blocks vs IPFS blocks + +The term *block* has different meanings depending on the context, many times both meanings coexist at once in the code and it is important to distinguish them. (FIXME: link to IPFS blocks and related doc throughout this explanation). In terms of the lower IPFS layer, in charge of storing and retrieving data, both present at the repo or accessible through the network (e.g., through the BitSwap protocol discussed later), a block is a string of raw bytes identified by its hash, embedded and fully qualified in a CID identifier. IPFS blocks are the "building blocks" of almost any other piece of (chain) data described in the Filecoin protocol. + +In contrast, in the higher Filecoin (application) layer, a block is roughly (FIXME: link to spec definition, if we have any) a set of zero or more messages grouped together by a single miner which is itself grouped with other blocks (from other miners) in the same round to form a tipset. The Filecoin blockchain is a series of "chained" tipsets, each referencing its parent by its header's *CID*, that is, its header as seen as a single IPFS block, this is where both layers interact. + +Using now the full Go package qualifiers to avoid any ambiguity, the Filecoin block, `github.com/filecoin-project/lotus/chain/types.FullBlock`, is defined as, + +```Go +package types + +import "github.com/ipfs/go-cid" + +type FullBlock struct { + Header *BlockHeader + BlsMessages []*Message + SecpkMessages []*SignedMessage +} + +func (fb *FullBlock) Cid() cid.Cid { + return fb.Header.Cid() +} +``` + +It has, besides the Filecoin messages, a header with protocol related information (e.g., its `Height`) which is (like virtually any other piece of data in the Filecoin protocol) stored, retrieved and shared as an IPFS block with its corresponding CID, + +```Go +func (b *BlockHeader) Cid() cid.Cid { + sb, err := b.ToStorageBlock() + + return sb.Cid() +} + +func (b *BlockHeader) ToStorageBlock() (block.Block, error) { + data, err := b.Serialize() + + return github.com/ipfs/go-block-format.block.NewBlockWithCid(data) +} +``` + +These edited extracts from the `BlockHeader` show how it's treated as an IPFS block, `github.com/ipfs/go-block-format.block.BasicBlock`, to be both stored and referenced by its block storage CID. + +This duality permeates the code (and the Filecoin spec for that matter) but it is usually clear within the context to which block we are referring to. Normally the unqualified *block* is reserved for the Filecoin block and we won't usually refer to the IPFS one but only implicitly through the concept of its CID. With enough understanding of both stack's architecture the two definitions can coexist without much confusion as we will abstract away the IPFS layer and just use the CID as an identifier that we now its unique for two sequences of different *raw* byte strings. + +(FIXME: We use to do this presentation when talking about `gossipsub` topics and incoming blocks, and had to deal with, besides the block ambiguity, a similar confusion with the *message* term, used in libp2p to name anything that comes through the network, needing to present the extremely confusing hierarchy of a libp2p message containing a Filecoin block, identified by a IPFS block CID, containing Filecoin messages.) + +FIXME: Move the following tipset definition to sync or wherever is most needed, to avoid making this more confusing. + +Messages from the same round are collected into a block set (`chain/store/fts.go`): + +```Go +type FullTipSet struct { + Blocks []*types.FullBlock + tipset *types.TipSet + cids []cid.Cid +} +``` + +The "tipset" denomination might be a bit misleading as it doesn't refer *only* to the tip, the block set from the last round in the chain, but to *any* set of blocks, depending on the context the tipset is the actual tip or not. From its own perspective any block set is always the tip because it assumes nothing from following blocks. + +# CLI, API + +Explain how do we communicate with the node, both in terms of the CLI and the programmatic way (to create our own tools). + +## Client/server architecture + +In terms of the Filecoin network the node is a peer on a distributed hierarchy, but in terms of how we interact with the node we have client/server architecture. + +The node itself was initiated with the `daemon` command, it already started syncing to the chain by default. Along with that service it also started a [JSON-RPC](https://en.wikipedia.org/wiki/JSON-RPC) server to allow a client to interact with it. (FIXME: Check if this client is local or can be remote, link to external documentation of connection API.) + +We can connect to this server through the Lotus CLI. Virtually any other command other than `daemon` will run a client that will connect (by default) to the address specified in the `api` file in the repo associated with the node (by default in `~/.lotus`), e.g., + +```sh +cat ~/.lotus/api && echo +# /ip4/127.0.0.1/tcp/1234/http + +# With `lotus daemon` running in another terminal. +nc -v -z 127.0.0.1 1234 + +# Start daemon and turn off the logs to not clutter the command line. +bash -c "lotus daemon &" && + lotus wait-api && + lotus log set-level error # Or a env.var in the daemon command. + +nc -v -z 127.0.0.1 1234 +# Connection to 127.0.0.1 1234 port [tcp/*] succeeded! + +killall lotus +# FIXME: We need a lotus stop command: +# https://github.com/filecoin-project/lotus/issues/1827 +``` + +FIXME: Link to more in-depth documentation of the CLI architecture, maybe some IPFS documentation (since they share some common logic). + +## Node API + +The JSON-RPC server exposes the node API, the `FullNode` interface (defined in `api/api_full.go`). When we issue a command like `lotus sync status` to query the progress of the node sync we don't access the node's internals, those are decoupled in a separate daemon process, we call the `SyncState` function (of the `FullNode` API interface) through the RPC client started by our own command (see `NewFullNodeRPC` in `api/client/client.go` for more details). + +FIXME: Link to (and create) documentation about API fulfillment. + +Because we rely heavily on reflection for this part of the code the call chain is not easily visible by just following the references through the symbolic analysis of the IDE. If we start by the `lotus sync` command definition (in `cli/sync.go`), we eventually end up in the method interface `SyncState`, and when we look for its implementation we will find two functions: + +* `(*SyncAPI).SyncState()` (in `node/impl/full/sync.go`): this is the actual implementation of the API function that shows what the node (here acting as the RPC server) will execute when it receives the RPC request issued from the CLI acting as the client. + +* `(*FullNodeStruct).SyncState()`: this is an "empty placeholder" structure that will get later connected to the JSON-RPC client logic (see `NewMergeClient` in `lib/jsonrpc/client.go`, which is called by `NewFullNodeRPC`). (FIXME: check if this is accurate). The CLI (JSON-RPC client) will actually execute this function which will connect to the server and send the corresponding JSON request that will trigger the call of `(*SyncAPI).SyncState()` with the node implementation. + +This means that when we are tracking the logic of a CLI command we will eventually find this bifurcation and need to study the code of the server-side implementation in `node/impl/full` (mostly in the `common/` and `full/` directories). If we understand this architecture going directly to that part of the code abstracts away the JSON-RPC client/server logic and we can think that the CLI is actually running the node's logic. + +FIXME: Explain that "*the* node" is actually an API structure like `impl.FullNodeAPI` with the different API subcomponents like `full.SyncAPI`. We won't see a *single* node structure, each API (full node, minder, etc) will gather the necessary subcomponents it needs to service its calls. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/faqs.md b/vendor/github.com/filecoin-project/lotus/documentation/en/faqs.md new file mode 100644 index 0000000000..dd6610aeb5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/faqs.md @@ -0,0 +1,138 @@ +# Frequently Asked Questions + +Here are some FAQs concerning the Lotus implementation and participation in +Testnet. +For questions concerning the broader Filecoin project, please +go [here](https://filecoin.io/faqs/). + +## Introduction to Lotus + +### What is Lotus? + +Lotus is an implementation of the **Filecoin Distributed Storage Network**, written in Go. +It is designed to be modular and interoperable with any other implementation of the Filecoin Protocol. +More information about Lotus can be found [here](https://lotu.sh/). + +### What are the components of Lotus? + +Lotus is composed of two separate pieces that can talk to each other: + +The Lotus Node can sync the blockchain, validating all blocks, transfers, and deals +along the way. It can also facilitate the creation of new storage deals. If you are not +interested in providing your own storage to the network, and do not want to produce blocks +yourself, then the Lotus Node is all you need! + +The Lotus Storage Miner does everything you need for the registration of storage, and the +production of new blocks. The Lotus Storage Miner communicates with the network +by talking to a Lotus Node over the JSON-RPC API. + +## Setting up a Lotus Node + +### How do I set up a Lotus Node? + +Follow the instructions found [here](https://docs.lotu.sh/en+getting-started). + +### Where can I get the latest version of Lotus? + +Download the binary tagged as the `Latest Release` from the + [Lotus Github repo](https://github.com/filecoin-project/lotus/releases). + +### What operating systems can Lotus run on? + +Lotus can build and run on most Linux and MacOS systems with at least +8GB of RAM. Windows is not yet supported. + +### How can I update to the latest version of Lotus? + +To update Lotus, follow the instructions [here](https://lotu.sh/en+updating-lotus). + +### How do I prepare a fresh installation of Lotus? + +Stop the Lotus daemon, and delete all related files, including sealed and chain data by +running `rm ~/.lotus ~/.lotusstorage`. + +Then, install Lotus afresh by following the instructions +found [here](https://docs.lotu.sh/en+getting-started). + +## Interacting with a Lotus Node + +### How can I communicate with a Lotus Node? + +Lotus Nodes have a command-line interface, as well as a JSON-RPC API. + +### What are the commands I can send using the command-line interface? + +The command-line interface is self-documenting, try running `lotus --help` from the `lotus` home +directory for more. + +### How can I send a request over the JSON-RPC API? + +Information on how to send a `cURL` request to the JSON-RPC API can be found +[here](https://lotu.sh/en+api). A JavaScript client is under development. + +### What are the requests I can send over the JSON-RPC API? + +Please have a look at the +[source code](https://github.com/filecoin-project/lotus/blob/master/api/api_full.go) +for a list of methods supported by the JSON-RPC API. +## The Test Network + +### What is Testnet? + +Testnet is a live network of Lotus Nodes run by the +community for testing purposes. + It has 2 PiB of storage (and growing!) dedicated to it. + +### Is FIL on the Testnet worth anything? + +Nothing at all! Real-world incentives may be provided in a future phase of Testnet, but this is +yet to be confirmed. + +### How can I see the status of Testnet? + +The [dashboard](https://stats.testnet.filecoin.io/) displays the status of the network as +well as a ton +of other metrics you might find interesting. + +## Mining with a Lotus Node on Testnet + +### How do I get started mining with Lotus? + +Follow the instructions found [here](https://lotu.sh/en+mining). + +### What are the minimum hardware requirements? + +An example test configuration, and minimum hardware requirements can be found +[here](https://lotu.sh/en+hardware-mining). + +Note that these might NOT be the minimum requirements for mining on Mainnet. + +### What are some GPUs that have been tested? + +A list of benchmarked GPUs can be found [here](https://lotu.sh/en+hardware-mining#benchmarked-gpus-7393). + +### Why is my GPU not being used when sealing a sector? + +Sealing a sector does not involve constant GPU operations. It's possible +that your GPU simply isn't necessary at the moment you checked. + +## Advanced questions + +### Is there a Docker image for lotus? + +Community-contributed Docker and Docker Compose examples are available +[here](https://github.com/filecoin-project/lotus/tree/master/tools/dockers/docker-examples). + +### How can I run two miners on the same machine? + +You can do so by changing the storage path variable for the second miner, e.g., +`LOTUS_STORAGE_PATH=~/.lotusstorage2`. You will also need to make sure that no ports collide. + +### How do I setup my own local devnet? + +Follow the instructions found [here](https://lotu.sh/en+setup-local-dev-net). + +### Are there any other implementations of Filecoin? + +Yes! Check out the [go-filecoin](https://github.com/filecoin-project/go-filecoin#filecoin-go-filecoin) +implementation, which is fully interoperable with Lotus! diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/getting-started.md b/vendor/github.com/filecoin-project/lotus/documentation/en/getting-started.md new file mode 100644 index 0000000000..7acd03f34e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/getting-started.md @@ -0,0 +1,23 @@ +# Lotus + +Lotus is an implementation of the **Filecoin Distributed Storage Network**. You can run the Lotus software client to join the **Filecoin Testnet**. + +For more details about Filecoin, check out the [Filecoin Docs](https://docs.filecoin.io) and [Filecoin Spec](https://filecoin-project.github.io/specs/). + +## What can I learn here? + +- How to install Lotus on [Arch Linux](https://docs.lotu.sh/en+install-lotus-arch), [Ubuntu](https://docs.lotu.sh/en+install-lotus-ubuntu), or [MacOS](https://docs.lotu.sh/en+install-lotus-macos). +- Joining the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet). +- [Storing](https://docs.lotu.sh/en+storing-data) or [retrieving](https://docs.lotu.sh/en+retrieving-data) data. +- Mining Filecoin using the **Lotus Storage Miner** in your [CLI](https://docs.lotu.sh/en+mining). + +## How is Lotus designed? + +Lotus is architected modularly to keep clean API boundaries while using the same process. Installing Lotus will include two separate programs: + +- The **Lotus Node** +- The **Lotus Storage Miner** + +The **Lotus Storage Miner** is intended to be run on the machine that manages a single storage miner instance, and is meant to communicate with the **Lotus Node** via the websocket **JSON-RPC** API for all of the chain interaction needs. + +This way, a mining operation may easily run a **Lotus Storage Miner** or many of them, connected to one or many **Lotus Node** instances. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/hardware-mining.md b/vendor/github.com/filecoin-project/lotus/documentation/en/hardware-mining.md new file mode 100644 index 0000000000..459b6074b1 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/hardware-mining.md @@ -0,0 +1,54 @@ +# Protocol Labs Standard Testing Configuration + +> This documentation page describes the standard testing configuration the Protocol Labs team has used to test **Lotus Storage Miner**s on Lotus. There is no guarantee this testing configuration will be suitable for Filecoin storage mining at MainNet launch. If you need to buy new hardware to join the Filecoin Testnet, we recommend to buy no more hardware than you require for testing. To learn more please read this [Protocol Labs Standard Testing Configuration post](https://filecoin.io/blog/filecoin-testnet-mining/). + +**Sector sizes** and **minimum pledged storage** required to mine blocks are two very important Filecoin Testnet parameters that impact hardware decisions. We will continue to refine all parameters during Testnet. + +BECAUSE OF THIS, OUR STANDARD TESTING CONFIGURATION FOR FILECOIN MAINNET CAN AND WILL CHANGE. YOU HAVE BEEN WARNED. + +## Example configuration + +The setup below is a minimal example for sealing 32 GiB sectors on Lotus: + +- 2 TB of hard drive space. +- 8 core CPU +- 128 GiB of RAM + +Note that 1GB sectors don't require as high of specs, but are likely to be removed as we improve the performance of 32GB sector sealing. + +For the first part of the sealing process, AMD CPU's are __highly recommended__, because of the `Intel SHA Extensions` instruction set that is available there ever since the `Zen` microarchitecture. Hence, AMD CPU's seem to perform much better on the testnet than other CPU's. Contrary to what the name implies, this extended instruction set is not available on recent Intel desktop/server chips. + +## Testnet discoveries + +- If you only have 128GiB of ram, enabling 256GB of **NVMe** swap on an SSD will help you avoid out-of-memory issues while mining. + +## Benchmarked GPUs + +GPUs are a must for getting **block rewards**. Here are a few that have been confirmed to generate **SNARKs** quickly enough to successfully mine blocks on the Lotus Testnet. + +- GeForce RTX 2080 Ti +- GeForce RTX 2080 SUPER +- GeForce RTX 2080 +- GeForce GTX 1080 Ti +- GeForce GTX 1080 +- GeForce GTX 1060 + +## Testing other GPUs + +If you want to test a GPU that is not explicitly supported, use the following global **environment variable**: + +```sh +BELLMAN_CUSTOM_GPU=":" +``` + +Here is an example of trying a GeForce GTX 1660 Ti with 1536 cores. + +```sh +BELLMAN_CUSTOM_GPU="GeForce GTX 1660 Ti:1536" +``` + +To get the number of cores for your GPU, you will need to check your card’s specifications. + +## Benchmarking + +Here is a [benchmarking tool](https://github.com/filecoin-project/lotus/tree/master/cmd/lotus-bench) and a [GitHub issue thread](https://github.com/filecoin-project/lotus/issues/694) for those who wish to experiment with and contribute hardware setups for the **Filecoin Testnet**. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/hardware.md b/vendor/github.com/filecoin-project/lotus/documentation/en/hardware.md new file mode 100644 index 0000000000..f6250548ad --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/hardware.md @@ -0,0 +1,7 @@ +# Hardware + +> This page is a work in progress. Exact mining requirements are still in the works. + +Lotus can build and run on most [Linux](https://ubuntu.com/) and [MacOS](https://www.apple.com/macos) systems with at least 8GiB of RAM. + +Windows is not yet supported. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-arch.md b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-arch.md new file mode 100644 index 0000000000..e5131424bb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-arch.md @@ -0,0 +1,44 @@ +# Arch Linux Instructions + +These steps will install the following dependencies: + +- go (1.14 or higher) +- gcc (7.4.0 or higher) +- git (version 2 or higher) +- bzr (some go dependency needs this) +- jq +- pkg-config +- opencl-icd-loader +- opencl driver (like nvidia-opencl on arch) (for GPU acceleration) +- opencl-headers (build) +- rustup (proofs build) +- llvm (proofs build) +- clang (proofs build) + +Run + +```sh +sudo pacman -Syu opencl-icd-loader +``` + +Build + +```sh +sudo pacman -Syu go gcc git bzr jq pkg-config opencl-icd-loader opencl-headers +``` + +Clone + +```sh +git clone https://github.com/filecoin-project/lotus.git +cd lotus/ +``` + +Install + +```sh +make clean && make all +sudo make install +``` + +After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet). diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-fedora.md b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-fedora.md new file mode 100644 index 0000000000..8473ef88b5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-fedora.md @@ -0,0 +1,41 @@ +# Fedora Instructions + +> tested on 30 + +**NOTE:** If you have an AMD GPU the opencl instructions may be incorrect... + +These steps will install the following dependencies: + +- go (1.14 or higher) +- gcc (7.4.0 or higher) +- git (version 2 or higher) +- bzr (some go dependency needs this) +- jq +- pkg-config +- rustup (proofs build) +- llvm (proofs build) +- clang (proofs build) + +Run + +```sh +$ sudo dnf -y update +$ sudo dnf -y install go gcc git bzr jq pkgconfig mesa-libOpenCL mesa-libOpenCL-devel opencl-headers ocl-icd ocl-icd-devel clang llvm +$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +Clone + +```sh +git clone https://github.com/filecoin-project/lotus.git +cd lotus/ +``` + +Install + +```sh +$ make clean && make all +$ sudo make install +``` + +After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus TestNet](https://docs.lotu.sh/en+join-testnet). diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-macos.md b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-macos.md new file mode 100644 index 0000000000..f4afa67b5f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-macos.md @@ -0,0 +1,62 @@ +# MacOS Instructions + +## Get XCode Command Line Tools + +To check if you already have the XCode Command Line Tools installed via the CLI, run: + +```sh +xcode-select -p +``` + +If this command returns a path, you can move on to the next step. Otherwise, to install via the CLI, run: + +```sh +xcode-select --install +``` + +To update, run: + +```sh +sudo rm -rf /Library/Developer/CommandLineTools +xcode-select --install +``` + +## Get HomeBrew + +We recommend that MacOS users use [HomeBrew](https://brew.sh) to install each the necessary packages. + +Check if you have HomeBrew: + +```sh +brew -v +``` + +This command returns a version number if you have HomeBrew installed and nothing otherwise. + +In your terminal, enter this command to install Homebrew: + +```sh +/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + +Use the command `brew install` to install the following packages: + +```sh +brew install go bzr jq pkg-config rustup +``` + +Clone + +```sh +git clone https://github.com/filecoin-project/lotus.git +cd lotus/ +``` + +Build + +```sh +make clean && make all +sudo make install +``` + +After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet). diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-ubuntu.md b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-ubuntu.md new file mode 100644 index 0000000000..a72f56a068 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/install-lotus-ubuntu.md @@ -0,0 +1,53 @@ +# Ubuntu Instructions + +These steps will install the following dependencies: + +- go (1.14 or higher) +- gcc (7.4.0 or higher) +- git (version 2 or higher) +- bzr (some go dependency needs this) +- jq +- pkg-config +- opencl-icd-loader +- opencl driver (like nvidia-opencl on arch) (for GPU acceleration) +- opencl-headers (build) +- rustup (proofs build) +- llvm (proofs build) +- clang (proofs build) + +### Install dependencies + +```sh +sudo apt update +sudo apt install mesa-opencl-icd ocl-icd-opencl-dev gcc git bzr jq pkg-config curl +sudo apt upgrade +``` + +### Install Go 1.14 + +Install the latest version of Go by following [the docs on their website](https://golang.org/doc/install). + +### Clone the Lotus repository + +```sh +git clone https://github.com/filecoin-project/lotus.git +cd lotus/ +``` + +### Build the Lotus binaries from source and install + +```sh +make clean && make all +sudo make install +``` + +After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet). + +### Interopnet + +If you seek a smaller network to test, you can join the `interopnet`. Please note that this network is meant for developers - it resets much more often, and is much smaller. To join this network, checkout the branch `interopnet` instead of `master` before building and installing; +``` +git checkout interopnet +``` + +Please also note that this documentation (if viewed on the website) might not be up to date with the interopnet. For the latest documentation on the interopnet branch, see the [Lotus Documentation Interopnet Branch on GitHub](https://github.com/filecoin-project/lotus/tree/interopnet/documentation/en) diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/install-systemd-services.md b/vendor/github.com/filecoin-project/lotus/documentation/en/install-systemd-services.md new file mode 100644 index 0000000000..0bc23cfae9 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/install-systemd-services.md @@ -0,0 +1,29 @@ +# Use Lotus with systemd + +Lotus is capable of running as a systemd service daemon. You can find installable service files for systemd in the [lotus repo scripts directory](https://github.com/filecoin-project/lotus/tree/master/scripts) as files with `.service` extension. In order to install these service files, you can copy these `.service` files to the default systemd service path. + +## Installing via `make` + +NOTE: Before using lotus and lotus-miner as systemd services, don't forget to `sudo make install` to ensure the binaries are accessible by the root user. + +If your host uses the default systemd service path, it can be installed with `sudo make install-services`: + +```sh +$ sudo make install-services +``` + +## Interacting with service logs + +Logs from the services can be reviewed using `journalctl`. + +### Follow logs from a specific service unit + +```sh +$ sudo journalctl -u lotus-daemon -f +``` + +### View logs in reverse order + +```sh +$ sudo journalctl -u lotus-miner -r +``` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/join-testnet.md b/vendor/github.com/filecoin-project/lotus/documentation/en/join-testnet.md new file mode 100644 index 0000000000..d01d7eafa3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/join-testnet.md @@ -0,0 +1,84 @@ +# Join Testnet + +## Introduction + +Anyone can set up a **Lotus Node** and connect to the **Lotus Testnet**. This is the best way to explore the current CLI and the **Filecoin Decentralized Storage Market**. + +## Note: Using the Lotus Node from China + +If you are trying to use `lotus` from China. You should set this **environment variable** on your machine: + +```sh +IPFS_GATEWAY="https://proof-parameters.s3.cn-south-1.jdcloud-oss.com/ipfs/" +``` + +## Get started + +Start the **daemon** using the default configuration in `./build`: + +```sh +lotus daemon +``` + +In another terminal window, check your connection with peers: + +```sh +lotus net peers | wc -l +``` + +In order to connect to the network, you need to be connected to at least 1 peer. If you’re seeing 0 peers, read our [troubleshooting notes](https://docs.lotu.sh/en+setup-troubleshooting). + +Make sure that you have a reasonable "open files limit" set on your machine, such as 10000. If you're seeing a lower value, such as 256 (default on macOS), read our [troubleshooting notes](https://docs.lotu.sh/en+setup-troubleshooting) on how to update it prior to starting the Lotus daemon. + +## Chain sync + +While the daemon is running, the next requirement is to sync the chain. Run the command below to view the chain sync progress. To see current chain height, visit the [network stats page](https://stats.testnet.filecoin.io/). + +```sh +lotus sync wait +``` + +- This step will take anywhere between a few hours to a couple of days. +- You will be able to perform **Lotus Testnet** operations after it is finished. + +## Create your first address + +Initialize a new wallet: + +```sh +lotus wallet new +``` + +Sometimes your operating system may limit file name length to under 150 characters. You need to use a file system that supports long filenames. + +Here is an example of the response: + +```sh +t1aswwvjsae63tcrniz6x5ykvsuotlgkvlulnqpsi +``` + +- Visit the [faucet](https://faucet.testnet.filecoin.io) to add funds. +- Paste the address you created. +- Press the send button. + +## Check wallet address balance + +Wallet balances in the Lotus Testnet are in **FIL**, the smallest denomination of FIL is an **attoFil**, where 1 attoFil = 10^-18 FIL. + +```sh +lotus wallet balance +``` + +You will not see any attoFIL in your wallet if your **chain** is not fully synced. + +## Send FIL to another wallet + +To send FIL to another wallet from your default account, use this command: + +``` +lotus send +``` + +## Monitor the dashboard + +To see the latest network activity, including **chain block height**, **block height**, **blocktime**, **total network power**, largest **block producer miner**, check out the [monitoring dashboard](https://stats.testnet.filecoin.io). diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/local-dev-net.md b/vendor/github.com/filecoin-project/lotus/documentation/en/local-dev-net.md new file mode 100644 index 0000000000..e11d9b3584 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/local-dev-net.md @@ -0,0 +1,46 @@ +# Setup Local Devnet + +Build the Lotus Binaries in debug mode, This enables the use of 2048 byte sectors. + +```sh +make 2k +``` + +Download the 2048 byte parameters: +```sh +./lotus fetch-params 2048 +``` + +Pre-seal some sectors: + +```sh +./lotus-seed pre-seal --sector-size 2KiB --num-sectors 2 +``` + +Create the genesis block and start up the first node: + +```sh +./lotus-seed genesis new localnet.json +./lotus-seed genesis add-miner localnet.json ~/.genesis-sectors/pre-seal-t01000.json +./lotus daemon --lotus-make-genesis=dev.gen --genesis-template=localnet.json --bootstrap=false +``` + +Then, in another console, import the genesis miner key: + +```sh +./lotus wallet import ~/.genesis-sectors/pre-seal-t01000.key +``` + +Set up the genesis miner: + +```sh +./lotus-storage-miner init --genesis-miner --actor=t01000 --sector-size=2KiB --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json --nosync +``` + +Now, finally, start up the miner: + +```sh +./lotus-storage-miner run --nosync +``` + +If all went well, you will have your own local Lotus Devnet running. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/miner-deals.md b/vendor/github.com/filecoin-project/lotus/documentation/en/miner-deals.md new file mode 100644 index 0000000000..7934793856 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/miner-deals.md @@ -0,0 +1,39 @@ +# Information for Miners + +Here is how a miner can get set up to accept storage deals. The first step is +to install a Lotus node and sync to the top of the chain. + +## Set up an ask + +``` +lotus-storage-miner set-price +``` + +This command will set up your miner to accept deal proposals that meet the input price. +The price is inputted in FIL per GiB per epoch, and the default is 0.0000000005. + +## Ensure you can be discovered + +Clients need to be able to find you in order to make storage deals with you. +While there isn't necessarily anything you need to do to become discoverable, here are some things you can +try to check that people can connect to you. + +To start off, make sure you are connected to at least some peers, and your port is +open and working. + +### Connect to your own node + +If you are in contact with someone else running Lotus, you can ask them to try connecting +to your node. To do so, provide them your peer ID, which you can get by running `lotus net id` on +your node. + +They can then try running `lotus net findpeer ` to get your address(es), and can then +run `lotus net connect
    ` to connect to you. If successful, your node will now +appear on their peers list (run `lotus net peers` to check). + +You can also check this by running a second instance of Lotus yourself. + +### Query your own ask + +A client should be able to find your ask by running `lotus client query-ask `. If +someone is not able to retrieve your ask by doing so, then there is an issue with your node. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/mining-lotus-seal-worker.md b/vendor/github.com/filecoin-project/lotus/documentation/en/mining-lotus-seal-worker.md new file mode 100644 index 0000000000..aba1156617 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/mining-lotus-seal-worker.md @@ -0,0 +1,81 @@ +# Lotus Seal Worker + +The **Lotus Seal Worker** is an extra process that can offload heavy processing tasks from your **Lotus Storage Miner**. The sealing process automatically runs in the **Lotus Storage Miner** process, but you can use the Seal Worker on another machine communicating over a fast network to free up resources on the machine running the mining process. + +## Note: Using the Lotus Seal Worker from China + +If you are trying to use `lotus-seal-worker` from China. You should set this **environment variable** on your machine: + +```sh +IPFS_GATEWAY="https://proof-parameters.s3.cn-south-1.jdcloud-oss.com/ipfs/" +``` + +## Get Started + +Make sure that the `lotus-seal-worker` is compiled and installed by running: + +```sh +make lotus-seal-worker +``` + +## Setting up the Storage Miner + +First, you will need to ensure your `lotus-storage-miner`'s API is accessible over the network. + +To do this, open up `~/.lotusstorage/config.toml` (Or if you manually set `LOTUS_STORAGE_PATH`, look under that directory) and look for the API field. + +Default config: + +```toml +[API] +ListenAddress = "/ip4/127.0.0.1/tcp/2345/http" +RemoteListenAddress = "127.0.0.1:2345" +``` + +To make your node accessible over the local area network, you will need to determine your machines IP on the LAN, and change the `127.0.0.1` in the file to that address. + +A more permissive and less secure option is to change it to `0.0.0.0`. This will allow anyone who can connect to your computer on that port to access the [API](https://docs.lotu.sh/en+api). They will still need an auth token. + +`RemoteListenAddress` must be set to an address which other nodes on your network will be able to reach. + +Next, you will need to [create an authentication token](https://docs.lotu.sh/en+api-scripting-support#generate-a-jwt-46). All Lotus APIs require authentication tokens to ensure your processes are as secure against attackers attempting to make unauthenticated requests to them. + +### Connect the Lotus Seal Worker + +On the machine that will run `lotus-seal-worker`, set the `STORAGE_API_INFO` environment variable to `TOKEN:STORAGE_NODE_MULTIADDR`. Where `TOKEN` is the token we created above, and `STORAGE_NODE_MULTIADDR` is the `multiaddr` of the **Lotus Storage Miner** API that was set in `config.toml`. + +Once this is set, run: + +```sh +lotus-seal-worker run --address 192.168.2.10:2345 +``` + +Replace `192.168.2.10:2345` with the proper IP and port. + +To check that the **Lotus Seal Worker** is connected to your **Lotus Storage Miner**, run `lotus-storage-miner workers list` and check that the remote worker count has increased. + +```sh +why@computer ~/lotus> lotus-storage-miner workers list +Worker 0, host computer + CPU: [ ] 0 core(s) in use + RAM: [|||||||||||||||||| ] 28% 18.1 GiB/62.7 GiB + VMEM: [|||||||||||||||||| ] 28% 18.1 GiB/62.7 GiB + GPU: GeForce RTX 2080, not used + +Worker 1, host othercomputer + CPU: [ ] 0 core(s) in use + RAM: [|||||||||||||| ] 23% 14 GiB/62.7 GiB + VMEM: [|||||||||||||| ] 23% 14 GiB/62.7 GiB + GPU: GeForce RTX 2080, not used +``` + +### Running locally for manually managing process priority + +You can also run the **Lotus Seal Worker** on the same machine as your **Lotus Storage Miner**, so you can manually manage the process priority. +To do so you have to first __disable all seal task types__ in the miner config. This is important to prevent conflicts between the two processes. + +You can then run the storage miner on your local-loopback interface; + +```sh +lotus-seal-worker run --address 127.0.0.1:2345 +``` \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/mining-troubleshooting.md b/vendor/github.com/filecoin-project/lotus/documentation/en/mining-troubleshooting.md new file mode 100644 index 0000000000..561031c5dc --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/mining-troubleshooting.md @@ -0,0 +1,66 @@ +# Mining Troubleshooting + +## Config: Filecoin Proof Parameters directory + +If you want to put the **Filecoin Proof Parameters** in a different directory, use the following environment variable: + +```sh +FIL_PROOFS_PARAMETER_CACHE +``` + +## Error: Can't acquire bellman.lock + +The **Bellman** lockfile is created to lock a GPU for a process. This bug can occur when this file isn't properly cleaned up: + +```sh +mining block failed: computing election proof: github.com/filecoin-project/lotus/miner.(*Miner).mineOne +``` + +This bug occurs when the storage miner can't acquire the `bellman.lock`. To fix it you need to stop the `lotus-storage-miner` and remove `/tmp/bellman.lock`. + +## Error: Failed to get api endpoint + +```sh +lotus-storage-miner info +# WARN main lotus-storage-miner/main.go:73 failed to get api endpoint: (/Users/myrmidon/.lotusstorage) %!w(*errors.errorString=&{API not running (no endpoint)}): +``` + +If you see this, that means your **Lotus Storage Miner** isn't ready yet. You need to finish [syncing the chain](https://docs.lotu.sh/en+join-testnet). + +## Error: Your computer may not be fast enough + +```sh +CAUTION: block production took longer than the block delay. Your computer may not be fast enough to keep up +``` + +If you see this, that means your computer is too slow and your blocks are not included in the chain, and you will not receive any rewards. + +## Error: No space left on device + +```sh +lotus-storage-miner sectors pledge +# No space left on device (os error 28) +``` + +If you see this, that means `pledge-sector` wrote too much data to `$TMPDIR` which by default is the root partition (This is common for Linux setups). Usually your root partition does not get the largest partition of storage so you will need to change the environment variable to something else. + +## Error: GPU unused + +If you suspect that your GPU is not being used, first make sure it is properly configured as described in the [testing configuration page](hardware-mining.md). Once you've done that (and set the `BELLMAN_CUSTOM_GPU` as appropriate if necessary) you can verify your GPU is being used by running a quick lotus-bench benchmark. + +First, to watch GPU utilization run `nvtop` in one terminal, then in a separate terminal, run: + +```sh +make bench +./bench sealing --sector-size=2KiB +``` + +This process uses a fair amount of GPU, and generally takes ~4 minutes to complete. If you do not see any activity in nvtop from lotus during the entire process, it is likely something is misconfigured with your GPU. + +## Checking Sync Progress + +You can use this command to check how far behind you are on syncing: + +```sh +date -d @$(./lotus chain getblock $(./lotus chain head) | jq .Timestamp) +``` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/mining.md b/vendor/github.com/filecoin-project/lotus/documentation/en/mining.md new file mode 100644 index 0000000000..3b1f5a8a3d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/mining.md @@ -0,0 +1,101 @@ +# Storage Mining + +Here are instructions to learn how to perform storage mining. For hardware specifications please read [this](https://docs.lotu.sh/en+hardware-mining). + +It is useful to [join the Testnet](https://docs.lotu.sh/en+join-testnet) prior to attempting storage mining for the first time. + +## Note: Using the Lotus Storage Miner from China + +If you are trying to use `lotus-storage-miner` from China. You should set this **environment variable** on your machine. + +```sh +IPFS_GATEWAY="https://proof-parameters.s3.cn-south-1.jdcloud-oss.com/ipfs/" +``` + +## Get started + +Please ensure that at least one **BLS address** (starts with `t3`) in your wallet exists with the following command: + +```sh +lotus wallet list +``` + +If you do not have a bls address, create a new bls wallet: + +```sh +lotus wallet new bls +``` + +With your wallet address: + +- Visit the [faucet](https://faucet.testnet.filecoin.io) +- Click "Create Miner" +- DO NOT REFRESH THE PAGE. THIS OPERATION CAN TAKE SOME TIME. + +The task will be complete when you see: + +```sh +New storage miners address is: +``` + +## Initialize the storage miner + +In a CLI window, use the following command to start your miner: + +```sh +lotus-storage-miner init --actor=ACTOR_VALUE_RECEIVED --owner=OWNER_VALUE_RECEIVED +``` + +Example + +```sh +lotus-storage-miner init --actor=t01424 --owner=t3spmep2xxsl33o4gxk7yjxcobyohzgj3vejzerug25iinbznpzob6a6kexcbeix73th6vjtzfq7boakfdtd6a +``` + +You will have to wait some time for this operation to complete. + +## Mining + +To mine: + +```sh +lotus-storage-miner run +``` + +If you are downloading **Filecoin Proof Parameters**, the download can take some time. + +Get information about your miner: + +```sh +lotus-storage-miner info +# example: miner id `t0111` +``` + +**Seal** random data to start producing **PoSts**: + +```sh +lotus-storage-miner sectors pledge +``` + +- Warning: On Linux configurations, this command will write data to `$TMPDIR` which is not usually the largest partition. You should point the value to a larger partition if possible. + +Get **miner power** and **sector usage**: + +```sh +lotus state power +# returns total power + +lotus state power + +lotus state sectors +``` + +## Performance tuning + +### `FIL_PROOFS_MAXIMIZE_CACHING=1` Environment variable + +This env var can be used with `lotus-storage-miner`, `lotus-seal-worker`, and `lotus-bench` to make the precommit1 step faster at the cost of some memory use (1x sector size) + +### `FIL_PROOFS_USE_GPU_COLUMN_BUILDER=1` Environment variable + +This env var can be used with `lotus-storage-miner`, `lotus-seal-worker`, and `lotus-bench` to enable experimental precommit2 GPU acceleration diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/retrieving-data.md b/vendor/github.com/filecoin-project/lotus/documentation/en/retrieving-data.md new file mode 100644 index 0000000000..56f8296e89 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/retrieving-data.md @@ -0,0 +1,27 @@ +# Retrieving Data + +> There are recent bug reports with these instructions. If you happen to encounter any problems, please create a [GitHub issue](https://github.com/filecoin-project/lotus/issues/new) and a maintainer will address the problem as soon as they can. + +Here are the operations you can perform after you have stored and sealed a **Data CID** with the **Lotus Storage Miner** in the network. + +If you would like to learn how to store a **Data CID** on a miner, read the instructions [here](https://docs.lotu.sh/en+storing-data). + +## Find by Data CID + +```sh +lotus client find +# LOCAL +# RETRIEVAL @-- +``` + +## Retrieve by Data CID + +All fields are required. + +```sh +lotus client retrieve +``` + +If the outfile does not exist it will be created in the Lotus repository directory. + +This command will initiate a **retrieval deal** and write the data to your computer. This process may take 2 to 10 minutes. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/sealing-procs.md b/vendor/github.com/filecoin-project/lotus/documentation/en/sealing-procs.md new file mode 100644 index 0000000000..1b4f2877ce --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/sealing-procs.md @@ -0,0 +1,70 @@ +# Why does Filecoin mining work best on AMD? +Currently, Filecoin's Proof of Replication (PoRep) prefers to be run on AMD +processors. More accurately, it runs much much slower on Intel CPUs (it runs +competitively fast on some ARM processors, like the ones in newer Samsung +phones, but they lack the RAM to seal the larger sector sizes). The main reason +that we see this benefit on AMD processors is due to their implementation of +the SHA hardware instructions. Now, why do we use the SHA instruction? + +## PoRep security assumptions +Our research team has two different models for the security of Proofs of +Replication. These are the Latency Assumption, and the Cost Assumption. These +assumptions are arguments for why an attacker cannot pull off a 'regeneration +attack'. That is, the attacker cannot seal and commit random data (generated by +a function), delete it, and then reseal it on the fly to respond to PoSt +challenges, without actually storing the data for that time period. + +### Cost Assumptions +The cost assumption states that the real money cost (hardware, electricity, +etc) of generating a sector is higher than the real money cost of simply +storing it on disks. NSE is a new PoRep our research team is working on that is +based on the cost assumption, and is thus able to be very parallelizable (In +comparison to schemes based on a latency assumption, as will be explained +next). However, cost assumptions vary greatly with available and hypothetical +hardware. For example, someone making an ASIC for NSE could break the cost +assumption by lowering the cost of sealing too much. This is one of our main +hesitations around shipping NSE. + +### Latency Assumptions +A Proof of Replication that is secure under a latency assumption is secure +because an attacker cannot regenerate the data in time. We use this assumption +for SDR, where we assume that an attacker cannot regenerate enough of a sector +fast enough to respond to a PoSt. The way we achieve this is through the use +of depth-robust graphs. Without going into too much detail, depth-robust +graphs guarantee a minimum number of serial operations to compute an encoding +based on the graph. Each edge in the graph represents an operation we need to +perform. We thus have a guarantee that someone has to perform some operation +N times in a row in order to compute the encoding. That means that the +computation of the encoding must take at least as long as N times the fastest +someone can do that operation. + +Now, to make this secure, we need to choose an operation that can't be made +much faster. There are many potential candidates here, depending on what +hardware you want to require. We opted not to require ASICs in order to mine +Filecoin, so that limits our choices severely. We have to look at what +operations CPUs are really good at. One candidate was AES encryption, which +also has hardware instructions. However, the difference between the performance +of CPU AES instructions, and the hypothetical 'best' performance you get was +still too great. This gap is generally called 'Amax', an attacker’s maximum +advantage. The higher the Amax of an algorithm we choose, the more expensive +the overall process has to become in order to bound how fast the attacker could +do it. +As we were doing our research, we noticed that AMD shipped their new processors +with a builtin SHA function, and we looked into how fast someone could possibly +compute a SHA hash. We found that AMD’s implementation is only around 3 times +slower than anyone could reasonably do (given estimates by the hardware +engineers at [Supranational](https://www.supranational.net/) ). This is +incredibly impressive for something you can get in consumer hardware. With +this, we were able to make SDR sealing reasonably performant for people with +off-the-shelf hardware. + +## Super Optimized CPUs + +Given all of the above, with a latency assumption that we're basing our proofs +on right now, you need a processor that can do iterated SHA hashes really fast. +As mentioned earlier, this isn’t just AMD processors, but many ARM processors +also have support for this. Hopefully, new Intel processors also follow suit. +But for now, Filecoin works best on AMD processors. + + + diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/setting-a-static-port.md b/vendor/github.com/filecoin-project/lotus/documentation/en/setting-a-static-port.md new file mode 100644 index 0000000000..714f455b0e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/setting-a-static-port.md @@ -0,0 +1,54 @@ +# Static Ports + +Depending on how your network is set up, you may need to set a static port to successfully connect to peers to perform storage deals with your **Lotus Storage Miner**. + +## Setup + +To change the random **swarm port**, you may edit the `config.toml` file located under `$LOTUS_STORAGE_PATH`. The default location of this file is `$HOME/.lotusstorage`. + +To change the port to `1347`: + +```sh +[Libp2p] + ListenAddresses = ["/ip4/0.0.0.0/tcp/1347", "/ip6/::/tcp/1347"] +``` + +After changing the port value, restart your **daemon**. + +## Announce Addresses + +If the **swarm port** is port-forwarded from another address, it is possible to control what addresses +are announced to the network. + +```sh +[Libp2p] + AnnounceAddresses = ["/ip4//tcp/1347"] +``` + +If non-empty, this array specifies the swarm addresses to announce to the network. If empty, the daemon will announce inferred swarm addresses. + +Similarly, it is possible to set `NoAnnounceAddresses` with an array of addresses to not announce to the network. + +## Ubuntu's Uncomplicated Firewall + +Open firewall manually: + +```sh +ufw allow 1347/tcp +``` + +Or open and modify the profile located at `/etc/ufw/applications.d/lotus-daemon`: + +```sh +[Lotus Daemon] +title=Lotus Daemon +description=Lotus Daemon firewall rules +ports=1347/tcp +``` + +Then run these commands: + +```sh +ufw update lotus-daemon +ufw allow lotus-daemon +``` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/setup-troubleshooting.md b/vendor/github.com/filecoin-project/lotus/documentation/en/setup-troubleshooting.md new file mode 100644 index 0000000000..8a23544d91 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/setup-troubleshooting.md @@ -0,0 +1,46 @@ +# Setup Troubleshooting + +## Config: Clearing data + +Here is a command that will delete your chain data, stored wallets, stored data and any miners you have set up: + +```sh +rm -rf ~/.lotus ~/.lotusstorage +``` + +This command usually resolves any issues with running `lotus` but it is not always required for updates. We will share information about when resetting your chain data and miners is required for an update in the future. + +## Error: Failed to connect bootstrap peer + +```sh +WARN peermgr peermgr/peermgr.go:131 failed to connect to bootstrap peer: failed to dial : all dials failed + * [/ip4/147.75.80.17/tcp/1347] failed to negotiate security protocol: connected to wrong peer +``` + +- Try running the build steps again and make sure that you have the latest code from GitHub. + +```sh +ERROR hello hello/hello.go:81 other peer has different genesis! +``` + +- Try deleting your file system's `~/.lotus` directory. Check that it exists with `ls ~/.lotus`. + +```sh +- repo is already locked +``` + +- You already have another lotus daemon running. + +## Config: Open files limit + +On most systems you can check the open files limit with: + +```sh +ulimit -n +``` + +You can also modify this number by using the `ulimit` command. It gives you the ability to control the resources available for the shell or process started by it. If the number is below 10000, you can change it with the following command prior to starting the Lotus daemon: + +```sh +ulimit -n 10000 +``` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/storing-data-troubleshooting.md b/vendor/github.com/filecoin-project/lotus/documentation/en/storing-data-troubleshooting.md new file mode 100644 index 0000000000..2f1a6b607a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/storing-data-troubleshooting.md @@ -0,0 +1,27 @@ +# Storage Troubleshooting + +## Error: Routing: not found + +```sh +WARN main lotus/main.go:72 routing: not found +``` + +- This miner is offline. + +## Error: Failed to start deal + +```sh +WARN main lotus/main.go:72 failed to start deal: computing commP failed: generating CommP: Piece must be at least 127 bytes +``` + +- There is a minimum file size of 127 bytes. + +## Error: 0kb file response during retrieval + +In order to retrieve a file, it must be sealed. Miners can check sealing progress with this command: + +```sh +lotus-storage-miner sectors list +``` + +When sealing is complete, `pSet: NO` will become `pSet: YES`. From now on the **Data CID** is [retrievable](https://docs.lotu.sh/en+retrieving-data) from the **Lotus Storage Miner**. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/storing-data.md b/vendor/github.com/filecoin-project/lotus/documentation/en/storing-data.md new file mode 100644 index 0000000000..357ebc0645 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/storing-data.md @@ -0,0 +1,62 @@ +# Storing Data + +> There are recent bug reports with these instructions. If you happen to encounter any problems, please create a [GitHub issue](https://github.com/filecoin-project/lotus/issues/new) and a maintainer will address the problem as soon as they can. + +Here are instructions for how to store data on the **Lotus Testnet**. + +## Adding a file locally + +Adding a file locally allows you to make miner deals on the **Lotus Testnet**. + +```sh +lotus client import ./your-example-file.txt +``` + +Upon success, this command will return a **Data CID**. + +## List your local files + +The command to see a list of files by `CID`, `name`, `size` in bytes, and `status`: + +```sh +lotus client local +``` + +An example of the output: + +```sh +bafkreierupr5ioxn4obwly4i2a5cd2rwxqi6kwmcyyylifxjsmos7hrgpe Development/sample-1.txt 2332 ok +bafkreieuk7h4zs5alzpdyhlph4lxkefowvwdho3a3pml6j7dam5mipzaii Development/sample-2.txt 30618 ok +``` + +## Make a Miner Deal on Lotus Testnet + +Get a list of all miners that can store data: + +```sh +lotus state list-miners +``` + +Get the requirements of a miner you wish to store data with: + +```sh +lotus client query-ask +``` + +Store a **Data CID** with a miner: + +```sh +lotus client deal +``` + +Check the status of a deal: + +```sh +lotus client list-deals +``` + +- The `duration`, which represents how long the miner will keep your file hosted, is represented in blocks. Each block represents 25 seconds. + +Upon success, this command will return a **Deal CID**. + +The storage miner will need to **seal** the file before it can be retrieved. If the **Lotus Storage Miner** is not running on a machine designed for sealing, the process will take a very long time. diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/storing-ipfs-integration.md b/vendor/github.com/filecoin-project/lotus/documentation/en/storing-ipfs-integration.md new file mode 100644 index 0000000000..0413643809 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/storing-ipfs-integration.md @@ -0,0 +1,20 @@ +# IPFS Integration + +Lotus supports making deals with data stored in IPFS, without having to re-import it into lotus. + +To enable this integration, you need to have an IPFS daemon running in the background. +Then, open up `~/.lotus/config.toml` (or if you manually set `LOTUS_PATH`, look under that directory) +and look for the Client field, and set `UseIpfs` to `true`. + +```toml +[Client] +UseIpfs = true +``` + +After restarting the lotus daemon, you should be able to make deals with data in your IPFS node: + +```sh +$ ipfs add -r SomeData +QmSomeData +$ ./lotus client deal QmSomeData t01000 0.0000000001 80000 +``` diff --git a/vendor/github.com/filecoin-project/lotus/documentation/en/updating-lotus.md b/vendor/github.com/filecoin-project/lotus/documentation/en/updating-lotus.md new file mode 100644 index 0000000000..62a825bbf0 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/documentation/en/updating-lotus.md @@ -0,0 +1,11 @@ +# Updating Lotus + +If you installed Lotus on your machine, you can upgrade to the latest version by doing the following: + +```sh +# get the latest +git pull origin master + +# clean and remake the binaries +make clean && make build +``` \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/documentation/images/lotus_logo_h.png b/vendor/github.com/filecoin-project/lotus/documentation/images/lotus_logo_h.png new file mode 100644 index 0000000000000000000000000000000000000000..701191aae4572003966e048b3f678844199b15df GIT binary patch literal 5976 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 bJtl@FVO45@$PVKpD#w5-YeQlotus_logo_h \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.circleci/config.yml b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.circleci/config.yml new file mode 100644 index 0000000000..650e6e574d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.circleci/config.yml @@ -0,0 +1,348 @@ +version: 2.1 + +orbs: + go: gotest/tools@0.0.9 + shellcheck: circleci/shellcheck@1.3.15 + +executors: + golang: + docker: + - image: circleci/golang:1.13 + resource_class: 2xlarge + rust: + docker: + - image: filecoin/rust:latest + resource_class: 2xlarge + +jobs: + gofmt: + executor: golang + steps: + - configure_environment_variables + - prepare + - go/mod-download + - run: + command: "! go fmt ./... 2>&1 | read" + go_lint: + description: Run various linters + executor: golang + steps: + - configure_environment_variables + - prepare + - go/mod-download + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: 1.23.8 + - run: + command: make go-lint + build_and_test_linux_cgo_bindings: + parameters: + run_leak_detector: + type: boolean + default: false + executor: golang + working_directory: ~/go/src/github.com/filecoin-project/filecoin-ffi + steps: + - configure_environment_variables + - prepare + - build_project + - restore_parameter_cache + - obtain_filecoin_parameters + - save_parameter_cache + - run_tests: + run_leak_detector: << parameters.run_leak_detector >> + build_darwin_cgo_bindings: + macos: + xcode: "10.0.0" + working_directory: ~/go/src/github.com/filecoin-project/filecoin-ffi + resource_class: large + steps: + - configure_environment_variables: + linux: false + darwin: true + - prepare: + linux: false + darwin: true + - build_project + - compile_tests + - ensure_generated_cgo_up_to_date + publish_linux_staticlib: + executor: golang + steps: + - configure_environment_variables + - prepare + - publish_release + publish_darwin_staticlib: + macos: + xcode: "10.0.0" + working_directory: ~/crate + steps: + - configure_environment_variables: + linux: false + darwin: true + - prepare: + linux: false + darwin: true + - run: cd rust && rustup install $(cat rust-toolchain) + - run: cd rust && rustup default $(cat rust-toolchain) + - run: cd rust && cargo fetch + - publish_release + cargo_fetch: + executor: rust + working_directory: /mnt/crate + steps: + - configure_environment_variables + - checkout + - restore_cache: + keys: + - cargo-v0-{{ checksum "rust/rust-toolchain" }}-{{ checksum "rust/Cargo.toml" }}-{{ checksum "rust/Cargo.lock" }}-{{ arch }} + - run: cd rust && rustup install $(cat rust-toolchain) + - run: cd rust && rustup default $(cat rust-toolchain) + - run: cd rust && rustup component add rustfmt + - run: cd rust && rustup component add clippy + - run: cd rust && cargo fetch + - run: cd rust && rustc +$(cat rust-toolchain) --version + - persist_to_workspace: + root: "." + paths: + - rust/Cargo.lock + - save_cache: + key: cargo-v0-{{ checksum "rust/rust-toolchain" }}-{{ checksum "rust/Cargo.toml" }}-{{ checksum "rust/Cargo.lock" }}-{{ arch }} + paths: + - /root/.cargo + - /root/.rustup + rustfmt: + executor: rust + working_directory: /mnt/crate + steps: + - configure_environment_variables + - checkout + - restore_cache: + keys: + - cargo-v0-{{ checksum "rust/rust-toolchain" }}-{{ checksum "rust/Cargo.toml" }}-{{ checksum "rust/Cargo.lock" }}-{{ arch }} + - run: + name: Run cargo fmt + command: cargo fmt --manifest-path ./rust/Cargo.toml --all -- --check + clippy: + executor: rust + working_directory: /mnt/crate + steps: + - configure_environment_variables + - checkout + - restore_cache: + keys: + - cargo-v0-{{ checksum "rust/rust-toolchain" }}-{{ checksum "rust/Cargo.toml" }}-{{ checksum "rust/Cargo.lock" }}-{{ arch }} + - run: cd rust && rustup install $(cat rust-toolchain) + - run: cd rust && rustup default $(cat rust-toolchain) + - run: cd rust && rustup component add rustfmt + - run: cd rust && rustup component add clippy + - run: cd rust && cargo fetch + - run: + name: Run cargo clippy + command: cd rust && cargo +$(cat rust-toolchain) clippy --all-targets --all-features -- -D warnings + +workflows: + version: 2 + test_all: + jobs: + # Lint the install Bash script + - shellcheck/check: + pattern: 'install-filcrypto' + - cargo_fetch + - rustfmt: + requires: + - cargo_fetch + - clippy: + requires: + - cargo_fetch + - gofmt + - go_lint + - build_and_test_linux_cgo_bindings: + filters: + branches: + only: + - master + run_leak_detector: true + - build_and_test_linux_cgo_bindings: + filters: + branches: + ignore: + - master + run_leak_detector: false + - publish_linux_staticlib: + filters: + branches: + only: + - master + - build_darwin_cgo_bindings + - publish_darwin_staticlib: + filters: + branches: + only: + - master + +commands: + prepare: + parameters: + linux: + default: true + description: is a linux build environment? + type: boolean + darwin: + default: false + description: is a darwin build environment? + type: boolean + steps: + - checkout + - when: + condition: << parameters.linux >> + steps: + - go/install-ssh + - go/install: {package: git} + - run: sudo apt-get update + - run: sudo apt-get install -y jq valgrind ocl-icd-opencl-dev clang libssl-dev + - run: curl https://sh.rustup.rs -sSf | sh -s -- -y + - when: + condition: << parameters.darwin >> + steps: + - run: + name: Install Go + command: | + curl https://dl.google.com/go/go1.13.7.darwin-amd64.pkg -o /tmp/go.pkg && \ + sudo installer -pkg /tmp/go.pkg -target / + go version + - run: + name: Install other dependencies with Homebrew + command: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config md5sha1sum jq + - run: + name: Install Rust toolchain + command: | + curl https://sh.rustup.rs -sSf | sh -s -- -y + rustc --version + - run: + name: Ensure appropriate toolchain is installed + command: | + rustup install $(cat ./rust/rust-toolchain) + - run: git submodule sync + - run: git submodule update --init + + publish_release: + steps: + - run: + name: Build and publish the standard release + command: | + cd rust + + TARBALL_PATH="/tmp/${CIRCLE_PROJECT_REPONAME}-$(uname)-standard.tar.gz" + RELEASE_NAME="${CIRCLE_PROJECT_REPONAME}-$(uname)-standard" + + ./scripts/build-release.sh filcrypto $(cat ./rust-toolchain) --verbose --locked --all + ./scripts/package-release.sh $TARBALL_PATH + ./scripts/publish-release.sh $TARBALL_PATH $RELEASE_NAME + - run: + name: Build and publish the optimized release + command: | + cd rust + + TARBALL_PATH="/tmp/${CIRCLE_PROJECT_REPONAME}-$(uname)-optimized.tar.gz" + RELEASE_NAME="${CIRCLE_PROJECT_REPONAME}-$(uname)-optimized" + RUSTFLAGS="-C target-feature=$(cat rustc-target-features-optimized.json | jq -r '.[].rustc_target_feature' | tr '\n' ',')" + + ./scripts/build-release.sh filcrypto $(cat ./rust-toolchain) --verbose --locked --all + ./scripts/package-release.sh $TARBALL_PATH + ./scripts/publish-release.sh $TARBALL_PATH $RELEASE_NAME + configure_environment_variables: + parameters: + linux: + default: true + description: is a Linux build environment? + type: boolean + darwin: + default: false + description: is a Darwin build environment? + type: boolean + steps: + - run: + name: Configure environment variables + command: | + echo 'export FIL_PROOFS_PARAMETER_CACHE="${HOME}/filecoin-proof-parameters/"' >> $BASH_ENV + echo 'export GO111MODULE=on' >> $BASH_ENV + echo 'export GOPATH="${HOME}/go"' >> $BASH_ENV + echo 'export PATH="/usr/local/go/bin:${HOME}/.cargo/bin:${PATH}:${HOME}/go/bin:${HOME}/.bin"' >> $BASH_ENV + echo 'export RUST_LOG=info' >> $BASH_ENV + echo 'export CIRCLE_ARTIFACTS="/tmp"' >> $BASH_ENV + - when: + condition: << parameters.darwin >> + steps: + - run: + name: Add a few more environment variables + command: | + echo 'export PATH="${HOME}/.cargo/bin:${HOME}/.bin:${PATH}"' >> $BASH_ENV + obtain_filecoin_parameters: + steps: + - run: | + DIR=$(pwd) + cd $(mktemp -d) + GOPATH=/tmp GO111MODULE=off go get github.com/filecoin-project/go-paramfetch/paramfetch + GOPATH=/tmp GO111MODULE=off go build -o go-paramfetch github.com/filecoin-project/go-paramfetch/paramfetch + ./go-paramfetch 2048 "${DIR}/parameters.json" + build_project: + steps: + - run: + name: Build project + command: make + - run: + name: Build project without CGO + command: env CGO_ENABLED=0 go build . + ensure_generated_cgo_up_to_date: + steps: + - run: + name: Generate CGO bindings (using forked c-for-go) and compare with what's tracked by Git + command: | + DIR=$(pwd) + git clone git@github.com:dtynn/c-for-go.git $GOPATH/src/github.com/xlab/c-for-go + cd $GOPATH/src/github.com/xlab/c-for-go + git checkout fix/2-mem-issues + GO111MODULE=off go get + GO111MODULE=off go build -o /tmp/c-for-go-forked main.go process.go + cd $DIR + /tmp/c-for-go-forked --ccincl --ccdefs --nostamp filcrypto.yml + git diff --exit-code ./generated/ + run_tests: + parameters: + run_leak_detector: + type: boolean + default: false + steps: + - when: + condition: <> + steps: + - run: + name: Run leak detector + command: make cgo-leakdetect + no_output_timeout: 60m + + - run: + name: Run the Rust tests + command: cd rust && FIL_PROOFS_PARAMETER_CACHE="${HOME}/filecoin-proof-parameters/" RUST_LOG=info cargo test --all --release && cd .. + no_output_timeout: 60m + - run: + name: Run the Go tests + command: GODEBUG=cgocheck=2 RUST_LOG=info go test -p 1 -timeout 60m + no_output_timeout: 60m + compile_tests: + steps: + - run: + name: Build project and tests, but don't actually run the tests (used to verify that build/link works with Darwin) + command: GODEBUG=cgocheck=2 RUST_LOG=info go test -run=^$ + restore_parameter_cache: + steps: + - restore_cache: + keys: + - v27b-proof-params-{{ arch }} + save_parameter_cache: + steps: + - save_cache: + key: v27b-proof-params-{{ arch }} + paths: + - "~/filecoin-proof-parameters/" diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.gitignore b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.gitignore new file mode 100644 index 0000000000..f35581b975 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/.gitignore @@ -0,0 +1,11 @@ +**/*.rs.bk +**/include +**/paramcache +**/target +.install-filcrypto +filcrypto.h +filcrypto.pc +filecoin.h +filecoin.pc +*.a +simulator diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/CHANGELOG.md b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/CHANGELOG.md new file mode 100644 index 0000000000..5ab6121825 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/CHANGELOG.md @@ -0,0 +1,258 @@ +# filecoin-ffi changelog + +## 0.30.1 + +This release wil include Window PoSt speedups (2x measured for 32GiB sectors), +RAM reduction of 56GiB for 32GiB sectors (mmap'd parent cache with windows for +access, rather than all in RAM at once), and some phase2/trusted setup related +updates (for the trusted setup participants). + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - update to rust-fil-proofs 4.0.2 (#113) ([filecoin-project/filecoin-ffi#113](https://github.com/filecoin-project/filecoin-ffi/pull/113)) + - run the Rust tests before running the Go tests (#112) ([filecoin-project/filecoin-ffi#112](https://github.com/filecoin-project/filecoin-ffi/pull/112)) + - Update master dependencies ([filecoin-project/filecoin-ffi#111](https://github.com/filecoin-project/filecoin-ffi/pull/111)) + - update changelog for 0.30.0 release ([filecoin-project/filecoin-ffi#109](https://github.com/filecoin-project/filecoin-ffi/pull/109)) +- github.com/filecoin-project/specs-actors (v0.6.0 -> v0.6.1) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| nemo | 3 | +1463/-1782 | 17 | +| Alex North | 2 | +139/-116 | 3 | +| Erin Swenson-Healey | 2 | +90/-68 | 7 | +| laser | 1 | +31/-0 | 1 | + +## 0.30.0 + +This release includes an update specs-actors (splits abi.RegisteredProof into +two new types - one for seal and one for PoSt) and an update to rust-fil-proofs +4.0.0, which you can read about [here](https://github.com/filecoin-project/rust-fil-proofs/blob/master/CHANGELOG.md#400---2020-06-15). + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - update to rust-fil-proofs 4.0.0 (#108) ([filecoin-project/filecoin-ffi#108](https://github.com/filecoin-project/filecoin-ffi/pull/108)) + - specs-actors v0.6 ([filecoin-project/filecoin-ffi#107](https://github.com/filecoin-project/filecoin-ffi/pull/107)) + - changelog for 0.28.0, 0.28.1, and 0.29.0 (#106) ([filecoin-project/filecoin-ffi#106](https://github.com/filecoin-project/filecoin-ffi/pull/106)) +- github.com/filecoin-project/specs-actors (v0.5.4-0.20200521014528-0df536f7e461 -> v0.6.0) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Frrist | 3 | +454/-239 | 22 | +| Whyrusleeping | 2 | +485/-119 | 19 | +| Alex North | 7 | +424/-151 | 15 | +| Łukasz Magiera | 4 | +227/-154 | 13 | +| Alex Cruikshank | 4 | +262/-85 | 10 | +| porcuquine | 1 | +172/-171 | 15 | +| Erin Swenson-Healey | 3 | +153/-30 | 5 | +| ZenGround0 | 3 | +42/-17 | 16 | +| ZX | 2 | +16/-19 | 4 | +| WEI YANG | 1 | +6/-2 | 1 | +| Henri | 1 | +2/-2 | 1 | + + +## 0.29.0 + +Big changes here! We moved off of the nightly Rust channel, fixed a nasty file +descriptor-leak, and (most importantly) updated to [v27 parameters and keys](https://github.com/filecoin-project/rust-fil-proofs/blob/master/CHANGELOG.md#300---2020-06-08). + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - fix: update to filecoin-proofs-api v3.0.0 ([filecoin-project/filecoin-ffi#105](https://github.com/filecoin-project/filecoin-ffi/pull/105)) + - explicitly close os.File to force release of file descriptor (#97) ([filecoin-project/filecoin-ffi#97](https://github.com/filecoin-project/filecoin-ffi/pull/97)) + - fix: use stable 1.43.1 release ([filecoin-project/filecoin-ffi#102](https://github.com/filecoin-project/filecoin-ffi/pull/102)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| nemo | 2 | +133/-132 | 4 | +| Erin Swenson-Healey | 1 | +47/-1 | 2 | +| Volker Mische | 1 | +1/-3 | 3 | + + +## 0.28.1 + +This release modifies the rust-filecoin-proofs-api dependency, downloading it +from crates.io instead of GitHub. No behavior changes. + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - fix: point to published filecoin-proofs-api crate ([filecoin-project/filecoin-ffi#104](https://github.com/filecoin-project/filecoin-ffi/pull/104)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| nemo | 1 | +6/-5 | 3 | + + +## 0.28.0 + +This release adds unseal-to-a-file-descriptor functionality to the API, improves +merkle tree cache usage, [and more](https://github.com/filecoin-project/rust-fil-proofs/blob/master/CHANGELOG.md#200---2020-05-27). + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - integrate rust-fil-proofs 2.0.0 release (#98) ([filecoin-project/filecoin-ffi#98](https://github.com/filecoin-project/filecoin-ffi/pull/98)) + - release notes for 0.27.0 (#96) ([filecoin-project/filecoin-ffi#96](https://github.com/filecoin-project/filecoin-ffi/pull/96)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Erin Swenson-Healey | 2 | +245/-371 | 9 | + + +## 0.27.0 + +This release migrates from specs-actors 0.4.1 to 0.5.4. + +### Breaking Changes + +- The `VerifySeal` function has been modified to accept the revamped `abi.SealVerifyInfo` type. + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - consume new abi.SealVerifyInfo structure (#89) ([filecoin-project/filecoin-ffi#89](https://github.com/filecoin-project/filecoin-ffi/pull/89)) + - add changelog and changelog generator (#95) ([filecoin-project/filecoin-ffi#95](https://github.com/filecoin-project/filecoin-ffi/pull/95)) +- github.com/filecoin-project/go-bitfield (v0.0.0-20200416002808-b3ee67ec9060 -> v0.0.1): + - zero out bitfields during subtraction when they end up empty ([filecoin-project/go-bitfield#4](https://github.com/filecoin-project/go-bitfield/pull/4)) + - Create go.yml +- github.com/filecoin-project/specs-actors (v0.4.1-0.20200509020627-3c96f54f3d7d -> v0.5.4-0.20200521014528-0df536f7e461): + - decouple SealVerifyInfo from OnChainSealVerifyInfo (and rename to SealVerifyParams) (#378) ([filecoin-project/specs-actors#378](https://github.com/filecoin-project/specs-actors/pull/378)) + - add Unencodable Return method to puppet actor (#384) ([filecoin-project/specs-actors#384](https://github.com/filecoin-project/specs-actors/pull/384)) + - call validate caller (#379) ([filecoin-project/specs-actors#379](https://github.com/filecoin-project/specs-actors/pull/379)) + - handle last cron tick in market actor properly (#376) ([filecoin-project/specs-actors#376](https://github.com/filecoin-project/specs-actors/pull/376)) + - stop puppet actor panic when sendreturn is nil (#375) ([filecoin-project/specs-actors#375](https://github.com/filecoin-project/specs-actors/pull/375)) + - Change window post deadline duration to 1hr. (#373) ([filecoin-project/specs-actors#373](https://github.com/filecoin-project/specs-actors/pull/373)) + - cbor-gen for reward actor state (#372) ([filecoin-project/specs-actors#372](https://github.com/filecoin-project/specs-actors/pull/372)) + - Fractional network time (#367) ([filecoin-project/specs-actors#367](https://github.com/filecoin-project/specs-actors/pull/367)) + - deps: go-bitfield v0.0.1 (#369) ([filecoin-project/specs-actors#369](https://github.com/filecoin-project/specs-actors/pull/369)) + - update block reward target from KPI event, use that value to pay block rewards (#366) ([filecoin-project/specs-actors#366](https://github.com/filecoin-project/specs-actors/pull/366)) + - Helpers and mocks for miner window post unit tests. (#354) ([filecoin-project/specs-actors#354](https://github.com/filecoin-project/specs-actors/pull/354)) + - Change min miner power from 10TiB to 1TiB for testnet-2 (#368) ([filecoin-project/specs-actors#368](https://github.com/filecoin-project/specs-actors/pull/368)) + - Remove incorrect assumption about window post proof slice (#361) ([filecoin-project/specs-actors#361](https://github.com/filecoin-project/specs-actors/pull/361)) + - miner: Restrict supported proof types in miner ctor (#363) ([filecoin-project/specs-actors#363](https://github.com/filecoin-project/specs-actors/pull/363)) + - dont include value in the error message for set errors (#365) ([filecoin-project/specs-actors#365](https://github.com/filecoin-project/specs-actors/pull/365)) + - Fix nil verified deal weight (#360) ([filecoin-project/specs-actors#360](https://github.com/filecoin-project/specs-actors/pull/360)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Erin Swenson-Healey | 3 | +501/-293 | 12 | +| Łukasz Magiera | 4 | +388/-181 | 21 | +| Alex North | 5 | +346/-71 | 9 | +| Jakub Sztandera | 3 | +94/-9 | 5 | +| Whyrusleeping | 4 | +66/-36 | 9 | +| ZX | 1 | +21/-42 | 3 | +| Jeromy | 1 | +62/-0 | 2 | +| Frrist | 2 | +27/-8 | 2 | +| cerasusland | 1 | +2/-5 | 1 | + +## 0.26.2 + +This release contains a fix for a bug which prevented unmodified miners from +generating Winning PoSts for 64GiB sectors. It also contains a fix for a bug +which was an occasional source of `bad file descriptor` errors observed during +CommP generation (our hypothesis is that the `*os.File` was being GC'ed before +the CGO call returned). + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - don't let Go garbage collect FD until FFI call returns ([filecoin-project/filecoin-ffi#84](https://github.com/filecoin-project/filecoin-ffi/pull/84)) + - fix: error if there is already a logger + - add winning PoSt for 64 GiB (#93) ([filecoin-project/filecoin-ffi#93](https://github.com/filecoin-project/filecoin-ffi/pull/93)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Volker Mische | 1 | +24/-7 | 1 | +| laser | 1 | +5/-5 | 1 | +| shannon-6block | 1 | +2/-0 | 1 | + +## 0.26.1 + +This release updates to version 0.4.1 of specs-actors, which (among other +things) extends the `RegisteredProof` types to include 64GiB sector sizes. It +also includes a fix for Window PoSt (multiple proofs were being flattened into +a single byte array) and various fixes for bellperson and neptune Rust crates. + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - Update deps revisited ([filecoin-project/filecoin-ffi#91](https://github.com/filecoin-project/filecoin-ffi/pull/91)) + - newest upstream (#88) ([filecoin-project/filecoin-ffi#88](https://github.com/filecoin-project/filecoin-ffi/pull/88)) + - update rust-filecoin-proofs-api to include PoSt fix (#87) ([filecoin-project/filecoin-ffi#87](https://github.com/filecoin-project/filecoin-ffi/pull/87)) + - upgrade to specs-actors 0.4.1 (64GiB sector support) ([filecoin-project/filecoin-ffi#85](https://github.com/filecoin-project/filecoin-ffi/pull/85)) + - Upgrade to specs-actors v0.3.0 (#81) ([filecoin-project/filecoin-ffi#81](https://github.com/filecoin-project/filecoin-ffi/pull/81)) +- github.com/filecoin-project/go-amt-ipld (v2.0.1-0.20200131012142-05d80eeccc5e -> v2.0.1-0.20200424220931-6263827e49f2): + - implement method to get first index in amt ([filecoin-project/go-amt-ipld#11](https://github.com/filecoin-project/go-amt-ipld/pull/11)) + - implement ForEachAt method to support iteration starting at a given i… ([filecoin-project/go-amt-ipld#10](https://github.com/filecoin-project/go-amt-ipld/pull/10)) +- github.com/filecoin-project/specs-actors (v0.2.0 -> v0.4.1-0.20200509020627-3c96f54f3d7d): + - Minting function maintainability (#356) ([filecoin-project/specs-actors#356](https://github.com/filecoin-project/specs-actors/pull/356)) + - support for 64GiB sectors (#355) ([filecoin-project/specs-actors#355](https://github.com/filecoin-project/specs-actors/pull/355)) + - Temporary param update (#352) ([filecoin-project/specs-actors#352](https://github.com/filecoin-project/specs-actors/pull/352)) + - document reward minting function tests (#348) ([filecoin-project/specs-actors#348](https://github.com/filecoin-project/specs-actors/pull/348)) + - puppet type and method for failed marshal to cbor (#347) ([filecoin-project/specs-actors#347](https://github.com/filecoin-project/specs-actors/pull/347)) + - Unit tests for prove commit sector (#351) ([filecoin-project/specs-actors#351](https://github.com/filecoin-project/specs-actors/pull/351)) + - Fix failure to detect faults of exactly-full top partition (#350) ([filecoin-project/specs-actors#350](https://github.com/filecoin-project/specs-actors/pull/350)) + - Fix checking of fault/recovery declaration deadlines (#349) ([filecoin-project/specs-actors#349](https://github.com/filecoin-project/specs-actors/pull/349)) + - Set ConsensusMinerMinPower to 10TiB (#344) ([filecoin-project/specs-actors#344](https://github.com/filecoin-project/specs-actors/pull/344)) + - improve deal accounting performance (#309) ([filecoin-project/specs-actors#309](https://github.com/filecoin-project/specs-actors/pull/309)) + - DeadlineInfo handles expired proving period (#343) ([filecoin-project/specs-actors#343](https://github.com/filecoin-project/specs-actors/pull/343)) + - document reward-minting taylorSeriesExpansion (#338) ([filecoin-project/specs-actors#338](https://github.com/filecoin-project/specs-actors/pull/338)) + - implement puppet actor (#290) ([filecoin-project/specs-actors#290](https://github.com/filecoin-project/specs-actors/pull/290)) + - Fix the 32GiB Window PoSt partition size again (#337) ([filecoin-project/specs-actors#337](https://github.com/filecoin-project/specs-actors/pull/337)) + - Fix seal proof type in miner actor and parameterize WPoSt partition size by it (#336) ([filecoin-project/specs-actors#336](https://github.com/filecoin-project/specs-actors/pull/336)) + - Change WPoStPartitionSectors to 2349 (#332) ([filecoin-project/specs-actors#332](https://github.com/filecoin-project/specs-actors/pull/332)) + - Remove unused SectorSize from VerifyDealsOnSectorProveCommitParams (#328) ([filecoin-project/specs-actors#328](https://github.com/filecoin-project/specs-actors/pull/328)) + - require success in reward actor send reward (#331) ([filecoin-project/specs-actors#331](https://github.com/filecoin-project/specs-actors/pull/331)) + - Power actor CreateMiner passes on value received to new actor (#327) ([filecoin-project/specs-actors#327](https://github.com/filecoin-project/specs-actors/pull/327)) + - Specify cron genesis entries (#326) ([filecoin-project/specs-actors#326](https://github.com/filecoin-project/specs-actors/pull/326)) + - Remove SysErrInternal definition, use of which is always a bug (#304) ([filecoin-project/specs-actors#304](https://github.com/filecoin-project/specs-actors/pull/304)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Alex North | 13 | +654/-280 | 35 | +| Whyrusleeping | 2 | +273/-437 | 13 | +| Frrist | 3 | +455/-6 | 7 | +| davidad (David A. Dalrymple) | 3 | +245/-46 | 5 | +| Jeromy | 2 | +166/-4 | 4 | +| laser | 4 | +110/-48 | 6 | +| Erin Swenson-Healey | 3 | +50/-30 | 5 | +| ZX | 1 | +48/-20 | 5 | +| nemo | 1 | +4/-56 | 2 | + +## 0.26.0 + +This release migrates from v25 to v26 Groth parameters, which allows us to use +64GiB sectors. It also adds some safety to the CGO bindings, which were +previously sharing Go memory with C, resulting in some errors when running with +`cgocheck=2`. + +### Changelog + +- github.com/filecoin-project/filecoin-ffi: + - update to v26 Groth parameters (#83) ([filecoin-project/filecoin-ffi#83](https://github.com/filecoin-project/filecoin-ffi/pull/83)) + - handle allocations for problematic structs to avoid sharing pointers-to-pointers with C (from Go) (#82) ([filecoin-project/filecoin-ffi#82](https://github.com/filecoin-project/filecoin-ffi/pull/82)) + +### Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Erin Swenson-Healey | 2 | +514/-375 | 15 | diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-APACHE b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-APACHE new file mode 100644 index 0000000000..25d5a0058a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-APACHE @@ -0,0 +1,7 @@ + Copyright (c) 2018 Filecoin Project + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-MIT b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-MIT new file mode 100644 index 0000000000..468cd79a8f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/Makefile b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/Makefile new file mode 100644 index 0000000000..94b0b30a05 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/Makefile @@ -0,0 +1,40 @@ +DEPS:=filcrypto.h filcrypto.pc libfilcrypto.a + +all: $(DEPS) +.PHONY: all + +# Create a file so that parallel make doesn't call `./install-filcrypto` for +# each of the deps +$(DEPS): .install-filcrypto ; + +.install-filcrypto: rust + ./install-filcrypto + @touch $@ + +clean: + rm -rf $(DEPS) .install-filcrypto + rm -f ./runner + cd rust && cargo clean && cd .. +.PHONY: clean + +go-lint: $(DEPS) + golangci-lint run -v --concurrency 2 --new-from-rev origin/master +.PHONY: go-lint + +shellcheck: + shellcheck install-filcrypto + +lint: shellcheck go-lint + +cgo-leakdetect: runner + valgrind --leak-check=full --show-leak-kinds=definite ./runner +.PHONY: cgo-leakdetect + +cgo-gen: $(DEPS) + c-for-go --ccincl --ccdefs --nostamp filcrypto.yml +.PHONY: cgo-gen + +runner: $(DEPS) + rm -f ./runner + go build -o ./runner ./cgoleakdetect/ +.PHONY: runner diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/README.md b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/README.md new file mode 100644 index 0000000000..678ccd96a3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/README.md @@ -0,0 +1,74 @@ +# Filecoin Proofs FFI + +> C and CGO bindings for Filecoin's Rust libraries + +## Building + +To build and install libfilcrypto, its header file and pkg-config manifest, run: + +```shell +make +``` + +To optionally authenticate with GitHub for assets download (to increase API limits) +set `GITHUB_TOKEN` to personal access token. + +If no precompiled static library is available for your operating system, the +build tooling will attempt to compile a static library from local Rust sources. + +### Forcing Local Build + +To opt out of downloading precompiled assets, set `FFI_BUILD_FROM_SOURCE=1`: + +```shell +rm .install-filcrypto \ + ; make clean \ + ; FFI_BUILD_FROM_SOURCE=1 make +``` + +## Updating rust-fil-proofs (via rust-filecoin-proofs-api) + +If rust-fil-proofs has changed from commit X to Y and you wish to get Y into +the filecoin-ffi project, you need to do a few things: + +1. Update the rust-filecoin-proofs-api [Cargo.toml][1] file to point to Y +2. Run `cd rust && cargo update -p "filecoin-proofs-api"` from the root of the filecoin-ffi project +3. After the previous step alters your Cargo.lock file, commit and push + +## go get + +`go get` needs some additional steps in order to work as expected. + +Get the source, add this repo as a submodule to your repo, build it and point to it: + +```shell +$ go get github.com/filecoin-project/filecoin-ffi +$ git submodule add https://github.com/filecoin-project/filecoin-ffi.git extern/filecoin-ffi +$ make -C extern/filecoin-ffi +$ go mod edit -replace=github.com/filecoin-project/filecoin-ffi=./extern/filecoin-ffi +``` + +## Updating CGO Bindings + +The CGO bindings are generated using [c-for-go](https://github.com/xlab/c-for-go) +and committed to Git. To generate bindings yourself, install the c-for-go +binary, ensure that it's on your path, and then run `make cgo-gen`. CI builds +will fail if generated CGO diverges from what's checked into Git. + +## Updating the Changelog + +The `mkreleaselog` script (in the project root) can be used to generate a good +portion of the filecoin-ffi changelog. For historical reasons, the script must +be run from the root of a filecoin-ffi checkout which is in your `$GOPATH`. + +Run it like so: + +```shell +./mkreleaselog v0.25.0 v0.26.0 > /tmp/v0.26.0.notes.txt +``` + +## License + +MIT or Apache 2.0 + +[1]: https://github.com/filecoin-project/rust-filecoin-proofs-api/commit/61fde0e581cc38abc4e13dbe96145c9ad2f1f0f5 diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls.go new file mode 100644 index 0000000000..3fce99b28b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls.go @@ -0,0 +1,140 @@ +//+build cgo + +package ffi + +import ( + "github.com/filecoin-project/filecoin-ffi/generated" +) + +// #cgo LDFLAGS: ${SRCDIR}/libfilcrypto.a +// #cgo pkg-config: ${SRCDIR}/filcrypto.pc +// #include "./filcrypto.h" +import "C" + +// Hash computes the digest of a message +func Hash(message Message) Digest { + resp := generated.FilHash(string(message), uint(len(message))) + resp.Deref() + resp.Digest.Deref() + + defer generated.FilDestroyHashResponse(resp) + + var out Digest + copy(out[:], resp.Digest.Inner[:]) + return out +} + +// Verify verifies that a signature is the aggregated signature of digests - pubkeys +func Verify(signature *Signature, digests []Digest, publicKeys []PublicKey) bool { + // prep data + flattenedDigests := make([]byte, DigestBytes*len(digests)) + for idx, digest := range digests { + copy(flattenedDigests[(DigestBytes*idx):(DigestBytes*(1+idx))], digest[:]) + } + + flattenedPublicKeys := make([]byte, PublicKeyBytes*len(publicKeys)) + for idx, publicKey := range publicKeys { + copy(flattenedPublicKeys[(PublicKeyBytes*idx):(PublicKeyBytes*(1+idx))], publicKey[:]) + } + + isValid := generated.FilVerify(string(signature[:]), string(flattenedDigests), uint(len(flattenedDigests)), string(flattenedPublicKeys), uint(len(flattenedPublicKeys))) + + return isValid > 0 +} + +// HashVerify verifies that a signature is the aggregated signature of hashed messages. +func HashVerify(signature *Signature, messages []Message, publicKeys []PublicKey) bool { + var flattenedMessages string + messagesSizes := make([]uint, len(messages)) + for idx := range messages { + flattenedMessages = flattenedMessages + string(messages[idx]) + messagesSizes[idx] = uint(len(messages[idx])) + } + + flattenedPublicKeys := make([]byte, PublicKeyBytes*len(publicKeys)) + for idx, publicKey := range publicKeys { + copy(flattenedPublicKeys[(PublicKeyBytes*idx):(PublicKeyBytes*(1+idx))], publicKey[:]) + } + + isValid := generated.FilHashVerify(string(signature[:]), flattenedMessages, uint(len(flattenedMessages)), messagesSizes, uint(len(messagesSizes)), string(flattenedPublicKeys), uint(len(flattenedPublicKeys))) + + return isValid > 0 +} + +// Aggregate aggregates signatures together into a new signature. If the +// provided signatures cannot be aggregated (due to invalid input or an +// an operational error), Aggregate will return nil. +func Aggregate(signatures []Signature) *Signature { + // prep data + flattenedSignatures := make([]byte, SignatureBytes*len(signatures)) + for idx, sig := range signatures { + copy(flattenedSignatures[(SignatureBytes*idx):(SignatureBytes*(1+idx))], sig[:]) + } + + resp := generated.FilAggregate(string(flattenedSignatures), uint(len(flattenedSignatures))) + if resp == nil { + return nil + } + + defer generated.FilDestroyAggregateResponse(resp) + + resp.Deref() + resp.Signature.Deref() + + var out Signature + copy(out[:], resp.Signature.Inner[:]) + return &out +} + +// PrivateKeyGenerate generates a private key +func PrivateKeyGenerate() PrivateKey { + resp := generated.FilPrivateKeyGenerate() + resp.Deref() + resp.PrivateKey.Deref() + defer generated.FilDestroyPrivateKeyGenerateResponse(resp) + + var out PrivateKey + copy(out[:], resp.PrivateKey.Inner[:]) + return out +} + +// PrivateKeyGenerate generates a private key in a predictable manner +func PrivateKeyGenerateWithSeed(seed PrivateKeyGenSeed) PrivateKey { + var ary generated.Fil32ByteArray + copy(ary.Inner[:], seed[:]) + + resp := generated.FilPrivateKeyGenerateWithSeed(ary) + resp.Deref() + resp.PrivateKey.Deref() + defer generated.FilDestroyPrivateKeyGenerateResponse(resp) + + var out PrivateKey + copy(out[:], resp.PrivateKey.Inner[:]) + return out +} + +// PrivateKeySign signs a message +func PrivateKeySign(privateKey PrivateKey, message Message) *Signature { + resp := generated.FilPrivateKeySign(string(privateKey[:]), string(message), uint(len(message))) + resp.Deref() + resp.Signature.Deref() + + defer generated.FilDestroyPrivateKeySignResponse(resp) + + var signature Signature + copy(signature[:], resp.Signature.Inner[:]) + return &signature +} + +// PrivateKeyPublicKey gets the public key for a private key +func PrivateKeyPublicKey(privateKey PrivateKey) PublicKey { + resp := generated.FilPrivateKeyPublicKey(string(privateKey[:])) + resp.Deref() + resp.PublicKey.Deref() + + defer generated.FilDestroyPrivateKeyPublicKeyResponse(resp) + + var publicKey PublicKey + copy(publicKey[:], resp.PublicKey.Inner[:]) + return publicKey +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls_test.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls_test.go new file mode 100644 index 0000000000..430c5fb6af --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/bls_test.go @@ -0,0 +1,177 @@ +package ffi + +import ( + "fmt" + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDeterministicPrivateKeyGeneration(t *testing.T) { + rand.Seed(time.Now().UnixNano()) + + for i := 0; i < 10000; i++ { + var xs [32]byte + n, err := rand.Read(xs[:]) + require.NoError(t, err) + require.Equal(t, len(xs), n) + + first := PrivateKeyGenerateWithSeed(xs) + secnd := PrivateKeyGenerateWithSeed(xs) + + assert.Equal(t, first, secnd) + } +} + +func TestBLSSigningAndVerification(t *testing.T) { + // generate private keys + fooPrivateKey := PrivateKeyGenerate() + barPrivateKey := PrivateKeyGenerate() + + // get the public keys for the private keys + fooPublicKey := PrivateKeyPublicKey(fooPrivateKey) + barPublicKey := PrivateKeyPublicKey(barPrivateKey) + + // make messages to sign with the keys + fooMessage := Message("hello foo") + barMessage := Message("hello bar!") + + // calculate the digests of the messages + fooDigest := Hash(fooMessage) + barDigest := Hash(barMessage) + + // get the signature when signing the messages with the private keys + fooSignature := PrivateKeySign(fooPrivateKey, fooMessage) + barSignature := PrivateKeySign(barPrivateKey, barMessage) + + // assert the foo message was signed with the foo key + assert.True(t, Verify(fooSignature, []Digest{fooDigest}, []PublicKey{fooPublicKey})) + + // assert the bar message was signed with the bar key + assert.True(t, Verify(barSignature, []Digest{barDigest}, []PublicKey{barPublicKey})) + + // assert the foo message was signed with the foo key + assert.True(t, HashVerify(fooSignature, []Message{fooMessage}, []PublicKey{fooPublicKey})) + + // assert the bar message was signed with the bar key + assert.True(t, HashVerify(barSignature, []Message{barMessage}, []PublicKey{barPublicKey})) + + // assert the foo message was not signed by the bar key + assert.False(t, Verify(fooSignature, []Digest{fooDigest}, []PublicKey{barPublicKey})) + + // assert the bar/foo message was not signed by the foo/bar key + assert.False(t, Verify(barSignature, []Digest{barDigest}, []PublicKey{fooPublicKey})) + assert.False(t, Verify(barSignature, []Digest{fooDigest}, []PublicKey{barPublicKey})) + assert.False(t, Verify(fooSignature, []Digest{barDigest}, []PublicKey{fooPublicKey})) +} + +func BenchmarkBLSVerify(b *testing.B) { + priv := PrivateKeyGenerate() + + msg := Message("this is a message that i will be signing") + digest := Hash(msg) + + sig := PrivateKeySign(priv, msg) + // fmt.Println("SIG SIZE: ", len(sig)) + // fmt.Println("SIG: ", sig) + pubk := PrivateKeyPublicKey(priv) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if !Verify(sig, []Digest{digest}, []PublicKey{pubk}) { + b.Fatal("failed to verify") + } + } +} + +func TestBlsAggregateErrors(t *testing.T) { + t.Run("no signatures", func(t *testing.T) { + var empty []Signature + out := Aggregate(empty) + require.Nil(t, out) + }) + + t.Run("nil signatures", func(t *testing.T) { + out := Aggregate(nil) + require.Nil(t, out) + }) +} + +func BenchmarkBLSVerifyBatch(b *testing.B) { + b.Run("10", benchmarkBLSVerifyBatchSize(10)) + b.Run("50", benchmarkBLSVerifyBatchSize(50)) + b.Run("100", benchmarkBLSVerifyBatchSize(100)) + b.Run("300", benchmarkBLSVerifyBatchSize(300)) + b.Run("1000", benchmarkBLSVerifyBatchSize(1000)) + b.Run("4000", benchmarkBLSVerifyBatchSize(4000)) +} + +func benchmarkBLSVerifyBatchSize(size int) func(b *testing.B) { + return func(b *testing.B) { + var digests []Digest + var msgs []Message + var sigs []Signature + var pubks []PublicKey + for i := 0; i < size; i++ { + msg := Message(fmt.Sprintf("cats cats cats cats %d %d %d dogs", i, i, i)) + msgs = append(msgs, msg) + digests = append(digests, Hash(msg)) + priv := PrivateKeyGenerate() + sig := PrivateKeySign(priv, msg) + sigs = append(sigs, *sig) + pubk := PrivateKeyPublicKey(priv) + pubks = append(pubks, pubk) + } + + t := time.Now() + agsig := Aggregate(sigs) + fmt.Println("Aggregate took: ", time.Since(t)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if !Verify(agsig, digests, pubks) { + b.Fatal("failed to verify") + } + } + } +} + +func BenchmarkBLSHashAndVerify(b *testing.B) { + priv := PrivateKeyGenerate() + + msg := Message("this is a message that i will be signing") + sig := PrivateKeySign(priv, msg) + + // fmt.Println("SIG SIZE: ", len(sig)) + // fmt.Println("SIG: ", sig) + pubk := PrivateKeyPublicKey(priv) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + digest := Hash(msg) + if !Verify(sig, []Digest{digest}, []PublicKey{pubk}) { + b.Fatal("failed to verify") + } + } +} + +func BenchmarkBLSHashVerify(b *testing.B) { + priv := PrivateKeyGenerate() + + msg := Message("this is a message that i will be signing") + sig := PrivateKeySign(priv, msg) + + // fmt.Println("SIG SIZE: ", len(sig)) + // fmt.Println("SIG: ", sig) + pubk := PrivateKeyPublicKey(priv) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if !HashVerify(sig, []Message{msg}, []PublicKey{pubk}) { + b.Fatal("failed to verify") + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/build.sh b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/build.sh new file mode 100755 index 0000000000..f3b27a6cd2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +make clean +cd rust +rm Cargo.lock +cargo update -p "filecoin-proofs-api" +cargo install cbindgen +cbindgen --clean --config cbindgen.toml --crate filcrypto --output ../include/filcrypto.h +cd .. +FFI_BUILD_FROM_SOURCE=1 make diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/cgoleakdetect/runner.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/cgoleakdetect/runner.go new file mode 100644 index 0000000000..2bfc33b93b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/cgoleakdetect/runner.go @@ -0,0 +1,63 @@ +//+build cgo + +package main + +import ( + "fmt" + "os" + + ffi "github.com/filecoin-project/filecoin-ffi" +) + +func main() { + os.Setenv("RUST_LOG", "info") + th := panicOnFailureTestHelper{} + ffi.WorkflowGetGPUDevicesDoesNotProduceAnError(&th) + ffi.WorkflowProofsLifecycle(&th) + ffi.WorkflowRegisteredPoStProofFunctions(&th) + ffi.WorkflowRegisteredSealProofFunctions(&th) +} + +type panicOnFailureTestHelper struct{} + +func (p panicOnFailureTestHelper) AssertEqual(expected, actual interface{}, msgAndArgs ...interface{}) bool { + if expected != actual { + panic(fmt.Sprintf("not equal: %+v, %+v, %+v", expected, actual, msgAndArgs)) + } + + return true +} + +func (p panicOnFailureTestHelper) AssertNoError(err error, msgAndArgs ...interface{}) bool { + if err != nil { + panic(fmt.Sprintf("there was an error: %+v, %+v", err, msgAndArgs)) + } + + return true +} + +func (p panicOnFailureTestHelper) AssertTrue(value bool, msgAndArgs ...interface{}) bool { + if !value { + panic(fmt.Sprintf("not true: %+v, %+v", value, msgAndArgs)) + } + + return true +} + +func (p panicOnFailureTestHelper) RequireEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if expected != actual { + panic(fmt.Sprintf("not equal: %+v, %+v, %+v", expected, actual, msgAndArgs)) + } +} + +func (p panicOnFailureTestHelper) RequireNoError(err error, msgAndArgs ...interface{}) { + if err != nil { + panic(fmt.Sprintf("there was an error: %+v, %+v", err, msgAndArgs)) + } +} + +func (p panicOnFailureTestHelper) RequireTrue(value bool, msgAndArgs ...interface{}) { + if !value { + panic(fmt.Sprintf("not true: %+v, %+v", value, msgAndArgs)) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/filcrypto.yml b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/filcrypto.yml new file mode 100644 index 0000000000..f38f4e215e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/filcrypto.yml @@ -0,0 +1,38 @@ +--- +GENERATOR: + PackageName: generated + PackageDescription: + PackageLicense: + Options: + SafeStrings: true + Includes: + - ../filcrypto.h + FlagGroups: + - {name: LDFLAGS, flags: ["-L${SRCDIR}/.. -lfilcrypto"]} + - {name: pkg-config, flags: ["${SRCDIR}/../filcrypto.pc"]} + +PARSER: + Defines: + __has_include_next(x): 1 + IncludePaths: + - /usr/include + SourcesPaths: + - ./filcrypto.h + +TRANSLATOR: + ConstRules: + defines: expand + enum: cgo + PtrTips: + function: + - {target: "^fil_destroy", tips: [ref]} + Rules: + global: + - {action: accept, from: "^fil"} + - {action: accept, from: "^FCPResponseStatus"} + - {transform: export} + private: + - {transform: unexport} + post-global: + - {transform: export} + - {load: snakecase} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.go new file mode 100644 index 0000000000..a7ecf0742a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.go @@ -0,0 +1,3517 @@ +// WARNING: This file has automatically been generated +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +package generated + +/* +#cgo LDFLAGS: -L${SRCDIR}/.. -lfilcrypto +#cgo pkg-config: ${SRCDIR}/../filcrypto.pc +#include "../filcrypto.h" +#include +#include "cgo_helpers.h" +*/ +import "C" +import ( + "fmt" + "runtime" + "sync" + "unsafe" +) + +// cgoAllocMap stores pointers to C allocated memory for future reference. +type cgoAllocMap struct { + mux sync.RWMutex + m map[unsafe.Pointer]struct{} +} + +var cgoAllocsUnknown = new(cgoAllocMap) + +func (a *cgoAllocMap) Add(ptr unsafe.Pointer) { + a.mux.Lock() + if a.m == nil { + a.m = make(map[unsafe.Pointer]struct{}) + } + a.m[ptr] = struct{}{} + a.mux.Unlock() +} + +func (a *cgoAllocMap) IsEmpty() bool { + a.mux.RLock() + isEmpty := len(a.m) == 0 + a.mux.RUnlock() + return isEmpty +} + +func (a *cgoAllocMap) Borrow(b *cgoAllocMap) { + if b == nil || b.IsEmpty() { + return + } + b.mux.Lock() + a.mux.Lock() + for ptr := range b.m { + if a.m == nil { + a.m = make(map[unsafe.Pointer]struct{}) + } + a.m[ptr] = struct{}{} + delete(b.m, ptr) + } + a.mux.Unlock() + b.mux.Unlock() +} + +func (a *cgoAllocMap) Free() { + a.mux.Lock() + for ptr := range a.m { + C.free(ptr) + delete(a.m, ptr) + } + a.mux.Unlock() +} + +// allocFilBLSSignatureMemory allocates memory for type C.fil_BLSSignature in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilBLSSignatureMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilBLSSignatureValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilBLSSignatureValue = unsafe.Sizeof([1]C.fil_BLSSignature{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilBLSSignature) Ref() *C.fil_BLSSignature { + if x == nil { + return nil + } + return x.refa2ac09ba +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilBLSSignature) Free() { + if x != nil && x.allocsa2ac09ba != nil { + x.allocsa2ac09ba.(*cgoAllocMap).Free() + x.refa2ac09ba = nil + } +} + +// NewFilBLSSignatureRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilBLSSignatureRef(ref unsafe.Pointer) *FilBLSSignature { + if ref == nil { + return nil + } + obj := new(FilBLSSignature) + obj.refa2ac09ba = (*C.fil_BLSSignature)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilBLSSignature) PassRef() (*C.fil_BLSSignature, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refa2ac09ba != nil { + return x.refa2ac09ba, nil + } + mema2ac09ba := allocFilBLSSignatureMemory(1) + refa2ac09ba := (*C.fil_BLSSignature)(mema2ac09ba) + allocsa2ac09ba := new(cgoAllocMap) + allocsa2ac09ba.Add(mema2ac09ba) + + var cinner_allocs *cgoAllocMap + refa2ac09ba.inner, cinner_allocs = *(*[96]C.uint8_t)(unsafe.Pointer(&x.Inner)), cgoAllocsUnknown + allocsa2ac09ba.Borrow(cinner_allocs) + + x.refa2ac09ba = refa2ac09ba + x.allocsa2ac09ba = allocsa2ac09ba + return refa2ac09ba, allocsa2ac09ba + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilBLSSignature) PassValue() (C.fil_BLSSignature, *cgoAllocMap) { + if x.refa2ac09ba != nil { + return *x.refa2ac09ba, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilBLSSignature) Deref() { + if x.refa2ac09ba == nil { + return + } + x.Inner = *(*[96]byte)(unsafe.Pointer(&x.refa2ac09ba.inner)) +} + +// allocFilAggregateResponseMemory allocates memory for type C.fil_AggregateResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilAggregateResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilAggregateResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilAggregateResponseValue = unsafe.Sizeof([1]C.fil_AggregateResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilAggregateResponse) Ref() *C.fil_AggregateResponse { + if x == nil { + return nil + } + return x.refb3efa36d +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilAggregateResponse) Free() { + if x != nil && x.allocsb3efa36d != nil { + x.allocsb3efa36d.(*cgoAllocMap).Free() + x.refb3efa36d = nil + } +} + +// NewFilAggregateResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilAggregateResponseRef(ref unsafe.Pointer) *FilAggregateResponse { + if ref == nil { + return nil + } + obj := new(FilAggregateResponse) + obj.refb3efa36d = (*C.fil_AggregateResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilAggregateResponse) PassRef() (*C.fil_AggregateResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refb3efa36d != nil { + return x.refb3efa36d, nil + } + memb3efa36d := allocFilAggregateResponseMemory(1) + refb3efa36d := (*C.fil_AggregateResponse)(memb3efa36d) + allocsb3efa36d := new(cgoAllocMap) + allocsb3efa36d.Add(memb3efa36d) + + var csignature_allocs *cgoAllocMap + refb3efa36d.signature, csignature_allocs = x.Signature.PassValue() + allocsb3efa36d.Borrow(csignature_allocs) + + x.refb3efa36d = refb3efa36d + x.allocsb3efa36d = allocsb3efa36d + return refb3efa36d, allocsb3efa36d + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilAggregateResponse) PassValue() (C.fil_AggregateResponse, *cgoAllocMap) { + if x.refb3efa36d != nil { + return *x.refb3efa36d, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilAggregateResponse) Deref() { + if x.refb3efa36d == nil { + return + } + x.Signature = *NewFilBLSSignatureRef(unsafe.Pointer(&x.refb3efa36d.signature)) +} + +// allocFilClearCacheResponseMemory allocates memory for type C.fil_ClearCacheResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilClearCacheResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilClearCacheResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilClearCacheResponseValue = unsafe.Sizeof([1]C.fil_ClearCacheResponse{}) + +// unpackPCharString represents the data from Go string as *C.char and avoids copying. +func unpackPCharString(str string) (*C.char, *cgoAllocMap) { + str = safeString(str) + h := (*stringHeader)(unsafe.Pointer(&str)) + return (*C.char)(h.Data), cgoAllocsUnknown +} + +type stringHeader struct { + Data unsafe.Pointer + Len int +} + +// safeString ensures that the string is NULL-terminated, a NULL-terminated copy is created otherwise. +func safeString(str string) string { + if len(str) > 0 && str[len(str)-1] != '\x00' { + str = str + "\x00" + } else if len(str) == 0 { + str = "\x00" + } + return str +} + +// packPCharString creates a Go string backed by *C.char and avoids copying. +func packPCharString(p *C.char) (raw string) { + if p != nil && *p != 0 { + h := (*stringHeader)(unsafe.Pointer(&raw)) + h.Data = unsafe.Pointer(p) + for *p != 0 { + p = (*C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) // p++ + } + h.Len = int(uintptr(unsafe.Pointer(p)) - uintptr(h.Data)) + } + return +} + +// RawString reperesents a string backed by data on the C side. +type RawString string + +// Copy returns a Go-managed copy of raw string. +func (raw RawString) Copy() string { + if len(raw) == 0 { + return "" + } + h := (*stringHeader)(unsafe.Pointer(&raw)) + return C.GoStringN((*C.char)(h.Data), C.int(h.Len)) +} + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilClearCacheResponse) Ref() *C.fil_ClearCacheResponse { + if x == nil { + return nil + } + return x.refa9a80400 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilClearCacheResponse) Free() { + if x != nil && x.allocsa9a80400 != nil { + x.allocsa9a80400.(*cgoAllocMap).Free() + x.refa9a80400 = nil + } +} + +// NewFilClearCacheResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilClearCacheResponseRef(ref unsafe.Pointer) *FilClearCacheResponse { + if ref == nil { + return nil + } + obj := new(FilClearCacheResponse) + obj.refa9a80400 = (*C.fil_ClearCacheResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilClearCacheResponse) PassRef() (*C.fil_ClearCacheResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refa9a80400 != nil { + return x.refa9a80400, nil + } + mema9a80400 := allocFilClearCacheResponseMemory(1) + refa9a80400 := (*C.fil_ClearCacheResponse)(mema9a80400) + allocsa9a80400 := new(cgoAllocMap) + allocsa9a80400.Add(mema9a80400) + + var cerror_msg_allocs *cgoAllocMap + refa9a80400.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocsa9a80400.Borrow(cerror_msg_allocs) + + var cstatus_code_allocs *cgoAllocMap + refa9a80400.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocsa9a80400.Borrow(cstatus_code_allocs) + + x.refa9a80400 = refa9a80400 + x.allocsa9a80400 = allocsa9a80400 + return refa9a80400, allocsa9a80400 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilClearCacheResponse) PassValue() (C.fil_ClearCacheResponse, *cgoAllocMap) { + if x.refa9a80400 != nil { + return *x.refa9a80400, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilClearCacheResponse) Deref() { + if x.refa9a80400 == nil { + return + } + x.ErrorMsg = packPCharString(x.refa9a80400.error_msg) + x.StatusCode = (FCPResponseStatus)(x.refa9a80400.status_code) +} + +// allocFilFauxRepResponseMemory allocates memory for type C.fil_FauxRepResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilFauxRepResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilFauxRepResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilFauxRepResponseValue = unsafe.Sizeof([1]C.fil_FauxRepResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilFauxRepResponse) Ref() *C.fil_FauxRepResponse { + if x == nil { + return nil + } + return x.refaa003f71 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilFauxRepResponse) Free() { + if x != nil && x.allocsaa003f71 != nil { + x.allocsaa003f71.(*cgoAllocMap).Free() + x.refaa003f71 = nil + } +} + +// NewFilFauxRepResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilFauxRepResponseRef(ref unsafe.Pointer) *FilFauxRepResponse { + if ref == nil { + return nil + } + obj := new(FilFauxRepResponse) + obj.refaa003f71 = (*C.fil_FauxRepResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilFauxRepResponse) PassRef() (*C.fil_FauxRepResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refaa003f71 != nil { + return x.refaa003f71, nil + } + memaa003f71 := allocFilFauxRepResponseMemory(1) + refaa003f71 := (*C.fil_FauxRepResponse)(memaa003f71) + allocsaa003f71 := new(cgoAllocMap) + allocsaa003f71.Add(memaa003f71) + + var cerror_msg_allocs *cgoAllocMap + refaa003f71.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocsaa003f71.Borrow(cerror_msg_allocs) + + var cstatus_code_allocs *cgoAllocMap + refaa003f71.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocsaa003f71.Borrow(cstatus_code_allocs) + + var ccommitment_allocs *cgoAllocMap + refaa003f71.commitment, ccommitment_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.Commitment)), cgoAllocsUnknown + allocsaa003f71.Borrow(ccommitment_allocs) + + x.refaa003f71 = refaa003f71 + x.allocsaa003f71 = allocsaa003f71 + return refaa003f71, allocsaa003f71 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilFauxRepResponse) PassValue() (C.fil_FauxRepResponse, *cgoAllocMap) { + if x.refaa003f71 != nil { + return *x.refaa003f71, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilFauxRepResponse) Deref() { + if x.refaa003f71 == nil { + return + } + x.ErrorMsg = packPCharString(x.refaa003f71.error_msg) + x.StatusCode = (FCPResponseStatus)(x.refaa003f71.status_code) + x.Commitment = *(*[32]byte)(unsafe.Pointer(&x.refaa003f71.commitment)) +} + +// allocFilFinalizeTicketResponseMemory allocates memory for type C.fil_FinalizeTicketResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilFinalizeTicketResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilFinalizeTicketResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilFinalizeTicketResponseValue = unsafe.Sizeof([1]C.fil_FinalizeTicketResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilFinalizeTicketResponse) Ref() *C.fil_FinalizeTicketResponse { + if x == nil { + return nil + } + return x.refb370fa86 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilFinalizeTicketResponse) Free() { + if x != nil && x.allocsb370fa86 != nil { + x.allocsb370fa86.(*cgoAllocMap).Free() + x.refb370fa86 = nil + } +} + +// NewFilFinalizeTicketResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilFinalizeTicketResponseRef(ref unsafe.Pointer) *FilFinalizeTicketResponse { + if ref == nil { + return nil + } + obj := new(FilFinalizeTicketResponse) + obj.refb370fa86 = (*C.fil_FinalizeTicketResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilFinalizeTicketResponse) PassRef() (*C.fil_FinalizeTicketResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refb370fa86 != nil { + return x.refb370fa86, nil + } + memb370fa86 := allocFilFinalizeTicketResponseMemory(1) + refb370fa86 := (*C.fil_FinalizeTicketResponse)(memb370fa86) + allocsb370fa86 := new(cgoAllocMap) + allocsb370fa86.Add(memb370fa86) + + var cstatus_code_allocs *cgoAllocMap + refb370fa86.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocsb370fa86.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + refb370fa86.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocsb370fa86.Borrow(cerror_msg_allocs) + + var cticket_allocs *cgoAllocMap + refb370fa86.ticket, cticket_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.Ticket)), cgoAllocsUnknown + allocsb370fa86.Borrow(cticket_allocs) + + x.refb370fa86 = refb370fa86 + x.allocsb370fa86 = allocsb370fa86 + return refb370fa86, allocsb370fa86 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilFinalizeTicketResponse) PassValue() (C.fil_FinalizeTicketResponse, *cgoAllocMap) { + if x.refb370fa86 != nil { + return *x.refb370fa86, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilFinalizeTicketResponse) Deref() { + if x.refb370fa86 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.refb370fa86.status_code) + x.ErrorMsg = packPCharString(x.refb370fa86.error_msg) + x.Ticket = *(*[32]byte)(unsafe.Pointer(&x.refb370fa86.ticket)) +} + +// allocFilGenerateDataCommitmentResponseMemory allocates memory for type C.fil_GenerateDataCommitmentResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilGenerateDataCommitmentResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilGenerateDataCommitmentResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilGenerateDataCommitmentResponseValue = unsafe.Sizeof([1]C.fil_GenerateDataCommitmentResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilGenerateDataCommitmentResponse) Ref() *C.fil_GenerateDataCommitmentResponse { + if x == nil { + return nil + } + return x.ref87da7dd9 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilGenerateDataCommitmentResponse) Free() { + if x != nil && x.allocs87da7dd9 != nil { + x.allocs87da7dd9.(*cgoAllocMap).Free() + x.ref87da7dd9 = nil + } +} + +// NewFilGenerateDataCommitmentResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilGenerateDataCommitmentResponseRef(ref unsafe.Pointer) *FilGenerateDataCommitmentResponse { + if ref == nil { + return nil + } + obj := new(FilGenerateDataCommitmentResponse) + obj.ref87da7dd9 = (*C.fil_GenerateDataCommitmentResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilGenerateDataCommitmentResponse) PassRef() (*C.fil_GenerateDataCommitmentResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref87da7dd9 != nil { + return x.ref87da7dd9, nil + } + mem87da7dd9 := allocFilGenerateDataCommitmentResponseMemory(1) + ref87da7dd9 := (*C.fil_GenerateDataCommitmentResponse)(mem87da7dd9) + allocs87da7dd9 := new(cgoAllocMap) + allocs87da7dd9.Add(mem87da7dd9) + + var cstatus_code_allocs *cgoAllocMap + ref87da7dd9.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs87da7dd9.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref87da7dd9.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs87da7dd9.Borrow(cerror_msg_allocs) + + var ccomm_d_allocs *cgoAllocMap + ref87da7dd9.comm_d, ccomm_d_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommD)), cgoAllocsUnknown + allocs87da7dd9.Borrow(ccomm_d_allocs) + + x.ref87da7dd9 = ref87da7dd9 + x.allocs87da7dd9 = allocs87da7dd9 + return ref87da7dd9, allocs87da7dd9 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilGenerateDataCommitmentResponse) PassValue() (C.fil_GenerateDataCommitmentResponse, *cgoAllocMap) { + if x.ref87da7dd9 != nil { + return *x.ref87da7dd9, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilGenerateDataCommitmentResponse) Deref() { + if x.ref87da7dd9 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref87da7dd9.status_code) + x.ErrorMsg = packPCharString(x.ref87da7dd9.error_msg) + x.CommD = *(*[32]byte)(unsafe.Pointer(&x.ref87da7dd9.comm_d)) +} + +// allocFilGeneratePieceCommitmentResponseMemory allocates memory for type C.fil_GeneratePieceCommitmentResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilGeneratePieceCommitmentResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilGeneratePieceCommitmentResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilGeneratePieceCommitmentResponseValue = unsafe.Sizeof([1]C.fil_GeneratePieceCommitmentResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilGeneratePieceCommitmentResponse) Ref() *C.fil_GeneratePieceCommitmentResponse { + if x == nil { + return nil + } + return x.ref4b00fda4 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilGeneratePieceCommitmentResponse) Free() { + if x != nil && x.allocs4b00fda4 != nil { + x.allocs4b00fda4.(*cgoAllocMap).Free() + x.ref4b00fda4 = nil + } +} + +// NewFilGeneratePieceCommitmentResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilGeneratePieceCommitmentResponseRef(ref unsafe.Pointer) *FilGeneratePieceCommitmentResponse { + if ref == nil { + return nil + } + obj := new(FilGeneratePieceCommitmentResponse) + obj.ref4b00fda4 = (*C.fil_GeneratePieceCommitmentResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilGeneratePieceCommitmentResponse) PassRef() (*C.fil_GeneratePieceCommitmentResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref4b00fda4 != nil { + return x.ref4b00fda4, nil + } + mem4b00fda4 := allocFilGeneratePieceCommitmentResponseMemory(1) + ref4b00fda4 := (*C.fil_GeneratePieceCommitmentResponse)(mem4b00fda4) + allocs4b00fda4 := new(cgoAllocMap) + allocs4b00fda4.Add(mem4b00fda4) + + var cstatus_code_allocs *cgoAllocMap + ref4b00fda4.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs4b00fda4.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref4b00fda4.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs4b00fda4.Borrow(cerror_msg_allocs) + + var ccomm_p_allocs *cgoAllocMap + ref4b00fda4.comm_p, ccomm_p_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommP)), cgoAllocsUnknown + allocs4b00fda4.Borrow(ccomm_p_allocs) + + var cnum_bytes_aligned_allocs *cgoAllocMap + ref4b00fda4.num_bytes_aligned, cnum_bytes_aligned_allocs = (C.uint64_t)(x.NumBytesAligned), cgoAllocsUnknown + allocs4b00fda4.Borrow(cnum_bytes_aligned_allocs) + + x.ref4b00fda4 = ref4b00fda4 + x.allocs4b00fda4 = allocs4b00fda4 + return ref4b00fda4, allocs4b00fda4 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilGeneratePieceCommitmentResponse) PassValue() (C.fil_GeneratePieceCommitmentResponse, *cgoAllocMap) { + if x.ref4b00fda4 != nil { + return *x.ref4b00fda4, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilGeneratePieceCommitmentResponse) Deref() { + if x.ref4b00fda4 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref4b00fda4.status_code) + x.ErrorMsg = packPCharString(x.ref4b00fda4.error_msg) + x.CommP = *(*[32]byte)(unsafe.Pointer(&x.ref4b00fda4.comm_p)) + x.NumBytesAligned = (uint64)(x.ref4b00fda4.num_bytes_aligned) +} + +// allocFilPoStProofMemory allocates memory for type C.fil_PoStProof in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilPoStProofMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilPoStProofValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilPoStProofValue = unsafe.Sizeof([1]C.fil_PoStProof{}) + +// unpackPUint8TString represents the data from Go string as *C.uint8_t and avoids copying. +func unpackPUint8TString(str string) (*C.uint8_t, *cgoAllocMap) { + str = safeString(str) + h := (*stringHeader)(unsafe.Pointer(&str)) + return (*C.uint8_t)(h.Data), cgoAllocsUnknown +} + +// packPUint8TString creates a Go string backed by *C.uint8_t and avoids copying. +func packPUint8TString(p *C.uint8_t) (raw string) { + if p != nil && *p != 0 { + h := (*stringHeader)(unsafe.Pointer(&raw)) + h.Data = unsafe.Pointer(p) + for *p != 0 { + p = (*C.uint8_t)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) // p++ + } + h.Len = int(uintptr(unsafe.Pointer(p)) - uintptr(h.Data)) + } + return +} + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilPoStProof) Ref() *C.fil_PoStProof { + if x == nil { + return nil + } + return x.ref3451bfa +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilPoStProof) Free() { + if x != nil && x.allocs3451bfa != nil { + x.allocs3451bfa.(*cgoAllocMap).Free() + x.ref3451bfa = nil + } +} + +// NewFilPoStProofRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilPoStProofRef(ref unsafe.Pointer) *FilPoStProof { + if ref == nil { + return nil + } + obj := new(FilPoStProof) + obj.ref3451bfa = (*C.fil_PoStProof)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilPoStProof) PassRef() (*C.fil_PoStProof, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref3451bfa != nil { + return x.ref3451bfa, nil + } + mem3451bfa := allocFilPoStProofMemory(1) + ref3451bfa := (*C.fil_PoStProof)(mem3451bfa) + allocs3451bfa := new(cgoAllocMap) + allocs3451bfa.Add(mem3451bfa) + + var cregistered_proof_allocs *cgoAllocMap + ref3451bfa.registered_proof, cregistered_proof_allocs = (C.fil_RegisteredPoStProof)(x.RegisteredProof), cgoAllocsUnknown + allocs3451bfa.Borrow(cregistered_proof_allocs) + + var cproof_len_allocs *cgoAllocMap + ref3451bfa.proof_len, cproof_len_allocs = (C.size_t)(x.ProofLen), cgoAllocsUnknown + allocs3451bfa.Borrow(cproof_len_allocs) + + var cproof_ptr_allocs *cgoAllocMap + ref3451bfa.proof_ptr, cproof_ptr_allocs = unpackPUint8TString(x.ProofPtr) + allocs3451bfa.Borrow(cproof_ptr_allocs) + + x.ref3451bfa = ref3451bfa + x.allocs3451bfa = allocs3451bfa + return ref3451bfa, allocs3451bfa + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilPoStProof) PassValue() (C.fil_PoStProof, *cgoAllocMap) { + if x.ref3451bfa != nil { + return *x.ref3451bfa, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilPoStProof) Deref() { + if x.ref3451bfa == nil { + return + } + x.RegisteredProof = (FilRegisteredPoStProof)(x.ref3451bfa.registered_proof) + x.ProofLen = (uint)(x.ref3451bfa.proof_len) + x.ProofPtr = packPUint8TString(x.ref3451bfa.proof_ptr) +} + +// allocFilGenerateWindowPoStResponseMemory allocates memory for type C.fil_GenerateWindowPoStResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilGenerateWindowPoStResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilGenerateWindowPoStResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilGenerateWindowPoStResponseValue = unsafe.Sizeof([1]C.fil_GenerateWindowPoStResponse{}) + +type sliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} + +const sizeOfPtr = unsafe.Sizeof(&struct{}{}) + +// unpackSFilPoStProof transforms a sliced Go data structure into plain C format. +func unpackSFilPoStProof(x []FilPoStProof) (unpacked *C.fil_PoStProof, allocs *cgoAllocMap) { + if x == nil { + return nil, nil + } + allocs = new(cgoAllocMap) + defer runtime.SetFinalizer(allocs, func(a *cgoAllocMap) { + go a.Free() + }) + + len0 := len(x) + mem0 := allocFilPoStProofMemory(len0) + allocs.Add(mem0) + h0 := &sliceHeader{ + Data: mem0, + Cap: len0, + Len: len0, + } + v0 := *(*[]C.fil_PoStProof)(unsafe.Pointer(h0)) + for i0 := range x { + allocs0 := new(cgoAllocMap) + v0[i0], allocs0 = x[i0].PassValue() + allocs.Borrow(allocs0) + } + h := (*sliceHeader)(unsafe.Pointer(&v0)) + unpacked = (*C.fil_PoStProof)(h.Data) + return +} + +// packSFilPoStProof reads sliced Go data structure out from plain C format. +func packSFilPoStProof(v []FilPoStProof, ptr0 *C.fil_PoStProof) { + const m = 0x7fffffff + for i0 := range v { + ptr1 := (*(*[m / sizeOfFilPoStProofValue]C.fil_PoStProof)(unsafe.Pointer(ptr0)))[i0] + v[i0] = *NewFilPoStProofRef(unsafe.Pointer(&ptr1)) + } +} + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilGenerateWindowPoStResponse) Ref() *C.fil_GenerateWindowPoStResponse { + if x == nil { + return nil + } + return x.ref2a5f3ba8 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilGenerateWindowPoStResponse) Free() { + if x != nil && x.allocs2a5f3ba8 != nil { + x.allocs2a5f3ba8.(*cgoAllocMap).Free() + x.ref2a5f3ba8 = nil + } +} + +// NewFilGenerateWindowPoStResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilGenerateWindowPoStResponseRef(ref unsafe.Pointer) *FilGenerateWindowPoStResponse { + if ref == nil { + return nil + } + obj := new(FilGenerateWindowPoStResponse) + obj.ref2a5f3ba8 = (*C.fil_GenerateWindowPoStResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilGenerateWindowPoStResponse) PassRef() (*C.fil_GenerateWindowPoStResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref2a5f3ba8 != nil { + return x.ref2a5f3ba8, nil + } + mem2a5f3ba8 := allocFilGenerateWindowPoStResponseMemory(1) + ref2a5f3ba8 := (*C.fil_GenerateWindowPoStResponse)(mem2a5f3ba8) + allocs2a5f3ba8 := new(cgoAllocMap) + allocs2a5f3ba8.Add(mem2a5f3ba8) + + var cerror_msg_allocs *cgoAllocMap + ref2a5f3ba8.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs2a5f3ba8.Borrow(cerror_msg_allocs) + + var cproofs_len_allocs *cgoAllocMap + ref2a5f3ba8.proofs_len, cproofs_len_allocs = (C.size_t)(x.ProofsLen), cgoAllocsUnknown + allocs2a5f3ba8.Borrow(cproofs_len_allocs) + + var cproofs_ptr_allocs *cgoAllocMap + ref2a5f3ba8.proofs_ptr, cproofs_ptr_allocs = unpackSFilPoStProof(x.ProofsPtr) + allocs2a5f3ba8.Borrow(cproofs_ptr_allocs) + + var cstatus_code_allocs *cgoAllocMap + ref2a5f3ba8.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs2a5f3ba8.Borrow(cstatus_code_allocs) + + x.ref2a5f3ba8 = ref2a5f3ba8 + x.allocs2a5f3ba8 = allocs2a5f3ba8 + return ref2a5f3ba8, allocs2a5f3ba8 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilGenerateWindowPoStResponse) PassValue() (C.fil_GenerateWindowPoStResponse, *cgoAllocMap) { + if x.ref2a5f3ba8 != nil { + return *x.ref2a5f3ba8, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilGenerateWindowPoStResponse) Deref() { + if x.ref2a5f3ba8 == nil { + return + } + x.ErrorMsg = packPCharString(x.ref2a5f3ba8.error_msg) + x.ProofsLen = (uint)(x.ref2a5f3ba8.proofs_len) + packSFilPoStProof(x.ProofsPtr, x.ref2a5f3ba8.proofs_ptr) + x.StatusCode = (FCPResponseStatus)(x.ref2a5f3ba8.status_code) +} + +// allocFilGenerateWinningPoStResponseMemory allocates memory for type C.fil_GenerateWinningPoStResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilGenerateWinningPoStResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilGenerateWinningPoStResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilGenerateWinningPoStResponseValue = unsafe.Sizeof([1]C.fil_GenerateWinningPoStResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilGenerateWinningPoStResponse) Ref() *C.fil_GenerateWinningPoStResponse { + if x == nil { + return nil + } + return x.ref1405b8ec +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilGenerateWinningPoStResponse) Free() { + if x != nil && x.allocs1405b8ec != nil { + x.allocs1405b8ec.(*cgoAllocMap).Free() + x.ref1405b8ec = nil + } +} + +// NewFilGenerateWinningPoStResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilGenerateWinningPoStResponseRef(ref unsafe.Pointer) *FilGenerateWinningPoStResponse { + if ref == nil { + return nil + } + obj := new(FilGenerateWinningPoStResponse) + obj.ref1405b8ec = (*C.fil_GenerateWinningPoStResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilGenerateWinningPoStResponse) PassRef() (*C.fil_GenerateWinningPoStResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref1405b8ec != nil { + return x.ref1405b8ec, nil + } + mem1405b8ec := allocFilGenerateWinningPoStResponseMemory(1) + ref1405b8ec := (*C.fil_GenerateWinningPoStResponse)(mem1405b8ec) + allocs1405b8ec := new(cgoAllocMap) + allocs1405b8ec.Add(mem1405b8ec) + + var cerror_msg_allocs *cgoAllocMap + ref1405b8ec.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs1405b8ec.Borrow(cerror_msg_allocs) + + var cproofs_len_allocs *cgoAllocMap + ref1405b8ec.proofs_len, cproofs_len_allocs = (C.size_t)(x.ProofsLen), cgoAllocsUnknown + allocs1405b8ec.Borrow(cproofs_len_allocs) + + var cproofs_ptr_allocs *cgoAllocMap + ref1405b8ec.proofs_ptr, cproofs_ptr_allocs = unpackSFilPoStProof(x.ProofsPtr) + allocs1405b8ec.Borrow(cproofs_ptr_allocs) + + var cstatus_code_allocs *cgoAllocMap + ref1405b8ec.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs1405b8ec.Borrow(cstatus_code_allocs) + + x.ref1405b8ec = ref1405b8ec + x.allocs1405b8ec = allocs1405b8ec + return ref1405b8ec, allocs1405b8ec + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilGenerateWinningPoStResponse) PassValue() (C.fil_GenerateWinningPoStResponse, *cgoAllocMap) { + if x.ref1405b8ec != nil { + return *x.ref1405b8ec, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilGenerateWinningPoStResponse) Deref() { + if x.ref1405b8ec == nil { + return + } + x.ErrorMsg = packPCharString(x.ref1405b8ec.error_msg) + x.ProofsLen = (uint)(x.ref1405b8ec.proofs_len) + packSFilPoStProof(x.ProofsPtr, x.ref1405b8ec.proofs_ptr) + x.StatusCode = (FCPResponseStatus)(x.ref1405b8ec.status_code) +} + +// allocFilGenerateWinningPoStSectorChallengeMemory allocates memory for type C.fil_GenerateWinningPoStSectorChallenge in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilGenerateWinningPoStSectorChallengeMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilGenerateWinningPoStSectorChallengeValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilGenerateWinningPoStSectorChallengeValue = unsafe.Sizeof([1]C.fil_GenerateWinningPoStSectorChallenge{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilGenerateWinningPoStSectorChallenge) Ref() *C.fil_GenerateWinningPoStSectorChallenge { + if x == nil { + return nil + } + return x.ref69d2a405 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilGenerateWinningPoStSectorChallenge) Free() { + if x != nil && x.allocs69d2a405 != nil { + x.allocs69d2a405.(*cgoAllocMap).Free() + x.ref69d2a405 = nil + } +} + +// NewFilGenerateWinningPoStSectorChallengeRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilGenerateWinningPoStSectorChallengeRef(ref unsafe.Pointer) *FilGenerateWinningPoStSectorChallenge { + if ref == nil { + return nil + } + obj := new(FilGenerateWinningPoStSectorChallenge) + obj.ref69d2a405 = (*C.fil_GenerateWinningPoStSectorChallenge)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilGenerateWinningPoStSectorChallenge) PassRef() (*C.fil_GenerateWinningPoStSectorChallenge, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref69d2a405 != nil { + return x.ref69d2a405, nil + } + mem69d2a405 := allocFilGenerateWinningPoStSectorChallengeMemory(1) + ref69d2a405 := (*C.fil_GenerateWinningPoStSectorChallenge)(mem69d2a405) + allocs69d2a405 := new(cgoAllocMap) + allocs69d2a405.Add(mem69d2a405) + + var cerror_msg_allocs *cgoAllocMap + ref69d2a405.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs69d2a405.Borrow(cerror_msg_allocs) + + var cstatus_code_allocs *cgoAllocMap + ref69d2a405.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs69d2a405.Borrow(cstatus_code_allocs) + + var cids_ptr_allocs *cgoAllocMap + ref69d2a405.ids_ptr, cids_ptr_allocs = (*C.uint64_t)(unsafe.Pointer((*sliceHeader)(unsafe.Pointer(&x.IdsPtr)).Data)), cgoAllocsUnknown + allocs69d2a405.Borrow(cids_ptr_allocs) + + var cids_len_allocs *cgoAllocMap + ref69d2a405.ids_len, cids_len_allocs = (C.size_t)(x.IdsLen), cgoAllocsUnknown + allocs69d2a405.Borrow(cids_len_allocs) + + x.ref69d2a405 = ref69d2a405 + x.allocs69d2a405 = allocs69d2a405 + return ref69d2a405, allocs69d2a405 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilGenerateWinningPoStSectorChallenge) PassValue() (C.fil_GenerateWinningPoStSectorChallenge, *cgoAllocMap) { + if x.ref69d2a405 != nil { + return *x.ref69d2a405, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilGenerateWinningPoStSectorChallenge) Deref() { + if x.ref69d2a405 == nil { + return + } + x.ErrorMsg = packPCharString(x.ref69d2a405.error_msg) + x.StatusCode = (FCPResponseStatus)(x.ref69d2a405.status_code) + hxfc4425b := (*sliceHeader)(unsafe.Pointer(&x.IdsPtr)) + hxfc4425b.Data = unsafe.Pointer(x.ref69d2a405.ids_ptr) + hxfc4425b.Cap = 0x7fffffff + // hxfc4425b.Len = ? + + x.IdsLen = (uint)(x.ref69d2a405.ids_len) +} + +// allocFilGpuDeviceResponseMemory allocates memory for type C.fil_GpuDeviceResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilGpuDeviceResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilGpuDeviceResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilGpuDeviceResponseValue = unsafe.Sizeof([1]C.fil_GpuDeviceResponse{}) + +// allocPCharMemory allocates memory for type *C.char in C. +// The caller is responsible for freeing the this memory via C.free. +func allocPCharMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfPCharValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfPCharValue = unsafe.Sizeof([1]*C.char{}) + +// unpackSString transforms a sliced Go data structure into plain C format. +func unpackSString(x []string) (unpacked **C.char, allocs *cgoAllocMap) { + if x == nil { + return nil, nil + } + allocs = new(cgoAllocMap) + defer runtime.SetFinalizer(allocs, func(a *cgoAllocMap) { + go a.Free() + }) + + len0 := len(x) + mem0 := allocPCharMemory(len0) + allocs.Add(mem0) + h0 := &sliceHeader{ + Data: mem0, + Cap: len0, + Len: len0, + } + v0 := *(*[]*C.char)(unsafe.Pointer(h0)) + for i0 := range x { + v0[i0], _ = unpackPCharString(x[i0]) + } + h := (*sliceHeader)(unsafe.Pointer(&v0)) + unpacked = (**C.char)(h.Data) + return +} + +// packSString reads sliced Go data structure out from plain C format. +func packSString(v []string, ptr0 **C.char) { + const m = 0x7fffffff + for i0 := range v { + ptr1 := (*(*[m / sizeOfPtr]*C.char)(unsafe.Pointer(ptr0)))[i0] + v[i0] = packPCharString(ptr1) + } +} + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilGpuDeviceResponse) Ref() *C.fil_GpuDeviceResponse { + if x == nil { + return nil + } + return x.ref58f92915 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilGpuDeviceResponse) Free() { + if x != nil && x.allocs58f92915 != nil { + x.allocs58f92915.(*cgoAllocMap).Free() + x.ref58f92915 = nil + } +} + +// NewFilGpuDeviceResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilGpuDeviceResponseRef(ref unsafe.Pointer) *FilGpuDeviceResponse { + if ref == nil { + return nil + } + obj := new(FilGpuDeviceResponse) + obj.ref58f92915 = (*C.fil_GpuDeviceResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilGpuDeviceResponse) PassRef() (*C.fil_GpuDeviceResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref58f92915 != nil { + return x.ref58f92915, nil + } + mem58f92915 := allocFilGpuDeviceResponseMemory(1) + ref58f92915 := (*C.fil_GpuDeviceResponse)(mem58f92915) + allocs58f92915 := new(cgoAllocMap) + allocs58f92915.Add(mem58f92915) + + var cstatus_code_allocs *cgoAllocMap + ref58f92915.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs58f92915.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref58f92915.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs58f92915.Borrow(cerror_msg_allocs) + + var cdevices_len_allocs *cgoAllocMap + ref58f92915.devices_len, cdevices_len_allocs = (C.size_t)(x.DevicesLen), cgoAllocsUnknown + allocs58f92915.Borrow(cdevices_len_allocs) + + var cdevices_ptr_allocs *cgoAllocMap + ref58f92915.devices_ptr, cdevices_ptr_allocs = unpackSString(x.DevicesPtr) + allocs58f92915.Borrow(cdevices_ptr_allocs) + + x.ref58f92915 = ref58f92915 + x.allocs58f92915 = allocs58f92915 + return ref58f92915, allocs58f92915 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilGpuDeviceResponse) PassValue() (C.fil_GpuDeviceResponse, *cgoAllocMap) { + if x.ref58f92915 != nil { + return *x.ref58f92915, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilGpuDeviceResponse) Deref() { + if x.ref58f92915 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref58f92915.status_code) + x.ErrorMsg = packPCharString(x.ref58f92915.error_msg) + x.DevicesLen = (uint)(x.ref58f92915.devices_len) + packSString(x.DevicesPtr, x.ref58f92915.devices_ptr) +} + +// allocFilBLSDigestMemory allocates memory for type C.fil_BLSDigest in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilBLSDigestMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilBLSDigestValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilBLSDigestValue = unsafe.Sizeof([1]C.fil_BLSDigest{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilBLSDigest) Ref() *C.fil_BLSDigest { + if x == nil { + return nil + } + return x.ref215fc78c +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilBLSDigest) Free() { + if x != nil && x.allocs215fc78c != nil { + x.allocs215fc78c.(*cgoAllocMap).Free() + x.ref215fc78c = nil + } +} + +// NewFilBLSDigestRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilBLSDigestRef(ref unsafe.Pointer) *FilBLSDigest { + if ref == nil { + return nil + } + obj := new(FilBLSDigest) + obj.ref215fc78c = (*C.fil_BLSDigest)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilBLSDigest) PassRef() (*C.fil_BLSDigest, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref215fc78c != nil { + return x.ref215fc78c, nil + } + mem215fc78c := allocFilBLSDigestMemory(1) + ref215fc78c := (*C.fil_BLSDigest)(mem215fc78c) + allocs215fc78c := new(cgoAllocMap) + allocs215fc78c.Add(mem215fc78c) + + var cinner_allocs *cgoAllocMap + ref215fc78c.inner, cinner_allocs = *(*[96]C.uint8_t)(unsafe.Pointer(&x.Inner)), cgoAllocsUnknown + allocs215fc78c.Borrow(cinner_allocs) + + x.ref215fc78c = ref215fc78c + x.allocs215fc78c = allocs215fc78c + return ref215fc78c, allocs215fc78c + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilBLSDigest) PassValue() (C.fil_BLSDigest, *cgoAllocMap) { + if x.ref215fc78c != nil { + return *x.ref215fc78c, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilBLSDigest) Deref() { + if x.ref215fc78c == nil { + return + } + x.Inner = *(*[96]byte)(unsafe.Pointer(&x.ref215fc78c.inner)) +} + +// allocFilHashResponseMemory allocates memory for type C.fil_HashResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilHashResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilHashResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilHashResponseValue = unsafe.Sizeof([1]C.fil_HashResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilHashResponse) Ref() *C.fil_HashResponse { + if x == nil { + return nil + } + return x.refc52a22ef +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilHashResponse) Free() { + if x != nil && x.allocsc52a22ef != nil { + x.allocsc52a22ef.(*cgoAllocMap).Free() + x.refc52a22ef = nil + } +} + +// NewFilHashResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilHashResponseRef(ref unsafe.Pointer) *FilHashResponse { + if ref == nil { + return nil + } + obj := new(FilHashResponse) + obj.refc52a22ef = (*C.fil_HashResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilHashResponse) PassRef() (*C.fil_HashResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refc52a22ef != nil { + return x.refc52a22ef, nil + } + memc52a22ef := allocFilHashResponseMemory(1) + refc52a22ef := (*C.fil_HashResponse)(memc52a22ef) + allocsc52a22ef := new(cgoAllocMap) + allocsc52a22ef.Add(memc52a22ef) + + var cdigest_allocs *cgoAllocMap + refc52a22ef.digest, cdigest_allocs = x.Digest.PassValue() + allocsc52a22ef.Borrow(cdigest_allocs) + + x.refc52a22ef = refc52a22ef + x.allocsc52a22ef = allocsc52a22ef + return refc52a22ef, allocsc52a22ef + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilHashResponse) PassValue() (C.fil_HashResponse, *cgoAllocMap) { + if x.refc52a22ef != nil { + return *x.refc52a22ef, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilHashResponse) Deref() { + if x.refc52a22ef == nil { + return + } + x.Digest = *NewFilBLSDigestRef(unsafe.Pointer(&x.refc52a22ef.digest)) +} + +// allocFilInitLogFdResponseMemory allocates memory for type C.fil_InitLogFdResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilInitLogFdResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilInitLogFdResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilInitLogFdResponseValue = unsafe.Sizeof([1]C.fil_InitLogFdResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilInitLogFdResponse) Ref() *C.fil_InitLogFdResponse { + if x == nil { + return nil + } + return x.ref3c1a0a08 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilInitLogFdResponse) Free() { + if x != nil && x.allocs3c1a0a08 != nil { + x.allocs3c1a0a08.(*cgoAllocMap).Free() + x.ref3c1a0a08 = nil + } +} + +// NewFilInitLogFdResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilInitLogFdResponseRef(ref unsafe.Pointer) *FilInitLogFdResponse { + if ref == nil { + return nil + } + obj := new(FilInitLogFdResponse) + obj.ref3c1a0a08 = (*C.fil_InitLogFdResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilInitLogFdResponse) PassRef() (*C.fil_InitLogFdResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref3c1a0a08 != nil { + return x.ref3c1a0a08, nil + } + mem3c1a0a08 := allocFilInitLogFdResponseMemory(1) + ref3c1a0a08 := (*C.fil_InitLogFdResponse)(mem3c1a0a08) + allocs3c1a0a08 := new(cgoAllocMap) + allocs3c1a0a08.Add(mem3c1a0a08) + + var cstatus_code_allocs *cgoAllocMap + ref3c1a0a08.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs3c1a0a08.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref3c1a0a08.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs3c1a0a08.Borrow(cerror_msg_allocs) + + x.ref3c1a0a08 = ref3c1a0a08 + x.allocs3c1a0a08 = allocs3c1a0a08 + return ref3c1a0a08, allocs3c1a0a08 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilInitLogFdResponse) PassValue() (C.fil_InitLogFdResponse, *cgoAllocMap) { + if x.ref3c1a0a08 != nil { + return *x.ref3c1a0a08, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilInitLogFdResponse) Deref() { + if x.ref3c1a0a08 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref3c1a0a08.status_code) + x.ErrorMsg = packPCharString(x.ref3c1a0a08.error_msg) +} + +// allocFilBLSPrivateKeyMemory allocates memory for type C.fil_BLSPrivateKey in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilBLSPrivateKeyMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilBLSPrivateKeyValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilBLSPrivateKeyValue = unsafe.Sizeof([1]C.fil_BLSPrivateKey{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilBLSPrivateKey) Ref() *C.fil_BLSPrivateKey { + if x == nil { + return nil + } + return x.ref2f77fe3a +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilBLSPrivateKey) Free() { + if x != nil && x.allocs2f77fe3a != nil { + x.allocs2f77fe3a.(*cgoAllocMap).Free() + x.ref2f77fe3a = nil + } +} + +// NewFilBLSPrivateKeyRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilBLSPrivateKeyRef(ref unsafe.Pointer) *FilBLSPrivateKey { + if ref == nil { + return nil + } + obj := new(FilBLSPrivateKey) + obj.ref2f77fe3a = (*C.fil_BLSPrivateKey)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilBLSPrivateKey) PassRef() (*C.fil_BLSPrivateKey, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref2f77fe3a != nil { + return x.ref2f77fe3a, nil + } + mem2f77fe3a := allocFilBLSPrivateKeyMemory(1) + ref2f77fe3a := (*C.fil_BLSPrivateKey)(mem2f77fe3a) + allocs2f77fe3a := new(cgoAllocMap) + allocs2f77fe3a.Add(mem2f77fe3a) + + var cinner_allocs *cgoAllocMap + ref2f77fe3a.inner, cinner_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.Inner)), cgoAllocsUnknown + allocs2f77fe3a.Borrow(cinner_allocs) + + x.ref2f77fe3a = ref2f77fe3a + x.allocs2f77fe3a = allocs2f77fe3a + return ref2f77fe3a, allocs2f77fe3a + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilBLSPrivateKey) PassValue() (C.fil_BLSPrivateKey, *cgoAllocMap) { + if x.ref2f77fe3a != nil { + return *x.ref2f77fe3a, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilBLSPrivateKey) Deref() { + if x.ref2f77fe3a == nil { + return + } + x.Inner = *(*[32]byte)(unsafe.Pointer(&x.ref2f77fe3a.inner)) +} + +// allocFilPrivateKeyGenerateResponseMemory allocates memory for type C.fil_PrivateKeyGenerateResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilPrivateKeyGenerateResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilPrivateKeyGenerateResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilPrivateKeyGenerateResponseValue = unsafe.Sizeof([1]C.fil_PrivateKeyGenerateResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilPrivateKeyGenerateResponse) Ref() *C.fil_PrivateKeyGenerateResponse { + if x == nil { + return nil + } + return x.ref2dba09f +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilPrivateKeyGenerateResponse) Free() { + if x != nil && x.allocs2dba09f != nil { + x.allocs2dba09f.(*cgoAllocMap).Free() + x.ref2dba09f = nil + } +} + +// NewFilPrivateKeyGenerateResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilPrivateKeyGenerateResponseRef(ref unsafe.Pointer) *FilPrivateKeyGenerateResponse { + if ref == nil { + return nil + } + obj := new(FilPrivateKeyGenerateResponse) + obj.ref2dba09f = (*C.fil_PrivateKeyGenerateResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilPrivateKeyGenerateResponse) PassRef() (*C.fil_PrivateKeyGenerateResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref2dba09f != nil { + return x.ref2dba09f, nil + } + mem2dba09f := allocFilPrivateKeyGenerateResponseMemory(1) + ref2dba09f := (*C.fil_PrivateKeyGenerateResponse)(mem2dba09f) + allocs2dba09f := new(cgoAllocMap) + allocs2dba09f.Add(mem2dba09f) + + var cprivate_key_allocs *cgoAllocMap + ref2dba09f.private_key, cprivate_key_allocs = x.PrivateKey.PassValue() + allocs2dba09f.Borrow(cprivate_key_allocs) + + x.ref2dba09f = ref2dba09f + x.allocs2dba09f = allocs2dba09f + return ref2dba09f, allocs2dba09f + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilPrivateKeyGenerateResponse) PassValue() (C.fil_PrivateKeyGenerateResponse, *cgoAllocMap) { + if x.ref2dba09f != nil { + return *x.ref2dba09f, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilPrivateKeyGenerateResponse) Deref() { + if x.ref2dba09f == nil { + return + } + x.PrivateKey = *NewFilBLSPrivateKeyRef(unsafe.Pointer(&x.ref2dba09f.private_key)) +} + +// allocFilBLSPublicKeyMemory allocates memory for type C.fil_BLSPublicKey in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilBLSPublicKeyMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilBLSPublicKeyValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilBLSPublicKeyValue = unsafe.Sizeof([1]C.fil_BLSPublicKey{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilBLSPublicKey) Ref() *C.fil_BLSPublicKey { + if x == nil { + return nil + } + return x.ref6d0cab13 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilBLSPublicKey) Free() { + if x != nil && x.allocs6d0cab13 != nil { + x.allocs6d0cab13.(*cgoAllocMap).Free() + x.ref6d0cab13 = nil + } +} + +// NewFilBLSPublicKeyRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilBLSPublicKeyRef(ref unsafe.Pointer) *FilBLSPublicKey { + if ref == nil { + return nil + } + obj := new(FilBLSPublicKey) + obj.ref6d0cab13 = (*C.fil_BLSPublicKey)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilBLSPublicKey) PassRef() (*C.fil_BLSPublicKey, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref6d0cab13 != nil { + return x.ref6d0cab13, nil + } + mem6d0cab13 := allocFilBLSPublicKeyMemory(1) + ref6d0cab13 := (*C.fil_BLSPublicKey)(mem6d0cab13) + allocs6d0cab13 := new(cgoAllocMap) + allocs6d0cab13.Add(mem6d0cab13) + + var cinner_allocs *cgoAllocMap + ref6d0cab13.inner, cinner_allocs = *(*[48]C.uint8_t)(unsafe.Pointer(&x.Inner)), cgoAllocsUnknown + allocs6d0cab13.Borrow(cinner_allocs) + + x.ref6d0cab13 = ref6d0cab13 + x.allocs6d0cab13 = allocs6d0cab13 + return ref6d0cab13, allocs6d0cab13 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilBLSPublicKey) PassValue() (C.fil_BLSPublicKey, *cgoAllocMap) { + if x.ref6d0cab13 != nil { + return *x.ref6d0cab13, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilBLSPublicKey) Deref() { + if x.ref6d0cab13 == nil { + return + } + x.Inner = *(*[48]byte)(unsafe.Pointer(&x.ref6d0cab13.inner)) +} + +// allocFilPrivateKeyPublicKeyResponseMemory allocates memory for type C.fil_PrivateKeyPublicKeyResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilPrivateKeyPublicKeyResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilPrivateKeyPublicKeyResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilPrivateKeyPublicKeyResponseValue = unsafe.Sizeof([1]C.fil_PrivateKeyPublicKeyResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilPrivateKeyPublicKeyResponse) Ref() *C.fil_PrivateKeyPublicKeyResponse { + if x == nil { + return nil + } + return x.refee14e59d +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilPrivateKeyPublicKeyResponse) Free() { + if x != nil && x.allocsee14e59d != nil { + x.allocsee14e59d.(*cgoAllocMap).Free() + x.refee14e59d = nil + } +} + +// NewFilPrivateKeyPublicKeyResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilPrivateKeyPublicKeyResponseRef(ref unsafe.Pointer) *FilPrivateKeyPublicKeyResponse { + if ref == nil { + return nil + } + obj := new(FilPrivateKeyPublicKeyResponse) + obj.refee14e59d = (*C.fil_PrivateKeyPublicKeyResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilPrivateKeyPublicKeyResponse) PassRef() (*C.fil_PrivateKeyPublicKeyResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refee14e59d != nil { + return x.refee14e59d, nil + } + memee14e59d := allocFilPrivateKeyPublicKeyResponseMemory(1) + refee14e59d := (*C.fil_PrivateKeyPublicKeyResponse)(memee14e59d) + allocsee14e59d := new(cgoAllocMap) + allocsee14e59d.Add(memee14e59d) + + var cpublic_key_allocs *cgoAllocMap + refee14e59d.public_key, cpublic_key_allocs = x.PublicKey.PassValue() + allocsee14e59d.Borrow(cpublic_key_allocs) + + x.refee14e59d = refee14e59d + x.allocsee14e59d = allocsee14e59d + return refee14e59d, allocsee14e59d + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilPrivateKeyPublicKeyResponse) PassValue() (C.fil_PrivateKeyPublicKeyResponse, *cgoAllocMap) { + if x.refee14e59d != nil { + return *x.refee14e59d, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilPrivateKeyPublicKeyResponse) Deref() { + if x.refee14e59d == nil { + return + } + x.PublicKey = *NewFilBLSPublicKeyRef(unsafe.Pointer(&x.refee14e59d.public_key)) +} + +// allocFilPrivateKeySignResponseMemory allocates memory for type C.fil_PrivateKeySignResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilPrivateKeySignResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilPrivateKeySignResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilPrivateKeySignResponseValue = unsafe.Sizeof([1]C.fil_PrivateKeySignResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilPrivateKeySignResponse) Ref() *C.fil_PrivateKeySignResponse { + if x == nil { + return nil + } + return x.refcdf97b28 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilPrivateKeySignResponse) Free() { + if x != nil && x.allocscdf97b28 != nil { + x.allocscdf97b28.(*cgoAllocMap).Free() + x.refcdf97b28 = nil + } +} + +// NewFilPrivateKeySignResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilPrivateKeySignResponseRef(ref unsafe.Pointer) *FilPrivateKeySignResponse { + if ref == nil { + return nil + } + obj := new(FilPrivateKeySignResponse) + obj.refcdf97b28 = (*C.fil_PrivateKeySignResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilPrivateKeySignResponse) PassRef() (*C.fil_PrivateKeySignResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refcdf97b28 != nil { + return x.refcdf97b28, nil + } + memcdf97b28 := allocFilPrivateKeySignResponseMemory(1) + refcdf97b28 := (*C.fil_PrivateKeySignResponse)(memcdf97b28) + allocscdf97b28 := new(cgoAllocMap) + allocscdf97b28.Add(memcdf97b28) + + var csignature_allocs *cgoAllocMap + refcdf97b28.signature, csignature_allocs = x.Signature.PassValue() + allocscdf97b28.Borrow(csignature_allocs) + + x.refcdf97b28 = refcdf97b28 + x.allocscdf97b28 = allocscdf97b28 + return refcdf97b28, allocscdf97b28 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilPrivateKeySignResponse) PassValue() (C.fil_PrivateKeySignResponse, *cgoAllocMap) { + if x.refcdf97b28 != nil { + return *x.refcdf97b28, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilPrivateKeySignResponse) Deref() { + if x.refcdf97b28 == nil { + return + } + x.Signature = *NewFilBLSSignatureRef(unsafe.Pointer(&x.refcdf97b28.signature)) +} + +// allocFilSealCommitPhase1ResponseMemory allocates memory for type C.fil_SealCommitPhase1Response in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilSealCommitPhase1ResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilSealCommitPhase1ResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilSealCommitPhase1ResponseValue = unsafe.Sizeof([1]C.fil_SealCommitPhase1Response{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilSealCommitPhase1Response) Ref() *C.fil_SealCommitPhase1Response { + if x == nil { + return nil + } + return x.ref61ed8561 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilSealCommitPhase1Response) Free() { + if x != nil && x.allocs61ed8561 != nil { + x.allocs61ed8561.(*cgoAllocMap).Free() + x.ref61ed8561 = nil + } +} + +// NewFilSealCommitPhase1ResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilSealCommitPhase1ResponseRef(ref unsafe.Pointer) *FilSealCommitPhase1Response { + if ref == nil { + return nil + } + obj := new(FilSealCommitPhase1Response) + obj.ref61ed8561 = (*C.fil_SealCommitPhase1Response)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilSealCommitPhase1Response) PassRef() (*C.fil_SealCommitPhase1Response, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref61ed8561 != nil { + return x.ref61ed8561, nil + } + mem61ed8561 := allocFilSealCommitPhase1ResponseMemory(1) + ref61ed8561 := (*C.fil_SealCommitPhase1Response)(mem61ed8561) + allocs61ed8561 := new(cgoAllocMap) + allocs61ed8561.Add(mem61ed8561) + + var cstatus_code_allocs *cgoAllocMap + ref61ed8561.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs61ed8561.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref61ed8561.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs61ed8561.Borrow(cerror_msg_allocs) + + var cseal_commit_phase1_output_ptr_allocs *cgoAllocMap + ref61ed8561.seal_commit_phase1_output_ptr, cseal_commit_phase1_output_ptr_allocs = unpackPUint8TString(x.SealCommitPhase1OutputPtr) + allocs61ed8561.Borrow(cseal_commit_phase1_output_ptr_allocs) + + var cseal_commit_phase1_output_len_allocs *cgoAllocMap + ref61ed8561.seal_commit_phase1_output_len, cseal_commit_phase1_output_len_allocs = (C.size_t)(x.SealCommitPhase1OutputLen), cgoAllocsUnknown + allocs61ed8561.Borrow(cseal_commit_phase1_output_len_allocs) + + x.ref61ed8561 = ref61ed8561 + x.allocs61ed8561 = allocs61ed8561 + return ref61ed8561, allocs61ed8561 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilSealCommitPhase1Response) PassValue() (C.fil_SealCommitPhase1Response, *cgoAllocMap) { + if x.ref61ed8561 != nil { + return *x.ref61ed8561, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilSealCommitPhase1Response) Deref() { + if x.ref61ed8561 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref61ed8561.status_code) + x.ErrorMsg = packPCharString(x.ref61ed8561.error_msg) + x.SealCommitPhase1OutputPtr = packPUint8TString(x.ref61ed8561.seal_commit_phase1_output_ptr) + x.SealCommitPhase1OutputLen = (uint)(x.ref61ed8561.seal_commit_phase1_output_len) +} + +// allocFilSealCommitPhase2ResponseMemory allocates memory for type C.fil_SealCommitPhase2Response in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilSealCommitPhase2ResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilSealCommitPhase2ResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilSealCommitPhase2ResponseValue = unsafe.Sizeof([1]C.fil_SealCommitPhase2Response{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilSealCommitPhase2Response) Ref() *C.fil_SealCommitPhase2Response { + if x == nil { + return nil + } + return x.ref5860b9a4 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilSealCommitPhase2Response) Free() { + if x != nil && x.allocs5860b9a4 != nil { + x.allocs5860b9a4.(*cgoAllocMap).Free() + x.ref5860b9a4 = nil + } +} + +// NewFilSealCommitPhase2ResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilSealCommitPhase2ResponseRef(ref unsafe.Pointer) *FilSealCommitPhase2Response { + if ref == nil { + return nil + } + obj := new(FilSealCommitPhase2Response) + obj.ref5860b9a4 = (*C.fil_SealCommitPhase2Response)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilSealCommitPhase2Response) PassRef() (*C.fil_SealCommitPhase2Response, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref5860b9a4 != nil { + return x.ref5860b9a4, nil + } + mem5860b9a4 := allocFilSealCommitPhase2ResponseMemory(1) + ref5860b9a4 := (*C.fil_SealCommitPhase2Response)(mem5860b9a4) + allocs5860b9a4 := new(cgoAllocMap) + allocs5860b9a4.Add(mem5860b9a4) + + var cstatus_code_allocs *cgoAllocMap + ref5860b9a4.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs5860b9a4.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref5860b9a4.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs5860b9a4.Borrow(cerror_msg_allocs) + + var cproof_ptr_allocs *cgoAllocMap + ref5860b9a4.proof_ptr, cproof_ptr_allocs = unpackPUint8TString(x.ProofPtr) + allocs5860b9a4.Borrow(cproof_ptr_allocs) + + var cproof_len_allocs *cgoAllocMap + ref5860b9a4.proof_len, cproof_len_allocs = (C.size_t)(x.ProofLen), cgoAllocsUnknown + allocs5860b9a4.Borrow(cproof_len_allocs) + + x.ref5860b9a4 = ref5860b9a4 + x.allocs5860b9a4 = allocs5860b9a4 + return ref5860b9a4, allocs5860b9a4 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilSealCommitPhase2Response) PassValue() (C.fil_SealCommitPhase2Response, *cgoAllocMap) { + if x.ref5860b9a4 != nil { + return *x.ref5860b9a4, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilSealCommitPhase2Response) Deref() { + if x.ref5860b9a4 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref5860b9a4.status_code) + x.ErrorMsg = packPCharString(x.ref5860b9a4.error_msg) + x.ProofPtr = packPUint8TString(x.ref5860b9a4.proof_ptr) + x.ProofLen = (uint)(x.ref5860b9a4.proof_len) +} + +// allocFilSealPreCommitPhase1ResponseMemory allocates memory for type C.fil_SealPreCommitPhase1Response in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilSealPreCommitPhase1ResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilSealPreCommitPhase1ResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilSealPreCommitPhase1ResponseValue = unsafe.Sizeof([1]C.fil_SealPreCommitPhase1Response{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilSealPreCommitPhase1Response) Ref() *C.fil_SealPreCommitPhase1Response { + if x == nil { + return nil + } + return x.ref132bbfd8 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilSealPreCommitPhase1Response) Free() { + if x != nil && x.allocs132bbfd8 != nil { + x.allocs132bbfd8.(*cgoAllocMap).Free() + x.ref132bbfd8 = nil + } +} + +// NewFilSealPreCommitPhase1ResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilSealPreCommitPhase1ResponseRef(ref unsafe.Pointer) *FilSealPreCommitPhase1Response { + if ref == nil { + return nil + } + obj := new(FilSealPreCommitPhase1Response) + obj.ref132bbfd8 = (*C.fil_SealPreCommitPhase1Response)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilSealPreCommitPhase1Response) PassRef() (*C.fil_SealPreCommitPhase1Response, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref132bbfd8 != nil { + return x.ref132bbfd8, nil + } + mem132bbfd8 := allocFilSealPreCommitPhase1ResponseMemory(1) + ref132bbfd8 := (*C.fil_SealPreCommitPhase1Response)(mem132bbfd8) + allocs132bbfd8 := new(cgoAllocMap) + allocs132bbfd8.Add(mem132bbfd8) + + var cerror_msg_allocs *cgoAllocMap + ref132bbfd8.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs132bbfd8.Borrow(cerror_msg_allocs) + + var cstatus_code_allocs *cgoAllocMap + ref132bbfd8.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs132bbfd8.Borrow(cstatus_code_allocs) + + var cseal_pre_commit_phase1_output_ptr_allocs *cgoAllocMap + ref132bbfd8.seal_pre_commit_phase1_output_ptr, cseal_pre_commit_phase1_output_ptr_allocs = unpackPUint8TString(x.SealPreCommitPhase1OutputPtr) + allocs132bbfd8.Borrow(cseal_pre_commit_phase1_output_ptr_allocs) + + var cseal_pre_commit_phase1_output_len_allocs *cgoAllocMap + ref132bbfd8.seal_pre_commit_phase1_output_len, cseal_pre_commit_phase1_output_len_allocs = (C.size_t)(x.SealPreCommitPhase1OutputLen), cgoAllocsUnknown + allocs132bbfd8.Borrow(cseal_pre_commit_phase1_output_len_allocs) + + x.ref132bbfd8 = ref132bbfd8 + x.allocs132bbfd8 = allocs132bbfd8 + return ref132bbfd8, allocs132bbfd8 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilSealPreCommitPhase1Response) PassValue() (C.fil_SealPreCommitPhase1Response, *cgoAllocMap) { + if x.ref132bbfd8 != nil { + return *x.ref132bbfd8, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilSealPreCommitPhase1Response) Deref() { + if x.ref132bbfd8 == nil { + return + } + x.ErrorMsg = packPCharString(x.ref132bbfd8.error_msg) + x.StatusCode = (FCPResponseStatus)(x.ref132bbfd8.status_code) + x.SealPreCommitPhase1OutputPtr = packPUint8TString(x.ref132bbfd8.seal_pre_commit_phase1_output_ptr) + x.SealPreCommitPhase1OutputLen = (uint)(x.ref132bbfd8.seal_pre_commit_phase1_output_len) +} + +// allocFilSealPreCommitPhase2ResponseMemory allocates memory for type C.fil_SealPreCommitPhase2Response in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilSealPreCommitPhase2ResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilSealPreCommitPhase2ResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilSealPreCommitPhase2ResponseValue = unsafe.Sizeof([1]C.fil_SealPreCommitPhase2Response{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilSealPreCommitPhase2Response) Ref() *C.fil_SealPreCommitPhase2Response { + if x == nil { + return nil + } + return x.ref2aa6831d +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilSealPreCommitPhase2Response) Free() { + if x != nil && x.allocs2aa6831d != nil { + x.allocs2aa6831d.(*cgoAllocMap).Free() + x.ref2aa6831d = nil + } +} + +// NewFilSealPreCommitPhase2ResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilSealPreCommitPhase2ResponseRef(ref unsafe.Pointer) *FilSealPreCommitPhase2Response { + if ref == nil { + return nil + } + obj := new(FilSealPreCommitPhase2Response) + obj.ref2aa6831d = (*C.fil_SealPreCommitPhase2Response)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilSealPreCommitPhase2Response) PassRef() (*C.fil_SealPreCommitPhase2Response, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref2aa6831d != nil { + return x.ref2aa6831d, nil + } + mem2aa6831d := allocFilSealPreCommitPhase2ResponseMemory(1) + ref2aa6831d := (*C.fil_SealPreCommitPhase2Response)(mem2aa6831d) + allocs2aa6831d := new(cgoAllocMap) + allocs2aa6831d.Add(mem2aa6831d) + + var cerror_msg_allocs *cgoAllocMap + ref2aa6831d.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs2aa6831d.Borrow(cerror_msg_allocs) + + var cstatus_code_allocs *cgoAllocMap + ref2aa6831d.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs2aa6831d.Borrow(cstatus_code_allocs) + + var cregistered_proof_allocs *cgoAllocMap + ref2aa6831d.registered_proof, cregistered_proof_allocs = (C.fil_RegisteredSealProof)(x.RegisteredProof), cgoAllocsUnknown + allocs2aa6831d.Borrow(cregistered_proof_allocs) + + var ccomm_d_allocs *cgoAllocMap + ref2aa6831d.comm_d, ccomm_d_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommD)), cgoAllocsUnknown + allocs2aa6831d.Borrow(ccomm_d_allocs) + + var ccomm_r_allocs *cgoAllocMap + ref2aa6831d.comm_r, ccomm_r_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommR)), cgoAllocsUnknown + allocs2aa6831d.Borrow(ccomm_r_allocs) + + x.ref2aa6831d = ref2aa6831d + x.allocs2aa6831d = allocs2aa6831d + return ref2aa6831d, allocs2aa6831d + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilSealPreCommitPhase2Response) PassValue() (C.fil_SealPreCommitPhase2Response, *cgoAllocMap) { + if x.ref2aa6831d != nil { + return *x.ref2aa6831d, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilSealPreCommitPhase2Response) Deref() { + if x.ref2aa6831d == nil { + return + } + x.ErrorMsg = packPCharString(x.ref2aa6831d.error_msg) + x.StatusCode = (FCPResponseStatus)(x.ref2aa6831d.status_code) + x.RegisteredProof = (FilRegisteredSealProof)(x.ref2aa6831d.registered_proof) + x.CommD = *(*[32]byte)(unsafe.Pointer(&x.ref2aa6831d.comm_d)) + x.CommR = *(*[32]byte)(unsafe.Pointer(&x.ref2aa6831d.comm_r)) +} + +// allocFilStringResponseMemory allocates memory for type C.fil_StringResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilStringResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilStringResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilStringResponseValue = unsafe.Sizeof([1]C.fil_StringResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilStringResponse) Ref() *C.fil_StringResponse { + if x == nil { + return nil + } + return x.ref4f413043 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilStringResponse) Free() { + if x != nil && x.allocs4f413043 != nil { + x.allocs4f413043.(*cgoAllocMap).Free() + x.ref4f413043 = nil + } +} + +// NewFilStringResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilStringResponseRef(ref unsafe.Pointer) *FilStringResponse { + if ref == nil { + return nil + } + obj := new(FilStringResponse) + obj.ref4f413043 = (*C.fil_StringResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilStringResponse) PassRef() (*C.fil_StringResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref4f413043 != nil { + return x.ref4f413043, nil + } + mem4f413043 := allocFilStringResponseMemory(1) + ref4f413043 := (*C.fil_StringResponse)(mem4f413043) + allocs4f413043 := new(cgoAllocMap) + allocs4f413043.Add(mem4f413043) + + var cstatus_code_allocs *cgoAllocMap + ref4f413043.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs4f413043.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref4f413043.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs4f413043.Borrow(cerror_msg_allocs) + + var cstring_val_allocs *cgoAllocMap + ref4f413043.string_val, cstring_val_allocs = unpackPCharString(x.StringVal) + allocs4f413043.Borrow(cstring_val_allocs) + + x.ref4f413043 = ref4f413043 + x.allocs4f413043 = allocs4f413043 + return ref4f413043, allocs4f413043 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilStringResponse) PassValue() (C.fil_StringResponse, *cgoAllocMap) { + if x.ref4f413043 != nil { + return *x.ref4f413043, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilStringResponse) Deref() { + if x.ref4f413043 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref4f413043.status_code) + x.ErrorMsg = packPCharString(x.ref4f413043.error_msg) + x.StringVal = packPCharString(x.ref4f413043.string_val) +} + +// allocFilUnsealRangeResponseMemory allocates memory for type C.fil_UnsealRangeResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilUnsealRangeResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilUnsealRangeResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilUnsealRangeResponseValue = unsafe.Sizeof([1]C.fil_UnsealRangeResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilUnsealRangeResponse) Ref() *C.fil_UnsealRangeResponse { + if x == nil { + return nil + } + return x.ref61e219c9 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilUnsealRangeResponse) Free() { + if x != nil && x.allocs61e219c9 != nil { + x.allocs61e219c9.(*cgoAllocMap).Free() + x.ref61e219c9 = nil + } +} + +// NewFilUnsealRangeResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilUnsealRangeResponseRef(ref unsafe.Pointer) *FilUnsealRangeResponse { + if ref == nil { + return nil + } + obj := new(FilUnsealRangeResponse) + obj.ref61e219c9 = (*C.fil_UnsealRangeResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilUnsealRangeResponse) PassRef() (*C.fil_UnsealRangeResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref61e219c9 != nil { + return x.ref61e219c9, nil + } + mem61e219c9 := allocFilUnsealRangeResponseMemory(1) + ref61e219c9 := (*C.fil_UnsealRangeResponse)(mem61e219c9) + allocs61e219c9 := new(cgoAllocMap) + allocs61e219c9.Add(mem61e219c9) + + var cstatus_code_allocs *cgoAllocMap + ref61e219c9.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs61e219c9.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref61e219c9.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs61e219c9.Borrow(cerror_msg_allocs) + + x.ref61e219c9 = ref61e219c9 + x.allocs61e219c9 = allocs61e219c9 + return ref61e219c9, allocs61e219c9 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilUnsealRangeResponse) PassValue() (C.fil_UnsealRangeResponse, *cgoAllocMap) { + if x.ref61e219c9 != nil { + return *x.ref61e219c9, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilUnsealRangeResponse) Deref() { + if x.ref61e219c9 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref61e219c9.status_code) + x.ErrorMsg = packPCharString(x.ref61e219c9.error_msg) +} + +// allocFilVerifySealResponseMemory allocates memory for type C.fil_VerifySealResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilVerifySealResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilVerifySealResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilVerifySealResponseValue = unsafe.Sizeof([1]C.fil_VerifySealResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilVerifySealResponse) Ref() *C.fil_VerifySealResponse { + if x == nil { + return nil + } + return x.refd4397079 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilVerifySealResponse) Free() { + if x != nil && x.allocsd4397079 != nil { + x.allocsd4397079.(*cgoAllocMap).Free() + x.refd4397079 = nil + } +} + +// NewFilVerifySealResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilVerifySealResponseRef(ref unsafe.Pointer) *FilVerifySealResponse { + if ref == nil { + return nil + } + obj := new(FilVerifySealResponse) + obj.refd4397079 = (*C.fil_VerifySealResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilVerifySealResponse) PassRef() (*C.fil_VerifySealResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refd4397079 != nil { + return x.refd4397079, nil + } + memd4397079 := allocFilVerifySealResponseMemory(1) + refd4397079 := (*C.fil_VerifySealResponse)(memd4397079) + allocsd4397079 := new(cgoAllocMap) + allocsd4397079.Add(memd4397079) + + var cstatus_code_allocs *cgoAllocMap + refd4397079.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocsd4397079.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + refd4397079.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocsd4397079.Borrow(cerror_msg_allocs) + + var cis_valid_allocs *cgoAllocMap + refd4397079.is_valid, cis_valid_allocs = (C._Bool)(x.IsValid), cgoAllocsUnknown + allocsd4397079.Borrow(cis_valid_allocs) + + x.refd4397079 = refd4397079 + x.allocsd4397079 = allocsd4397079 + return refd4397079, allocsd4397079 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilVerifySealResponse) PassValue() (C.fil_VerifySealResponse, *cgoAllocMap) { + if x.refd4397079 != nil { + return *x.refd4397079, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilVerifySealResponse) Deref() { + if x.refd4397079 == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.refd4397079.status_code) + x.ErrorMsg = packPCharString(x.refd4397079.error_msg) + x.IsValid = (bool)(x.refd4397079.is_valid) +} + +// allocFilVerifyWindowPoStResponseMemory allocates memory for type C.fil_VerifyWindowPoStResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilVerifyWindowPoStResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilVerifyWindowPoStResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilVerifyWindowPoStResponseValue = unsafe.Sizeof([1]C.fil_VerifyWindowPoStResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilVerifyWindowPoStResponse) Ref() *C.fil_VerifyWindowPoStResponse { + if x == nil { + return nil + } + return x.ref34c4d49f +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilVerifyWindowPoStResponse) Free() { + if x != nil && x.allocs34c4d49f != nil { + x.allocs34c4d49f.(*cgoAllocMap).Free() + x.ref34c4d49f = nil + } +} + +// NewFilVerifyWindowPoStResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilVerifyWindowPoStResponseRef(ref unsafe.Pointer) *FilVerifyWindowPoStResponse { + if ref == nil { + return nil + } + obj := new(FilVerifyWindowPoStResponse) + obj.ref34c4d49f = (*C.fil_VerifyWindowPoStResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilVerifyWindowPoStResponse) PassRef() (*C.fil_VerifyWindowPoStResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref34c4d49f != nil { + return x.ref34c4d49f, nil + } + mem34c4d49f := allocFilVerifyWindowPoStResponseMemory(1) + ref34c4d49f := (*C.fil_VerifyWindowPoStResponse)(mem34c4d49f) + allocs34c4d49f := new(cgoAllocMap) + allocs34c4d49f.Add(mem34c4d49f) + + var cstatus_code_allocs *cgoAllocMap + ref34c4d49f.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocs34c4d49f.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + ref34c4d49f.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocs34c4d49f.Borrow(cerror_msg_allocs) + + var cis_valid_allocs *cgoAllocMap + ref34c4d49f.is_valid, cis_valid_allocs = (C._Bool)(x.IsValid), cgoAllocsUnknown + allocs34c4d49f.Borrow(cis_valid_allocs) + + x.ref34c4d49f = ref34c4d49f + x.allocs34c4d49f = allocs34c4d49f + return ref34c4d49f, allocs34c4d49f + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilVerifyWindowPoStResponse) PassValue() (C.fil_VerifyWindowPoStResponse, *cgoAllocMap) { + if x.ref34c4d49f != nil { + return *x.ref34c4d49f, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilVerifyWindowPoStResponse) Deref() { + if x.ref34c4d49f == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.ref34c4d49f.status_code) + x.ErrorMsg = packPCharString(x.ref34c4d49f.error_msg) + x.IsValid = (bool)(x.ref34c4d49f.is_valid) +} + +// allocFilVerifyWinningPoStResponseMemory allocates memory for type C.fil_VerifyWinningPoStResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilVerifyWinningPoStResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilVerifyWinningPoStResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilVerifyWinningPoStResponseValue = unsafe.Sizeof([1]C.fil_VerifyWinningPoStResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilVerifyWinningPoStResponse) Ref() *C.fil_VerifyWinningPoStResponse { + if x == nil { + return nil + } + return x.refaca6860c +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilVerifyWinningPoStResponse) Free() { + if x != nil && x.allocsaca6860c != nil { + x.allocsaca6860c.(*cgoAllocMap).Free() + x.refaca6860c = nil + } +} + +// NewFilVerifyWinningPoStResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilVerifyWinningPoStResponseRef(ref unsafe.Pointer) *FilVerifyWinningPoStResponse { + if ref == nil { + return nil + } + obj := new(FilVerifyWinningPoStResponse) + obj.refaca6860c = (*C.fil_VerifyWinningPoStResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilVerifyWinningPoStResponse) PassRef() (*C.fil_VerifyWinningPoStResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refaca6860c != nil { + return x.refaca6860c, nil + } + memaca6860c := allocFilVerifyWinningPoStResponseMemory(1) + refaca6860c := (*C.fil_VerifyWinningPoStResponse)(memaca6860c) + allocsaca6860c := new(cgoAllocMap) + allocsaca6860c.Add(memaca6860c) + + var cstatus_code_allocs *cgoAllocMap + refaca6860c.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocsaca6860c.Borrow(cstatus_code_allocs) + + var cerror_msg_allocs *cgoAllocMap + refaca6860c.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocsaca6860c.Borrow(cerror_msg_allocs) + + var cis_valid_allocs *cgoAllocMap + refaca6860c.is_valid, cis_valid_allocs = (C._Bool)(x.IsValid), cgoAllocsUnknown + allocsaca6860c.Borrow(cis_valid_allocs) + + x.refaca6860c = refaca6860c + x.allocsaca6860c = allocsaca6860c + return refaca6860c, allocsaca6860c + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilVerifyWinningPoStResponse) PassValue() (C.fil_VerifyWinningPoStResponse, *cgoAllocMap) { + if x.refaca6860c != nil { + return *x.refaca6860c, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilVerifyWinningPoStResponse) Deref() { + if x.refaca6860c == nil { + return + } + x.StatusCode = (FCPResponseStatus)(x.refaca6860c.status_code) + x.ErrorMsg = packPCharString(x.refaca6860c.error_msg) + x.IsValid = (bool)(x.refaca6860c.is_valid) +} + +// allocFilWriteWithAlignmentResponseMemory allocates memory for type C.fil_WriteWithAlignmentResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilWriteWithAlignmentResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilWriteWithAlignmentResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilWriteWithAlignmentResponseValue = unsafe.Sizeof([1]C.fil_WriteWithAlignmentResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilWriteWithAlignmentResponse) Ref() *C.fil_WriteWithAlignmentResponse { + if x == nil { + return nil + } + return x.refa330e79 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilWriteWithAlignmentResponse) Free() { + if x != nil && x.allocsa330e79 != nil { + x.allocsa330e79.(*cgoAllocMap).Free() + x.refa330e79 = nil + } +} + +// NewFilWriteWithAlignmentResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilWriteWithAlignmentResponseRef(ref unsafe.Pointer) *FilWriteWithAlignmentResponse { + if ref == nil { + return nil + } + obj := new(FilWriteWithAlignmentResponse) + obj.refa330e79 = (*C.fil_WriteWithAlignmentResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilWriteWithAlignmentResponse) PassRef() (*C.fil_WriteWithAlignmentResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refa330e79 != nil { + return x.refa330e79, nil + } + mema330e79 := allocFilWriteWithAlignmentResponseMemory(1) + refa330e79 := (*C.fil_WriteWithAlignmentResponse)(mema330e79) + allocsa330e79 := new(cgoAllocMap) + allocsa330e79.Add(mema330e79) + + var ccomm_p_allocs *cgoAllocMap + refa330e79.comm_p, ccomm_p_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommP)), cgoAllocsUnknown + allocsa330e79.Borrow(ccomm_p_allocs) + + var cerror_msg_allocs *cgoAllocMap + refa330e79.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocsa330e79.Borrow(cerror_msg_allocs) + + var cleft_alignment_unpadded_allocs *cgoAllocMap + refa330e79.left_alignment_unpadded, cleft_alignment_unpadded_allocs = (C.uint64_t)(x.LeftAlignmentUnpadded), cgoAllocsUnknown + allocsa330e79.Borrow(cleft_alignment_unpadded_allocs) + + var cstatus_code_allocs *cgoAllocMap + refa330e79.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocsa330e79.Borrow(cstatus_code_allocs) + + var ctotal_write_unpadded_allocs *cgoAllocMap + refa330e79.total_write_unpadded, ctotal_write_unpadded_allocs = (C.uint64_t)(x.TotalWriteUnpadded), cgoAllocsUnknown + allocsa330e79.Borrow(ctotal_write_unpadded_allocs) + + x.refa330e79 = refa330e79 + x.allocsa330e79 = allocsa330e79 + return refa330e79, allocsa330e79 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilWriteWithAlignmentResponse) PassValue() (C.fil_WriteWithAlignmentResponse, *cgoAllocMap) { + if x.refa330e79 != nil { + return *x.refa330e79, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilWriteWithAlignmentResponse) Deref() { + if x.refa330e79 == nil { + return + } + x.CommP = *(*[32]byte)(unsafe.Pointer(&x.refa330e79.comm_p)) + x.ErrorMsg = packPCharString(x.refa330e79.error_msg) + x.LeftAlignmentUnpadded = (uint64)(x.refa330e79.left_alignment_unpadded) + x.StatusCode = (FCPResponseStatus)(x.refa330e79.status_code) + x.TotalWriteUnpadded = (uint64)(x.refa330e79.total_write_unpadded) +} + +// allocFilWriteWithoutAlignmentResponseMemory allocates memory for type C.fil_WriteWithoutAlignmentResponse in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilWriteWithoutAlignmentResponseMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilWriteWithoutAlignmentResponseValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilWriteWithoutAlignmentResponseValue = unsafe.Sizeof([1]C.fil_WriteWithoutAlignmentResponse{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilWriteWithoutAlignmentResponse) Ref() *C.fil_WriteWithoutAlignmentResponse { + if x == nil { + return nil + } + return x.refc8e1ed8 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilWriteWithoutAlignmentResponse) Free() { + if x != nil && x.allocsc8e1ed8 != nil { + x.allocsc8e1ed8.(*cgoAllocMap).Free() + x.refc8e1ed8 = nil + } +} + +// NewFilWriteWithoutAlignmentResponseRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilWriteWithoutAlignmentResponseRef(ref unsafe.Pointer) *FilWriteWithoutAlignmentResponse { + if ref == nil { + return nil + } + obj := new(FilWriteWithoutAlignmentResponse) + obj.refc8e1ed8 = (*C.fil_WriteWithoutAlignmentResponse)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilWriteWithoutAlignmentResponse) PassRef() (*C.fil_WriteWithoutAlignmentResponse, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refc8e1ed8 != nil { + return x.refc8e1ed8, nil + } + memc8e1ed8 := allocFilWriteWithoutAlignmentResponseMemory(1) + refc8e1ed8 := (*C.fil_WriteWithoutAlignmentResponse)(memc8e1ed8) + allocsc8e1ed8 := new(cgoAllocMap) + allocsc8e1ed8.Add(memc8e1ed8) + + var ccomm_p_allocs *cgoAllocMap + refc8e1ed8.comm_p, ccomm_p_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommP)), cgoAllocsUnknown + allocsc8e1ed8.Borrow(ccomm_p_allocs) + + var cerror_msg_allocs *cgoAllocMap + refc8e1ed8.error_msg, cerror_msg_allocs = unpackPCharString(x.ErrorMsg) + allocsc8e1ed8.Borrow(cerror_msg_allocs) + + var cstatus_code_allocs *cgoAllocMap + refc8e1ed8.status_code, cstatus_code_allocs = (C.FCPResponseStatus)(x.StatusCode), cgoAllocsUnknown + allocsc8e1ed8.Borrow(cstatus_code_allocs) + + var ctotal_write_unpadded_allocs *cgoAllocMap + refc8e1ed8.total_write_unpadded, ctotal_write_unpadded_allocs = (C.uint64_t)(x.TotalWriteUnpadded), cgoAllocsUnknown + allocsc8e1ed8.Borrow(ctotal_write_unpadded_allocs) + + x.refc8e1ed8 = refc8e1ed8 + x.allocsc8e1ed8 = allocsc8e1ed8 + return refc8e1ed8, allocsc8e1ed8 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilWriteWithoutAlignmentResponse) PassValue() (C.fil_WriteWithoutAlignmentResponse, *cgoAllocMap) { + if x.refc8e1ed8 != nil { + return *x.refc8e1ed8, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilWriteWithoutAlignmentResponse) Deref() { + if x.refc8e1ed8 == nil { + return + } + x.CommP = *(*[32]byte)(unsafe.Pointer(&x.refc8e1ed8.comm_p)) + x.ErrorMsg = packPCharString(x.refc8e1ed8.error_msg) + x.StatusCode = (FCPResponseStatus)(x.refc8e1ed8.status_code) + x.TotalWriteUnpadded = (uint64)(x.refc8e1ed8.total_write_unpadded) +} + +// allocFilPublicPieceInfoMemory allocates memory for type C.fil_PublicPieceInfo in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilPublicPieceInfoMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilPublicPieceInfoValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilPublicPieceInfoValue = unsafe.Sizeof([1]C.fil_PublicPieceInfo{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilPublicPieceInfo) Ref() *C.fil_PublicPieceInfo { + if x == nil { + return nil + } + return x.refd00025ac +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilPublicPieceInfo) Free() { + if x != nil && x.allocsd00025ac != nil { + x.allocsd00025ac.(*cgoAllocMap).Free() + x.refd00025ac = nil + } +} + +// NewFilPublicPieceInfoRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilPublicPieceInfoRef(ref unsafe.Pointer) *FilPublicPieceInfo { + if ref == nil { + return nil + } + obj := new(FilPublicPieceInfo) + obj.refd00025ac = (*C.fil_PublicPieceInfo)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilPublicPieceInfo) PassRef() (*C.fil_PublicPieceInfo, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.refd00025ac != nil { + return x.refd00025ac, nil + } + memd00025ac := allocFilPublicPieceInfoMemory(1) + refd00025ac := (*C.fil_PublicPieceInfo)(memd00025ac) + allocsd00025ac := new(cgoAllocMap) + allocsd00025ac.Add(memd00025ac) + + var cnum_bytes_allocs *cgoAllocMap + refd00025ac.num_bytes, cnum_bytes_allocs = (C.uint64_t)(x.NumBytes), cgoAllocsUnknown + allocsd00025ac.Borrow(cnum_bytes_allocs) + + var ccomm_p_allocs *cgoAllocMap + refd00025ac.comm_p, ccomm_p_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommP)), cgoAllocsUnknown + allocsd00025ac.Borrow(ccomm_p_allocs) + + x.refd00025ac = refd00025ac + x.allocsd00025ac = allocsd00025ac + return refd00025ac, allocsd00025ac + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilPublicPieceInfo) PassValue() (C.fil_PublicPieceInfo, *cgoAllocMap) { + if x.refd00025ac != nil { + return *x.refd00025ac, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilPublicPieceInfo) Deref() { + if x.refd00025ac == nil { + return + } + x.NumBytes = (uint64)(x.refd00025ac.num_bytes) + x.CommP = *(*[32]byte)(unsafe.Pointer(&x.refd00025ac.comm_p)) +} + +// allocFil32ByteArrayMemory allocates memory for type C.fil_32ByteArray in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFil32ByteArrayMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFil32ByteArrayValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFil32ByteArrayValue = unsafe.Sizeof([1]C.fil_32ByteArray{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *Fil32ByteArray) Ref() *C.fil_32ByteArray { + if x == nil { + return nil + } + return x.ref373ec61a +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *Fil32ByteArray) Free() { + if x != nil && x.allocs373ec61a != nil { + x.allocs373ec61a.(*cgoAllocMap).Free() + x.ref373ec61a = nil + } +} + +// NewFil32ByteArrayRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFil32ByteArrayRef(ref unsafe.Pointer) *Fil32ByteArray { + if ref == nil { + return nil + } + obj := new(Fil32ByteArray) + obj.ref373ec61a = (*C.fil_32ByteArray)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *Fil32ByteArray) PassRef() (*C.fil_32ByteArray, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref373ec61a != nil { + return x.ref373ec61a, nil + } + mem373ec61a := allocFil32ByteArrayMemory(1) + ref373ec61a := (*C.fil_32ByteArray)(mem373ec61a) + allocs373ec61a := new(cgoAllocMap) + allocs373ec61a.Add(mem373ec61a) + + var cinner_allocs *cgoAllocMap + ref373ec61a.inner, cinner_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.Inner)), cgoAllocsUnknown + allocs373ec61a.Borrow(cinner_allocs) + + x.ref373ec61a = ref373ec61a + x.allocs373ec61a = allocs373ec61a + return ref373ec61a, allocs373ec61a + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x Fil32ByteArray) PassValue() (C.fil_32ByteArray, *cgoAllocMap) { + if x.ref373ec61a != nil { + return *x.ref373ec61a, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *Fil32ByteArray) Deref() { + if x.ref373ec61a == nil { + return + } + x.Inner = *(*[32]byte)(unsafe.Pointer(&x.ref373ec61a.inner)) +} + +// allocFilPrivateReplicaInfoMemory allocates memory for type C.fil_PrivateReplicaInfo in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilPrivateReplicaInfoMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilPrivateReplicaInfoValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilPrivateReplicaInfoValue = unsafe.Sizeof([1]C.fil_PrivateReplicaInfo{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilPrivateReplicaInfo) Ref() *C.fil_PrivateReplicaInfo { + if x == nil { + return nil + } + return x.ref81a31e9b +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilPrivateReplicaInfo) Free() { + if x != nil && x.allocs81a31e9b != nil { + x.allocs81a31e9b.(*cgoAllocMap).Free() + x.ref81a31e9b = nil + } +} + +// NewFilPrivateReplicaInfoRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilPrivateReplicaInfoRef(ref unsafe.Pointer) *FilPrivateReplicaInfo { + if ref == nil { + return nil + } + obj := new(FilPrivateReplicaInfo) + obj.ref81a31e9b = (*C.fil_PrivateReplicaInfo)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilPrivateReplicaInfo) PassRef() (*C.fil_PrivateReplicaInfo, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref81a31e9b != nil { + return x.ref81a31e9b, nil + } + mem81a31e9b := allocFilPrivateReplicaInfoMemory(1) + ref81a31e9b := (*C.fil_PrivateReplicaInfo)(mem81a31e9b) + allocs81a31e9b := new(cgoAllocMap) + allocs81a31e9b.Add(mem81a31e9b) + + var cregistered_proof_allocs *cgoAllocMap + ref81a31e9b.registered_proof, cregistered_proof_allocs = (C.fil_RegisteredPoStProof)(x.RegisteredProof), cgoAllocsUnknown + allocs81a31e9b.Borrow(cregistered_proof_allocs) + + var ccache_dir_path_allocs *cgoAllocMap + ref81a31e9b.cache_dir_path, ccache_dir_path_allocs = unpackPCharString(x.CacheDirPath) + allocs81a31e9b.Borrow(ccache_dir_path_allocs) + + var ccomm_r_allocs *cgoAllocMap + ref81a31e9b.comm_r, ccomm_r_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommR)), cgoAllocsUnknown + allocs81a31e9b.Borrow(ccomm_r_allocs) + + var creplica_path_allocs *cgoAllocMap + ref81a31e9b.replica_path, creplica_path_allocs = unpackPCharString(x.ReplicaPath) + allocs81a31e9b.Borrow(creplica_path_allocs) + + var csector_id_allocs *cgoAllocMap + ref81a31e9b.sector_id, csector_id_allocs = (C.uint64_t)(x.SectorId), cgoAllocsUnknown + allocs81a31e9b.Borrow(csector_id_allocs) + + x.ref81a31e9b = ref81a31e9b + x.allocs81a31e9b = allocs81a31e9b + return ref81a31e9b, allocs81a31e9b + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilPrivateReplicaInfo) PassValue() (C.fil_PrivateReplicaInfo, *cgoAllocMap) { + if x.ref81a31e9b != nil { + return *x.ref81a31e9b, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilPrivateReplicaInfo) Deref() { + if x.ref81a31e9b == nil { + return + } + x.RegisteredProof = (FilRegisteredPoStProof)(x.ref81a31e9b.registered_proof) + x.CacheDirPath = packPCharString(x.ref81a31e9b.cache_dir_path) + x.CommR = *(*[32]byte)(unsafe.Pointer(&x.ref81a31e9b.comm_r)) + x.ReplicaPath = packPCharString(x.ref81a31e9b.replica_path) + x.SectorId = (uint64)(x.ref81a31e9b.sector_id) +} + +// allocFilPublicReplicaInfoMemory allocates memory for type C.fil_PublicReplicaInfo in C. +// The caller is responsible for freeing the this memory via C.free. +func allocFilPublicReplicaInfoMemory(n int) unsafe.Pointer { + mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfFilPublicReplicaInfoValue)) + if mem == nil { + panic(fmt.Sprintln("memory alloc error: ", err)) + } + return mem +} + +const sizeOfFilPublicReplicaInfoValue = unsafe.Sizeof([1]C.fil_PublicReplicaInfo{}) + +// Ref returns the underlying reference to C object or nil if struct is nil. +func (x *FilPublicReplicaInfo) Ref() *C.fil_PublicReplicaInfo { + if x == nil { + return nil + } + return x.ref81b617c2 +} + +// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free. +// Does nothing if struct is nil or has no allocation map. +func (x *FilPublicReplicaInfo) Free() { + if x != nil && x.allocs81b617c2 != nil { + x.allocs81b617c2.(*cgoAllocMap).Free() + x.ref81b617c2 = nil + } +} + +// NewFilPublicReplicaInfoRef creates a new wrapper struct with underlying reference set to the original C object. +// Returns nil if the provided pointer to C object is nil too. +func NewFilPublicReplicaInfoRef(ref unsafe.Pointer) *FilPublicReplicaInfo { + if ref == nil { + return nil + } + obj := new(FilPublicReplicaInfo) + obj.ref81b617c2 = (*C.fil_PublicReplicaInfo)(unsafe.Pointer(ref)) + return obj +} + +// PassRef returns the underlying C object, otherwise it will allocate one and set its values +// from this wrapping struct, counting allocations into an allocation map. +func (x *FilPublicReplicaInfo) PassRef() (*C.fil_PublicReplicaInfo, *cgoAllocMap) { + if x == nil { + return nil, nil + } else if x.ref81b617c2 != nil { + return x.ref81b617c2, nil + } + mem81b617c2 := allocFilPublicReplicaInfoMemory(1) + ref81b617c2 := (*C.fil_PublicReplicaInfo)(mem81b617c2) + allocs81b617c2 := new(cgoAllocMap) + allocs81b617c2.Add(mem81b617c2) + + var cregistered_proof_allocs *cgoAllocMap + ref81b617c2.registered_proof, cregistered_proof_allocs = (C.fil_RegisteredPoStProof)(x.RegisteredProof), cgoAllocsUnknown + allocs81b617c2.Borrow(cregistered_proof_allocs) + + var ccomm_r_allocs *cgoAllocMap + ref81b617c2.comm_r, ccomm_r_allocs = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommR)), cgoAllocsUnknown + allocs81b617c2.Borrow(ccomm_r_allocs) + + var csector_id_allocs *cgoAllocMap + ref81b617c2.sector_id, csector_id_allocs = (C.uint64_t)(x.SectorId), cgoAllocsUnknown + allocs81b617c2.Borrow(csector_id_allocs) + + x.ref81b617c2 = ref81b617c2 + x.allocs81b617c2 = allocs81b617c2 + return ref81b617c2, allocs81b617c2 + +} + +// PassValue does the same as PassRef except that it will try to dereference the returned pointer. +func (x FilPublicReplicaInfo) PassValue() (C.fil_PublicReplicaInfo, *cgoAllocMap) { + if x.ref81b617c2 != nil { + return *x.ref81b617c2, nil + } + ref, allocs := x.PassRef() + return *ref, allocs +} + +// Deref uses the underlying reference to C object and fills the wrapping struct with values. +// Do not forget to call this method whether you get a struct for C object and want to read its values. +func (x *FilPublicReplicaInfo) Deref() { + if x.ref81b617c2 == nil { + return + } + x.RegisteredProof = (FilRegisteredPoStProof)(x.ref81b617c2.registered_proof) + x.CommR = *(*[32]byte)(unsafe.Pointer(&x.ref81b617c2.comm_r)) + x.SectorId = (uint64)(x.ref81b617c2.sector_id) +} + +// unpackArgSFilPublicPieceInfo transforms a sliced Go data structure into plain C format. +func unpackArgSFilPublicPieceInfo(x []FilPublicPieceInfo) (unpacked *C.fil_PublicPieceInfo, allocs *cgoAllocMap) { + if x == nil { + return nil, nil + } + allocs = new(cgoAllocMap) + defer runtime.SetFinalizer(allocs, func(a *cgoAllocMap) { + go a.Free() + }) + + len0 := len(x) + mem0 := allocFilPublicPieceInfoMemory(len0) + allocs.Add(mem0) + h0 := &sliceHeader{ + Data: mem0, + Cap: len0, + Len: len0, + } + v0 := *(*[]C.fil_PublicPieceInfo)(unsafe.Pointer(h0)) + for i0 := range x { + allocs0 := new(cgoAllocMap) + v0[i0], allocs0 = x[i0].PassValue() + allocs.Borrow(allocs0) + } + h := (*sliceHeader)(unsafe.Pointer(&v0)) + unpacked = (*C.fil_PublicPieceInfo)(h.Data) + return +} + +// packSFilPublicPieceInfo reads sliced Go data structure out from plain C format. +func packSFilPublicPieceInfo(v []FilPublicPieceInfo, ptr0 *C.fil_PublicPieceInfo) { + const m = 0x7fffffff + for i0 := range v { + ptr1 := (*(*[m / sizeOfFilPublicPieceInfoValue]C.fil_PublicPieceInfo)(unsafe.Pointer(ptr0)))[i0] + v[i0] = *NewFilPublicPieceInfoRef(unsafe.Pointer(&ptr1)) + } +} + +// unpackArgSFilPrivateReplicaInfo transforms a sliced Go data structure into plain C format. +func unpackArgSFilPrivateReplicaInfo(x []FilPrivateReplicaInfo) (unpacked *C.fil_PrivateReplicaInfo, allocs *cgoAllocMap) { + if x == nil { + return nil, nil + } + allocs = new(cgoAllocMap) + defer runtime.SetFinalizer(allocs, func(a *cgoAllocMap) { + go a.Free() + }) + + len0 := len(x) + mem0 := allocFilPrivateReplicaInfoMemory(len0) + allocs.Add(mem0) + h0 := &sliceHeader{ + Data: mem0, + Cap: len0, + Len: len0, + } + v0 := *(*[]C.fil_PrivateReplicaInfo)(unsafe.Pointer(h0)) + for i0 := range x { + allocs0 := new(cgoAllocMap) + v0[i0], allocs0 = x[i0].PassValue() + allocs.Borrow(allocs0) + } + h := (*sliceHeader)(unsafe.Pointer(&v0)) + unpacked = (*C.fil_PrivateReplicaInfo)(h.Data) + return +} + +// packSFilPrivateReplicaInfo reads sliced Go data structure out from plain C format. +func packSFilPrivateReplicaInfo(v []FilPrivateReplicaInfo, ptr0 *C.fil_PrivateReplicaInfo) { + const m = 0x7fffffff + for i0 := range v { + ptr1 := (*(*[m / sizeOfFilPrivateReplicaInfoValue]C.fil_PrivateReplicaInfo)(unsafe.Pointer(ptr0)))[i0] + v[i0] = *NewFilPrivateReplicaInfoRef(unsafe.Pointer(&ptr1)) + } +} + +// unpackArgSFilPublicReplicaInfo transforms a sliced Go data structure into plain C format. +func unpackArgSFilPublicReplicaInfo(x []FilPublicReplicaInfo) (unpacked *C.fil_PublicReplicaInfo, allocs *cgoAllocMap) { + if x == nil { + return nil, nil + } + allocs = new(cgoAllocMap) + defer runtime.SetFinalizer(allocs, func(a *cgoAllocMap) { + go a.Free() + }) + + len0 := len(x) + mem0 := allocFilPublicReplicaInfoMemory(len0) + allocs.Add(mem0) + h0 := &sliceHeader{ + Data: mem0, + Cap: len0, + Len: len0, + } + v0 := *(*[]C.fil_PublicReplicaInfo)(unsafe.Pointer(h0)) + for i0 := range x { + allocs0 := new(cgoAllocMap) + v0[i0], allocs0 = x[i0].PassValue() + allocs.Borrow(allocs0) + } + h := (*sliceHeader)(unsafe.Pointer(&v0)) + unpacked = (*C.fil_PublicReplicaInfo)(h.Data) + return +} + +// packSFilPublicReplicaInfo reads sliced Go data structure out from plain C format. +func packSFilPublicReplicaInfo(v []FilPublicReplicaInfo, ptr0 *C.fil_PublicReplicaInfo) { + const m = 0x7fffffff + for i0 := range v { + ptr1 := (*(*[m / sizeOfFilPublicReplicaInfoValue]C.fil_PublicReplicaInfo)(unsafe.Pointer(ptr0)))[i0] + v[i0] = *NewFilPublicReplicaInfoRef(unsafe.Pointer(&ptr1)) + } +} + +// unpackArgSFilPoStProof transforms a sliced Go data structure into plain C format. +func unpackArgSFilPoStProof(x []FilPoStProof) (unpacked *C.fil_PoStProof, allocs *cgoAllocMap) { + if x == nil { + return nil, nil + } + allocs = new(cgoAllocMap) + defer runtime.SetFinalizer(allocs, func(a *cgoAllocMap) { + go a.Free() + }) + + len0 := len(x) + mem0 := allocFilPoStProofMemory(len0) + allocs.Add(mem0) + h0 := &sliceHeader{ + Data: mem0, + Cap: len0, + Len: len0, + } + v0 := *(*[]C.fil_PoStProof)(unsafe.Pointer(h0)) + for i0 := range x { + allocs0 := new(cgoAllocMap) + v0[i0], allocs0 = x[i0].PassValue() + allocs.Borrow(allocs0) + } + h := (*sliceHeader)(unsafe.Pointer(&v0)) + unpacked = (*C.fil_PoStProof)(h.Data) + return +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.h b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.h new file mode 100644 index 0000000000..952ed279b1 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/cgo_helpers.h @@ -0,0 +1,9 @@ +// WARNING: This file has automatically been generated +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +#include "../filcrypto.h" +#include +#pragma once + +#define __CGOGEN 1 + diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/const.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/const.go new file mode 100644 index 0000000000..181aea886b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/const.go @@ -0,0 +1,53 @@ +// WARNING: This file has automatically been generated +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +package generated + +/* +#cgo LDFLAGS: -L${SRCDIR}/.. -lfilcrypto +#cgo pkg-config: ${SRCDIR}/../filcrypto.pc +#include "../filcrypto.h" +#include +#include "cgo_helpers.h" +*/ +import "C" + +// FCPResponseStatus as declared in filecoin-ffi/filcrypto.h:31 +type FCPResponseStatus int32 + +// FCPResponseStatus enumeration from filecoin-ffi/filcrypto.h:31 +const ( + FCPResponseStatusFCPNoError FCPResponseStatus = C.FCPResponseStatus_FCPNoError + FCPResponseStatusFCPUnclassifiedError FCPResponseStatus = C.FCPResponseStatus_FCPUnclassifiedError + FCPResponseStatusFCPCallerError FCPResponseStatus = C.FCPResponseStatus_FCPCallerError + FCPResponseStatusFCPReceiverError FCPResponseStatus = C.FCPResponseStatus_FCPReceiverError +) + +// FilRegisteredPoStProof as declared in filecoin-ffi/filcrypto.h:44 +type FilRegisteredPoStProof int32 + +// FilRegisteredPoStProof enumeration from filecoin-ffi/filcrypto.h:44 +const ( + FilRegisteredPoStProofStackedDrgWinning2KiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWinning2KiBV1 + FilRegisteredPoStProofStackedDrgWinning8MiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWinning8MiBV1 + FilRegisteredPoStProofStackedDrgWinning512MiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWinning512MiBV1 + FilRegisteredPoStProofStackedDrgWinning32GiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWinning32GiBV1 + FilRegisteredPoStProofStackedDrgWinning64GiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWinning64GiBV1 + FilRegisteredPoStProofStackedDrgWindow2KiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWindow2KiBV1 + FilRegisteredPoStProofStackedDrgWindow8MiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWindow8MiBV1 + FilRegisteredPoStProofStackedDrgWindow512MiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWindow512MiBV1 + FilRegisteredPoStProofStackedDrgWindow32GiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWindow32GiBV1 + FilRegisteredPoStProofStackedDrgWindow64GiBV1 FilRegisteredPoStProof = C.fil_RegisteredPoStProof_StackedDrgWindow64GiBV1 +) + +// FilRegisteredSealProof as declared in filecoin-ffi/filcrypto.h:52 +type FilRegisteredSealProof int32 + +// FilRegisteredSealProof enumeration from filecoin-ffi/filcrypto.h:52 +const ( + FilRegisteredSealProofStackedDrg2KiBV1 FilRegisteredSealProof = C.fil_RegisteredSealProof_StackedDrg2KiBV1 + FilRegisteredSealProofStackedDrg8MiBV1 FilRegisteredSealProof = C.fil_RegisteredSealProof_StackedDrg8MiBV1 + FilRegisteredSealProofStackedDrg512MiBV1 FilRegisteredSealProof = C.fil_RegisteredSealProof_StackedDrg512MiBV1 + FilRegisteredSealProofStackedDrg32GiBV1 FilRegisteredSealProof = C.fil_RegisteredSealProof_StackedDrg32GiBV1 + FilRegisteredSealProofStackedDrg64GiBV1 FilRegisteredSealProof = C.fil_RegisteredSealProof_StackedDrg64GiBV1 +) diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/customallocs.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/customallocs.go new file mode 100644 index 0000000000..4c8d10dd4a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/customallocs.go @@ -0,0 +1,54 @@ +package generated + +/* +#cgo LDFLAGS: -L${SRCDIR}/.. -lfilcrypto +#cgo pkg-config: ${SRCDIR}/../filcrypto.pc +#include "../filcrypto.h" +#include +#include "cgo_helpers.h" +*/ +import "C" +import ( + "unsafe" +) + +// AllocateProxy allocates a FilPrivateReplicaInfo proxy object in the C heap, +// returning a function which, when called, frees the allocated memory. This +// method exists because the default c-for-go allocation strategy allocates a +// C struct with a field whose values is a pointer into the Go heap, which is +// not permitted by the most strict CGO check (cgocheck=2). +func (x *FilPrivateReplicaInfo) AllocateProxy() func() { + mem := allocFilPrivateReplicaInfoMemory(1) + proxy := (*C.fil_PrivateReplicaInfo)(mem) + proxy.cache_dir_path = C.CString(x.CacheDirPath) + proxy.comm_r = *(*[32]C.uint8_t)(unsafe.Pointer(&x.CommR)) + proxy.registered_proof = (C.fil_RegisteredPoStProof)(x.RegisteredProof) + proxy.replica_path = C.CString(x.ReplicaPath) + proxy.sector_id = (C.uint64_t)(x.SectorId) + + x.ref81a31e9b = proxy + + return func() { + C.free(unsafe.Pointer(proxy.cache_dir_path)) + C.free(unsafe.Pointer(proxy.replica_path)) + C.free(unsafe.Pointer(proxy)) + } +} + +// AllocateProxy allocates a FilPoStProof proxy object in the C heap, +// returning a function which, when called, frees the allocated memory. +func (x *FilPoStProof) AllocateProxy() func() { + mem := allocFilPoStProofMemory(1) + proxy := (*C.fil_PoStProof)(mem) + + proxy.registered_proof = (C.fil_RegisteredPoStProof)(x.RegisteredProof) + proxy.proof_len = (C.size_t)(x.ProofLen) + proxy.proof_ptr = (*C.uchar)(unsafe.Pointer(C.CString(x.ProofPtr))) + + x.ref3451bfa = proxy + + return func() { + C.free(unsafe.Pointer(proxy.proof_ptr)) + C.free(unsafe.Pointer(proxy)) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/generated.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/generated.go new file mode 100644 index 0000000000..4c88d3874c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/generated.go @@ -0,0 +1,792 @@ +// WARNING: This file has automatically been generated +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +package generated + +/* +#cgo LDFLAGS: -L${SRCDIR}/.. -lfilcrypto +#cgo pkg-config: ${SRCDIR}/../filcrypto.pc +#include "../filcrypto.h" +#include +#include "cgo_helpers.h" +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +// FilAggregate function as declared in filecoin-ffi/filcrypto.h:287 +func FilAggregate(flattenedSignaturesPtr string, flattenedSignaturesLen uint) *FilAggregateResponse { + flattenedSignaturesPtr = safeString(flattenedSignaturesPtr) + cflattenedSignaturesPtr, cflattenedSignaturesPtrAllocMap := unpackPUint8TString(flattenedSignaturesPtr) + cflattenedSignaturesLen, cflattenedSignaturesLenAllocMap := (C.size_t)(flattenedSignaturesLen), cgoAllocsUnknown + __ret := C.fil_aggregate(cflattenedSignaturesPtr, cflattenedSignaturesLen) + runtime.KeepAlive(cflattenedSignaturesLenAllocMap) + runtime.KeepAlive(flattenedSignaturesPtr) + runtime.KeepAlive(cflattenedSignaturesPtrAllocMap) + __v := NewFilAggregateResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilClearCache function as declared in filecoin-ffi/filcrypto.h:290 +func FilClearCache(sectorSize uint64, cacheDirPath string) *FilClearCacheResponse { + csectorSize, csectorSizeAllocMap := (C.uint64_t)(sectorSize), cgoAllocsUnknown + cacheDirPath = safeString(cacheDirPath) + ccacheDirPath, ccacheDirPathAllocMap := unpackPCharString(cacheDirPath) + __ret := C.fil_clear_cache(csectorSize, ccacheDirPath) + runtime.KeepAlive(cacheDirPath) + runtime.KeepAlive(ccacheDirPathAllocMap) + runtime.KeepAlive(csectorSizeAllocMap) + __v := NewFilClearCacheResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilDestroyAggregateResponse function as declared in filecoin-ffi/filcrypto.h:292 +func FilDestroyAggregateResponse(ptr *FilAggregateResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_aggregate_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyClearCacheResponse function as declared in filecoin-ffi/filcrypto.h:294 +func FilDestroyClearCacheResponse(ptr *FilClearCacheResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_clear_cache_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyFauxrepResponse function as declared in filecoin-ffi/filcrypto.h:296 +func FilDestroyFauxrepResponse(ptr *FilFauxRepResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_fauxrep_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyFinalizeTicketResponse function as declared in filecoin-ffi/filcrypto.h:298 +func FilDestroyFinalizeTicketResponse(ptr *FilFinalizeTicketResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_finalize_ticket_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyGenerateDataCommitmentResponse function as declared in filecoin-ffi/filcrypto.h:300 +func FilDestroyGenerateDataCommitmentResponse(ptr *FilGenerateDataCommitmentResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_generate_data_commitment_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyGeneratePieceCommitmentResponse function as declared in filecoin-ffi/filcrypto.h:302 +func FilDestroyGeneratePieceCommitmentResponse(ptr *FilGeneratePieceCommitmentResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_generate_piece_commitment_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyGenerateWindowPostResponse function as declared in filecoin-ffi/filcrypto.h:304 +func FilDestroyGenerateWindowPostResponse(ptr *FilGenerateWindowPoStResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_generate_window_post_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyGenerateWinningPostResponse function as declared in filecoin-ffi/filcrypto.h:306 +func FilDestroyGenerateWinningPostResponse(ptr *FilGenerateWinningPoStResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_generate_winning_post_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyGenerateWinningPostSectorChallenge function as declared in filecoin-ffi/filcrypto.h:308 +func FilDestroyGenerateWinningPostSectorChallenge(ptr *FilGenerateWinningPoStSectorChallenge) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_generate_winning_post_sector_challenge(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyGpuDeviceResponse function as declared in filecoin-ffi/filcrypto.h:310 +func FilDestroyGpuDeviceResponse(ptr *FilGpuDeviceResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_gpu_device_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyHashResponse function as declared in filecoin-ffi/filcrypto.h:312 +func FilDestroyHashResponse(ptr *FilHashResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_hash_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyInitLogFdResponse function as declared in filecoin-ffi/filcrypto.h:314 +func FilDestroyInitLogFdResponse(ptr *FilInitLogFdResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_init_log_fd_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyPrivateKeyGenerateResponse function as declared in filecoin-ffi/filcrypto.h:316 +func FilDestroyPrivateKeyGenerateResponse(ptr *FilPrivateKeyGenerateResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_private_key_generate_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyPrivateKeyPublicKeyResponse function as declared in filecoin-ffi/filcrypto.h:318 +func FilDestroyPrivateKeyPublicKeyResponse(ptr *FilPrivateKeyPublicKeyResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_private_key_public_key_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyPrivateKeySignResponse function as declared in filecoin-ffi/filcrypto.h:320 +func FilDestroyPrivateKeySignResponse(ptr *FilPrivateKeySignResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_private_key_sign_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroySealCommitPhase1Response function as declared in filecoin-ffi/filcrypto.h:322 +func FilDestroySealCommitPhase1Response(ptr *FilSealCommitPhase1Response) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_seal_commit_phase1_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroySealCommitPhase2Response function as declared in filecoin-ffi/filcrypto.h:324 +func FilDestroySealCommitPhase2Response(ptr *FilSealCommitPhase2Response) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_seal_commit_phase2_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroySealPreCommitPhase1Response function as declared in filecoin-ffi/filcrypto.h:326 +func FilDestroySealPreCommitPhase1Response(ptr *FilSealPreCommitPhase1Response) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_seal_pre_commit_phase1_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroySealPreCommitPhase2Response function as declared in filecoin-ffi/filcrypto.h:328 +func FilDestroySealPreCommitPhase2Response(ptr *FilSealPreCommitPhase2Response) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_seal_pre_commit_phase2_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyStringResponse function as declared in filecoin-ffi/filcrypto.h:330 +func FilDestroyStringResponse(ptr *FilStringResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_string_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyUnsealRangeResponse function as declared in filecoin-ffi/filcrypto.h:332 +func FilDestroyUnsealRangeResponse(ptr *FilUnsealRangeResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_unseal_range_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyVerifySealResponse function as declared in filecoin-ffi/filcrypto.h:338 +func FilDestroyVerifySealResponse(ptr *FilVerifySealResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_verify_seal_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyVerifyWindowPostResponse function as declared in filecoin-ffi/filcrypto.h:340 +func FilDestroyVerifyWindowPostResponse(ptr *FilVerifyWindowPoStResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_verify_window_post_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyVerifyWinningPostResponse function as declared in filecoin-ffi/filcrypto.h:346 +func FilDestroyVerifyWinningPostResponse(ptr *FilVerifyWinningPoStResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_verify_winning_post_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyWriteWithAlignmentResponse function as declared in filecoin-ffi/filcrypto.h:348 +func FilDestroyWriteWithAlignmentResponse(ptr *FilWriteWithAlignmentResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_write_with_alignment_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilDestroyWriteWithoutAlignmentResponse function as declared in filecoin-ffi/filcrypto.h:350 +func FilDestroyWriteWithoutAlignmentResponse(ptr *FilWriteWithoutAlignmentResponse) { + cptr, cptrAllocMap := ptr.PassRef() + C.fil_destroy_write_without_alignment_response(cptr) + runtime.KeepAlive(cptrAllocMap) +} + +// FilFauxrep function as declared in filecoin-ffi/filcrypto.h:352 +func FilFauxrep(registeredProof FilRegisteredSealProof, cacheDirPath string, sealedSectorPath string) *FilFauxRepResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + cacheDirPath = safeString(cacheDirPath) + ccacheDirPath, ccacheDirPathAllocMap := unpackPCharString(cacheDirPath) + sealedSectorPath = safeString(sealedSectorPath) + csealedSectorPath, csealedSectorPathAllocMap := unpackPCharString(sealedSectorPath) + __ret := C.fil_fauxrep(cregisteredProof, ccacheDirPath, csealedSectorPath) + runtime.KeepAlive(sealedSectorPath) + runtime.KeepAlive(csealedSectorPathAllocMap) + runtime.KeepAlive(cacheDirPath) + runtime.KeepAlive(ccacheDirPathAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilFauxRepResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGenerateDataCommitment function as declared in filecoin-ffi/filcrypto.h:359 +func FilGenerateDataCommitment(registeredProof FilRegisteredSealProof, piecesPtr []FilPublicPieceInfo, piecesLen uint) *FilGenerateDataCommitmentResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + cpiecesPtr, cpiecesPtrAllocMap := unpackArgSFilPublicPieceInfo(piecesPtr) + cpiecesLen, cpiecesLenAllocMap := (C.size_t)(piecesLen), cgoAllocsUnknown + __ret := C.fil_generate_data_commitment(cregisteredProof, cpiecesPtr, cpiecesLen) + runtime.KeepAlive(cpiecesLenAllocMap) + packSFilPublicPieceInfo(piecesPtr, cpiecesPtr) + runtime.KeepAlive(cpiecesPtrAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilGenerateDataCommitmentResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGeneratePieceCommitment function as declared in filecoin-ffi/filcrypto.h:367 +func FilGeneratePieceCommitment(registeredProof FilRegisteredSealProof, pieceFdRaw int32, unpaddedPieceSize uint64) *FilGeneratePieceCommitmentResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + cpieceFdRaw, cpieceFdRawAllocMap := (C.int)(pieceFdRaw), cgoAllocsUnknown + cunpaddedPieceSize, cunpaddedPieceSizeAllocMap := (C.uint64_t)(unpaddedPieceSize), cgoAllocsUnknown + __ret := C.fil_generate_piece_commitment(cregisteredProof, cpieceFdRaw, cunpaddedPieceSize) + runtime.KeepAlive(cunpaddedPieceSizeAllocMap) + runtime.KeepAlive(cpieceFdRawAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilGeneratePieceCommitmentResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGenerateWindowPost function as declared in filecoin-ffi/filcrypto.h:375 +func FilGenerateWindowPost(randomness Fil32ByteArray, replicasPtr []FilPrivateReplicaInfo, replicasLen uint, proverId Fil32ByteArray) *FilGenerateWindowPoStResponse { + crandomness, crandomnessAllocMap := randomness.PassValue() + creplicasPtr, creplicasPtrAllocMap := unpackArgSFilPrivateReplicaInfo(replicasPtr) + creplicasLen, creplicasLenAllocMap := (C.size_t)(replicasLen), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + __ret := C.fil_generate_window_post(crandomness, creplicasPtr, creplicasLen, cproverId) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(creplicasLenAllocMap) + packSFilPrivateReplicaInfo(replicasPtr, creplicasPtr) + runtime.KeepAlive(creplicasPtrAllocMap) + runtime.KeepAlive(crandomnessAllocMap) + __v := NewFilGenerateWindowPoStResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGenerateWinningPost function as declared in filecoin-ffi/filcrypto.h:384 +func FilGenerateWinningPost(randomness Fil32ByteArray, replicasPtr []FilPrivateReplicaInfo, replicasLen uint, proverId Fil32ByteArray) *FilGenerateWinningPoStResponse { + crandomness, crandomnessAllocMap := randomness.PassValue() + creplicasPtr, creplicasPtrAllocMap := unpackArgSFilPrivateReplicaInfo(replicasPtr) + creplicasLen, creplicasLenAllocMap := (C.size_t)(replicasLen), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + __ret := C.fil_generate_winning_post(crandomness, creplicasPtr, creplicasLen, cproverId) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(creplicasLenAllocMap) + packSFilPrivateReplicaInfo(replicasPtr, creplicasPtr) + runtime.KeepAlive(creplicasPtrAllocMap) + runtime.KeepAlive(crandomnessAllocMap) + __v := NewFilGenerateWinningPoStResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGenerateWinningPostSectorChallenge function as declared in filecoin-ffi/filcrypto.h:393 +func FilGenerateWinningPostSectorChallenge(registeredProof FilRegisteredPoStProof, randomness Fil32ByteArray, sectorSetLen uint64, proverId Fil32ByteArray) *FilGenerateWinningPoStSectorChallenge { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredPoStProof)(registeredProof), cgoAllocsUnknown + crandomness, crandomnessAllocMap := randomness.PassValue() + csectorSetLen, csectorSetLenAllocMap := (C.uint64_t)(sectorSetLen), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + __ret := C.fil_generate_winning_post_sector_challenge(cregisteredProof, crandomness, csectorSetLen, cproverId) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(csectorSetLenAllocMap) + runtime.KeepAlive(crandomnessAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilGenerateWinningPoStSectorChallengeRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetGpuDevices function as declared in filecoin-ffi/filcrypto.h:401 +func FilGetGpuDevices() *FilGpuDeviceResponse { + __ret := C.fil_get_gpu_devices() + __v := NewFilGpuDeviceResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetMaxUserBytesPerStagedSector function as declared in filecoin-ffi/filcrypto.h:407 +func FilGetMaxUserBytesPerStagedSector(registeredProof FilRegisteredSealProof) uint64 { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_max_user_bytes_per_staged_sector(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := (uint64)(__ret) + return __v +} + +// FilGetPostCircuitIdentifier function as declared in filecoin-ffi/filcrypto.h:413 +func FilGetPostCircuitIdentifier(registeredProof FilRegisteredPoStProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredPoStProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_post_circuit_identifier(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetPostParamsCid function as declared in filecoin-ffi/filcrypto.h:419 +func FilGetPostParamsCid(registeredProof FilRegisteredPoStProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredPoStProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_post_params_cid(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetPostParamsPath function as declared in filecoin-ffi/filcrypto.h:426 +func FilGetPostParamsPath(registeredProof FilRegisteredPoStProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredPoStProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_post_params_path(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetPostVerifyingKeyCid function as declared in filecoin-ffi/filcrypto.h:432 +func FilGetPostVerifyingKeyCid(registeredProof FilRegisteredPoStProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredPoStProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_post_verifying_key_cid(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetPostVerifyingKeyPath function as declared in filecoin-ffi/filcrypto.h:439 +func FilGetPostVerifyingKeyPath(registeredProof FilRegisteredPoStProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredPoStProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_post_verifying_key_path(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetPostVersion function as declared in filecoin-ffi/filcrypto.h:445 +func FilGetPostVersion(registeredProof FilRegisteredPoStProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredPoStProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_post_version(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetSealCircuitIdentifier function as declared in filecoin-ffi/filcrypto.h:451 +func FilGetSealCircuitIdentifier(registeredProof FilRegisteredSealProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_seal_circuit_identifier(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetSealParamsCid function as declared in filecoin-ffi/filcrypto.h:457 +func FilGetSealParamsCid(registeredProof FilRegisteredSealProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_seal_params_cid(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetSealParamsPath function as declared in filecoin-ffi/filcrypto.h:464 +func FilGetSealParamsPath(registeredProof FilRegisteredSealProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_seal_params_path(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetSealVerifyingKeyCid function as declared in filecoin-ffi/filcrypto.h:470 +func FilGetSealVerifyingKeyCid(registeredProof FilRegisteredSealProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_seal_verifying_key_cid(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetSealVerifyingKeyPath function as declared in filecoin-ffi/filcrypto.h:477 +func FilGetSealVerifyingKeyPath(registeredProof FilRegisteredSealProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_seal_verifying_key_path(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilGetSealVersion function as declared in filecoin-ffi/filcrypto.h:483 +func FilGetSealVersion(registeredProof FilRegisteredSealProof) *FilStringResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + __ret := C.fil_get_seal_version(cregisteredProof) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilStringResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilHash function as declared in filecoin-ffi/filcrypto.h:493 +func FilHash(messagePtr string, messageLen uint) *FilHashResponse { + messagePtr = safeString(messagePtr) + cmessagePtr, cmessagePtrAllocMap := unpackPUint8TString(messagePtr) + cmessageLen, cmessageLenAllocMap := (C.size_t)(messageLen), cgoAllocsUnknown + __ret := C.fil_hash(cmessagePtr, cmessageLen) + runtime.KeepAlive(cmessageLenAllocMap) + runtime.KeepAlive(messagePtr) + runtime.KeepAlive(cmessagePtrAllocMap) + __v := NewFilHashResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilHashVerify function as declared in filecoin-ffi/filcrypto.h:507 +func FilHashVerify(signaturePtr string, flattenedMessagesPtr string, flattenedMessagesLen uint, messageSizesPtr []uint, messageSizesLen uint, flattenedPublicKeysPtr string, flattenedPublicKeysLen uint) int32 { + signaturePtr = safeString(signaturePtr) + csignaturePtr, csignaturePtrAllocMap := unpackPUint8TString(signaturePtr) + flattenedMessagesPtr = safeString(flattenedMessagesPtr) + cflattenedMessagesPtr, cflattenedMessagesPtrAllocMap := unpackPUint8TString(flattenedMessagesPtr) + cflattenedMessagesLen, cflattenedMessagesLenAllocMap := (C.size_t)(flattenedMessagesLen), cgoAllocsUnknown + cmessageSizesPtr, cmessageSizesPtrAllocMap := (*C.size_t)(unsafe.Pointer((*sliceHeader)(unsafe.Pointer(&messageSizesPtr)).Data)), cgoAllocsUnknown + cmessageSizesLen, cmessageSizesLenAllocMap := (C.size_t)(messageSizesLen), cgoAllocsUnknown + flattenedPublicKeysPtr = safeString(flattenedPublicKeysPtr) + cflattenedPublicKeysPtr, cflattenedPublicKeysPtrAllocMap := unpackPUint8TString(flattenedPublicKeysPtr) + cflattenedPublicKeysLen, cflattenedPublicKeysLenAllocMap := (C.size_t)(flattenedPublicKeysLen), cgoAllocsUnknown + __ret := C.fil_hash_verify(csignaturePtr, cflattenedMessagesPtr, cflattenedMessagesLen, cmessageSizesPtr, cmessageSizesLen, cflattenedPublicKeysPtr, cflattenedPublicKeysLen) + runtime.KeepAlive(cflattenedPublicKeysLenAllocMap) + runtime.KeepAlive(flattenedPublicKeysPtr) + runtime.KeepAlive(cflattenedPublicKeysPtrAllocMap) + runtime.KeepAlive(cmessageSizesLenAllocMap) + runtime.KeepAlive(cmessageSizesPtrAllocMap) + runtime.KeepAlive(cflattenedMessagesLenAllocMap) + runtime.KeepAlive(flattenedMessagesPtr) + runtime.KeepAlive(cflattenedMessagesPtrAllocMap) + runtime.KeepAlive(signaturePtr) + runtime.KeepAlive(csignaturePtrAllocMap) + __v := (int32)(__ret) + return __v +} + +// FilInitLogFd function as declared in filecoin-ffi/filcrypto.h:524 +func FilInitLogFd(logFd int32) *FilInitLogFdResponse { + clogFd, clogFdAllocMap := (C.int)(logFd), cgoAllocsUnknown + __ret := C.fil_init_log_fd(clogFd) + runtime.KeepAlive(clogFdAllocMap) + __v := NewFilInitLogFdResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilPrivateKeyGenerate function as declared in filecoin-ffi/filcrypto.h:529 +func FilPrivateKeyGenerate() *FilPrivateKeyGenerateResponse { + __ret := C.fil_private_key_generate() + __v := NewFilPrivateKeyGenerateResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilPrivateKeyGenerateWithSeed function as declared in filecoin-ffi/filcrypto.h:542 +func FilPrivateKeyGenerateWithSeed(rawSeed Fil32ByteArray) *FilPrivateKeyGenerateResponse { + crawSeed, crawSeedAllocMap := rawSeed.PassValue() + __ret := C.fil_private_key_generate_with_seed(crawSeed) + runtime.KeepAlive(crawSeedAllocMap) + __v := NewFilPrivateKeyGenerateResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilPrivateKeyPublicKey function as declared in filecoin-ffi/filcrypto.h:553 +func FilPrivateKeyPublicKey(rawPrivateKeyPtr string) *FilPrivateKeyPublicKeyResponse { + rawPrivateKeyPtr = safeString(rawPrivateKeyPtr) + crawPrivateKeyPtr, crawPrivateKeyPtrAllocMap := unpackPUint8TString(rawPrivateKeyPtr) + __ret := C.fil_private_key_public_key(crawPrivateKeyPtr) + runtime.KeepAlive(rawPrivateKeyPtr) + runtime.KeepAlive(crawPrivateKeyPtrAllocMap) + __v := NewFilPrivateKeyPublicKeyResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilPrivateKeySign function as declared in filecoin-ffi/filcrypto.h:566 +func FilPrivateKeySign(rawPrivateKeyPtr string, messagePtr string, messageLen uint) *FilPrivateKeySignResponse { + rawPrivateKeyPtr = safeString(rawPrivateKeyPtr) + crawPrivateKeyPtr, crawPrivateKeyPtrAllocMap := unpackPUint8TString(rawPrivateKeyPtr) + messagePtr = safeString(messagePtr) + cmessagePtr, cmessagePtrAllocMap := unpackPUint8TString(messagePtr) + cmessageLen, cmessageLenAllocMap := (C.size_t)(messageLen), cgoAllocsUnknown + __ret := C.fil_private_key_sign(crawPrivateKeyPtr, cmessagePtr, cmessageLen) + runtime.KeepAlive(cmessageLenAllocMap) + runtime.KeepAlive(messagePtr) + runtime.KeepAlive(cmessagePtrAllocMap) + runtime.KeepAlive(rawPrivateKeyPtr) + runtime.KeepAlive(crawPrivateKeyPtrAllocMap) + __v := NewFilPrivateKeySignResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilSealCommitPhase1 function as declared in filecoin-ffi/filcrypto.h:574 +func FilSealCommitPhase1(registeredProof FilRegisteredSealProof, commR Fil32ByteArray, commD Fil32ByteArray, cacheDirPath string, replicaPath string, sectorId uint64, proverId Fil32ByteArray, ticket Fil32ByteArray, seed Fil32ByteArray, piecesPtr []FilPublicPieceInfo, piecesLen uint) *FilSealCommitPhase1Response { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + ccommR, ccommRAllocMap := commR.PassValue() + ccommD, ccommDAllocMap := commD.PassValue() + cacheDirPath = safeString(cacheDirPath) + ccacheDirPath, ccacheDirPathAllocMap := unpackPCharString(cacheDirPath) + replicaPath = safeString(replicaPath) + creplicaPath, creplicaPathAllocMap := unpackPCharString(replicaPath) + csectorId, csectorIdAllocMap := (C.uint64_t)(sectorId), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + cticket, cticketAllocMap := ticket.PassValue() + cseed, cseedAllocMap := seed.PassValue() + cpiecesPtr, cpiecesPtrAllocMap := unpackArgSFilPublicPieceInfo(piecesPtr) + cpiecesLen, cpiecesLenAllocMap := (C.size_t)(piecesLen), cgoAllocsUnknown + __ret := C.fil_seal_commit_phase1(cregisteredProof, ccommR, ccommD, ccacheDirPath, creplicaPath, csectorId, cproverId, cticket, cseed, cpiecesPtr, cpiecesLen) + runtime.KeepAlive(cpiecesLenAllocMap) + packSFilPublicPieceInfo(piecesPtr, cpiecesPtr) + runtime.KeepAlive(cpiecesPtrAllocMap) + runtime.KeepAlive(cseedAllocMap) + runtime.KeepAlive(cticketAllocMap) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(csectorIdAllocMap) + runtime.KeepAlive(replicaPath) + runtime.KeepAlive(creplicaPathAllocMap) + runtime.KeepAlive(cacheDirPath) + runtime.KeepAlive(ccacheDirPathAllocMap) + runtime.KeepAlive(ccommDAllocMap) + runtime.KeepAlive(ccommRAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilSealCommitPhase1ResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilSealCommitPhase2 function as declared in filecoin-ffi/filcrypto.h:586 +func FilSealCommitPhase2(sealCommitPhase1OutputPtr string, sealCommitPhase1OutputLen uint, sectorId uint64, proverId Fil32ByteArray) *FilSealCommitPhase2Response { + sealCommitPhase1OutputPtr = safeString(sealCommitPhase1OutputPtr) + csealCommitPhase1OutputPtr, csealCommitPhase1OutputPtrAllocMap := unpackPUint8TString(sealCommitPhase1OutputPtr) + csealCommitPhase1OutputLen, csealCommitPhase1OutputLenAllocMap := (C.size_t)(sealCommitPhase1OutputLen), cgoAllocsUnknown + csectorId, csectorIdAllocMap := (C.uint64_t)(sectorId), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + __ret := C.fil_seal_commit_phase2(csealCommitPhase1OutputPtr, csealCommitPhase1OutputLen, csectorId, cproverId) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(csectorIdAllocMap) + runtime.KeepAlive(csealCommitPhase1OutputLenAllocMap) + runtime.KeepAlive(sealCommitPhase1OutputPtr) + runtime.KeepAlive(csealCommitPhase1OutputPtrAllocMap) + __v := NewFilSealCommitPhase2ResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilSealPreCommitPhase1 function as declared in filecoin-ffi/filcrypto.h:595 +func FilSealPreCommitPhase1(registeredProof FilRegisteredSealProof, cacheDirPath string, stagedSectorPath string, sealedSectorPath string, sectorId uint64, proverId Fil32ByteArray, ticket Fil32ByteArray, piecesPtr []FilPublicPieceInfo, piecesLen uint) *FilSealPreCommitPhase1Response { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + cacheDirPath = safeString(cacheDirPath) + ccacheDirPath, ccacheDirPathAllocMap := unpackPCharString(cacheDirPath) + stagedSectorPath = safeString(stagedSectorPath) + cstagedSectorPath, cstagedSectorPathAllocMap := unpackPCharString(stagedSectorPath) + sealedSectorPath = safeString(sealedSectorPath) + csealedSectorPath, csealedSectorPathAllocMap := unpackPCharString(sealedSectorPath) + csectorId, csectorIdAllocMap := (C.uint64_t)(sectorId), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + cticket, cticketAllocMap := ticket.PassValue() + cpiecesPtr, cpiecesPtrAllocMap := unpackArgSFilPublicPieceInfo(piecesPtr) + cpiecesLen, cpiecesLenAllocMap := (C.size_t)(piecesLen), cgoAllocsUnknown + __ret := C.fil_seal_pre_commit_phase1(cregisteredProof, ccacheDirPath, cstagedSectorPath, csealedSectorPath, csectorId, cproverId, cticket, cpiecesPtr, cpiecesLen) + runtime.KeepAlive(cpiecesLenAllocMap) + packSFilPublicPieceInfo(piecesPtr, cpiecesPtr) + runtime.KeepAlive(cpiecesPtrAllocMap) + runtime.KeepAlive(cticketAllocMap) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(csectorIdAllocMap) + runtime.KeepAlive(sealedSectorPath) + runtime.KeepAlive(csealedSectorPathAllocMap) + runtime.KeepAlive(stagedSectorPath) + runtime.KeepAlive(cstagedSectorPathAllocMap) + runtime.KeepAlive(cacheDirPath) + runtime.KeepAlive(ccacheDirPathAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilSealPreCommitPhase1ResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilSealPreCommitPhase2 function as declared in filecoin-ffi/filcrypto.h:609 +func FilSealPreCommitPhase2(sealPreCommitPhase1OutputPtr string, sealPreCommitPhase1OutputLen uint, cacheDirPath string, sealedSectorPath string) *FilSealPreCommitPhase2Response { + sealPreCommitPhase1OutputPtr = safeString(sealPreCommitPhase1OutputPtr) + csealPreCommitPhase1OutputPtr, csealPreCommitPhase1OutputPtrAllocMap := unpackPUint8TString(sealPreCommitPhase1OutputPtr) + csealPreCommitPhase1OutputLen, csealPreCommitPhase1OutputLenAllocMap := (C.size_t)(sealPreCommitPhase1OutputLen), cgoAllocsUnknown + cacheDirPath = safeString(cacheDirPath) + ccacheDirPath, ccacheDirPathAllocMap := unpackPCharString(cacheDirPath) + sealedSectorPath = safeString(sealedSectorPath) + csealedSectorPath, csealedSectorPathAllocMap := unpackPCharString(sealedSectorPath) + __ret := C.fil_seal_pre_commit_phase2(csealPreCommitPhase1OutputPtr, csealPreCommitPhase1OutputLen, ccacheDirPath, csealedSectorPath) + runtime.KeepAlive(sealedSectorPath) + runtime.KeepAlive(csealedSectorPathAllocMap) + runtime.KeepAlive(cacheDirPath) + runtime.KeepAlive(ccacheDirPathAllocMap) + runtime.KeepAlive(csealPreCommitPhase1OutputLenAllocMap) + runtime.KeepAlive(sealPreCommitPhase1OutputPtr) + runtime.KeepAlive(csealPreCommitPhase1OutputPtrAllocMap) + __v := NewFilSealPreCommitPhase2ResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilUnsealRange function as declared in filecoin-ffi/filcrypto.h:617 +func FilUnsealRange(registeredProof FilRegisteredSealProof, cacheDirPath string, sealedSectorFdRaw int32, unsealOutputFdRaw int32, sectorId uint64, proverId Fil32ByteArray, ticket Fil32ByteArray, commD Fil32ByteArray, unpaddedByteIndex uint64, unpaddedBytesAmount uint64) *FilUnsealRangeResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + cacheDirPath = safeString(cacheDirPath) + ccacheDirPath, ccacheDirPathAllocMap := unpackPCharString(cacheDirPath) + csealedSectorFdRaw, csealedSectorFdRawAllocMap := (C.int)(sealedSectorFdRaw), cgoAllocsUnknown + cunsealOutputFdRaw, cunsealOutputFdRawAllocMap := (C.int)(unsealOutputFdRaw), cgoAllocsUnknown + csectorId, csectorIdAllocMap := (C.uint64_t)(sectorId), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + cticket, cticketAllocMap := ticket.PassValue() + ccommD, ccommDAllocMap := commD.PassValue() + cunpaddedByteIndex, cunpaddedByteIndexAllocMap := (C.uint64_t)(unpaddedByteIndex), cgoAllocsUnknown + cunpaddedBytesAmount, cunpaddedBytesAmountAllocMap := (C.uint64_t)(unpaddedBytesAmount), cgoAllocsUnknown + __ret := C.fil_unseal_range(cregisteredProof, ccacheDirPath, csealedSectorFdRaw, cunsealOutputFdRaw, csectorId, cproverId, cticket, ccommD, cunpaddedByteIndex, cunpaddedBytesAmount) + runtime.KeepAlive(cunpaddedBytesAmountAllocMap) + runtime.KeepAlive(cunpaddedByteIndexAllocMap) + runtime.KeepAlive(ccommDAllocMap) + runtime.KeepAlive(cticketAllocMap) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(csectorIdAllocMap) + runtime.KeepAlive(cunsealOutputFdRawAllocMap) + runtime.KeepAlive(csealedSectorFdRawAllocMap) + runtime.KeepAlive(cacheDirPath) + runtime.KeepAlive(ccacheDirPathAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilUnsealRangeResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilVerify function as declared in filecoin-ffi/filcrypto.h:639 +func FilVerify(signaturePtr string, flattenedDigestsPtr string, flattenedDigestsLen uint, flattenedPublicKeysPtr string, flattenedPublicKeysLen uint) int32 { + signaturePtr = safeString(signaturePtr) + csignaturePtr, csignaturePtrAllocMap := unpackPUint8TString(signaturePtr) + flattenedDigestsPtr = safeString(flattenedDigestsPtr) + cflattenedDigestsPtr, cflattenedDigestsPtrAllocMap := unpackPUint8TString(flattenedDigestsPtr) + cflattenedDigestsLen, cflattenedDigestsLenAllocMap := (C.size_t)(flattenedDigestsLen), cgoAllocsUnknown + flattenedPublicKeysPtr = safeString(flattenedPublicKeysPtr) + cflattenedPublicKeysPtr, cflattenedPublicKeysPtrAllocMap := unpackPUint8TString(flattenedPublicKeysPtr) + cflattenedPublicKeysLen, cflattenedPublicKeysLenAllocMap := (C.size_t)(flattenedPublicKeysLen), cgoAllocsUnknown + __ret := C.fil_verify(csignaturePtr, cflattenedDigestsPtr, cflattenedDigestsLen, cflattenedPublicKeysPtr, cflattenedPublicKeysLen) + runtime.KeepAlive(cflattenedPublicKeysLenAllocMap) + runtime.KeepAlive(flattenedPublicKeysPtr) + runtime.KeepAlive(cflattenedPublicKeysPtrAllocMap) + runtime.KeepAlive(cflattenedDigestsLenAllocMap) + runtime.KeepAlive(flattenedDigestsPtr) + runtime.KeepAlive(cflattenedDigestsPtrAllocMap) + runtime.KeepAlive(signaturePtr) + runtime.KeepAlive(csignaturePtrAllocMap) + __v := (int32)(__ret) + return __v +} + +// FilVerifySeal function as declared in filecoin-ffi/filcrypto.h:649 +func FilVerifySeal(registeredProof FilRegisteredSealProof, commR Fil32ByteArray, commD Fil32ByteArray, proverId Fil32ByteArray, ticket Fil32ByteArray, seed Fil32ByteArray, sectorId uint64, proofPtr string, proofLen uint) *FilVerifySealResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + ccommR, ccommRAllocMap := commR.PassValue() + ccommD, ccommDAllocMap := commD.PassValue() + cproverId, cproverIdAllocMap := proverId.PassValue() + cticket, cticketAllocMap := ticket.PassValue() + cseed, cseedAllocMap := seed.PassValue() + csectorId, csectorIdAllocMap := (C.uint64_t)(sectorId), cgoAllocsUnknown + proofPtr = safeString(proofPtr) + cproofPtr, cproofPtrAllocMap := unpackPUint8TString(proofPtr) + cproofLen, cproofLenAllocMap := (C.size_t)(proofLen), cgoAllocsUnknown + __ret := C.fil_verify_seal(cregisteredProof, ccommR, ccommD, cproverId, cticket, cseed, csectorId, cproofPtr, cproofLen) + runtime.KeepAlive(cproofLenAllocMap) + runtime.KeepAlive(proofPtr) + runtime.KeepAlive(cproofPtrAllocMap) + runtime.KeepAlive(csectorIdAllocMap) + runtime.KeepAlive(cseedAllocMap) + runtime.KeepAlive(cticketAllocMap) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(ccommDAllocMap) + runtime.KeepAlive(ccommRAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilVerifySealResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilVerifyWindowPost function as declared in filecoin-ffi/filcrypto.h:662 +func FilVerifyWindowPost(randomness Fil32ByteArray, replicasPtr []FilPublicReplicaInfo, replicasLen uint, proofsPtr []FilPoStProof, proofsLen uint, proverId Fil32ByteArray) *FilVerifyWindowPoStResponse { + crandomness, crandomnessAllocMap := randomness.PassValue() + creplicasPtr, creplicasPtrAllocMap := unpackArgSFilPublicReplicaInfo(replicasPtr) + creplicasLen, creplicasLenAllocMap := (C.size_t)(replicasLen), cgoAllocsUnknown + cproofsPtr, cproofsPtrAllocMap := unpackArgSFilPoStProof(proofsPtr) + cproofsLen, cproofsLenAllocMap := (C.size_t)(proofsLen), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + __ret := C.fil_verify_window_post(crandomness, creplicasPtr, creplicasLen, cproofsPtr, cproofsLen, cproverId) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(cproofsLenAllocMap) + packSFilPoStProof(proofsPtr, cproofsPtr) + runtime.KeepAlive(cproofsPtrAllocMap) + runtime.KeepAlive(creplicasLenAllocMap) + packSFilPublicReplicaInfo(replicasPtr, creplicasPtr) + runtime.KeepAlive(creplicasPtrAllocMap) + runtime.KeepAlive(crandomnessAllocMap) + __v := NewFilVerifyWindowPoStResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilVerifyWinningPost function as declared in filecoin-ffi/filcrypto.h:672 +func FilVerifyWinningPost(randomness Fil32ByteArray, replicasPtr []FilPublicReplicaInfo, replicasLen uint, proofsPtr []FilPoStProof, proofsLen uint, proverId Fil32ByteArray) *FilVerifyWinningPoStResponse { + crandomness, crandomnessAllocMap := randomness.PassValue() + creplicasPtr, creplicasPtrAllocMap := unpackArgSFilPublicReplicaInfo(replicasPtr) + creplicasLen, creplicasLenAllocMap := (C.size_t)(replicasLen), cgoAllocsUnknown + cproofsPtr, cproofsPtrAllocMap := unpackArgSFilPoStProof(proofsPtr) + cproofsLen, cproofsLenAllocMap := (C.size_t)(proofsLen), cgoAllocsUnknown + cproverId, cproverIdAllocMap := proverId.PassValue() + __ret := C.fil_verify_winning_post(crandomness, creplicasPtr, creplicasLen, cproofsPtr, cproofsLen, cproverId) + runtime.KeepAlive(cproverIdAllocMap) + runtime.KeepAlive(cproofsLenAllocMap) + packSFilPoStProof(proofsPtr, cproofsPtr) + runtime.KeepAlive(cproofsPtrAllocMap) + runtime.KeepAlive(creplicasLenAllocMap) + packSFilPublicReplicaInfo(replicasPtr, creplicasPtr) + runtime.KeepAlive(creplicasPtrAllocMap) + runtime.KeepAlive(crandomnessAllocMap) + __v := NewFilVerifyWinningPoStResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilWriteWithAlignment function as declared in filecoin-ffi/filcrypto.h:683 +func FilWriteWithAlignment(registeredProof FilRegisteredSealProof, srcFd int32, srcSize uint64, dstFd int32, existingPieceSizesPtr []uint64, existingPieceSizesLen uint) *FilWriteWithAlignmentResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + csrcFd, csrcFdAllocMap := (C.int)(srcFd), cgoAllocsUnknown + csrcSize, csrcSizeAllocMap := (C.uint64_t)(srcSize), cgoAllocsUnknown + cdstFd, cdstFdAllocMap := (C.int)(dstFd), cgoAllocsUnknown + cexistingPieceSizesPtr, cexistingPieceSizesPtrAllocMap := (*C.uint64_t)(unsafe.Pointer((*sliceHeader)(unsafe.Pointer(&existingPieceSizesPtr)).Data)), cgoAllocsUnknown + cexistingPieceSizesLen, cexistingPieceSizesLenAllocMap := (C.size_t)(existingPieceSizesLen), cgoAllocsUnknown + __ret := C.fil_write_with_alignment(cregisteredProof, csrcFd, csrcSize, cdstFd, cexistingPieceSizesPtr, cexistingPieceSizesLen) + runtime.KeepAlive(cexistingPieceSizesLenAllocMap) + runtime.KeepAlive(cexistingPieceSizesPtrAllocMap) + runtime.KeepAlive(cdstFdAllocMap) + runtime.KeepAlive(csrcSizeAllocMap) + runtime.KeepAlive(csrcFdAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilWriteWithAlignmentResponseRef(unsafe.Pointer(__ret)) + return __v +} + +// FilWriteWithoutAlignment function as declared in filecoin-ffi/filcrypto.h:694 +func FilWriteWithoutAlignment(registeredProof FilRegisteredSealProof, srcFd int32, srcSize uint64, dstFd int32) *FilWriteWithoutAlignmentResponse { + cregisteredProof, cregisteredProofAllocMap := (C.fil_RegisteredSealProof)(registeredProof), cgoAllocsUnknown + csrcFd, csrcFdAllocMap := (C.int)(srcFd), cgoAllocsUnknown + csrcSize, csrcSizeAllocMap := (C.uint64_t)(srcSize), cgoAllocsUnknown + cdstFd, cdstFdAllocMap := (C.int)(dstFd), cgoAllocsUnknown + __ret := C.fil_write_without_alignment(cregisteredProof, csrcFd, csrcSize, cdstFd) + runtime.KeepAlive(cdstFdAllocMap) + runtime.KeepAlive(csrcSizeAllocMap) + runtime.KeepAlive(csrcFdAllocMap) + runtime.KeepAlive(cregisteredProofAllocMap) + __v := NewFilWriteWithoutAlignmentResponseRef(unsafe.Pointer(__ret)) + return __v +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/types.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/types.go new file mode 100644 index 0000000000..6e26e56efe --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/generated/types.go @@ -0,0 +1,319 @@ +// WARNING: This file has automatically been generated +// Code generated by https://git.io/c-for-go. DO NOT EDIT. + +package generated + +/* +#cgo LDFLAGS: -L${SRCDIR}/.. -lfilcrypto +#cgo pkg-config: ${SRCDIR}/../filcrypto.pc +#include "../filcrypto.h" +#include +#include "cgo_helpers.h" +*/ +import "C" + +// FilBLSSignature as declared in filecoin-ffi/filcrypto.h:56 +type FilBLSSignature struct { + Inner [96]byte + refa2ac09ba *C.fil_BLSSignature + allocsa2ac09ba interface{} +} + +// FilAggregateResponse as declared in filecoin-ffi/filcrypto.h:63 +type FilAggregateResponse struct { + Signature FilBLSSignature + refb3efa36d *C.fil_AggregateResponse + allocsb3efa36d interface{} +} + +// FilClearCacheResponse as declared in filecoin-ffi/filcrypto.h:68 +type FilClearCacheResponse struct { + ErrorMsg string + StatusCode FCPResponseStatus + refa9a80400 *C.fil_ClearCacheResponse + allocsa9a80400 interface{} +} + +// FilFauxRepResponse as declared in filecoin-ffi/filcrypto.h:74 +type FilFauxRepResponse struct { + ErrorMsg string + StatusCode FCPResponseStatus + Commitment [32]byte + refaa003f71 *C.fil_FauxRepResponse + allocsaa003f71 interface{} +} + +// FilFinalizeTicketResponse as declared in filecoin-ffi/filcrypto.h:80 +type FilFinalizeTicketResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + Ticket [32]byte + refb370fa86 *C.fil_FinalizeTicketResponse + allocsb370fa86 interface{} +} + +// FilGenerateDataCommitmentResponse as declared in filecoin-ffi/filcrypto.h:86 +type FilGenerateDataCommitmentResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + CommD [32]byte + ref87da7dd9 *C.fil_GenerateDataCommitmentResponse + allocs87da7dd9 interface{} +} + +// FilGeneratePieceCommitmentResponse as declared in filecoin-ffi/filcrypto.h:97 +type FilGeneratePieceCommitmentResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + CommP [32]byte + NumBytesAligned uint64 + ref4b00fda4 *C.fil_GeneratePieceCommitmentResponse + allocs4b00fda4 interface{} +} + +// FilPoStProof as declared in filecoin-ffi/filcrypto.h:103 +type FilPoStProof struct { + RegisteredProof FilRegisteredPoStProof + ProofLen uint + ProofPtr string + ref3451bfa *C.fil_PoStProof + allocs3451bfa interface{} +} + +// FilGenerateWindowPoStResponse as declared in filecoin-ffi/filcrypto.h:110 +type FilGenerateWindowPoStResponse struct { + ErrorMsg string + ProofsLen uint + ProofsPtr []FilPoStProof + StatusCode FCPResponseStatus + ref2a5f3ba8 *C.fil_GenerateWindowPoStResponse + allocs2a5f3ba8 interface{} +} + +// FilGenerateWinningPoStResponse as declared in filecoin-ffi/filcrypto.h:117 +type FilGenerateWinningPoStResponse struct { + ErrorMsg string + ProofsLen uint + ProofsPtr []FilPoStProof + StatusCode FCPResponseStatus + ref1405b8ec *C.fil_GenerateWinningPoStResponse + allocs1405b8ec interface{} +} + +// FilGenerateWinningPoStSectorChallenge as declared in filecoin-ffi/filcrypto.h:124 +type FilGenerateWinningPoStSectorChallenge struct { + ErrorMsg string + StatusCode FCPResponseStatus + IdsPtr []uint64 + IdsLen uint + ref69d2a405 *C.fil_GenerateWinningPoStSectorChallenge + allocs69d2a405 interface{} +} + +// FilGpuDeviceResponse as declared in filecoin-ffi/filcrypto.h:131 +type FilGpuDeviceResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + DevicesLen uint + DevicesPtr []string + ref58f92915 *C.fil_GpuDeviceResponse + allocs58f92915 interface{} +} + +// FilBLSDigest as declared in filecoin-ffi/filcrypto.h:135 +type FilBLSDigest struct { + Inner [96]byte + ref215fc78c *C.fil_BLSDigest + allocs215fc78c interface{} +} + +// FilHashResponse as declared in filecoin-ffi/filcrypto.h:142 +type FilHashResponse struct { + Digest FilBLSDigest + refc52a22ef *C.fil_HashResponse + allocsc52a22ef interface{} +} + +// FilInitLogFdResponse as declared in filecoin-ffi/filcrypto.h:147 +type FilInitLogFdResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + ref3c1a0a08 *C.fil_InitLogFdResponse + allocs3c1a0a08 interface{} +} + +// FilBLSPrivateKey as declared in filecoin-ffi/filcrypto.h:151 +type FilBLSPrivateKey struct { + Inner [32]byte + ref2f77fe3a *C.fil_BLSPrivateKey + allocs2f77fe3a interface{} +} + +// FilPrivateKeyGenerateResponse as declared in filecoin-ffi/filcrypto.h:158 +type FilPrivateKeyGenerateResponse struct { + PrivateKey FilBLSPrivateKey + ref2dba09f *C.fil_PrivateKeyGenerateResponse + allocs2dba09f interface{} +} + +// FilBLSPublicKey as declared in filecoin-ffi/filcrypto.h:162 +type FilBLSPublicKey struct { + Inner [48]byte + ref6d0cab13 *C.fil_BLSPublicKey + allocs6d0cab13 interface{} +} + +// FilPrivateKeyPublicKeyResponse as declared in filecoin-ffi/filcrypto.h:169 +type FilPrivateKeyPublicKeyResponse struct { + PublicKey FilBLSPublicKey + refee14e59d *C.fil_PrivateKeyPublicKeyResponse + allocsee14e59d interface{} +} + +// FilPrivateKeySignResponse as declared in filecoin-ffi/filcrypto.h:176 +type FilPrivateKeySignResponse struct { + Signature FilBLSSignature + refcdf97b28 *C.fil_PrivateKeySignResponse + allocscdf97b28 interface{} +} + +// FilSealCommitPhase1Response as declared in filecoin-ffi/filcrypto.h:183 +type FilSealCommitPhase1Response struct { + StatusCode FCPResponseStatus + ErrorMsg string + SealCommitPhase1OutputPtr string + SealCommitPhase1OutputLen uint + ref61ed8561 *C.fil_SealCommitPhase1Response + allocs61ed8561 interface{} +} + +// FilSealCommitPhase2Response as declared in filecoin-ffi/filcrypto.h:190 +type FilSealCommitPhase2Response struct { + StatusCode FCPResponseStatus + ErrorMsg string + ProofPtr string + ProofLen uint + ref5860b9a4 *C.fil_SealCommitPhase2Response + allocs5860b9a4 interface{} +} + +// FilSealPreCommitPhase1Response as declared in filecoin-ffi/filcrypto.h:197 +type FilSealPreCommitPhase1Response struct { + ErrorMsg string + StatusCode FCPResponseStatus + SealPreCommitPhase1OutputPtr string + SealPreCommitPhase1OutputLen uint + ref132bbfd8 *C.fil_SealPreCommitPhase1Response + allocs132bbfd8 interface{} +} + +// FilSealPreCommitPhase2Response as declared in filecoin-ffi/filcrypto.h:205 +type FilSealPreCommitPhase2Response struct { + ErrorMsg string + StatusCode FCPResponseStatus + RegisteredProof FilRegisteredSealProof + CommD [32]byte + CommR [32]byte + ref2aa6831d *C.fil_SealPreCommitPhase2Response + allocs2aa6831d interface{} +} + +// FilStringResponse as declared in filecoin-ffi/filcrypto.h:214 +type FilStringResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + StringVal string + ref4f413043 *C.fil_StringResponse + allocs4f413043 interface{} +} + +// FilUnsealRangeResponse as declared in filecoin-ffi/filcrypto.h:219 +type FilUnsealRangeResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + ref61e219c9 *C.fil_UnsealRangeResponse + allocs61e219c9 interface{} +} + +// FilVerifySealResponse as declared in filecoin-ffi/filcrypto.h:225 +type FilVerifySealResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + IsValid bool + refd4397079 *C.fil_VerifySealResponse + allocsd4397079 interface{} +} + +// FilVerifyWindowPoStResponse as declared in filecoin-ffi/filcrypto.h:231 +type FilVerifyWindowPoStResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + IsValid bool + ref34c4d49f *C.fil_VerifyWindowPoStResponse + allocs34c4d49f interface{} +} + +// FilVerifyWinningPoStResponse as declared in filecoin-ffi/filcrypto.h:237 +type FilVerifyWinningPoStResponse struct { + StatusCode FCPResponseStatus + ErrorMsg string + IsValid bool + refaca6860c *C.fil_VerifyWinningPoStResponse + allocsaca6860c interface{} +} + +// FilWriteWithAlignmentResponse as declared in filecoin-ffi/filcrypto.h:245 +type FilWriteWithAlignmentResponse struct { + CommP [32]byte + ErrorMsg string + LeftAlignmentUnpadded uint64 + StatusCode FCPResponseStatus + TotalWriteUnpadded uint64 + refa330e79 *C.fil_WriteWithAlignmentResponse + allocsa330e79 interface{} +} + +// FilWriteWithoutAlignmentResponse as declared in filecoin-ffi/filcrypto.h:252 +type FilWriteWithoutAlignmentResponse struct { + CommP [32]byte + ErrorMsg string + StatusCode FCPResponseStatus + TotalWriteUnpadded uint64 + refc8e1ed8 *C.fil_WriteWithoutAlignmentResponse + allocsc8e1ed8 interface{} +} + +// FilPublicPieceInfo as declared in filecoin-ffi/filcrypto.h:257 +type FilPublicPieceInfo struct { + NumBytes uint64 + CommP [32]byte + refd00025ac *C.fil_PublicPieceInfo + allocsd00025ac interface{} +} + +// Fil32ByteArray as declared in filecoin-ffi/filcrypto.h:261 +type Fil32ByteArray struct { + Inner [32]byte + ref373ec61a *C.fil_32ByteArray + allocs373ec61a interface{} +} + +// FilPrivateReplicaInfo as declared in filecoin-ffi/filcrypto.h:269 +type FilPrivateReplicaInfo struct { + RegisteredProof FilRegisteredPoStProof + CacheDirPath string + CommR [32]byte + ReplicaPath string + SectorId uint64 + ref81a31e9b *C.fil_PrivateReplicaInfo + allocs81a31e9b interface{} +} + +// FilPublicReplicaInfo as declared in filecoin-ffi/filcrypto.h:275 +type FilPublicReplicaInfo struct { + RegisteredProof FilRegisteredPoStProof + CommR [32]byte + SectorId uint64 + ref81b617c2 *C.fil_PublicReplicaInfo + allocs81b617c2 interface{} +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.mod b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.mod new file mode 100644 index 0000000000..8a09431b5d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.mod @@ -0,0 +1,12 @@ +module github.com/filecoin-project/filecoin-ffi + +go 1.13 + +require ( + github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be + github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5 + github.com/filecoin-project/specs-actors v0.6.1 + github.com/ipfs/go-cid v0.0.5 + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.4.0 +) diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.sum b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.sum new file mode 100644 index 0000000000..c78bf10e6f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/go.sum @@ -0,0 +1,147 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be h1:TooKBwR/g8jG0hZ3lqe9S5sy2vTUcLOZLlz3M5wGn2E= +github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-bitfield v0.0.1 h1:Xg/JnrqqE77aJVKdbEyR04n9FZQWhwrN+buDgQCVpZU= +github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= +github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5 h1:yvQJCW9mmi9zy+51xA01Ea2X7/dL7r8eKDPuGUjRmbo= +github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= +github.com/filecoin-project/specs-actors v0.6.1 h1:rhHlEzqcuuQU6oKc4csuq+/kQBDZ4EXtSomoN2XApCA= +github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.4 h1:Aw3KPOKXjvrm6VjwJvFf1F1ekR/BH3jdof3Bk7OTiSA= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= +github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-varint v0.0.2 h1:6sUvyh2YHpJCb8RZ6eYzj6iJQ4+chWYmyIHxszqlPTA= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1 h1:CskT+S6Ay54OwxBGB0R3Rsx4Muto6UnEYTyKJbyRIAI= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e h1:JY8o/ebUUrCYetWmjRCNghxC59cOEaili83rxPRQCLw= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/install-filcrypto b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/install-filcrypto new file mode 100755 index 0000000000..294e6ccb93 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/install-filcrypto @@ -0,0 +1,216 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2155 enable=require-variable-braces + +set -Exeo pipefail +auth_header=() +if [ -n "${GITHUB_TOKEN}" ]; then + auth_header=("-H" "Authorization: token ${GITHUB_TOKEN}") +fi + +# set CWD to the root of filecoin-ffi +# +cd "$(dirname "${BASH_SOURCE[0]}")" + +# tracks where the Rust sources are were we to build locally instead of +# downloading from GitHub Releases +# +rust_sources_dir="rust" + +# an array of values passed as 'target-feature' to the Rust compiler if we're +# building an optimized libfilcrypto (which takes advantage of some perf-boosting +# instruction sets) +# +optimized_release_rustc_target_features=$(jq -r '.[].rustc_target_feature' < "${rust_sources_dir}/rustc-target-features-optimized.json") + +# each value in this area is checked against the "features" of the hosts CPU +# in order to determine if the host is suitable for an optimized release +# +cpu_features_required_for_optimized_release=$(jq -r '.[].check_cpu_for_feature | select(. != null)' < "${rust_sources_dir}/rustc-target-features-optimized.json") + +main() { + local __release_type=$(get_release_type) + if [ "${FFI_BUILD_FROM_SOURCE}" != "1" ] && download_release_tarball __tarball_path "${rust_sources_dir}" "filecoin-ffi" "${__release_type}"; then + local __tmp_dir=$(mktemp -d) + + # silence shellcheck warning as the assignment happened in + # `download_release_tarball()` + # shellcheck disable=SC2154 + # extract downloaded tarball to temporary directory + # + tar -C "${__tmp_dir}" -xzf "${__tarball_path}" + + # copy build assets into root of filecoin-ffi + # + find -L "${__tmp_dir}" -type f -name filcrypto.h -exec cp -- "{}" . \; + find -L "${__tmp_dir}" -type f -name libfilcrypto.a -exec cp -- "{}" . \; + find -L "${__tmp_dir}" -type f -name filcrypto.pc -exec cp -- "{}" . \; + + check_installed_files + + (>&2 echo "[install-filcrypto/main] successfully installed prebuilt libfilcrypto") + else + (>&2 echo "[install-filcrypto/main] building libfilcrypto from local sources (dir = ${rust_sources_dir})") + + # build libfilcrypto (and corresponding header and pkg-config) + # + build_from_source "filcrypto" "${rust_sources_dir}" "${__release_type}" + + # copy from Rust's build directory (target) to root of filecoin-ffi + # + find -L "${rust_sources_dir}/target/release" -type f -name filcrypto.h -exec cp -- "{}" . \; + find -L "${rust_sources_dir}/target/release" -type f -name libfilcrypto.a -exec cp -- "{}" . \; + find -L "${rust_sources_dir}" -type f -name filcrypto.pc -exec cp -- "{}" . \; + + check_installed_files + + (>&2 echo "[install-filcrypto/main] successfully built and installed libfilcrypto from source") + fi +} + +download_release_tarball() { + local __resultvar=$1 + local __rust_sources_path=$2 + local __repo_name=$3 + local __release_type=$4 + local __release_sha1=$(git rev-parse HEAD) + local __release_tag="${__release_sha1:0:16}" + local __release_tag_url="https://api.github.com/repos/filecoin-project/${__repo_name}/releases/tags/${__release_tag}" + + # TODO: This function shouldn't make assumptions about how these releases' + # names are constructed. Marginally less-bad would be to require that this + # function's caller provide the release name. + # + local __release_name="${__repo_name}-$(uname)-${__release_type}" + + (>&2 echo "[download_release_tarball] acquiring release @ ${__release_tag}") + + local __release_response=$(curl "${auth_header[@]}" \ + --retry 3 \ + --location "${__release_tag_url}") + + local __release_url=$(echo "${__release_response}" | jq -r ".assets[] | select(.name | contains(\"${__release_name}\")) | .url") + + local __tar_path="/tmp/${__release_name}_$(basename "${__release_url}").tar.gz" + + if [[ -z "${__release_url}" ]]; then + (>&2 echo "[download_release_tarball] failed to download release (tag URL: ${__release_tag_url}, response: ${__release_response})") + return 1 + fi + + local __asset_url=$(curl "${auth_header[@]}" \ + --head \ + --retry 3 \ + --header "Accept:application/octet-stream" \ + --location \ + --output /dev/null \ + -w "%{url_effective}" \ + "${__release_url}") + + if ! curl --retry 3 --output "${__tar_path}" "${__asset_url}"; then + (>&2 echo "[download_release_tarball] failed to download release asset (tag URL: ${__release_tag_url}, asset URL: ${__asset_url})") + return 1 + fi + + # set $__resultvar (which the caller provided as $1), which is the poor + # man's way of returning a value from a function in Bash + # + eval "${__resultvar}='${__tar_path}'" +} + +build_from_source() { + local __library_name=$1 + local __rust_sources_path=$2 + local __release_type=$3 + local __repo_sha1=$(git rev-parse HEAD) + local __repo_sha1_truncated="${__repo_sha1:0:16}" + local __target_feature="" + + (>&2 echo "building from source @ ${__repo_sha1_truncated}") + + if ! [ -x "$(command -v cargo)" ]; then + (>&2 echo '[build_from_source] Error: cargo is not installed.') + (>&2 echo '[build_from_source] install Rust toolchain to resolve this problem.') + exit 1 + fi + + if ! [ -x "$(command -v rustup)" ]; then + (>&2 echo '[build_from_source] Error: rustup is not installed.') + (>&2 echo '[build_from_source] install Rust toolchain installer to resolve this problem.') + exit 1 + fi + + pushd "${__rust_sources_path}" + + cargo --version + + # reduce array of features into the rustc-specific 'target-feature' flag + # shellcheck disable=SC2068 # the splitting is intentional + for x in ${optimized_release_rustc_target_features[@]}; do + __target_feature="${x},${__target_feature}" + done + + if [ "${__release_type}" = "optimized" ]; then + RUSTFLAGS="-C target-feature=${__target_feature}" ./scripts/build-release.sh "${__library_name}" "$(cat rust-toolchain)" + else + ./scripts/build-release.sh "${__library_name}" "$(cat rust-toolchain)" + fi + + popd +} + +get_release_type() { + local __searched="" + local __features="" + local __optimized=true + + # determine where to look for CPU features + # + if [[ ! -f "/proc/cpuinfo" ]]; then + (>&2 echo "[get_release_type] no /proc/cpuinfo file; falling back to Darwin feature detection") + __searched="sysctl -a | grep machdep.cpu | tr '[:upper:]' '[:lower:]' | grep features" + else + __searched="cat /proc/cpuinfo | grep flags" + fi + __features=$(eval "${__searched}") + + # check for the presence of each required CPU feature + # + # shellcheck disable=SC2068 # the splitting is intentional + for x in ${cpu_features_required_for_optimized_release[@]}; do + if [ "${__optimized}" = true ]; then + if [ -n "${__features##*${x}*}" ]; then + (>&2 echo "[get_release_type] your CPU does not support the '${x}' feature (searched '${__searched}')") + __optimized=false + fi + fi + done + + # if we couldn't figure out where to look for features, use standard + # + if [ "${__optimized}" == true ] && [ -n "${__features}" ]; then + (>&2 echo "[get_release_type] configuring 'optimized' build") + echo "optimized" + else + (>&2 echo "[get_release_type] configuring 'standard' build") + echo "standard" + fi +} + +check_installed_files() { + if [[ ! -f "./filcrypto.h" ]]; then + (>&2 echo "[check_installed_files] failed to install filcrypto.h") + exit 1 + fi + + if [[ ! -f "./libfilcrypto.a" ]]; then + (>&2 echo "[check_installed_files] failed to install libfilcrypto.a") + exit 1 + fi + + if [[ ! -f "./filcrypto.pc" ]]; then + (>&2 echo "[check_installed_files] failed to install filcrypto.pc") + exit 1 + fi +} + +main "$@"; exit diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/mkreleaselog b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/mkreleaselog new file mode 100755 index 0000000000..c108622899 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/mkreleaselog @@ -0,0 +1,240 @@ +#!/bin/zsh + +# Note: This script is a modified version of the mkreleaselog script used by +# the go-ipfs team. +# +# Usage: ./mkreleaselog v0.25.0 v0.26.0 > /tmp/release.log + +set -euo pipefail +export GO111MODULE=on +export GOPATH="$(go env GOPATH)" + +alias jq="jq --unbuffered" + +REPO_SUFFIXES_TO_STRIP=( + "/v2" + "/v3" + "/v4" + "/v5" + "/v6" +) + +AUTHORS=( + # orgs + filecoin-project + + # Authors of personal repos used by filecoin-ffi that should be mentioned in the + # release notes. + xlab +) + +[[ -n "${REPO_FILTER+x}" ]] || REPO_FILTER="github.com/(${$(printf "|%s" "${AUTHORS[@]}"):1})" + +[[ -n "${IGNORED_FILES+x}" ]] || IGNORED_FILES='^\(\.gx\|package\.json\|\.travis\.yml\|go.mod\|go\.sum|\.github|\.circleci\)$' + +NL=$'\n' + +msg() { + echo "$*" >&2 +} + +statlog() { + rpath="$GOPATH/src/$1" + for s in $REPO_SUFFIXES_TO_STRIP; do + rpath=${rpath%$s} + done + + start="${2:-}" + end="${3:-HEAD}" + + git -C "$rpath" log --shortstat --no-merges --pretty="tformat:%H%n%aN%n%aE" "$start..$end" | while + read hash + read name + read email + read _ # empty line + read changes + do + changed=0 + insertions=0 + deletions=0 + while read count event; do + if [[ "$event" =~ ^file ]]; then + changed=$count + elif [[ "$event" =~ ^insertion ]]; then + insertions=$count + elif [[ "$event" =~ ^deletion ]]; then + deletions=$count + else + echo "unknown event $event" >&2 + exit 1 + fi + done<<<"${changes//,/$NL}" + + jq -n \ + --arg "hash" "$hash" \ + --arg "name" "$name" \ + --arg "email" "$email" \ + --argjson "changed" "$changed" \ + --argjson "insertions" "$insertions" \ + --argjson "deletions" "$deletions" \ + '{Commit: $hash, Author: $name, Email: $email, Files: $changed, Insertions: $insertions, Deletions: $deletions}' + done +} + +# Returns a stream of deps changed between $1 and $2. +dep_changes() { + { + <"$1" + <"$2" + } | jq -s 'JOIN(INDEX(.[0][]; .Path); .[1][]; .Path; {Path: .[0].Path, Old: (.[1] | del(.Path)), New: (.[0] | del(.Path))}) | select(.New.Version != .Old.Version)' +} + +# resolve_commits resolves a git ref for each version. +resolve_commits() { + jq '. + {Ref: (.Version|capture("^((?.*)\\+incompatible|v.*-(0\\.)?[0-9]{14}-(?[a-f0-9]{12})|(?v.*))$") | .ref1 // .ref2 // .ref3)}' +} + +pr_link() { + local repo="$1" + local prnum="$2" + local ghname="${repo##github.com/}" + printf -- "[%s#%s](https://%s/pull/%s)" "$ghname" "$prnum" "$repo" "$prnum" +} + +# Generate a release log for a range of commits in a single repo. +release_log() { + setopt local_options BASH_REMATCH + + local repo="$1" + local start="$2" + local end="${3:-HEAD}" + local dir="$GOPATH/src/$repo" + + local commit pr + git -C "$dir" log \ + --format='tformat:%H %s' \ + --first-parent \ + "$start..$end" | + while read commit subject; do + # Skip gx-only PRs. + git -C "$dir" diff-tree --no-commit-id --name-only "$commit^" "$commit" | + grep -v "${IGNORED_FILES}" >/dev/null || continue + + if [[ "$subject" =~ '^Merge pull request #([0-9]+) from' ]]; then + local prnum="${BASH_REMATCH[2]}" + local desc="$(git -C "$dir" show --summary --format='tformat:%b' "$commit" | head -1)" + printf -- "- %s (%s)\n" "$desc" "$(pr_link "$repo" "$prnum")" + elif [[ "$subject" =~ '\(#([0-9]+)\)$' ]]; then + local prnum="${BASH_REMATCH[2]}" + printf -- "- %s (%s)\n" "$subject" "$(pr_link "$repo" "$prnum")" + else + printf -- "- %s\n" "$subject" + fi + done +} + +indent() { + sed -e 's/^/ /' +} + +mod_deps() { + go list -json -m all | jq 'select(.Version != null)' +} + +ensure() { + local repo="$1" + for s in $REPO_SUFFIXES_TO_STRIP; do + repo=${repo%$s} + done + + local commit="$2" + + local rpath="$GOPATH/src/$repo" + if [[ ! -d "$rpath" ]]; then + msg "Cloning $repo..." + git clone "http://$repo" "$rpath" >&2 + fi + + if ! git -C "$rpath" rev-parse --verify "$commit" >/dev/null; then + msg "Fetching $repo..." + git -C "$rpath" fetch --all >&2 + fi + + git -C "$rpath" rev-parse --verify "$commit" >/dev/null || return 1 +} + +statsummary() { + jq -s 'group_by(.Author)[] | {Author: .[0].Author, Commits: (. | length), Insertions: (map(.Insertions) | add), Deletions: (map(.Deletions) | add), Files: (map(.Files) | add)}' | + jq '. + {Lines: (.Deletions + .Insertions)}' +} + +recursive_release_log() { + local start="${1:-$(git tag -l | sort -V | grep -v -- '-rc' | grep 'v'| tail -n1)}" + local end="${2:-$(git rev-parse HEAD)}" + local repo_root="$(git rev-parse --show-toplevel)" + local package="$(cd "$repo_root" && go list)" + + if ! [[ "${GOPATH}/${package}" != "${repo_root}" ]]; then + echo "This script requires the target package and all dependencies to live in a GOPATH." + return 1 + fi + + ( + local result=0 + local workspace="$(mktemp -d)" + trap "$(printf 'rm -rf "%q"' "$workspace")" INT TERM EXIT + cd "$workspace" + + echo "Computing old deps..." >&2 + git -C "$repo_root" show "$start:go.mod" >go.mod + mod_deps | resolve_commits | jq -s > old_deps.json + + echo "Computing new deps..." >&2 + git -C "$repo_root" show "$end:go.mod" >go.mod + mod_deps | resolve_commits | jq -s > new_deps.json + + rm -f go.mod go.sum + + printf -- "Generating Changelog for %s %s..%s\n" "$package" "$start" "$end" >&2 + + printf -- "- %s:\n" "$package" + release_log "$package" "$start" "$end" | indent + + statlog "$package" "$start" "$end" > statlog.json + + dep_changes old_deps.json new_deps.json | + jq --arg filter "$REPO_FILTER" 'select(.Path | match($filter))' | + # Compute changelogs + jq -r '"\(.Path) \(.New.Version) \(.New.Ref) \(.Old.Version) \(.Old.Ref // "")"' | + while read repo new new_ref old old_ref; do + for s in $REPO_SUFFIXES_TO_STRIP; do + repo=${repo%$s} + done + + if ! ensure "$repo" "$new_ref"; then + result=1 + local changelog="failed to fetch repo" + else + statlog "$repo" "$old_ref" "$new_ref" >> statlog.json + local changelog="$(release_log "$repo" "$old_ref" "$new_ref")" + fi + if [[ -n "$changelog" ]]; then + printf -- "- %s (%s -> %s):\n" "$repo" "$old" "$new" + echo "$changelog" | indent + fi + done + + echo + echo "Contributors" + echo + + echo "| Contributor | Commits | Lines ± | Files Changed |" + echo "|-------------|---------|---------|---------------|" + statsummary "] +license = "MIT OR Apache-2.0" +repository = "https://github.com/filecoin-project/filecoin-ffi" +readme = "README.md" +edition = "2018" +publish = false + +[lib] +crate-type = ["rlib", "staticlib"] + +[dependencies] +bls-signatures = "0.6.0" +byteorder = "1.2" +drop_struct_macro_derive = "0.4.0" +ff = { version = "0.2.1", package = "fff" } +ffi-toolkit = "0.4.0" +libc = "0.2.58" +log = "0.4.7" +paired = "0.20.0" +fil_logger = "0.1.0" +rand = "0.7" +rand_chacha = "0.2.1" +rayon = "1.2.1" +anyhow = "1.0.23" +bellperson = { version = "0.9.2", features = ["gpu"] } +serde_json = "1.0.46" + +[dependencies.filecoin-proofs-api] +package = "filecoin-proofs-api" +version = "4.0.2" + +[build-dependencies] +cbindgen = "= 0.14.0" + +[dev-dependencies] +tempfile = "3.0.8" + diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/build.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/build.rs new file mode 100644 index 0000000000..bb3cf60168 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/build.rs @@ -0,0 +1,11 @@ +use std::env; +use std::path::Path; + +fn main() { + let out_dir = env::var("OUT_DIR").unwrap(); + let hdr_out = Path::new(&out_dir).join("include/filcrypto.h"); + + cbindgen::generate(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .expect("Could not generate header") + .write_to_file(hdr_out); +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/cbindgen.toml b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/cbindgen.toml new file mode 100644 index 0000000000..b5e0faddf1 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/cbindgen.toml @@ -0,0 +1,23 @@ +header = """ +/* filcrypto Header */ + +#ifdef __cplusplus +extern "C" { +#endif +""" +trailer = """ +#ifdef __cplusplus +} /* extern "C" */ +#endif +""" + +include_guard = "filcrypto_H" +include_version = true +language = "C" + +[parse] +parse_deps = true +include = ["ffi-toolkit"] + +[enum] +prefix_with_name = true diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/filcrypto.pc.template b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/filcrypto.pc.template new file mode 100644 index 0000000000..56ab937dbe --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/filcrypto.pc.template @@ -0,0 +1,4 @@ +Name: filcrypto +Version: @VERSION@ +Description: C bindings for Filecoin Proofs +Libs: @PRIVATE_LIBS@ diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rust-toolchain b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rust-toolchain new file mode 100644 index 0000000000..3987c47294 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rust-toolchain @@ -0,0 +1 @@ +1.43.1 diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rustc-target-features-optimized.json b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rustc-target-features-optimized.json new file mode 100644 index 0000000000..10921060a3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/rustc-target-features-optimized.json @@ -0,0 +1,30 @@ +[ + { + "rustc_target_feature": "+adx", + "check_cpu_for_feature": "adx" + }, + { + "rustc_target_feature": "+sha", + "check_cpu_for_feature": null + }, + { + "rustc_target_feature": "+sse2", + "check_cpu_for_feature": "sse2" + }, + { + "rustc_target_feature": "+avx2", + "check_cpu_for_feature": "avx2" + }, + { + "rustc_target_feature": "+avx", + "check_cpu_for_feature": "avx" + }, + { + "rustc_target_feature": "+sse4.2", + "check_cpu_for_feature": "sse4_2" + }, + { + "rustc_target_feature": "+sse4.1", + "check_cpu_for_feature": "sse4_1" + } +] diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/build-release.sh b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/build-release.sh new file mode 100755 index 0000000000..14089fd681 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/build-release.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -Exeo pipefail + +main() { + if [[ -z "$1" ]] + then + (>&2 echo '[build-release/main] Error: script requires a library name, e.g. "filecoin" or "snark"') + exit 1 + fi + + if [[ -z "$2" ]] + then + (>&2 echo '[build-release/main] Error: script requires a toolchain, e.g. ./build-release.sh +nightly-2019-04-19') + exit 1 + fi + + # temporary place for storing build output (cannot use 'local', because + # 'trap' is not going to have access to variables scoped to this function) + # + __build_output_log_tmp=$(mktemp) + + # clean up temp file on exit + # + trap '{ rm -f $__build_output_log_tmp; }' EXIT + + # build with RUSTFLAGS configured to output linker flags for native libs + # + local __rust_flags="--print native-static-libs ${RUSTFLAGS}" + + RUSTFLAGS="${__rust_flags}" \ + cargo +$2 build \ + --release ${@:3} 2>&1 | tee ${__build_output_log_tmp} + + # parse build output for linker flags + # + local __linker_flags=$(cat ${__build_output_log_tmp} \ + | grep native-static-libs\: \ + | head -n 1 \ + | cut -d ':' -f 3) + + # generate pkg-config + # + sed -e "s;@VERSION@;$(git rev-parse HEAD);" \ + -e "s;@PRIVATE_LIBS@;${__linker_flags};" "$1.pc.template" > "$1.pc" + + # ensure header file was built + # + find -L . -type f -name "$1.h" | read + + # ensure the archive file was built + # + find -L . -type f -name "lib$1.a" | read +} + +main "$@"; exit diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/package-release.sh b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/package-release.sh new file mode 100755 index 0000000000..bf1d085f1d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/package-release.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +set -Exeuo pipefail + +main() { + if [[ -z "$1" ]] + then + (>&2 echo '[package-release/main] Error: script requires path to which it will write release (gzipped) tarball, e.g. "/tmp/filecoin-ffi-Darwin-standard.tar.tz"') + exit 1 + fi + + local __tarball_output_path=$1 + + # create temporary directory to hold build artifacts (must not be declared + # with 'local' because we will use 'trap' to clean it up) + # + __tmp_dir=$(mktemp -d) + + (>&2 echo "[package-release/main] preparing release files") + + # clean up temp directory on exit + # + trap '{ rm -rf $__tmp_dir; }' EXIT + + # copy assets into temporary directory + # + find -L . -type f -name filcrypto.h -exec cp -- "{}" $__tmp_dir/ \; + find -L . -type f -name libfilcrypto.a -exec cp -- "{}" $__tmp_dir/ \; + find -L . -type f -name filcrypto.pc -exec cp -- "{}" $__tmp_dir/ \; + + # create gzipped tarball from contents of temporary directory + # + tar -czf $__tarball_output_path $__tmp_dir/* + + (>&2 echo "[package-release/main] release file created: $__tarball_output_path") +} + +main "$@"; exit diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/publish-release.sh b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/publish-release.sh new file mode 100755 index 0000000000..017040ef8c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/scripts/publish-release.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +set -Exeuo pipefail + +main() { + if [[ -z "$1" ]] + then + (>&2 echo '[publish-release/main] Error: script requires a release (gzipped) tarball path, e.g. "/tmp/filecoin-ffi-Darwin-standard.tar.tz"') + exit 1 + fi + + if [[ -z "$2" ]] + then + (>&2 echo '[publish-release/main] Error: script requires a release name, e.g. "filecoin-ffi-Darwin-standard" or "filecoin-ffi-Linux-optimized"') + exit 1 + fi + + local __release_file=$1 + local __release_name=$2 + local __release_tag="${CIRCLE_SHA1:0:16}" + + # make sure we have a token set, api requests won't work otherwise + if [ -z $GITHUB_TOKEN ]; then + (>&2 echo "[publish-release/main] \$GITHUB_TOKEN not set, publish failed") + exit 1 + fi + + # see if the release already exists by tag + local __release_response=` + curl \ + --header "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/releases/tags/$__release_tag" + ` + + local __release_id=`echo $__release_response | jq '.id'` + + if [ "$__release_id" = "null" ]; then + (>&2 echo '[publish-release/main] creating release') + + RELEASE_DATA="{ + \"tag_name\": \"$__release_tag\", + \"target_commitish\": \"$CIRCLE_SHA1\", + \"name\": \"$__release_tag\", + \"body\": \"\" + }" + + # create it if it doesn't exist yet + # + __release_response=` + curl \ + --request POST \ + --header "Authorization: token $GITHUB_TOKEN" \ + --header "Content-Type: application/json" \ + --data "$RELEASE_DATA" \ + "https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/releases" + ` + else + (>&2 echo '[publish-release/main] release already exists') + fi + + __release_upload_url=`echo $__release_response | jq -r '.upload_url' | cut -d'{' -f1` + + curl \ + --request POST \ + --header "Authorization: token $GITHUB_TOKEN" \ + --header "Content-Type: application/octet-stream" \ + --data-binary "@$__release_file" \ + "$__release_upload_url?name=$(basename $__release_file)" + + (>&2 echo '[publish-release/main] release file uploaded') +} + +main "$@"; exit diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/api.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/api.rs new file mode 100644 index 0000000000..b1f542dfd1 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/api.rs @@ -0,0 +1,437 @@ +use std::slice::from_raw_parts; + +use bls_signatures::{ + aggregate as aggregate_sig, + groupy::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}, + hash as hash_sig, + paired::bls12_381::{G2Affine, G2Compressed}, + verify as verify_sig, PrivateKey, PublicKey, Serialize, Signature, +}; +use rand::rngs::OsRng; +use rand::SeedableRng; +use rand_chacha::ChaChaRng; +use rayon::prelude::*; + +use crate::bls::types; +use crate::proofs::types::fil_32ByteArray; + +pub const SIGNATURE_BYTES: usize = 96; +pub const PRIVATE_KEY_BYTES: usize = 32; +pub const PUBLIC_KEY_BYTES: usize = 48; +pub const DIGEST_BYTES: usize = 96; + +#[repr(C)] +pub struct fil_BLSSignature { + pub inner: [u8; SIGNATURE_BYTES], +} + +#[repr(C)] +pub struct fil_BLSPrivateKey { + pub inner: [u8; PRIVATE_KEY_BYTES], +} + +#[repr(C)] +pub struct fil_BLSPublicKey { + pub inner: [u8; PUBLIC_KEY_BYTES], +} + +#[repr(C)] +pub struct fil_BLSDigest { + pub inner: [u8; DIGEST_BYTES], +} + +/// Unwraps or returns the passed in value. +macro_rules! try_ffi { + ($res:expr, $val:expr) => {{ + match $res { + Ok(res) => res, + Err(_) => return $val, + } + }}; +} + +/// Compute the digest of a message +/// +/// # Arguments +/// +/// * `message_ptr` - pointer to a message byte array +/// * `message_len` - length of the byte array +#[no_mangle] +pub unsafe extern "C" fn fil_hash( + message_ptr: *const u8, + message_len: libc::size_t, +) -> *mut types::fil_HashResponse { + // prep request + let message = from_raw_parts(message_ptr, message_len); + + // call method + let digest = hash_sig(message); + + // prep response + let mut raw_digest: [u8; DIGEST_BYTES] = [0; DIGEST_BYTES]; + raw_digest.copy_from_slice(digest.into_affine().into_compressed().as_ref()); + + let response = types::fil_HashResponse { + digest: fil_BLSDigest { inner: raw_digest }, + }; + + Box::into_raw(Box::new(response)) +} + +/// Aggregate signatures together into a new signature +/// +/// # Arguments +/// +/// * `flattened_signatures_ptr` - pointer to a byte array containing signatures +/// * `flattened_signatures_len` - length of the byte array (multiple of SIGNATURE_BYTES) +/// +/// Returns `NULL` on error. Result must be freed using `destroy_aggregate_response`. +#[no_mangle] +pub unsafe extern "C" fn fil_aggregate( + flattened_signatures_ptr: *const u8, + flattened_signatures_len: libc::size_t, +) -> *mut types::fil_AggregateResponse { + // prep request + let signatures = try_ffi!( + from_raw_parts(flattened_signatures_ptr, flattened_signatures_len) + .par_chunks(SIGNATURE_BYTES) + .map(|item| { Signature::from_bytes(item) }) + .collect::, _>>(), + std::ptr::null_mut() + ); + + let mut raw_signature: [u8; SIGNATURE_BYTES] = [0; SIGNATURE_BYTES]; + + let aggregated = try_ffi!(aggregate_sig(&signatures), std::ptr::null_mut()); + aggregated + .write_bytes(&mut raw_signature.as_mut()) + .expect("preallocated"); + + let response = types::fil_AggregateResponse { + signature: fil_BLSSignature { + inner: raw_signature, + }, + }; + + Box::into_raw(Box::new(response)) +} + +/// Verify that a signature is the aggregated signature of hashes - pubkeys +/// +/// # Arguments +/// +/// * `signature_ptr` - pointer to a signature byte array (SIGNATURE_BYTES long) +/// * `flattened_digests_ptr` - pointer to a byte array containing digests +/// * `flattened_digests_len` - length of the byte array (multiple of DIGEST_BYTES) +/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys +/// * `flattened_public_keys_len` - length of the array +#[no_mangle] +pub unsafe extern "C" fn fil_verify( + signature_ptr: *const u8, + flattened_digests_ptr: *const u8, + flattened_digests_len: libc::size_t, + flattened_public_keys_ptr: *const u8, + flattened_public_keys_len: libc::size_t, +) -> libc::c_int { + // prep request + let raw_signature = from_raw_parts(signature_ptr, SIGNATURE_BYTES); + let signature = try_ffi!(Signature::from_bytes(raw_signature), 0); + + let raw_digests = from_raw_parts(flattened_digests_ptr, flattened_digests_len); + let raw_public_keys = from_raw_parts(flattened_public_keys_ptr, flattened_public_keys_len); + + if raw_digests.len() % DIGEST_BYTES != 0 { + return 0; + } + if raw_public_keys.len() % PUBLIC_KEY_BYTES != 0 { + return 0; + } + + if raw_digests.len() / DIGEST_BYTES != raw_public_keys.len() / PUBLIC_KEY_BYTES { + return 0; + } + + let digests: Vec<_> = try_ffi!( + raw_digests + .par_chunks(DIGEST_BYTES) + .map(|item: &[u8]| { + let mut digest = G2Compressed::empty(); + digest.as_mut().copy_from_slice(item); + + let affine: G2Affine = digest.into_affine()?; + let projective = affine.into_projective(); + Ok(projective) + }) + .collect::, GroupDecodingError>>(), + 0 + ); + + let public_keys: Vec<_> = try_ffi!( + raw_public_keys + .par_chunks(PUBLIC_KEY_BYTES) + .map(|item| { PublicKey::from_bytes(item) }) + .collect::>(), + 0 + ); + + verify_sig(&signature, digests.as_slice(), public_keys.as_slice()) as libc::c_int +} + +/// Verify that a signature is the aggregated signature of the hhashed messages +/// +/// # Arguments +/// +/// * `signature_ptr` - pointer to a signature byte array (SIGNATURE_BYTES long) +/// * `messages_ptr` - pointer to an array containing the pointers to the messages +/// * `messages_sizes_ptr` - pointer to an array containing the lengths of the messages +/// * `messages_len` - length of the two messages arrays +/// * `flattened_public_keys_ptr` - pointer to a byte array containing public keys +/// * `flattened_public_keys_len` - length of the array +#[no_mangle] +pub unsafe extern "C" fn fil_hash_verify( + signature_ptr: *const u8, + flattened_messages_ptr: *const u8, + flattened_messages_len: libc::size_t, + message_sizes_ptr: *const libc::size_t, + message_sizes_len: libc::size_t, + flattened_public_keys_ptr: *const u8, + flattened_public_keys_len: libc::size_t, +) -> libc::c_int { + // prep request + let raw_signature = from_raw_parts(signature_ptr, SIGNATURE_BYTES); + let signature = try_ffi!(Signature::from_bytes(raw_signature), 0); + + let flattened = from_raw_parts(flattened_messages_ptr, flattened_messages_len); + let chunk_sizes = from_raw_parts(message_sizes_ptr, message_sizes_len); + + // split the flattened message array into slices of individual messages to + // be hashed + let mut messages: Vec<&[u8]> = Vec::with_capacity(message_sizes_len); + let mut offset = 0; + for chunk_size in chunk_sizes.iter() { + messages.push(&flattened[offset..offset + *chunk_size]); + offset += *chunk_size + } + + let raw_public_keys = from_raw_parts(flattened_public_keys_ptr, flattened_public_keys_len); + + if raw_public_keys.len() % PUBLIC_KEY_BYTES != 0 { + return 0; + } + + let digests: Vec<_> = messages + .into_par_iter() + .map(|message: &[u8]| hash_sig(message)) + .collect::>(); + + let public_keys: Vec<_> = try_ffi!( + raw_public_keys + .par_chunks(PUBLIC_KEY_BYTES) + .map(|item| { PublicKey::from_bytes(item) }) + .collect::>(), + 0 + ); + + verify_sig(&signature, &digests, &public_keys) as libc::c_int +} + +/// Generate a new private key +#[no_mangle] +pub unsafe extern "C" fn fil_private_key_generate() -> *mut types::fil_PrivateKeyGenerateResponse { + let mut raw_private_key: [u8; PRIVATE_KEY_BYTES] = [0; PRIVATE_KEY_BYTES]; + PrivateKey::generate(&mut OsRng) + .write_bytes(&mut raw_private_key.as_mut()) + .expect("preallocated"); + + let response = types::fil_PrivateKeyGenerateResponse { + private_key: fil_BLSPrivateKey { + inner: raw_private_key, + }, + }; + + Box::into_raw(Box::new(response)) +} + +/// Generate a new private key with seed +/// +/// **Warning**: Use this function only for testing or with very secure seeds +/// +/// # Arguments +/// +/// * `raw_seed` - a seed byte array with 32 bytes +/// +/// Returns `NULL` when passed a NULL pointer. +#[no_mangle] +pub unsafe extern "C" fn fil_private_key_generate_with_seed( + raw_seed: fil_32ByteArray, +) -> *mut types::fil_PrivateKeyGenerateResponse { + let rng = &mut ChaChaRng::from_seed(raw_seed.inner); + + let mut raw_private_key: [u8; PRIVATE_KEY_BYTES] = [0; PRIVATE_KEY_BYTES]; + PrivateKey::generate(rng) + .write_bytes(&mut raw_private_key.as_mut()) + .expect("preallocated"); + + let response = types::fil_PrivateKeyGenerateResponse { + private_key: fil_BLSPrivateKey { + inner: raw_private_key, + }, + }; + + Box::into_raw(Box::new(response)) +} + +/// Sign a message with a private key and return the signature +/// +/// # Arguments +/// +/// * `raw_private_key_ptr` - pointer to a private key byte array +/// * `message_ptr` - pointer to a message byte array +/// * `message_len` - length of the byte array +/// +/// Returns `NULL` when passed invalid arguments. +#[no_mangle] +pub unsafe extern "C" fn fil_private_key_sign( + raw_private_key_ptr: *const u8, + message_ptr: *const u8, + message_len: libc::size_t, +) -> *mut types::fil_PrivateKeySignResponse { + // prep request + let private_key_slice = from_raw_parts(raw_private_key_ptr, PRIVATE_KEY_BYTES); + let private_key = try_ffi!( + PrivateKey::from_bytes(private_key_slice), + std::ptr::null_mut() + ); + let message = from_raw_parts(message_ptr, message_len); + + let mut raw_signature: [u8; SIGNATURE_BYTES] = [0; SIGNATURE_BYTES]; + PrivateKey::sign(&private_key, message) + .write_bytes(&mut raw_signature.as_mut()) + .expect("preallocated"); + + let response = types::fil_PrivateKeySignResponse { + signature: fil_BLSSignature { + inner: raw_signature, + }, + }; + + Box::into_raw(Box::new(response)) +} + +/// Generate the public key for a private key +/// +/// # Arguments +/// +/// * `raw_private_key_ptr` - pointer to a private key byte array +/// +/// Returns `NULL` when passed invalid arguments. +#[no_mangle] +pub unsafe extern "C" fn fil_private_key_public_key( + raw_private_key_ptr: *const u8, +) -> *mut types::fil_PrivateKeyPublicKeyResponse { + let private_key_slice = from_raw_parts(raw_private_key_ptr, PRIVATE_KEY_BYTES); + let private_key = try_ffi!( + PrivateKey::from_bytes(private_key_slice), + std::ptr::null_mut() + ); + + let mut raw_public_key: [u8; PUBLIC_KEY_BYTES] = [0; PUBLIC_KEY_BYTES]; + private_key + .public_key() + .write_bytes(&mut raw_public_key.as_mut()) + .expect("preallocated"); + + let response = types::fil_PrivateKeyPublicKeyResponse { + public_key: fil_BLSPublicKey { + inner: raw_public_key, + }, + }; + + Box::into_raw(Box::new(response)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn key_verification() { + unsafe { + let private_key = (*fil_private_key_generate()).private_key.inner; + let public_key = (*fil_private_key_public_key(&private_key[0])) + .public_key + .inner; + let message = b"hello world"; + let digest = (*fil_hash(&message[0], message.len())).digest.inner; + let signature = (*fil_private_key_sign(&private_key[0], &message[0], message.len())) + .signature + .inner; + let verified = fil_verify( + &signature[0], + &digest[0], + digest.len(), + &public_key[0], + public_key.len(), + ); + + assert_eq!(1, verified); + + let flattened_messages = message; + let message_sizes = [message.len()]; + let verified = fil_hash_verify( + signature.as_ptr(), + flattened_messages.as_ptr(), + flattened_messages.len(), + message_sizes.as_ptr(), + message_sizes.len(), + public_key.as_ptr(), + public_key.len(), + ); + + assert_eq!(1, verified); + + let different_message = b"bye world"; + let different_digest = (*fil_hash(&different_message[0], different_message.len())) + .digest + .inner; + let not_verified = fil_verify( + &signature[0], + &different_digest[0], + different_digest.len(), + &public_key[0], + public_key.len(), + ); + + assert_eq!(0, not_verified); + + // garbage verification + let different_digest = vec![0, 1, 2, 3, 4]; + let not_verified = fil_verify( + &signature[0], + &different_digest[0], + different_digest.len(), + &public_key[0], + public_key.len(), + ); + + assert_eq!(0, not_verified); + } + } + + #[test] + fn private_key_with_seed() { + unsafe { + let seed = fil_32ByteArray { inner: [5u8; 32] }; + let private_key = (*fil_private_key_generate_with_seed(seed)) + .private_key + .inner; + assert_eq!( + [ + 115, 245, 77, 209, 4, 57, 40, 107, 10, 153, 141, 16, 153, 172, 85, 197, 125, + 163, 35, 217, 108, 241, 64, 235, 231, 220, 131, 1, 77, 253, 176, 19 + ], + private_key, + ); + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/mod.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/mod.rs new file mode 100644 index 0000000000..8389f117b5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/mod.rs @@ -0,0 +1,2 @@ +pub mod api; +pub mod types; diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/types.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/types.rs new file mode 100644 index 0000000000..53cb8b565d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/bls/types.rs @@ -0,0 +1,67 @@ +use crate::bls::api::{fil_BLSDigest, fil_BLSPrivateKey, fil_BLSPublicKey, fil_BLSSignature}; + +/// HashResponse + +#[repr(C)] +pub struct fil_HashResponse { + pub digest: fil_BLSDigest, +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_hash_response(ptr: *mut fil_HashResponse) { + let _ = Box::from_raw(ptr); +} + +/// AggregateResponse + +#[repr(C)] +pub struct fil_AggregateResponse { + pub signature: fil_BLSSignature, +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_aggregate_response(ptr: *mut fil_AggregateResponse) { + let _ = Box::from_raw(ptr); +} + +/// PrivateKeyGenerateResponse + +#[repr(C)] +pub struct fil_PrivateKeyGenerateResponse { + pub private_key: fil_BLSPrivateKey, +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_private_key_generate_response( + ptr: *mut fil_PrivateKeyGenerateResponse, +) { + let _ = Box::from_raw(ptr); +} + +/// PrivateKeySignResponse + +#[repr(C)] +pub struct fil_PrivateKeySignResponse { + pub signature: fil_BLSSignature, +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_private_key_sign_response( + ptr: *mut fil_PrivateKeySignResponse, +) { + let _ = Box::from_raw(ptr); +} + +/// PrivateKeyPublicKeyResponse + +#[repr(C)] +pub struct fil_PrivateKeyPublicKeyResponse { + pub public_key: fil_BLSPublicKey, +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_private_key_public_key_response( + ptr: *mut fil_PrivateKeyPublicKeyResponse, +) { + let _ = Box::from_raw(ptr); +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/lib.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/lib.rs new file mode 100644 index 0000000000..9d7ec544a4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/lib.rs @@ -0,0 +1,6 @@ +#![deny(clippy::all)] +#![allow(clippy::missing_safety_doc)] + +pub mod bls; +pub mod proofs; +pub mod util; diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/api.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/api.rs new file mode 100644 index 0000000000..98eb5a9258 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/api.rs @@ -0,0 +1,1689 @@ +use ffi_toolkit::{ + c_str_to_pbuf, catch_panic_response, raw_ptr, rust_str_to_c_str, FCPResponseStatus, +}; +use filecoin_proofs_api::seal::SealPreCommitPhase2Output; +use filecoin_proofs_api::{ + PieceInfo, RegisteredPoStProof, RegisteredSealProof, SectorId, UnpaddedByteIndex, + UnpaddedBytesAmount, +}; +use log::info; +use std::mem; +use std::path::PathBuf; +use std::slice::from_raw_parts; + +use super::helpers::{c_to_rust_post_proofs, to_private_replica_info_map}; +use super::types::*; +use crate::util::api::init_log; + +/// TODO: document +/// +#[no_mangle] +#[cfg(not(target_os = "windows"))] +pub unsafe extern "C" fn fil_write_with_alignment( + registered_proof: fil_RegisteredSealProof, + src_fd: libc::c_int, + src_size: u64, + dst_fd: libc::c_int, + existing_piece_sizes_ptr: *const u64, + existing_piece_sizes_len: libc::size_t, +) -> *mut fil_WriteWithAlignmentResponse { + catch_panic_response(|| { + init_log(); + + info!("write_with_alignment: start"); + + let mut response = fil_WriteWithAlignmentResponse::default(); + + let piece_sizes: Vec = + from_raw_parts(existing_piece_sizes_ptr, existing_piece_sizes_len) + .iter() + .map(|n| UnpaddedBytesAmount(*n)) + .collect(); + + let n = UnpaddedBytesAmount(src_size); + + match filecoin_proofs_api::seal::add_piece( + registered_proof.into(), + FileDescriptorRef::new(src_fd), + FileDescriptorRef::new(dst_fd), + n, + &piece_sizes, + ) { + Ok((info, written)) => { + response.comm_p = info.commitment; + response.left_alignment_unpadded = (written - n).into(); + response.status_code = FCPResponseStatus::FCPNoError; + response.total_write_unpadded = written.into(); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("write_with_alignment: finish"); + + raw_ptr(response) + }) +} + +/// TODO: document +/// +#[no_mangle] +#[cfg(not(target_os = "windows"))] +pub unsafe extern "C" fn fil_write_without_alignment( + registered_proof: fil_RegisteredSealProof, + src_fd: libc::c_int, + src_size: u64, + dst_fd: libc::c_int, +) -> *mut fil_WriteWithoutAlignmentResponse { + catch_panic_response(|| { + init_log(); + + info!("write_without_alignment: start"); + + let mut response = fil_WriteWithoutAlignmentResponse::default(); + + match filecoin_proofs_api::seal::write_and_preprocess( + registered_proof.into(), + FileDescriptorRef::new(src_fd), + FileDescriptorRef::new(dst_fd), + UnpaddedBytesAmount(src_size), + ) { + Ok((info, written)) => { + response.comm_p = info.commitment; + response.status_code = FCPResponseStatus::FCPNoError; + response.total_write_unpadded = written.into(); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("write_without_alignment: finish"); + + raw_ptr(response) + }) +} + +#[no_mangle] +pub unsafe extern "C" fn fil_fauxrep( + registered_proof: fil_RegisteredSealProof, + cache_dir_path: *const libc::c_char, + sealed_sector_path: *const libc::c_char, +) -> *mut fil_FauxRepResponse { + catch_panic_response(|| { + init_log(); + + info!("fauxrep: start"); + + let mut response: fil_FauxRepResponse = Default::default(); + + let result = filecoin_proofs_api::seal::fauxrep( + registered_proof.into(), + c_str_to_pbuf(cache_dir_path), + c_str_to_pbuf(sealed_sector_path), + ); + + match result { + Ok(output) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.commitment = output; + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("fauxrep: finish"); + + raw_ptr(response) + }) +} + +/// TODO: document +/// +#[no_mangle] +pub unsafe extern "C" fn fil_seal_pre_commit_phase1( + registered_proof: fil_RegisteredSealProof, + cache_dir_path: *const libc::c_char, + staged_sector_path: *const libc::c_char, + sealed_sector_path: *const libc::c_char, + sector_id: u64, + prover_id: fil_32ByteArray, + ticket: fil_32ByteArray, + pieces_ptr: *const fil_PublicPieceInfo, + pieces_len: libc::size_t, +) -> *mut fil_SealPreCommitPhase1Response { + catch_panic_response(|| { + init_log(); + + info!("seal_pre_commit_phase1: start"); + + let public_pieces: Vec = from_raw_parts(pieces_ptr, pieces_len) + .iter() + .cloned() + .map(Into::into) + .collect(); + + let mut response: fil_SealPreCommitPhase1Response = Default::default(); + + let result = filecoin_proofs_api::seal::seal_pre_commit_phase1( + registered_proof.into(), + c_str_to_pbuf(cache_dir_path), + c_str_to_pbuf(staged_sector_path), + c_str_to_pbuf(sealed_sector_path), + prover_id.inner, + SectorId::from(sector_id), + ticket.inner, + &public_pieces, + ) + .and_then(|output| serde_json::to_vec(&output).map_err(Into::into)); + + match result { + Ok(output) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.seal_pre_commit_phase1_output_ptr = output.as_ptr(); + response.seal_pre_commit_phase1_output_len = output.len(); + mem::forget(output); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("seal_pre_commit_phase1: finish"); + + raw_ptr(response) + }) +} + +/// TODO: document +/// +#[no_mangle] +pub unsafe extern "C" fn fil_seal_pre_commit_phase2( + seal_pre_commit_phase1_output_ptr: *const u8, + seal_pre_commit_phase1_output_len: libc::size_t, + cache_dir_path: *const libc::c_char, + sealed_sector_path: *const libc::c_char, +) -> *mut fil_SealPreCommitPhase2Response { + catch_panic_response(|| { + init_log(); + + info!("seal_pre_commit_phase2: start"); + + let mut response: fil_SealPreCommitPhase2Response = Default::default(); + + let phase_1_output = serde_json::from_slice(from_raw_parts( + seal_pre_commit_phase1_output_ptr, + seal_pre_commit_phase1_output_len, + )) + .map_err(Into::into); + + let result = phase_1_output.and_then(|o| { + filecoin_proofs_api::seal::seal_pre_commit_phase2::( + o, + c_str_to_pbuf(cache_dir_path), + c_str_to_pbuf(sealed_sector_path), + ) + }); + + match result { + Ok(output) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.comm_r = output.comm_r; + response.comm_d = output.comm_d; + response.registered_proof = output.registered_proof.into(); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("seal_pre_commit_phase2: finish"); + + raw_ptr(response) + }) +} + +/// TODO: document +/// +#[no_mangle] +pub unsafe extern "C" fn fil_seal_commit_phase1( + registered_proof: fil_RegisteredSealProof, + comm_r: fil_32ByteArray, + comm_d: fil_32ByteArray, + cache_dir_path: *const libc::c_char, + replica_path: *const libc::c_char, + sector_id: u64, + prover_id: fil_32ByteArray, + ticket: fil_32ByteArray, + seed: fil_32ByteArray, + pieces_ptr: *const fil_PublicPieceInfo, + pieces_len: libc::size_t, +) -> *mut fil_SealCommitPhase1Response { + catch_panic_response(|| { + init_log(); + + info!("seal_commit_phase1: start"); + + let mut response = fil_SealCommitPhase1Response::default(); + + let spcp2o = SealPreCommitPhase2Output { + registered_proof: registered_proof.into(), + comm_r: comm_r.inner, + comm_d: comm_d.inner, + }; + + let public_pieces: Vec = from_raw_parts(pieces_ptr, pieces_len) + .iter() + .cloned() + .map(Into::into) + .collect(); + + let result = filecoin_proofs_api::seal::seal_commit_phase1( + c_str_to_pbuf(cache_dir_path), + c_str_to_pbuf(replica_path), + prover_id.inner, + SectorId::from(sector_id), + ticket.inner, + seed.inner, + spcp2o, + &public_pieces, + ); + + match result.and_then(|output| serde_json::to_vec(&output).map_err(Into::into)) { + Ok(output) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.seal_commit_phase1_output_ptr = output.as_ptr(); + response.seal_commit_phase1_output_len = output.len(); + mem::forget(output); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("seal_commit_phase1: finish"); + + raw_ptr(response) + }) +} + +#[no_mangle] +pub unsafe extern "C" fn fil_seal_commit_phase2( + seal_commit_phase1_output_ptr: *const u8, + seal_commit_phase1_output_len: libc::size_t, + sector_id: u64, + prover_id: fil_32ByteArray, +) -> *mut fil_SealCommitPhase2Response { + catch_panic_response(|| { + init_log(); + + info!("seal_commit_phase2: start"); + + let mut response = fil_SealCommitPhase2Response::default(); + + let scp1o = serde_json::from_slice(from_raw_parts( + seal_commit_phase1_output_ptr, + seal_commit_phase1_output_len, + )) + .map_err(Into::into); + + let result = scp1o.and_then(|o| { + filecoin_proofs_api::seal::seal_commit_phase2( + o, + prover_id.inner, + SectorId::from(sector_id), + ) + }); + + match result { + Ok(output) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.proof_ptr = output.proof.as_ptr(); + response.proof_len = output.proof.len(); + mem::forget(output.proof); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("seal_commit_phase2: finish"); + + raw_ptr(response) + }) +} + +/// TODO: document +#[no_mangle] +pub unsafe extern "C" fn fil_unseal_range( + registered_proof: fil_RegisteredSealProof, + cache_dir_path: *const libc::c_char, + sealed_sector_fd_raw: libc::c_int, + unseal_output_fd_raw: libc::c_int, + sector_id: u64, + prover_id: fil_32ByteArray, + ticket: fil_32ByteArray, + comm_d: fil_32ByteArray, + unpadded_byte_index: u64, + unpadded_bytes_amount: u64, +) -> *mut fil_UnsealRangeResponse { + catch_panic_response(|| { + init_log(); + + info!("unseal_range: start"); + + use std::os::unix::io::{FromRawFd, IntoRawFd}; + + let mut sealed_sector = std::fs::File::from_raw_fd(sealed_sector_fd_raw); + let mut unseal_output = std::fs::File::from_raw_fd(unseal_output_fd_raw); + + let result = filecoin_proofs_api::seal::unseal_range( + registered_proof.into(), + c_str_to_pbuf(cache_dir_path), + &mut sealed_sector, + &mut unseal_output, + prover_id.inner, + SectorId::from(sector_id), + comm_d.inner, + ticket.inner, + UnpaddedByteIndex(unpadded_byte_index), + UnpaddedBytesAmount(unpadded_bytes_amount), + ); + + // keep all file descriptors alive until unseal_range returns + let _ = sealed_sector.into_raw_fd(); + let _ = unseal_output.into_raw_fd(); + + let mut response = fil_UnsealRangeResponse::default(); + + match result { + Ok(_) => { + response.status_code = FCPResponseStatus::FCPNoError; + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + }; + + info!("unseal_range: finish"); + + raw_ptr(response) + }) +} + +/// Verifies the output of seal. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_verify_seal( + registered_proof: fil_RegisteredSealProof, + comm_r: fil_32ByteArray, + comm_d: fil_32ByteArray, + prover_id: fil_32ByteArray, + ticket: fil_32ByteArray, + seed: fil_32ByteArray, + sector_id: u64, + proof_ptr: *const u8, + proof_len: libc::size_t, +) -> *mut super::types::fil_VerifySealResponse { + catch_panic_response(|| { + init_log(); + + info!("verify_seal: start"); + + let mut proof_bytes: Vec = vec![0; proof_len]; + proof_bytes.clone_from_slice(from_raw_parts(proof_ptr, proof_len)); + + let result = filecoin_proofs_api::seal::verify_seal( + registered_proof.into(), + comm_r.inner, + comm_d.inner, + prover_id.inner, + SectorId::from(sector_id), + ticket.inner, + seed.inner, + &proof_bytes, + ); + + let mut response = fil_VerifySealResponse::default(); + + match result { + Ok(true) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.is_valid = true; + } + Ok(false) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.is_valid = false; + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + }; + + info!("verify_seal: finish"); + + raw_ptr(response) + }) +} + +/// Verifies that a proof-of-spacetime is valid. +#[no_mangle] +pub unsafe extern "C" fn fil_verify_winning_post( + randomness: fil_32ByteArray, + replicas_ptr: *const fil_PublicReplicaInfo, + replicas_len: libc::size_t, + proofs_ptr: *const fil_PoStProof, + proofs_len: libc::size_t, + prover_id: fil_32ByteArray, +) -> *mut fil_VerifyWinningPoStResponse { + catch_panic_response(|| { + init_log(); + + info!("verify_winning_post: start"); + + let mut response = fil_VerifyWinningPoStResponse::default(); + + let convert = super::helpers::to_public_replica_info_map(replicas_ptr, replicas_len); + + let result = convert.and_then(|replicas| { + let post_proofs = c_to_rust_post_proofs(proofs_ptr, proofs_len)?; + let proofs: Vec = post_proofs.iter().flat_map(|pp| pp.clone().proof).collect(); + + filecoin_proofs_api::post::verify_winning_post( + &randomness.inner, + &proofs, + &replicas, + prover_id.inner, + ) + }); + + match result { + Ok(is_valid) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.is_valid = is_valid; + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + }; + + info!("verify_winning_post: {}", "finish"); + raw_ptr(response) + }) +} + +/// TODO: document +/// +#[no_mangle] +pub unsafe extern "C" fn fil_generate_window_post( + randomness: fil_32ByteArray, + replicas_ptr: *const fil_PrivateReplicaInfo, + replicas_len: libc::size_t, + prover_id: fil_32ByteArray, +) -> *mut fil_GenerateWindowPoStResponse { + catch_panic_response(|| { + init_log(); + + info!("generate_window_post: start"); + + let mut response = fil_GenerateWindowPoStResponse::default(); + + let result = to_private_replica_info_map(replicas_ptr, replicas_len).and_then(|rs| { + filecoin_proofs_api::post::generate_window_post(&randomness.inner, &rs, prover_id.inner) + }); + + match result { + Ok(output) => { + let mapped: Vec = output + .iter() + .cloned() + .map(|(t, proof)| { + let out = fil_PoStProof { + registered_proof: (t).into(), + proof_len: proof.len(), + proof_ptr: proof.as_ptr(), + }; + + mem::forget(proof); + + out + }) + .collect(); + + response.status_code = FCPResponseStatus::FCPNoError; + response.proofs_ptr = mapped.as_ptr(); + response.proofs_len = mapped.len(); + mem::forget(mapped); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("generate_window_post: finish"); + + raw_ptr(response) + }) +} + +/// Verifies that a proof-of-spacetime is valid. +#[no_mangle] +pub unsafe extern "C" fn fil_verify_window_post( + randomness: fil_32ByteArray, + replicas_ptr: *const fil_PublicReplicaInfo, + replicas_len: libc::size_t, + proofs_ptr: *const fil_PoStProof, + proofs_len: libc::size_t, + prover_id: fil_32ByteArray, +) -> *mut fil_VerifyWindowPoStResponse { + catch_panic_response(|| { + init_log(); + + info!("verify_window_post: start"); + + let mut response = fil_VerifyWindowPoStResponse::default(); + + let convert = super::helpers::to_public_replica_info_map(replicas_ptr, replicas_len); + + let result = convert.and_then(|replicas| { + let post_proofs = c_to_rust_post_proofs(proofs_ptr, proofs_len)?; + + let proofs: Vec<(RegisteredPoStProof, &[u8])> = post_proofs + .iter() + .map(|x| (x.registered_proof, x.proof.as_ref())) + .collect(); + + filecoin_proofs_api::post::verify_window_post( + &randomness.inner, + &proofs, + &replicas, + prover_id.inner, + ) + }); + + match result { + Ok(is_valid) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.is_valid = is_valid; + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + }; + + info!("verify_window_post: {}", "finish"); + raw_ptr(response) + }) +} + +/// Returns the merkle root for a piece after piece padding and alignment. +/// The caller is responsible for closing the passed in file descriptor. +#[no_mangle] +#[cfg(not(target_os = "windows"))] +pub unsafe extern "C" fn fil_generate_piece_commitment( + registered_proof: fil_RegisteredSealProof, + piece_fd_raw: libc::c_int, + unpadded_piece_size: u64, +) -> *mut fil_GeneratePieceCommitmentResponse { + catch_panic_response(|| { + init_log(); + + use std::os::unix::io::{FromRawFd, IntoRawFd}; + + let mut piece_file = std::fs::File::from_raw_fd(piece_fd_raw); + + let unpadded_piece_size = UnpaddedBytesAmount(unpadded_piece_size); + let result = filecoin_proofs_api::seal::generate_piece_commitment( + registered_proof.into(), + &mut piece_file, + unpadded_piece_size, + ); + + // avoid dropping the File which closes it + let _ = piece_file.into_raw_fd(); + + let mut response = fil_GeneratePieceCommitmentResponse::default(); + + match result { + Ok(meta) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.comm_p = meta.commitment; + response.num_bytes_aligned = meta.size.into(); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + raw_ptr(response) + }) +} + +/// Returns the merkle root for a sector containing the provided pieces. +#[no_mangle] +pub unsafe extern "C" fn fil_generate_data_commitment( + registered_proof: fil_RegisteredSealProof, + pieces_ptr: *const fil_PublicPieceInfo, + pieces_len: libc::size_t, +) -> *mut fil_GenerateDataCommitmentResponse { + catch_panic_response(|| { + init_log(); + + info!("generate_data_commitment: start"); + + let public_pieces: Vec = from_raw_parts(pieces_ptr, pieces_len) + .iter() + .cloned() + .map(Into::into) + .collect(); + + let result = + filecoin_proofs_api::seal::compute_comm_d(registered_proof.into(), &public_pieces); + + let mut response = fil_GenerateDataCommitmentResponse::default(); + + match result { + Ok(commitment) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.comm_d = commitment; + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("generate_data_commitment: finish"); + + raw_ptr(response) + }) +} + +#[no_mangle] +pub unsafe extern "C" fn fil_clear_cache( + sector_size: u64, + cache_dir_path: *const libc::c_char, +) -> *mut fil_ClearCacheResponse { + catch_panic_response(|| { + init_log(); + + let result = + filecoin_proofs_api::seal::clear_cache(sector_size, &c_str_to_pbuf(cache_dir_path)); + + let mut response = fil_ClearCacheResponse::default(); + + match result { + Ok(_) => { + response.status_code = FCPResponseStatus::FCPNoError; + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + }; + + raw_ptr(response) + }) +} + +/// TODO: document +/// +#[no_mangle] +pub unsafe extern "C" fn fil_generate_winning_post_sector_challenge( + registered_proof: fil_RegisteredPoStProof, + randomness: fil_32ByteArray, + sector_set_len: u64, + prover_id: fil_32ByteArray, +) -> *mut fil_GenerateWinningPoStSectorChallenge { + catch_panic_response(|| { + init_log(); + + info!("generate_winning_post_sector_challenge: start"); + + let mut response = fil_GenerateWinningPoStSectorChallenge::default(); + + let result = filecoin_proofs_api::post::generate_winning_post_sector_challenge( + registered_proof.into(), + &randomness.inner, + sector_set_len, + prover_id.inner, + ); + + match result { + Ok(output) => { + let mapped: Vec = output.into_iter().map(u64::from).collect(); + + response.status_code = FCPResponseStatus::FCPNoError; + response.ids_ptr = mapped.as_ptr(); + response.ids_len = mapped.len(); + mem::forget(mapped); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("generate_winning_post_sector_challenge: finish"); + + raw_ptr(response) + }) +} + +/// TODO: document +/// +#[no_mangle] +pub unsafe extern "C" fn fil_generate_winning_post( + randomness: fil_32ByteArray, + replicas_ptr: *const fil_PrivateReplicaInfo, + replicas_len: libc::size_t, + prover_id: fil_32ByteArray, +) -> *mut fil_GenerateWinningPoStResponse { + catch_panic_response(|| { + init_log(); + + info!("generate_winning_post: start"); + + let mut response = fil_GenerateWinningPoStResponse::default(); + + let result = to_private_replica_info_map(replicas_ptr, replicas_len).and_then(|rs| { + filecoin_proofs_api::post::generate_winning_post( + &randomness.inner, + &rs, + prover_id.inner, + ) + }); + + match result { + Ok(output) => { + let mapped: Vec = output + .iter() + .cloned() + .map(|(t, proof)| { + let out = fil_PoStProof { + registered_proof: (t).into(), + proof_len: proof.len(), + proof_ptr: proof.as_ptr(), + }; + + mem::forget(proof); + + out + }) + .collect(); + + response.status_code = FCPResponseStatus::FCPNoError; + response.proofs_ptr = mapped.as_ptr(); + response.proofs_len = mapped.len(); + mem::forget(mapped); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + info!("generate_winning_post: finish"); + + raw_ptr(response) + }) +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_write_with_alignment_response( + ptr: *mut fil_WriteWithAlignmentResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_write_without_alignment_response( + ptr: *mut fil_WriteWithoutAlignmentResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_fauxrep_response(ptr: *mut fil_FauxRepResponse) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_seal_pre_commit_phase1_response( + ptr: *mut fil_SealPreCommitPhase1Response, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_seal_pre_commit_phase2_response( + ptr: *mut fil_SealPreCommitPhase2Response, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_seal_commit_phase1_response( + ptr: *mut fil_SealCommitPhase1Response, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_seal_commit_phase2_response( + ptr: *mut fil_SealCommitPhase2Response, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_unseal_range_response(ptr: *mut fil_UnsealRangeResponse) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_generate_piece_commitment_response( + ptr: *mut fil_GeneratePieceCommitmentResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_generate_data_commitment_response( + ptr: *mut fil_GenerateDataCommitmentResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_string_response(ptr: *mut fil_StringResponse) { + let _ = Box::from_raw(ptr); +} + +/// Returns the number of user bytes that will fit into a staged sector. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_max_user_bytes_per_staged_sector( + registered_proof: fil_RegisteredSealProof, +) -> u64 { + u64::from(UnpaddedBytesAmount::from( + RegisteredSealProof::from(registered_proof).sector_size(), + )) +} + +/// Returns the CID of the Groth parameter file for sealing. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_seal_params_cid( + registered_proof: fil_RegisteredSealProof, +) -> *mut fil_StringResponse { + registered_seal_proof_accessor(registered_proof, RegisteredSealProof::params_cid) +} + +/// Returns the CID of the verifying key-file for verifying a seal proof. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_seal_verifying_key_cid( + registered_proof: fil_RegisteredSealProof, +) -> *mut fil_StringResponse { + registered_seal_proof_accessor(registered_proof, RegisteredSealProof::verifying_key_cid) +} + +/// Returns the path from which the proofs library expects to find the Groth +/// parameter file used when sealing. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_seal_params_path( + registered_proof: fil_RegisteredSealProof, +) -> *mut fil_StringResponse { + registered_seal_proof_accessor(registered_proof, |p| { + p.cache_params_path() + .map(|pb| String::from(pb.to_string_lossy())) + }) +} + +/// Returns the path from which the proofs library expects to find the verifying +/// key-file used when verifying a seal proof. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_seal_verifying_key_path( + registered_proof: fil_RegisteredSealProof, +) -> *mut fil_StringResponse { + registered_seal_proof_accessor(registered_proof, |p| { + p.cache_verifying_key_path() + .map(|pb| String::from(pb.to_string_lossy())) + }) +} + +/// Returns the identity of the circuit for the provided seal proof. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_seal_circuit_identifier( + registered_proof: fil_RegisteredSealProof, +) -> *mut fil_StringResponse { + registered_seal_proof_accessor(registered_proof, RegisteredSealProof::circuit_identifier) +} + +/// Returns the version of the provided seal proof type. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_seal_version( + registered_proof: fil_RegisteredSealProof, +) -> *mut fil_StringResponse { + registered_seal_proof_accessor(registered_proof, |p| Ok(format!("{:?}", p))) +} + +/// Returns the CID of the Groth parameter file for generating a PoSt. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_post_params_cid( + registered_proof: fil_RegisteredPoStProof, +) -> *mut fil_StringResponse { + registered_post_proof_accessor(registered_proof, RegisteredPoStProof::params_cid) +} + +/// Returns the CID of the verifying key-file for verifying a PoSt proof. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_post_verifying_key_cid( + registered_proof: fil_RegisteredPoStProof, +) -> *mut fil_StringResponse { + registered_post_proof_accessor(registered_proof, RegisteredPoStProof::verifying_key_cid) +} + +/// Returns the path from which the proofs library expects to find the Groth +/// parameter file used when generating a PoSt. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_post_params_path( + registered_proof: fil_RegisteredPoStProof, +) -> *mut fil_StringResponse { + registered_post_proof_accessor(registered_proof, |p| { + p.cache_params_path() + .map(|pb| String::from(pb.to_string_lossy())) + }) +} + +/// Returns the path from which the proofs library expects to find the verifying +/// key-file used when verifying a PoSt proof. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_post_verifying_key_path( + registered_proof: fil_RegisteredPoStProof, +) -> *mut fil_StringResponse { + registered_post_proof_accessor(registered_proof, |p| { + p.cache_verifying_key_path() + .map(|pb| String::from(pb.to_string_lossy())) + }) +} + +/// Returns the identity of the circuit for the provided PoSt proof type. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_post_circuit_identifier( + registered_proof: fil_RegisteredPoStProof, +) -> *mut fil_StringResponse { + registered_post_proof_accessor(registered_proof, RegisteredPoStProof::circuit_identifier) +} + +/// Returns the version of the provided seal proof. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_get_post_version( + registered_proof: fil_RegisteredPoStProof, +) -> *mut fil_StringResponse { + registered_post_proof_accessor(registered_proof, |p| Ok(format!("{:?}", p))) +} + +unsafe fn registered_seal_proof_accessor( + registered_proof: fil_RegisteredSealProof, + op: fn(RegisteredSealProof) -> anyhow::Result, +) -> *mut fil_StringResponse { + let mut response = fil_StringResponse::default(); + + let rsp: RegisteredSealProof = registered_proof.into(); + + match op(rsp) { + Ok(s) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.string_val = rust_str_to_c_str(s); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + raw_ptr(response) +} + +unsafe fn registered_post_proof_accessor( + registered_proof: fil_RegisteredPoStProof, + op: fn(RegisteredPoStProof) -> anyhow::Result, +) -> *mut fil_StringResponse { + let mut response = fil_StringResponse::default(); + + let rsp: RegisteredPoStProof = registered_proof.into(); + + match op(rsp) { + Ok(s) => { + response.status_code = FCPResponseStatus::FCPNoError; + response.string_val = rust_str_to_c_str(s); + } + Err(err) => { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str(format!("{:?}", err)); + } + } + + raw_ptr(response) +} + +/// Deallocates a VerifySealResponse. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_verify_seal_response(ptr: *mut fil_VerifySealResponse) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_finalize_ticket_response( + ptr: *mut fil_FinalizeTicketResponse, +) { + let _ = Box::from_raw(ptr); +} + +/// Deallocates a VerifyPoStResponse. +/// +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_verify_winning_post_response( + ptr: *mut fil_VerifyWinningPoStResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_verify_window_post_response( + ptr: *mut fil_VerifyWindowPoStResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_generate_winning_post_response( + ptr: *mut fil_GenerateWinningPoStResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_generate_window_post_response( + ptr: *mut fil_GenerateWindowPoStResponse, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_generate_winning_post_sector_challenge( + ptr: *mut fil_GenerateWinningPoStSectorChallenge, +) { + let _ = Box::from_raw(ptr); +} + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_clear_cache_response(ptr: *mut fil_ClearCacheResponse) { + let _ = Box::from_raw(ptr); +} + +#[cfg(test)] +pub mod tests { + use std::io::{Read, Seek, SeekFrom, Write}; + use std::os::unix::io::IntoRawFd; + + use anyhow::Result; + use ffi_toolkit::{c_str_to_rust_str, FCPResponseStatus}; + use rand::{thread_rng, Rng}; + + use super::*; + use std::ffi::CStr; + + #[test] + fn test_write_with_and_without_alignment() -> Result<()> { + let registered_proof = fil_RegisteredSealProof::StackedDrg2KiBV1; + + // write some bytes to a temp file to be used as the byte source + let mut rng = thread_rng(); + let buf: Vec = (0..508).map(|_| rng.gen()).collect(); + + // first temp file occupies 4 nodes in a merkle tree built over the + // destination (after preprocessing) + let mut src_file_a = tempfile::tempfile()?; + src_file_a.write_all(&buf[0..127])?; + src_file_a.seek(SeekFrom::Start(0))?; + + // second occupies 16 nodes + let mut src_file_b = tempfile::tempfile()?; + src_file_b.write_all(&buf[0..508])?; + src_file_b.seek(SeekFrom::Start(0))?; + + // create a temp file to be used as the byte destination + let dest = tempfile::tempfile()?; + + // transmute temp files to file descriptors + let src_fd_a = src_file_a.into_raw_fd(); + let src_fd_b = src_file_b.into_raw_fd(); + let dst_fd = dest.into_raw_fd(); + + // write the first file + unsafe { + let resp = fil_write_without_alignment(registered_proof, src_fd_a, 127, dst_fd); + + if (*resp).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp).error_msg); + panic!("write_without_alignment failed: {:?}", msg); + } + + assert_eq!( + (*resp).total_write_unpadded, + 127, + "should have added 127 bytes of (unpadded) left alignment" + ); + } + + // write the second + unsafe { + let existing = vec![127u64]; + + let resp = fil_write_with_alignment( + registered_proof, + src_fd_b, + 508, + dst_fd, + existing.as_ptr(), + existing.len(), + ); + + if (*resp).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp).error_msg); + panic!("write_with_alignment failed: {:?}", msg); + } + + assert_eq!( + (*resp).left_alignment_unpadded, + 381, + "should have added 381 bytes of (unpadded) left alignment" + ); + } + + Ok(()) + } + + #[test] + fn test_proof_types() -> Result<()> { + let seal_types = vec![ + fil_RegisteredSealProof::StackedDrg2KiBV1, + fil_RegisteredSealProof::StackedDrg8MiBV1, + fil_RegisteredSealProof::StackedDrg512MiBV1, + fil_RegisteredSealProof::StackedDrg32GiBV1, + ]; + + let post_types = vec![ + fil_RegisteredPoStProof::StackedDrgWinning2KiBV1, + fil_RegisteredPoStProof::StackedDrgWinning8MiBV1, + fil_RegisteredPoStProof::StackedDrgWinning512MiBV1, + fil_RegisteredPoStProof::StackedDrgWinning32GiBV1, + fil_RegisteredPoStProof::StackedDrgWindow2KiBV1, + fil_RegisteredPoStProof::StackedDrgWindow8MiBV1, + fil_RegisteredPoStProof::StackedDrgWindow512MiBV1, + fil_RegisteredPoStProof::StackedDrgWindow32GiBV1, + ]; + + let num_ops = (seal_types.len() + post_types.len()) * 6; + + let mut pairs: Vec<(&str, *mut fil_StringResponse)> = Vec::with_capacity(num_ops); + + unsafe { + for st in seal_types { + pairs.push(("get_seal_params_cid", fil_get_seal_params_cid(st))); + pairs.push(( + "get_seal_verify_key_cid", + fil_get_seal_verifying_key_cid(st), + )); + pairs.push(("get_seal_verify_key_cid", fil_get_seal_params_path(st))); + pairs.push(( + "get_seal_verify_key_cid", + fil_get_seal_verifying_key_path(st), + )); + pairs.push(( + "get_seal_circuit_identifier", + fil_get_seal_circuit_identifier(st), + )); + pairs.push(("get_seal_version", fil_get_seal_version(st))); + } + + for pt in post_types { + pairs.push(("get_post_params_cid", fil_get_post_params_cid(pt))); + pairs.push(( + "get_post_verify_key_cid", + fil_get_post_verifying_key_cid(pt), + )); + pairs.push(("get_post_params_path", fil_get_post_params_path(pt))); + pairs.push(( + "get_post_verifying_key_path", + fil_get_post_verifying_key_path(pt), + )); + pairs.push(( + "get_post_circuit_identifier", + fil_get_post_circuit_identifier(pt), + )); + pairs.push(("get_post_version", fil_get_post_version(pt))); + } + } + + for (label, r) in pairs { + unsafe { + assert_eq!( + (*r).status_code, + FCPResponseStatus::FCPNoError, + "non-success exit code from {:?}: {:?}", + label, + c_str_to_rust_str((*r).error_msg) + ); + + let x = CStr::from_ptr((*r).string_val); + let y = x.to_str().unwrap(); + + assert!(!y.is_empty()); + + fil_destroy_string_response(r); + } + } + + Ok(()) + } + + #[test] + fn test_sealing() -> Result<()> { + let wrap = |x| fil_32ByteArray { inner: x }; + + // miscellaneous setup and shared values + let registered_proof_seal = fil_RegisteredSealProof::StackedDrg2KiBV1; + let registered_proof_winning_post = fil_RegisteredPoStProof::StackedDrgWinning2KiBV1; + let registered_proof_window_post = fil_RegisteredPoStProof::StackedDrgWindow2KiBV1; + + let cache_dir = tempfile::tempdir()?; + let cache_dir_path = cache_dir.into_path(); + + let prover_id = fil_32ByteArray { inner: [1u8; 32] }; + let randomness = fil_32ByteArray { inner: [7u8; 32] }; + let sector_id = 42; + let seed = fil_32ByteArray { inner: [5u8; 32] }; + let ticket = fil_32ByteArray { inner: [6u8; 32] }; + + // create a byte source (a user's piece) + let mut rng = thread_rng(); + let buf_a: Vec = (0..2032).map(|_| rng.gen()).collect(); + + let mut piece_file_a = tempfile::tempfile()?; + piece_file_a.write_all(&buf_a[0..127])?; + piece_file_a.seek(SeekFrom::Start(0))?; + + let mut piece_file_b = tempfile::tempfile()?; + piece_file_b.write_all(&buf_a[0..1016])?; + piece_file_b.seek(SeekFrom::Start(0))?; + + // create the staged sector (the byte destination) + let (staged_file, staged_path) = tempfile::NamedTempFile::new()?.keep()?; + + // create a temp file to be used as the byte destination + let (sealed_file, sealed_path) = tempfile::NamedTempFile::new()?.keep()?; + + // last temp file is used to output unsealed bytes + let (unseal_file, unseal_path) = tempfile::NamedTempFile::new()?.keep()?; + + // transmute temp files to file descriptors + let piece_file_a_fd = piece_file_a.into_raw_fd(); + let piece_file_b_fd = piece_file_b.into_raw_fd(); + let staged_sector_fd = staged_file.into_raw_fd(); + + unsafe { + let resp_a1 = fil_write_without_alignment( + registered_proof_seal, + piece_file_a_fd, + 127, + staged_sector_fd, + ); + + if (*resp_a1).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_a1).error_msg); + panic!("write_without_alignment failed: {:?}", msg); + } + + let existing_piece_sizes = vec![127]; + + let resp_a2 = fil_write_with_alignment( + registered_proof_seal, + piece_file_b_fd, + 1016, + staged_sector_fd, + existing_piece_sizes.as_ptr(), + existing_piece_sizes.len(), + ); + + if (*resp_a2).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_a2).error_msg); + panic!("write_with_alignment failed: {:?}", msg); + } + + let pieces = vec![ + fil_PublicPieceInfo { + num_bytes: 127, + comm_p: (*resp_a1).comm_p, + }, + fil_PublicPieceInfo { + num_bytes: 1016, + comm_p: (*resp_a2).comm_p, + }, + ]; + + let resp_x = + fil_generate_data_commitment(registered_proof_seal, pieces.as_ptr(), pieces.len()); + + if (*resp_x).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_x).error_msg); + panic!("generate_data_commitment failed: {:?}", msg); + } + + let cache_dir_path_c_str = rust_str_to_c_str(cache_dir_path.to_str().unwrap()); + let staged_path_c_str = rust_str_to_c_str(staged_path.to_str().unwrap()); + let replica_path_c_str = rust_str_to_c_str(sealed_path.to_str().unwrap()); + let unseal_path_c_str = rust_str_to_c_str(unseal_path.to_str().unwrap()); + + let resp_b1 = fil_seal_pre_commit_phase1( + registered_proof_seal, + cache_dir_path_c_str, + staged_path_c_str, + replica_path_c_str, + sector_id, + prover_id, + ticket, + pieces.as_ptr(), + pieces.len(), + ); + + if (*resp_b1).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_b1).error_msg); + panic!("seal_pre_commit_phase1 failed: {:?}", msg); + } + + let resp_b2 = fil_seal_pre_commit_phase2( + (*resp_b1).seal_pre_commit_phase1_output_ptr, + (*resp_b1).seal_pre_commit_phase1_output_len, + cache_dir_path_c_str, + replica_path_c_str, + ); + + if (*resp_b2).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_b2).error_msg); + panic!("seal_pre_commit_phase2 failed: {:?}", msg); + } + + let pre_computed_comm_d = &(*resp_x).comm_d; + let pre_commit_comm_d = &(*resp_b2).comm_d; + + assert_eq!( + format!("{:x?}", &pre_computed_comm_d), + format!("{:x?}", &pre_commit_comm_d), + "pre-computed CommD and pre-commit CommD don't match" + ); + + let resp_c1 = fil_seal_commit_phase1( + registered_proof_seal, + wrap((*resp_b2).comm_r), + wrap((*resp_b2).comm_d), + cache_dir_path_c_str, + replica_path_c_str, + sector_id, + prover_id, + ticket, + seed, + pieces.as_ptr(), + pieces.len(), + ); + + if (*resp_c1).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_c1).error_msg); + panic!("seal_commit_phase1 failed: {:?}", msg); + } + + let resp_c2 = fil_seal_commit_phase2( + (*resp_c1).seal_commit_phase1_output_ptr, + (*resp_c1).seal_commit_phase1_output_len, + sector_id, + prover_id, + ); + + if (*resp_c2).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_c2).error_msg); + panic!("seal_commit_phase2 failed: {:?}", msg); + } + + let resp_d = fil_verify_seal( + registered_proof_seal, + wrap((*resp_b2).comm_r), + wrap((*resp_b2).comm_d), + prover_id, + ticket, + seed, + sector_id, + (*resp_c2).proof_ptr, + (*resp_c2).proof_len, + ); + + if (*resp_d).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_d).error_msg); + panic!("seal_commit failed: {:?}", msg); + } + + assert!((*resp_d).is_valid, "proof was not valid"); + + let resp_e = fil_unseal_range( + registered_proof_seal, + cache_dir_path_c_str, + sealed_file.into_raw_fd(), + unseal_file.into_raw_fd(), + sector_id, + prover_id, + ticket, + wrap((*resp_b2).comm_d), + 0, + 2032, + ); + + if (*resp_e).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_e).error_msg); + panic!("unseal failed: {:?}", msg); + } + + // ensure unsealed bytes match what we had in our piece + let mut buf_b = Vec::with_capacity(2032); + let mut f = std::fs::File::open(unseal_path)?; + + let _ = f.read_to_end(&mut buf_b)?; + + let piece_a_len = (*resp_a1).total_write_unpadded as usize; + let piece_b_len = (*resp_a2).total_write_unpadded as usize; + let piece_b_prefix_len = (*resp_a2).left_alignment_unpadded as usize; + + let alignment = vec![0; piece_b_prefix_len]; + + let expected = [ + &buf_a[0..piece_a_len], + &alignment[..], + &buf_a[0..(piece_b_len - piece_b_prefix_len)], + ] + .concat(); + + assert_eq!( + format!("{:x?}", &expected), + format!("{:x?}", &buf_b), + "original bytes don't match unsealed bytes" + ); + + // generate a PoSt + + let sectors = vec![sector_id]; + let resp_f = fil_generate_winning_post_sector_challenge( + registered_proof_winning_post, + randomness, + sectors.len() as u64, + prover_id, + ); + + if (*resp_f).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_f).error_msg); + panic!("generate_candidates failed: {:?}", msg); + } + + // exercise the ticket-finalizing code path (but don't do anything + // with the results + let result: &[u64] = from_raw_parts((*resp_f).ids_ptr, (*resp_f).ids_len); + + if result.is_empty() { + panic!("generate_candidates produced no results"); + } + + let private_replicas = vec![fil_PrivateReplicaInfo { + registered_proof: registered_proof_winning_post, + cache_dir_path: cache_dir_path_c_str, + comm_r: (*resp_b2).comm_r, + replica_path: replica_path_c_str, + sector_id, + }]; + + // winning post + + let resp_h = fil_generate_winning_post( + randomness, + private_replicas.as_ptr(), + private_replicas.len(), + prover_id, + ); + + if (*resp_h).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_h).error_msg); + panic!("generate_winning_post failed: {:?}", msg); + } + let public_replicas = vec![fil_PublicReplicaInfo { + registered_proof: registered_proof_winning_post, + sector_id, + comm_r: (*resp_b2).comm_r, + }]; + + let resp_i = fil_verify_winning_post( + randomness, + public_replicas.as_ptr(), + public_replicas.len(), + (*resp_h).proofs_ptr, + (*resp_h).proofs_len, + prover_id, + ); + + if (*resp_i).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_i).error_msg); + panic!("verify_winning_post failed: {:?}", msg); + } + + if !(*resp_i).is_valid { + panic!("verify_winning_post rejected the provided proof as invalid"); + } + + // window post + + let private_replicas = vec![fil_PrivateReplicaInfo { + registered_proof: registered_proof_window_post, + cache_dir_path: cache_dir_path_c_str, + comm_r: (*resp_b2).comm_r, + replica_path: replica_path_c_str, + sector_id, + }]; + + let resp_j = fil_generate_window_post( + randomness, + private_replicas.as_ptr(), + private_replicas.len(), + prover_id, + ); + + if (*resp_j).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_j).error_msg); + panic!("generate_window_post failed: {:?}", msg); + } + + let public_replicas = vec![fil_PublicReplicaInfo { + registered_proof: registered_proof_window_post, + sector_id, + comm_r: (*resp_b2).comm_r, + }]; + + let resp_k = fil_verify_window_post( + randomness, + public_replicas.as_ptr(), + public_replicas.len(), + (*resp_j).proofs_ptr, + (*resp_j).proofs_len, + prover_id, + ); + + if (*resp_k).status_code != FCPResponseStatus::FCPNoError { + let msg = c_str_to_rust_str((*resp_k).error_msg); + panic!("verify_window_post failed: {:?}", msg); + } + + if !(*resp_k).is_valid { + panic!("verify_window_post rejected the provided proof as invalid"); + } + + fil_destroy_write_without_alignment_response(resp_a1); + fil_destroy_write_with_alignment_response(resp_a2); + fil_destroy_generate_data_commitment_response(resp_x); + + fil_destroy_seal_pre_commit_phase1_response(resp_b1); + fil_destroy_seal_pre_commit_phase2_response(resp_b2); + fil_destroy_seal_commit_phase1_response(resp_c1); + fil_destroy_seal_commit_phase2_response(resp_c2); + + fil_destroy_verify_seal_response(resp_d); + fil_destroy_unseal_range_response(resp_e); + + fil_destroy_generate_winning_post_sector_challenge(resp_f); + fil_destroy_generate_winning_post_response(resp_h); + fil_destroy_verify_winning_post_response(resp_i); + + fil_destroy_generate_window_post_response(resp_j); + fil_destroy_verify_window_post_response(resp_k); + + c_str_to_rust_str(cache_dir_path_c_str); + c_str_to_rust_str(staged_path_c_str); + c_str_to_rust_str(replica_path_c_str); + c_str_to_rust_str(unseal_path_c_str); + } + + Ok(()) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/helpers.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/helpers.rs new file mode 100644 index 0000000000..132666a457 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/helpers.rs @@ -0,0 +1,134 @@ +use std::collections::btree_map::BTreeMap; +use std::path::PathBuf; +use std::slice::from_raw_parts; + +use anyhow::{ensure, Result}; +use ffi_toolkit::{c_str_to_pbuf, c_str_to_rust_str}; +use filecoin_proofs_api::{PrivateReplicaInfo, PublicReplicaInfo, SectorId}; + +use super::types::{fil_PrivateReplicaInfo, fil_PublicReplicaInfo, fil_RegisteredPoStProof}; +use crate::proofs::types::{fil_PoStProof, PoStProof}; + +#[derive(Debug, Clone)] +struct PublicReplicaInfoTmp { + pub registered_proof: fil_RegisteredPoStProof, + pub comm_r: [u8; 32], + pub sector_id: u64, +} + +#[allow(clippy::type_complexity)] +pub unsafe fn to_public_replica_info_map( + replicas_ptr: *const fil_PublicReplicaInfo, + replicas_len: libc::size_t, +) -> Result> { + use rayon::prelude::*; + + ensure!(!replicas_ptr.is_null(), "replicas_ptr must not be null"); + + let mut replicas = Vec::new(); + + for ffi_info in from_raw_parts(replicas_ptr, replicas_len) { + replicas.push(PublicReplicaInfoTmp { + sector_id: ffi_info.sector_id, + registered_proof: ffi_info.registered_proof, + comm_r: ffi_info.comm_r, + }); + } + + let map = replicas + .into_par_iter() + .map(|info| { + let PublicReplicaInfoTmp { + registered_proof, + comm_r, + sector_id, + } = info; + + ( + SectorId::from(sector_id), + PublicReplicaInfo::new(registered_proof.into(), comm_r), + ) + }) + .collect(); + + Ok(map) +} + +#[derive(Debug, Clone)] +struct PrivateReplicaInfoTmp { + pub registered_proof: fil_RegisteredPoStProof, + pub cache_dir_path: std::path::PathBuf, + pub comm_r: [u8; 32], + pub replica_path: std::path::PathBuf, + pub sector_id: u64, +} + +pub unsafe fn to_private_replica_info_map( + replicas_ptr: *const fil_PrivateReplicaInfo, + replicas_len: libc::size_t, +) -> Result> { + use rayon::prelude::*; + + ensure!(!replicas_ptr.is_null(), "replicas_ptr must not be null"); + + let replicas: Vec<_> = from_raw_parts(replicas_ptr, replicas_len) + .iter() + .map(|ffi_info| { + let cache_dir_path = c_str_to_pbuf(ffi_info.cache_dir_path); + let replica_path = c_str_to_rust_str(ffi_info.replica_path).to_string(); + + PrivateReplicaInfoTmp { + registered_proof: ffi_info.registered_proof, + cache_dir_path, + comm_r: ffi_info.comm_r, + replica_path: PathBuf::from(replica_path), + sector_id: ffi_info.sector_id, + } + }) + .collect(); + + let map = replicas + .into_par_iter() + .map(|info| { + let PrivateReplicaInfoTmp { + registered_proof, + cache_dir_path, + comm_r, + replica_path, + sector_id, + } = info; + + ( + SectorId::from(sector_id), + PrivateReplicaInfo::new( + registered_proof.into(), + comm_r, + cache_dir_path, + replica_path, + ), + ) + }) + .collect(); + + Ok(map) +} + +pub unsafe fn c_to_rust_post_proofs( + post_proofs_ptr: *const fil_PoStProof, + post_proofs_len: libc::size_t, +) -> Result> { + ensure!( + !post_proofs_ptr.is_null(), + "post_proofs_ptr must not be null" + ); + + let out = from_raw_parts(post_proofs_ptr, post_proofs_len) + .iter() + .map(|fpp| PoStProof { + registered_proof: fpp.registered_proof.into(), + proof: from_raw_parts(fpp.proof_ptr, fpp.proof_len).to_vec(), + }) + .collect(); + + Ok(out) +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/mod.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/mod.rs new file mode 100644 index 0000000000..1a67a19206 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/mod.rs @@ -0,0 +1,4 @@ +mod helpers; + +pub mod api; +pub mod types; diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/types.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/types.rs new file mode 100644 index 0000000000..6ae0f85286 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/proofs/types.rs @@ -0,0 +1,609 @@ +use std::io::{Error, SeekFrom}; +use std::ptr; +use std::slice::from_raw_parts; + +use anyhow::Result; +use drop_struct_macro_derive::DropStructMacro; +use ffi_toolkit::{code_and_message_impl, free_c_str, CodeAndMessage, FCPResponseStatus}; +use filecoin_proofs_api::{ + PieceInfo, RegisteredPoStProof, RegisteredSealProof, UnpaddedBytesAmount, +}; + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct fil_32ByteArray { + pub inner: [u8; 32], +} + +/// FileDescriptorRef does not drop its file descriptor when it is dropped. Its +/// owner must manage the lifecycle of the file descriptor. +pub struct FileDescriptorRef(std::mem::ManuallyDrop); + +impl FileDescriptorRef { + #[cfg(not(target_os = "windows"))] + pub unsafe fn new(raw: std::os::unix::io::RawFd) -> Self { + use std::os::unix::io::FromRawFd; + FileDescriptorRef(std::mem::ManuallyDrop::new(std::fs::File::from_raw_fd(raw))) + } +} + +impl std::io::Read for FileDescriptorRef { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf) + } +} + +impl std::io::Write for FileDescriptorRef { + fn write(&mut self, buf: &[u8]) -> Result { + self.0.write(buf) + } + + fn flush(&mut self) -> Result<(), Error> { + self.0.flush() + } +} + +impl std::io::Seek for FileDescriptorRef { + fn seek(&mut self, pos: SeekFrom) -> Result { + self.0.seek(pos) + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum fil_RegisteredSealProof { + StackedDrg2KiBV1, + StackedDrg8MiBV1, + StackedDrg512MiBV1, + StackedDrg32GiBV1, + StackedDrg64GiBV1, +} + +impl From for fil_RegisteredSealProof { + fn from(other: RegisteredSealProof) -> Self { + match other { + RegisteredSealProof::StackedDrg2KiBV1 => fil_RegisteredSealProof::StackedDrg2KiBV1, + RegisteredSealProof::StackedDrg8MiBV1 => fil_RegisteredSealProof::StackedDrg8MiBV1, + RegisteredSealProof::StackedDrg512MiBV1 => fil_RegisteredSealProof::StackedDrg512MiBV1, + RegisteredSealProof::StackedDrg32GiBV1 => fil_RegisteredSealProof::StackedDrg32GiBV1, + RegisteredSealProof::StackedDrg64GiBV1 => fil_RegisteredSealProof::StackedDrg64GiBV1, + } + } +} + +impl From for RegisteredSealProof { + fn from(other: fil_RegisteredSealProof) -> Self { + match other { + fil_RegisteredSealProof::StackedDrg2KiBV1 => RegisteredSealProof::StackedDrg2KiBV1, + fil_RegisteredSealProof::StackedDrg8MiBV1 => RegisteredSealProof::StackedDrg8MiBV1, + fil_RegisteredSealProof::StackedDrg512MiBV1 => RegisteredSealProof::StackedDrg512MiBV1, + fil_RegisteredSealProof::StackedDrg32GiBV1 => RegisteredSealProof::StackedDrg32GiBV1, + fil_RegisteredSealProof::StackedDrg64GiBV1 => RegisteredSealProof::StackedDrg64GiBV1, + } + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum fil_RegisteredPoStProof { + StackedDrgWinning2KiBV1, + StackedDrgWinning8MiBV1, + StackedDrgWinning512MiBV1, + StackedDrgWinning32GiBV1, + StackedDrgWinning64GiBV1, + StackedDrgWindow2KiBV1, + StackedDrgWindow8MiBV1, + StackedDrgWindow512MiBV1, + StackedDrgWindow32GiBV1, + StackedDrgWindow64GiBV1, +} + +impl From for fil_RegisteredPoStProof { + fn from(other: RegisteredPoStProof) -> Self { + use RegisteredPoStProof::*; + + match other { + StackedDrgWinning2KiBV1 => fil_RegisteredPoStProof::StackedDrgWinning2KiBV1, + StackedDrgWinning8MiBV1 => fil_RegisteredPoStProof::StackedDrgWinning8MiBV1, + StackedDrgWinning512MiBV1 => fil_RegisteredPoStProof::StackedDrgWinning512MiBV1, + StackedDrgWinning32GiBV1 => fil_RegisteredPoStProof::StackedDrgWinning32GiBV1, + StackedDrgWinning64GiBV1 => fil_RegisteredPoStProof::StackedDrgWinning64GiBV1, + StackedDrgWindow2KiBV1 => fil_RegisteredPoStProof::StackedDrgWindow2KiBV1, + StackedDrgWindow8MiBV1 => fil_RegisteredPoStProof::StackedDrgWindow8MiBV1, + StackedDrgWindow512MiBV1 => fil_RegisteredPoStProof::StackedDrgWindow512MiBV1, + StackedDrgWindow32GiBV1 => fil_RegisteredPoStProof::StackedDrgWindow32GiBV1, + StackedDrgWindow64GiBV1 => fil_RegisteredPoStProof::StackedDrgWindow64GiBV1, + } + } +} + +impl From for RegisteredPoStProof { + fn from(other: fil_RegisteredPoStProof) -> Self { + use RegisteredPoStProof::*; + + match other { + fil_RegisteredPoStProof::StackedDrgWinning2KiBV1 => StackedDrgWinning2KiBV1, + fil_RegisteredPoStProof::StackedDrgWinning8MiBV1 => StackedDrgWinning8MiBV1, + fil_RegisteredPoStProof::StackedDrgWinning512MiBV1 => StackedDrgWinning512MiBV1, + fil_RegisteredPoStProof::StackedDrgWinning32GiBV1 => StackedDrgWinning32GiBV1, + fil_RegisteredPoStProof::StackedDrgWinning64GiBV1 => StackedDrgWinning64GiBV1, + fil_RegisteredPoStProof::StackedDrgWindow2KiBV1 => StackedDrgWindow2KiBV1, + fil_RegisteredPoStProof::StackedDrgWindow8MiBV1 => StackedDrgWindow8MiBV1, + fil_RegisteredPoStProof::StackedDrgWindow512MiBV1 => StackedDrgWindow512MiBV1, + fil_RegisteredPoStProof::StackedDrgWindow32GiBV1 => StackedDrgWindow32GiBV1, + fil_RegisteredPoStProof::StackedDrgWindow64GiBV1 => StackedDrgWindow64GiBV1, + } + } +} + +#[repr(C)] +#[derive(Clone)] +pub struct fil_PublicPieceInfo { + pub num_bytes: u64, + pub comm_p: [u8; 32], +} + +impl From for PieceInfo { + fn from(x: fil_PublicPieceInfo) -> Self { + let fil_PublicPieceInfo { num_bytes, comm_p } = x; + PieceInfo { + commitment: comm_p, + size: UnpaddedBytesAmount(num_bytes), + } + } +} + +#[repr(C)] +#[derive(Clone)] +pub struct fil_PoStProof { + pub registered_proof: fil_RegisteredPoStProof, + pub proof_len: libc::size_t, + pub proof_ptr: *const u8, +} + +impl Drop for fil_PoStProof { + fn drop(&mut self) { + let _ = unsafe { + Vec::from_raw_parts(self.proof_ptr as *mut u8, self.proof_len, self.proof_len) + }; + } +} + +#[derive(Clone, Debug)] +pub struct PoStProof { + pub registered_proof: RegisteredPoStProof, + pub proof: Vec, +} + +impl From for PoStProof { + fn from(other: fil_PoStProof) -> Self { + let proof = unsafe { from_raw_parts(other.proof_ptr, other.proof_len).to_vec() }; + + PoStProof { + registered_proof: other.registered_proof.into(), + proof, + } + } +} + +#[repr(C)] +#[derive(Clone)] +pub struct fil_PrivateReplicaInfo { + pub registered_proof: fil_RegisteredPoStProof, + pub cache_dir_path: *const libc::c_char, + pub comm_r: [u8; 32], + pub replica_path: *const libc::c_char, + pub sector_id: u64, +} + +#[repr(C)] +#[derive(Clone)] +pub struct fil_PublicReplicaInfo { + pub registered_proof: fil_RegisteredPoStProof, + pub comm_r: [u8; 32], + pub sector_id: u64, +} + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_GenerateWinningPoStSectorChallenge { + pub error_msg: *const libc::c_char, + pub status_code: FCPResponseStatus, + pub ids_ptr: *const u64, + pub ids_len: libc::size_t, +} + +impl Default for fil_GenerateWinningPoStSectorChallenge { + fn default() -> fil_GenerateWinningPoStSectorChallenge { + fil_GenerateWinningPoStSectorChallenge { + ids_len: 0, + ids_ptr: ptr::null(), + error_msg: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + } + } +} + +code_and_message_impl!(fil_GenerateWinningPoStSectorChallenge); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_GenerateWinningPoStResponse { + pub error_msg: *const libc::c_char, + pub proofs_len: libc::size_t, + pub proofs_ptr: *const fil_PoStProof, + pub status_code: FCPResponseStatus, +} + +impl Default for fil_GenerateWinningPoStResponse { + fn default() -> fil_GenerateWinningPoStResponse { + fil_GenerateWinningPoStResponse { + error_msg: ptr::null(), + proofs_len: 0, + proofs_ptr: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + } + } +} + +code_and_message_impl!(fil_GenerateWinningPoStResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_GenerateWindowPoStResponse { + pub error_msg: *const libc::c_char, + pub proofs_len: libc::size_t, + pub proofs_ptr: *const fil_PoStProof, + pub status_code: FCPResponseStatus, +} + +impl Default for fil_GenerateWindowPoStResponse { + fn default() -> fil_GenerateWindowPoStResponse { + fil_GenerateWindowPoStResponse { + error_msg: ptr::null(), + proofs_len: 0, + proofs_ptr: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + } + } +} + +code_and_message_impl!(fil_GenerateWindowPoStResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_WriteWithAlignmentResponse { + pub comm_p: [u8; 32], + pub error_msg: *const libc::c_char, + pub left_alignment_unpadded: u64, + pub status_code: FCPResponseStatus, + pub total_write_unpadded: u64, +} + +impl Default for fil_WriteWithAlignmentResponse { + fn default() -> fil_WriteWithAlignmentResponse { + fil_WriteWithAlignmentResponse { + comm_p: Default::default(), + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + left_alignment_unpadded: 0, + total_write_unpadded: 0, + } + } +} + +code_and_message_impl!(fil_WriteWithAlignmentResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_WriteWithoutAlignmentResponse { + pub comm_p: [u8; 32], + pub error_msg: *const libc::c_char, + pub status_code: FCPResponseStatus, + pub total_write_unpadded: u64, +} + +impl Default for fil_WriteWithoutAlignmentResponse { + fn default() -> fil_WriteWithoutAlignmentResponse { + fil_WriteWithoutAlignmentResponse { + comm_p: Default::default(), + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + total_write_unpadded: 0, + } + } +} + +code_and_message_impl!(fil_WriteWithoutAlignmentResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_SealPreCommitPhase1Response { + pub error_msg: *const libc::c_char, + pub status_code: FCPResponseStatus, + pub seal_pre_commit_phase1_output_ptr: *const u8, + pub seal_pre_commit_phase1_output_len: libc::size_t, +} + +impl Default for fil_SealPreCommitPhase1Response { + fn default() -> fil_SealPreCommitPhase1Response { + fil_SealPreCommitPhase1Response { + error_msg: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + seal_pre_commit_phase1_output_ptr: ptr::null(), + seal_pre_commit_phase1_output_len: 0, + } + } +} + +code_and_message_impl!(fil_SealPreCommitPhase1Response); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_FauxRepResponse { + pub error_msg: *const libc::c_char, + pub status_code: FCPResponseStatus, + pub commitment: [u8; 32], +} + +impl Default for fil_FauxRepResponse { + fn default() -> fil_FauxRepResponse { + fil_FauxRepResponse { + error_msg: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + commitment: Default::default(), + } + } +} + +code_and_message_impl!(fil_FauxRepResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_SealPreCommitPhase2Response { + pub error_msg: *const libc::c_char, + pub status_code: FCPResponseStatus, + pub registered_proof: fil_RegisteredSealProof, + pub comm_d: [u8; 32], + pub comm_r: [u8; 32], +} + +impl Default for fil_SealPreCommitPhase2Response { + fn default() -> fil_SealPreCommitPhase2Response { + fil_SealPreCommitPhase2Response { + error_msg: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + registered_proof: fil_RegisteredSealProof::StackedDrg2KiBV1, + comm_d: Default::default(), + comm_r: Default::default(), + } + } +} + +code_and_message_impl!(fil_SealPreCommitPhase2Response); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_SealCommitPhase1Response { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub seal_commit_phase1_output_ptr: *const u8, + pub seal_commit_phase1_output_len: libc::size_t, +} + +impl Default for fil_SealCommitPhase1Response { + fn default() -> fil_SealCommitPhase1Response { + fil_SealCommitPhase1Response { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + seal_commit_phase1_output_ptr: ptr::null(), + seal_commit_phase1_output_len: 0, + } + } +} + +code_and_message_impl!(fil_SealCommitPhase1Response); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_SealCommitPhase2Response { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub proof_ptr: *const u8, + pub proof_len: libc::size_t, +} + +impl Default for fil_SealCommitPhase2Response { + fn default() -> fil_SealCommitPhase2Response { + fil_SealCommitPhase2Response { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + proof_ptr: ptr::null(), + proof_len: 0, + } + } +} + +code_and_message_impl!(fil_SealCommitPhase2Response); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_UnsealRangeResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, +} + +impl Default for fil_UnsealRangeResponse { + fn default() -> fil_UnsealRangeResponse { + fil_UnsealRangeResponse { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + } + } +} + +code_and_message_impl!(fil_UnsealRangeResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_VerifySealResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub is_valid: bool, +} + +impl Default for fil_VerifySealResponse { + fn default() -> fil_VerifySealResponse { + fil_VerifySealResponse { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + is_valid: false, + } + } +} + +code_and_message_impl!(fil_VerifySealResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_VerifyWinningPoStResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub is_valid: bool, +} + +impl Default for fil_VerifyWinningPoStResponse { + fn default() -> fil_VerifyWinningPoStResponse { + fil_VerifyWinningPoStResponse { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + is_valid: false, + } + } +} + +code_and_message_impl!(fil_VerifyWinningPoStResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_VerifyWindowPoStResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub is_valid: bool, +} + +impl Default for fil_VerifyWindowPoStResponse { + fn default() -> fil_VerifyWindowPoStResponse { + fil_VerifyWindowPoStResponse { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + is_valid: false, + } + } +} + +code_and_message_impl!(fil_VerifyWindowPoStResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_FinalizeTicketResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub ticket: [u8; 32], +} + +impl Default for fil_FinalizeTicketResponse { + fn default() -> Self { + fil_FinalizeTicketResponse { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + ticket: [0u8; 32], + } + } +} + +code_and_message_impl!(fil_FinalizeTicketResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_GeneratePieceCommitmentResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub comm_p: [u8; 32], + /// The number of unpadded bytes in the original piece plus any (unpadded) + /// alignment bytes added to create a whole merkle tree. + pub num_bytes_aligned: u64, +} + +impl Default for fil_GeneratePieceCommitmentResponse { + fn default() -> fil_GeneratePieceCommitmentResponse { + fil_GeneratePieceCommitmentResponse { + status_code: FCPResponseStatus::FCPNoError, + comm_p: Default::default(), + error_msg: ptr::null(), + num_bytes_aligned: 0, + } + } +} + +code_and_message_impl!(fil_GeneratePieceCommitmentResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_GenerateDataCommitmentResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub comm_d: [u8; 32], +} + +impl Default for fil_GenerateDataCommitmentResponse { + fn default() -> fil_GenerateDataCommitmentResponse { + fil_GenerateDataCommitmentResponse { + status_code: FCPResponseStatus::FCPNoError, + comm_d: Default::default(), + error_msg: ptr::null(), + } + } +} + +code_and_message_impl!(fil_GenerateDataCommitmentResponse); + +/// + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_StringResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub string_val: *const libc::c_char, +} + +impl Default for fil_StringResponse { + fn default() -> fil_StringResponse { + fil_StringResponse { + status_code: FCPResponseStatus::FCPNoError, + error_msg: ptr::null(), + string_val: ptr::null(), + } + } +} + +code_and_message_impl!(fil_StringResponse); + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_ClearCacheResponse { + pub error_msg: *const libc::c_char, + pub status_code: FCPResponseStatus, +} + +impl Default for fil_ClearCacheResponse { + fn default() -> fil_ClearCacheResponse { + fil_ClearCacheResponse { + error_msg: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + } + } +} + +code_and_message_impl!(fil_ClearCacheResponse); diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/api.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/api.rs new file mode 100644 index 0000000000..9ddb017ffa --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/api.rs @@ -0,0 +1,168 @@ +use std::ffi::CString; +use std::fs::File; +use std::os::unix::io::FromRawFd; +use std::sync::Once; + +use bellperson::GPU_NVIDIA_DEVICES; +use ffi_toolkit::{catch_panic_response, raw_ptr, rust_str_to_c_str, FCPResponseStatus}; + +use super::types::{fil_GpuDeviceResponse, fil_InitLogFdResponse}; + +/// Protects the init off the logger. +static LOG_INIT: Once = Once::new(); + +/// Ensures the logger is initialized. +pub fn init_log() { + LOG_INIT.call_once(|| { + fil_logger::init(); + }); +} +/// Initialize the logger with a file to log into +/// +/// Returns `None` if there is already an active logger +pub fn init_log_with_file(file: File) -> Option<()> { + if LOG_INIT.is_completed() { + None + } else { + LOG_INIT.call_once(|| { + fil_logger::init_with_file(file); + }); + Some(()) + } +} + +/// Returns an array of strings containing the device names that can be used. +#[no_mangle] +pub unsafe extern "C" fn fil_get_gpu_devices() -> *mut fil_GpuDeviceResponse { + catch_panic_response(|| { + let n = GPU_NVIDIA_DEVICES.len(); + + let devices: Vec<*const libc::c_char> = GPU_NVIDIA_DEVICES + .iter() + .map(|d| d.name().unwrap_or_else(|_| "Unknown".to_string())) + .map(|d| { + CString::new(d) + .unwrap_or_else(|_| CString::new("Unknown").unwrap()) + .into_raw() as *const libc::c_char + }) + .collect(); + + let dyn_array = Box::into_raw(devices.into_boxed_slice()); + + let mut response = fil_GpuDeviceResponse::default(); + response.devices_len = n; + response.devices_ptr = dyn_array as *const *const libc::c_char; + + raw_ptr(response) + }) +} + +/// Initializes the logger with a file descriptor where logs will be logged into. +/// +/// This is usually a pipe that was opened on the receiving side of the logs. The logger is +/// initialized on the invocation, subsequent calls won't have any effect. +/// +/// This function must be called right at the start, before any other call. Else the logger will +/// be initializes implicitely and log to stderr. +#[no_mangle] +#[cfg(not(target_os = "windows"))] +pub unsafe extern "C" fn fil_init_log_fd(log_fd: libc::c_int) -> *mut fil_InitLogFdResponse { + catch_panic_response(|| { + let file = File::from_raw_fd(log_fd); + let mut response = fil_InitLogFdResponse::default(); + if init_log_with_file(file).is_none() { + response.status_code = FCPResponseStatus::FCPUnclassifiedError; + response.error_msg = rust_str_to_c_str("There is already an active logger. `fil_init_log_fd()` needs to be called before any other FFI function is called."); + } + raw_ptr(response) + }) +} + +#[cfg(test)] +mod tests { + + use crate::util::api::fil_get_gpu_devices; + use crate::util::types::fil_destroy_gpu_device_response; + + #[test] + fn test_get_gpu_devices() { + unsafe { + let resp = fil_get_gpu_devices(); + + let strings = std::slice::from_raw_parts_mut( + (*resp).devices_ptr as *mut *mut libc::c_char, + (*resp).devices_len as usize, + ); + + let devices: Vec = strings + .iter_mut() + .map(|s| { + std::ffi::CStr::from_ptr(*s) + .to_str() + .unwrap_or("Unknown") + .to_owned() + }) + .collect(); + + assert_eq!(devices.len(), (*resp).devices_len); + fil_destroy_gpu_device_response(resp); + } + } + + #[test] + #[ignore] + #[cfg(target_os = "linux")] + fn test_init_log_fd() { + /* + + Warning: This test is leaky. When run alongside other (Rust) tests in + this project, `[flexi_logger] writing log line failed` lines will be + observed in stderr, and various unrelated tests will fail. + + - @laser 20200725 + + */ + use std::env; + use std::fs::File; + use std::io::{BufRead, BufReader, Write}; + use std::os::unix::io::FromRawFd; + + use ffi_toolkit::FCPResponseStatus; + + use crate::util::api::fil_init_log_fd; + use crate::util::types::fil_destroy_init_log_fd_response; + + let mut fds: [libc::c_int; 2] = [0; 2]; + let res = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }; + if res != 0 { + panic!("Cannot create pipe"); + } + let [read_fd, write_fd] = fds; + + unsafe { + let mut reader = BufReader::new(File::from_raw_fd(read_fd)); + let mut writer = File::from_raw_fd(write_fd); + + // Without setting this env variable there won't be any log output + env::set_var("RUST_LOG", "debug"); + + let resp = fil_init_log_fd(write_fd); + fil_destroy_init_log_fd_response(resp); + + log::info!("a log message"); + + // Write a newline so that things don't block even if the logging doesn't work + writer.write_all(b"\n").unwrap(); + + let mut log_message = String::new(); + reader.read_line(&mut log_message).unwrap(); + + assert!(log_message.ends_with("a log message\n")); + + // Now test that there is an error when we try to init it again + let resp_error = fil_init_log_fd(write_fd); + assert_ne!((*resp_error).status_code, FCPResponseStatus::FCPNoError); + fil_destroy_init_log_fd_response(resp_error); + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/mod.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/mod.rs new file mode 100644 index 0000000000..8389f117b5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/mod.rs @@ -0,0 +1,2 @@ +pub mod api; +pub mod types; diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/types.rs b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/types.rs new file mode 100644 index 0000000000..732e22a1e7 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/rust/src/util/types.rs @@ -0,0 +1,55 @@ +use std::ptr; + +use drop_struct_macro_derive::DropStructMacro; +// `CodeAndMessage` is the trait implemented by `code_and_message_impl +use ffi_toolkit::{code_and_message_impl, free_c_str, CodeAndMessage, FCPResponseStatus}; + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_GpuDeviceResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, + pub devices_len: libc::size_t, + pub devices_ptr: *const *const libc::c_char, +} + +impl Default for fil_GpuDeviceResponse { + fn default() -> Self { + Self { + error_msg: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + devices_len: 0, + devices_ptr: ptr::null(), + } + } +} + +code_and_message_impl!(fil_GpuDeviceResponse); + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_gpu_device_response(ptr: *mut fil_GpuDeviceResponse) { + let _ = Box::from_raw(ptr); +} + +#[repr(C)] +#[derive(DropStructMacro)] +pub struct fil_InitLogFdResponse { + pub status_code: FCPResponseStatus, + pub error_msg: *const libc::c_char, +} + +impl Default for fil_InitLogFdResponse { + fn default() -> Self { + Self { + error_msg: ptr::null(), + status_code: FCPResponseStatus::FCPNoError, + } + } +} + +code_and_message_impl!(fil_InitLogFdResponse); + +#[no_mangle] +pub unsafe extern "C" fn fil_destroy_init_log_fd_response(ptr: *mut fil_InitLogFdResponse) { + let _ = Box::from_raw(ptr); +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/types.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/types.go new file mode 100644 index 0000000000..5a810ed43a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/types.go @@ -0,0 +1,127 @@ +package ffi + +import ( + "bytes" + "encoding/json" + "sort" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/ipfs/go-cid" +) + +// BLS + +// SignatureBytes is the length of a BLS signature +const SignatureBytes = 96 + +// PrivateKeyBytes is the length of a BLS private key +const PrivateKeyBytes = 32 + +// PublicKeyBytes is the length of a BLS public key +const PublicKeyBytes = 48 + +// DigestBytes is the length of a BLS message hash/digest +const DigestBytes = 96 + +// Signature is a compressed affine +type Signature [SignatureBytes]byte + +// PrivateKey is a compressed affine +type PrivateKey [PrivateKeyBytes]byte + +// PublicKey is a compressed affine +type PublicKey [PublicKeyBytes]byte + +// Message is a byte slice +type Message []byte + +// Digest is a compressed affine +type Digest [DigestBytes]byte + +// Used when generating a private key deterministically +type PrivateKeyGenSeed [32]byte + +// Proofs + +// SortedPublicSectorInfo is a slice of publicSectorInfo sorted +// (lexicographically, ascending) by sealed (replica) CID. +type SortedPublicSectorInfo struct { + f []publicSectorInfo +} + +// SortedPrivateSectorInfo is a slice of PrivateSectorInfo sorted +// (lexicographically, ascending) by sealed (replica) CID. +type SortedPrivateSectorInfo struct { + f []PrivateSectorInfo +} + +func newSortedPublicSectorInfo(sectorInfo ...publicSectorInfo) SortedPublicSectorInfo { + fn := func(i, j int) bool { + return bytes.Compare(sectorInfo[i].SealedCID.Bytes(), sectorInfo[j].SealedCID.Bytes()) == -1 + } + + sort.Slice(sectorInfo[:], fn) + + return SortedPublicSectorInfo{ + f: sectorInfo, + } +} + +// Values returns the sorted publicSectorInfo as a slice +func (s *SortedPublicSectorInfo) Values() []publicSectorInfo { + return s.f +} + +// MarshalJSON JSON-encodes and serializes the SortedPublicSectorInfo. +func (s SortedPublicSectorInfo) MarshalJSON() ([]byte, error) { + return json.Marshal(s.f) +} + +// UnmarshalJSON parses the JSON-encoded byte slice and stores the result in the +// value pointed to by s.f. Note that this method allows for construction of a +// SortedPublicSectorInfo which violates its invariant (that its publicSectorInfo are sorted +// in some defined way). Callers should take care to never provide a byte slice +// which would violate this invariant. +func (s *SortedPublicSectorInfo) UnmarshalJSON(b []byte) error { + return json.Unmarshal(b, &s.f) +} + +// NewSortedPrivateSectorInfo returns a SortedPrivateSectorInfo +func NewSortedPrivateSectorInfo(sectorInfo ...PrivateSectorInfo) SortedPrivateSectorInfo { + fn := func(i, j int) bool { + return bytes.Compare(sectorInfo[i].SealedCID.Bytes(), sectorInfo[j].SealedCID.Bytes()) == -1 + } + + sort.Slice(sectorInfo[:], fn) + + return SortedPrivateSectorInfo{ + f: sectorInfo, + } +} + +// Values returns the sorted PrivateSectorInfo as a slice +func (s *SortedPrivateSectorInfo) Values() []PrivateSectorInfo { + return s.f +} + +// MarshalJSON JSON-encodes and serializes the SortedPrivateSectorInfo. +func (s SortedPrivateSectorInfo) MarshalJSON() ([]byte, error) { + return json.Marshal(s.f) +} + +func (s *SortedPrivateSectorInfo) UnmarshalJSON(b []byte) error { + return json.Unmarshal(b, &s.f) +} + +type publicSectorInfo struct { + PoStProofType abi.RegisteredPoStProof + SealedCID cid.Cid + SectorNum abi.SectorNumber +} + +type PrivateSectorInfo struct { + abi.SectorInfo + CacheDirPath string + PoStProofType abi.RegisteredPoStProof + SealedSectorPath string +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/workflows.go b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/workflows.go new file mode 100644 index 0000000000..37a62f300e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/filecoin-ffi/workflows.go @@ -0,0 +1,388 @@ +//+build cgo + +package ffi + +import ( + "bytes" + "crypto/rand" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/ipfs/go-cid" +) + +func WorkflowProofsLifecycle(t TestHelper) { + minerID := abi.ActorID(42) + randomness := [32]byte{9, 9, 9} + sealProofType := abi.RegisteredSealProof_StackedDrg2KiBV1 + winningPostProofType := abi.RegisteredPoStProof_StackedDrgWinning2KiBV1 + sectorNum := abi.SectorNumber(42) + + ticket := abi.SealRandomness{5, 4, 2} + + seed := abi.InteractiveSealRandomness{7, 4, 2} + + // initialize a sector builder + metadataDir := requireTempDirPath(t, "metadata") + defer os.RemoveAll(metadataDir) + + sealedSectorsDir := requireTempDirPath(t, "sealed-sectors") + defer os.RemoveAll(sealedSectorsDir) + + stagedSectorsDir := requireTempDirPath(t, "staged-sectors") + defer os.RemoveAll(stagedSectorsDir) + + sectorCacheRootDir := requireTempDirPath(t, "sector-cache-root-dir") + defer os.RemoveAll(sectorCacheRootDir) + + sectorCacheDirPath := requireTempDirPath(t, "sector-cache-dir") + defer os.RemoveAll(sectorCacheDirPath) + + fauxSectorCacheDirPath := requireTempDirPath(t, "faux-sector-cache-dir") + defer os.RemoveAll(fauxSectorCacheDirPath) + + stagedSectorFile := requireTempFile(t, bytes.NewReader([]byte{}), 0) + defer stagedSectorFile.Close() + + sealedSectorFile := requireTempFile(t, bytes.NewReader([]byte{}), 0) + defer sealedSectorFile.Close() + + fauxSealedSectorFile := requireTempFile(t, bytes.NewReader([]byte{}), 0) + defer fauxSealedSectorFile.Close() + + unsealOutputFileA := requireTempFile(t, bytes.NewReader([]byte{}), 0) + defer unsealOutputFileA.Close() + + unsealOutputFileB := requireTempFile(t, bytes.NewReader([]byte{}), 0) + defer unsealOutputFileB.Close() + + unsealOutputFileC := requireTempFile(t, bytes.NewReader([]byte{}), 0) + defer unsealOutputFileC.Close() + + unsealOutputFileD := requireTempFile(t, bytes.NewReader([]byte{}), 0) + defer unsealOutputFileD.Close() + + // some rando bytes + someBytes := make([]byte, abi.PaddedPieceSize(2048).Unpadded()) + _, err := io.ReadFull(rand.Reader, someBytes) + t.RequireNoError(err) + + // write first piece + pieceFileA := requireTempFile(t, bytes.NewReader(someBytes[0:127]), 127) + + pieceCIDA, err := GeneratePieceCIDFromFile(sealProofType, pieceFileA, 127) + t.RequireNoError(err) + + // seek back to head (generating piece commitment moves offset) + _, err = pieceFileA.Seek(0, 0) + t.RequireNoError(err) + + // write the first piece using the alignment-free function + n, pieceCID, err := WriteWithoutAlignment(sealProofType, pieceFileA, 127, stagedSectorFile) + t.RequireNoError(err) + t.AssertEqual(int(n), 127) + t.AssertTrue(pieceCID.Equals(pieceCIDA)) + + // write second piece + alignment + t.RequireNoError(err) + pieceFileB := requireTempFile(t, bytes.NewReader(someBytes[0:1016]), 1016) + + pieceCIDB, err := GeneratePieceCIDFromFile(sealProofType, pieceFileB, 1016) + t.RequireNoError(err) + + // seek back to head + _, err = pieceFileB.Seek(0, 0) + t.RequireNoError(err) + + // second piece relies on the alignment-computing version + left, tot, pieceCID, err := WriteWithAlignment(sealProofType, pieceFileB, 1016, stagedSectorFile, []abi.UnpaddedPieceSize{127}) + t.RequireNoError(err) + t.AssertEqual(889, int(left)) + t.AssertEqual(1905, int(tot)) + t.AssertTrue(pieceCID.Equals(pieceCIDB)) + + publicPieces := []abi.PieceInfo{{ + Size: abi.UnpaddedPieceSize(127).Padded(), + PieceCID: pieceCIDA, + }, { + Size: abi.UnpaddedPieceSize(1016).Padded(), + PieceCID: pieceCIDB, + }} + + preGeneratedUnsealedCID, err := GenerateUnsealedCID(sealProofType, publicPieces) + t.RequireNoError(err) + + // pre-commit the sector + sealPreCommitPhase1Output, err := SealPreCommitPhase1(sealProofType, sectorCacheDirPath, stagedSectorFile.Name(), sealedSectorFile.Name(), sectorNum, minerID, ticket, publicPieces) + t.RequireNoError(err) + + sealedCID, unsealedCID, err := SealPreCommitPhase2(sealPreCommitPhase1Output, sectorCacheDirPath, sealedSectorFile.Name()) + t.RequireNoError(err) + + t.AssertTrue(unsealedCID.Equals(preGeneratedUnsealedCID), "prover and verifier should agree on data commitment") + + // commit the sector + sealCommitPhase1Output, err := SealCommitPhase1(sealProofType, sealedCID, unsealedCID, sectorCacheDirPath, sealedSectorFile.Name(), sectorNum, minerID, ticket, seed, publicPieces) + t.RequireNoError(err) + + proof, err := SealCommitPhase2(sealCommitPhase1Output, sectorNum, minerID) + t.RequireNoError(err) + + // verify the 'ole proofy + isValid, err := VerifySeal(abi.SealVerifyInfo{ + SectorID: abi.SectorID{ + Miner: minerID, + Number: sectorNum, + }, + SealedCID: sealedCID, + SealProof: sealProofType, + Proof: proof, + DealIDs: []abi.DealID{}, + Randomness: ticket, + InteractiveRandomness: seed, + UnsealedCID: unsealedCID, + }) + t.RequireNoError(err) + t.RequireTrue(isValid, "proof wasn't valid") + + // unseal the entire sector and verify that things went as we planned + _, err = sealedSectorFile.Seek(0, 0) + t.RequireNoError(err) + t.RequireNoError(Unseal(sealProofType, sectorCacheDirPath, sealedSectorFile, unsealOutputFileA, sectorNum, minerID, ticket, unsealedCID)) + _, err = unsealOutputFileA.Seek(0, 0) + t.RequireNoError(err) + contents, err := ioutil.ReadFile(unsealOutputFileA.Name()) + t.RequireNoError(err) + + // unsealed sector includes a bunch of alignment NUL-bytes + alignment := make([]byte, 889) + + // verify that we unsealed what we expected to unseal + t.AssertTrue(bytes.Equal(someBytes[0:127], contents[0:127]), "bytes aren't equal") + t.AssertTrue(bytes.Equal(alignment, contents[127:1016]), "bytes aren't equal") + t.AssertTrue(bytes.Equal(someBytes[0:1016], contents[1016:2032]), "bytes aren't equal") + + // unseal just the first piece + _, err = sealedSectorFile.Seek(0, 0) + t.RequireNoError(err) + err = UnsealRange(sealProofType, sectorCacheDirPath, sealedSectorFile, unsealOutputFileB, sectorNum, minerID, ticket, unsealedCID, 0, 127) + t.RequireNoError(err) + _, err = unsealOutputFileB.Seek(0, 0) + t.RequireNoError(err) + contentsB, err := ioutil.ReadFile(unsealOutputFileB.Name()) + t.RequireNoError(err) + t.AssertEqual(127, len(contentsB)) + t.AssertTrue(bytes.Equal(someBytes[0:127], contentsB[0:127]), "bytes aren't equal") + + // unseal just the second piece + _, err = sealedSectorFile.Seek(0, 0) + t.RequireNoError(err) + err = UnsealRange(sealProofType, sectorCacheDirPath, sealedSectorFile, unsealOutputFileC, sectorNum, minerID, ticket, unsealedCID, 1016, 1016) + t.RequireNoError(err) + _, err = unsealOutputFileC.Seek(0, 0) + t.RequireNoError(err) + contentsC, err := ioutil.ReadFile(unsealOutputFileC.Name()) + t.RequireNoError(err) + t.AssertEqual(1016, len(contentsC)) + t.AssertTrue(bytes.Equal(someBytes[0:1016], contentsC[0:1016]), "bytes aren't equal") + + // verify that the sector builder owns no sealed sectors + var sealedSectorPaths []string + t.RequireNoError(filepath.Walk(sealedSectorsDir, visit(&sealedSectorPaths))) + t.AssertEqual(1, len(sealedSectorPaths), sealedSectorPaths) + + // no sector cache dirs, either + var sectorCacheDirPaths []string + t.RequireNoError(filepath.Walk(sectorCacheRootDir, visit(§orCacheDirPaths))) + t.AssertEqual(1, len(sectorCacheDirPaths), sectorCacheDirPaths) + + // run the FauxRep routine, for good measure + fauxSectorCID, err := FauxRep(sealProofType, fauxSectorCacheDirPath, fauxSealedSectorFile.Name()) + t.RequireNoError(err, "FauxRep produced an error") + t.RequireTrue(!cid.Undef.Equals(fauxSectorCID), "faux sector CID shouldn't be undefined") + + // generate a PoSt over the proving set before importing, just to exercise + // the new API + privateInfo := NewSortedPrivateSectorInfo(PrivateSectorInfo{ + SectorInfo: abi.SectorInfo{ + SectorNumber: sectorNum, + SealedCID: sealedCID, + }, + CacheDirPath: sectorCacheDirPath, + PoStProofType: winningPostProofType, + SealedSectorPath: sealedSectorFile.Name(), + }) + + provingSet := []abi.SectorInfo{{ + SealProof: sealProofType, + SectorNumber: sectorNum, + SealedCID: sealedCID, + }} + + // figure out which sectors have been challenged + indicesInProvingSet, err := GenerateWinningPoStSectorChallenge(winningPostProofType, minerID, randomness[:], uint64(len(provingSet))) + t.RequireNoError(err) + + var challengedSectors []abi.SectorInfo + for idx := range indicesInProvingSet { + challengedSectors = append(challengedSectors, provingSet[indicesInProvingSet[idx]]) + } + + proofs, err := GenerateWinningPoSt(minerID, privateInfo, randomness[:]) + t.RequireNoError(err) + + isValid, err = VerifyWinningPoSt(abi.WinningPoStVerifyInfo{ + Randomness: randomness[:], + Proofs: proofs, + ChallengedSectors: challengedSectors, + Prover: minerID, + }) + t.RequireNoError(err) + t.AssertTrue(isValid, "VerifyWinningPoSt rejected the (standalone) proof as invalid") +} + +func WorkflowGetGPUDevicesDoesNotProduceAnError(t TestHelper) { + devices, err := GetGPUDevices() + t.RequireNoError(err) + fmt.Printf("devices: %+v\n", devices) // clutters up test output, but useful +} + +func WorkflowRegisteredSealProofFunctions(t TestHelper) { + sealTypes := []abi.RegisteredSealProof{ + abi.RegisteredSealProof_StackedDrg2KiBV1, + abi.RegisteredSealProof_StackedDrg8MiBV1, + abi.RegisteredSealProof_StackedDrg512MiBV1, + abi.RegisteredSealProof_StackedDrg32GiBV1, + abi.RegisteredSealProof_StackedDrg64GiBV1, + } + + for _, st := range sealTypes { + v, err := GetSealVersion(st) + t.AssertNoError(err) + t.AssertTrue(len(v) > 0) + } +} + +func WorkflowRegisteredPoStProofFunctions(t TestHelper) { + postTypes := []abi.RegisteredPoStProof{ + abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, + abi.RegisteredPoStProof_StackedDrgWinning8MiBV1, + abi.RegisteredPoStProof_StackedDrgWinning512MiBV1, + abi.RegisteredPoStProof_StackedDrgWinning32GiBV1, + abi.RegisteredPoStProof_StackedDrgWinning64GiBV1, + abi.RegisteredPoStProof_StackedDrgWindow2KiBV1, + abi.RegisteredPoStProof_StackedDrgWindow8MiBV1, + abi.RegisteredPoStProof_StackedDrgWindow512MiBV1, + abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, + abi.RegisteredPoStProof_StackedDrgWindow64GiBV1, + } + + for _, pt := range postTypes { + v, err := GetPoStVersion(pt) + t.AssertNoError(err) + t.AssertTrue(len(v) > 0) + } +} + +func WorkflowGenerateWinningPoStSectorChallengeEdgeCase(t TestHelper) { + for i := 0; i < 10000; i++ { + var randomnessFr32 [32]byte + _, err := io.ReadFull(rand.Reader, randomnessFr32[0:31]) // last byte of the 32 is always NUL + t.RequireNoError(err) + + minerID := abi.ActorID(randUInt64()) + eligibleSectorsLen := uint64(1) + + indices2, err := GenerateWinningPoStSectorChallenge(abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, minerID, randomnessFr32[:], eligibleSectorsLen) + t.RequireNoError(err) + t.AssertEqual(1, len(indices2)) + t.AssertEqual(0, int(indices2[0])) + } +} + +func WorkflowGenerateWinningPoStSectorChallenge(t TestHelper) { + for i := 0; i < 10000; i++ { + var randomnessFr32 [32]byte + _, err := io.ReadFull(rand.Reader, randomnessFr32[0:31]) // last byte of the 32 is always NUL + t.RequireNoError(err) + + minerID := abi.ActorID(randUInt64()) + eligibleSectorsLen := randUInt64() + + if eligibleSectorsLen == 0 { + continue // no fun + } + + indices, err := GenerateWinningPoStSectorChallenge(abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, minerID, randomnessFr32[:], eligibleSectorsLen) + t.AssertNoError(err) + + max := uint64(0) + for idx := range indices { + if indices[idx] > max { + max = indices[idx] + } + } + + t.AssertTrue(max < eligibleSectorsLen, "out of range value - max: ", max, "eligibleSectorsLen: ", eligibleSectorsLen) + t.AssertTrue(uint64(len(indices)) <= eligibleSectorsLen, "should never generate more indices than number of eligible sectors") + } +} + +func randUInt64() uint64 { + buf := make([]byte, 8) + _, err := rand.Read(buf) + if err != nil { + panic(err) + } + + return binary.LittleEndian.Uint64(buf) +} + +func requireTempFile(t TestHelper, fileContentsReader io.Reader, size uint64) *os.File { + file, err := ioutil.TempFile("", "") + t.RequireNoError(err) + + written, err := io.Copy(file, fileContentsReader) + t.RequireNoError(err) + // check that we wrote everything + t.RequireEqual(int(size), int(written)) + + t.RequireNoError(file.Sync()) + + // seek to the beginning + _, err = file.Seek(0, 0) + t.RequireNoError(err) + + return file +} + +func requireTempDirPath(t TestHelper, prefix string) string { + dir, err := ioutil.TempDir("", prefix) + t.RequireNoError(err) + + return dir +} + +func visit(paths *[]string) filepath.WalkFunc { + return func(path string, info os.FileInfo, err error) error { + if err != nil { + panic(err) + } + *paths = append(*paths, path) + return nil + } +} + +type TestHelper interface { + AssertEqual(expected, actual interface{}, msgAndArgs ...interface{}) bool + AssertNoError(err error, msgAndArgs ...interface{}) bool + AssertTrue(value bool, msgAndArgs ...interface{}) bool + RequireEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) + RequireNoError(err error, msgAndArgs ...interface{}) + RequireTrue(value bool, msgAndArgs ...interface{}) +} diff --git a/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/block_headers.json b/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/block_headers.json new file mode 100644 index 0000000000..bb8e3443cb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/block_headers.json @@ -0,0 +1,274 @@ +[ + { + "block": { + "Miner": "t01000", + "Ticket": { + "VRFProof": "uH8uSmN0lZqqqS5mn2jEKiUnZoGRZiB1fhzxf6MWRFl1x1+A8jWPdHrD7YwCOnvJAUPYYtdmriPcyqr0I+TnmUiWaDyTkeRuPJSz6W2vbrog7GaToIQK8iR0hRPoJSSK" + }, + "EPostProof": { + "Proofs": [ + { + "RegisteredProof": 0, + "ProofBytes": "dmFsaWQgcHJvb2Y=" + } + ], + "PostRand": "kwmOrN1jkkBqoUNiSFkBQKSQCVXqq3vgSsI4NaAr7F0vZjaJvNuUhz3KDLGRMYpNCEIfbVIuRncd5onoapuTZnXhcBs35DxvgSlDZrlXDbFEXdmYD1eg5kyigs3V8g8g", + "Candidates": [ + { + "Partial": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "SectorID": 1, + "ChallengeIndex": 1 + } + ] + }, + "Parents": [ + { + "/": "bafy2bzacecn2hldkhdxf6huptwdvycikhuhqdam4l7yj2jev244bof3iskne4" + } + ], + "ParentWeight": "3379", + "Height": 1, + "ParentStateRoot": { + "/": "bafy2bzacechxg4cxirc2wqcp6bfkt6svxp3dwellqssstr3shxj6yup7etuay" + }, + "ParentMessageReceipts": { + "/": "bafy2bzaceaa43et73tgxsoh2xizd4mxhbrcfig4kqp25zfa5scdgkzppllyuu" + }, + "Messages": { + "/": "bafy2bzaceasjvchtw7qkmjzlirjcstafxpo27cmndjlm3xrvwbnee6v4fhvqa" + }, + "BLSAggregate": { + "Type": 2, + "Data": "wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "Timestamp": 100025, + "BlockSig": { + "Type": 2, + "Data": "gbqOZ1zzHa8o81MAeBye0LWmjx9+2R8gtP/2xZRrb7LBlx5tmXAfYsbAn4Qs/mLnDExSZe/xDLP7p1USSyHjSmgYPRlxwKKcwgK7jJyC7eCxBcVesAo+38SL0PKJGKDL" + }, + "ForkSignaling": 0 + }, + "cbor_hex": "8d4300e807815860b87f2e4a6374959aaaa92e669f68c42a25276681916620757e1cf17fa316445975c75f80f2358f747ac3ed8c023a7bc90143d862d766ae23dccaaaf423e4e7994896683c9391e46e3c94b3e96daf6eba20ec6693a0840af224748513e825248a838182004b76616c69642070726f6f66586093098eacdd6392406aa1436248590140a4900955eaab7be04ac23835a02bec5d2f663689bcdb94873dca0cb191318a4d08421f6d522e46771de689e86a9b936675e1701b37e43c6f81294366b9570db1445dd9980f57a0e64ca282cdd5f20f20818358200000000000000000000000000000000000000000000000000000000000000000010181d82a5827000171a0e402209ba3ac6a38ee5f1e8f9d875c090a3d0f01819c5ff09d2495d738171768929a4e43000d3301d82a5827000171a0e402208f7370574445ab404ff04aa9fa55bbf63b116b84a529c7723dd3ec51ff24e80cd82a5827000171a0e4022001cd927fdccd7938faba323e32e70c44541b8a83f5dc941d90866565ef5af14ad82a5827000171a0e40220249a88f3b7e0a6272b4452294c05bbddaf898d1a56cdde35b05a427abc29eb00586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000186b958610281ba8e675cf31daf28f35300781c9ed0b5a68f1f7ed91f20b4fff6c5946b6fb2c1971e6d99701f62c6c09f842cfe62e70c4c5265eff10cb3fba755124b21e34a68183d1971c0a29cc202bb8c9c82ede0b105c55eb00a3edfc48bd0f28918a0cb00", + "cid": "bafy2bzaceburnvajqrq3izxuafmpgm23e2jkonmtzl4jvnyv3mbmauszfstfa" + }, + { + "block": { + "Miner": "t01000", + "Ticket": { + "VRFProof": "mFI5lBoxWv4ARBTRrXuzzt2Cx3W3koCq0yEsIcZkJLe3h3Ja7PceC+MmBKioMFjTEsE9uLe35qogctSMukv40sD/qZBrq8TG8gYIos+/Q5F1QBNj5243wSjIFwfP8fY2" + }, + "EPostProof": { + "Proofs": [ + { + "RegisteredProof": 0, + "ProofBytes": "dmFsaWQgcHJvb2Y=" + } + ], + "PostRand": "scCCCBggOTvOTvMFWTp58N9nf84J2uWMTEr53d+N5GSlLtLloQjDe75Z1UuQE86gAYfrChP7Yp9j4heXkpKXreV7sD6wj0xBMi0IM4bF0Nl4JyEUfJswgmLxDGucxzCn", + "Candidates": [ + { + "Partial": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "SectorID": 1, + "ChallengeIndex": 1 + } + ] + }, + "Parents": [ + { + "/": "bafy2bzaceaychypnea6bzwv3r34ekzs7ccwsuza3ie4xb5vru7sv7ybiowj3e" + }, + { + "/": "bafy2bzaceburnvajqrq3izxuafmpgm23e2jkonmtzl4jvnyv3mbmauszfstfa" + } + ], + "ParentWeight": "7065", + "Height": 2, + "ParentStateRoot": { + "/": "bafy2bzacea4vuib2pqk47fl2herx3um7wdvmvghhjgdvamcmgd5fv4zq43k36" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacebxaj4y5s7swiittq5rnhv7tklzfpm43z5ps27gornuueuqqbxuoy" + }, + "Messages": { + "/": "bafy2bzacecq54nhno5y2rdgtvgysd375sw3274cymg4t266ejllxuckazacaw" + }, + "BLSAggregate": { + "Type": 2, + "Data": "wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "Timestamp": 100050, + "BlockSig": { + "Type": 2, + "Data": "kpGzm3Vm4OCPt4W3I0PXlhkvDZTXCGVmAga7dNCvE8OGBUZWFhFuEMc6E+lcPbZgFWwA0DfU6dcozsncPWwJBJvZPl9PTtnLBKLge+vE8k1dwx8M3vAVKquTsd6zPYnL" + }, + "ForkSignaling": 0 + }, + "cbor_hex": "8d4300e807815860985239941a315afe004414d1ad7bb3cedd82c775b79280aad3212c21c66424b7b787725aecf71e0be32604a8a83058d312c13db8b7b7e6aa2072d48cba4bf8d2c0ffa9906babc4c6f20608a2cfbf439175401363e76e37c128c81707cff1f636838182004b76616c69642070726f6f665860b1c082081820393bce4ef305593a79f0df677fce09dae58c4c4af9dddf8de464a52ed2e5a108c37bbe59d54b9013cea00187eb0a13fb629f63e21797929297ade57bb03eb08f4c41322d083386c5d0d9782721147c9b308262f10c6b9cc730a7818358200000000000000000000000000000000000000000000000000000000000000000010182d82a5827000171a0e402203023e1ed203c1cdabb8ef845665f10ad2a641b413970f6b1a7e55fe0287593b2d82a5827000171a0e402206916d4098461b466f40158f3335b2692a73593caf89ab715db02c052592ca65043001b9902d82a5827000171a0e40220395a203a7c15cf957a39237dd19fb0eaca98e7498750304c30fa5af330e6d5bfd82a5827000171a0e402206e04f31d97e56422738762d3d7f352f257b39bcf5f2d7cce8b694252100de8ecd82a5827000171a0e40220a1de34ed7771a88cd3a9b121effd95b7aff05861b93d7bc44ad77a0940c8040b586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000186d25861029291b39b7566e0e08fb785b72343d796192f0d94d70865660206bb74d0af13c38605465616116e10c73a13e95c3db660156c00d037d4e9d728cec9dc3d6c09049bd93e5f4f4ed9cb04a2e07bebc4f24d5dc31f0cdef0152aab93b1deb33d89cb00", + "cid": "bafy2bzacedomcdl5qrc4zmlmumlsc5vyetkhbuk2ym6qkwoxmz2i7hh3zz54k" + }, + { + "block": { + "Miner": "t01000", + "Ticket": { + "VRFProof": "gEnk7iabKLh1evmdDXxcy19n16QxTWFshhIX+owHHD+8Bd5z9CUViKI5WEMEiCGFCnTcNII/pSIzUW48uNy3yyiWhp5M8D2izzyCyCf/sjcXfPEAGWOmXDWcfS6no+QS" + }, + "EPostProof": { + "Proofs": [ + { + "RegisteredProof": 0, + "ProofBytes": "dmFsaWQgcHJvb2Y=" + } + ], + "PostRand": "sqIzTug0FSO3bfqcJz2fOOEhTdr8zUho2gYE6pueKkeD6NifFwdiho48dP00GYJDGEh+Nvh6SAFaUtqIFviu1gvN3Ngpgb6aIlx8hdNyzgBs3PZfXgfF+opiwrXmlT4j", + "Candidates": [ + { + "Partial": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "SectorID": 1, + "ChallengeIndex": 1 + } + ] + }, + "Parents": [ + { + "/": "bafy2bzaceclpschhidxiarcwzaxycracy64ie65tukzljzhrll3gbwbilwvbs" + }, + { + "/": "bafy2bzacedomcdl5qrc4zmlmumlsc5vyetkhbuk2ym6qkwoxmz2i7hh3zz54k" + } + ], + "ParentWeight": "10751", + "Height": 3, + "ParentStateRoot": { + "/": "bafy2bzacedjfgs3fw3scgo6okrfqhq6uiz7fawxu6r3yfiq5whxxvs67di6yc" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacecudhp7svmtn6xeolrhznguq625rj3lfnnyrjsojxkenwyqth26fk" + }, + "Messages": { + "/": "bafy2bzacecjuhhvbhi3vobidzdlzlyxmudabte6fn35dgyuogdliq2c4elkgu" + }, + "BLSAggregate": { + "Type": 2, + "Data": "wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "Timestamp": 100075, + "BlockSig": { + "Type": 2, + "Data": "idOzaQChSZiRuvPuhHC0uZWBtUKCBnW3fqf4ZRUreaJ1pn6AzFPqZ1+NzI2GlBa6CnYwmCl2gEVOSqzTMxMcmyzbzcPo3Wk6GY31IfN21xvAq9dDkJjj3OCUnX/SUVO5" + }, + "ForkSignaling": 0 + }, + "cbor_hex": "8d4300e8078158608049e4ee269b28b8757af99d0d7c5ccb5f67d7a4314d616c861217fa8c071c3fbc05de73f4251588a2395843048821850a74dc34823fa52233516e3cb8dcb7cb2896869e4cf03da2cf3c82c827ffb237177cf1001963a65c359c7d2ea7a3e412838182004b76616c69642070726f6f665860b2a2334ee8341523b76dfa9c273d9f38e1214ddafccd4868da0604ea9b9e2a4783e8d89f170762868e3c74fd3419824318487e36f87a48015a52da8816f8aed60bcddcd82981be9a225c7c85d372ce006cdcf65f5e07c5fa8a62c2b5e6953e23818358200000000000000000000000000000000000000000000000000000000000000000010182d82a5827000171a0e4022096f908e740ee804456c82f814402c7b8827bb3a2b2b4e4f15af660d8285daa19d82a5827000171a0e40220dcc10d7d8445ccb16ca3172176b824d470d15ac33d0559d766748f9cfbce7bc5430029ff03d82a5827000171a0e40220d2534b65b6e4233bce544b03c3d4467e505af4f47782a21db1ef7acbdf1a3d81d82a5827000171a0e40220a833bff2ab26df5c8e5c4f969a90f6bb14ed656b7114c9c9ba88db62133ebc55d82a5827000171a0e4022093439ea13a37570503c8d795e2eca0c01993c56efa33628e30d688685c22d46a586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a000186eb58610289d3b36900a1499891baf3ee8470b4b99581b542820675b77ea7f865152b79a275a67e80cc53ea675f8dcc8d869416ba0a763098297680454e4aacd333131c9b2cdbcdc3e8dd693a198df521f376d71bc0abd7439098e3dce0949d7fd25153b900", + "cid": "bafy2bzacebgu23bc2nywena4m63il6zkbhk752ua4qhcrmysqek4yw5worbus" + }, + { + "block": { + "Miner": "t01000", + "Ticket": { + "VRFProof": "kTEYt/ZquHUsXR8kTyW+eZ+s2n76Q9n47nFCgOYOIuY3zr8n2VCcWHptpHMgaKvrF8S3QlcULVxZEIyCpR7DgK7nNYVCoYeZ0+ce1jqKoeJdINwXT4OGXvFY48ErNMY1" + }, + "EPostProof": { + "Proofs": [ + { + "RegisteredProof": 0, + "ProofBytes": "dmFsaWQgcHJvb2Y=" + } + ], + "PostRand": "ksL5lB4TRTdENJ96GxPWUoDuRClZyJTiLwZkAoG7KxKs+S3Vtw500gb3igpNH9g3DHwqKWhHFo3OMx8Xs7MzrPBZJtT+3AIyt9viK7ILS/J/PKOk3CHE2/prNaiCFg/h", + "Candidates": [ + { + "Partial": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "SectorID": 1, + "ChallengeIndex": 1 + } + ] + }, + "Parents": [ + { + "/": "bafy2bzaceacblov5axltmebdbogwzt2xnttlsiv4oldmrtytddyidv54grn6c" + }, + { + "/": "bafy2bzacebgu23bc2nywena4m63il6zkbhk752ua4qhcrmysqek4yw5worbus" + } + ], + "ParentWeight": "14437", + "Height": 4, + "ParentStateRoot": { + "/": "bafy2bzacec73blqtchqvkixqhmk7ff6kxvqumr5kgi6mdxhqx2nimfyr4jfhy" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacealhb77fyvcojou2hixtamim6hm2whxsjsp633lbbd7aeqenkxpie" + }, + "Messages": { + "/": "bafy2bzacebbqvsr2r3urgckmxeh3tdicj3jmpafxp4owddpd3t4wl2hnycouy" + }, + "BLSAggregate": { + "Type": 2, + "Data": "wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "Timestamp": 100100, + "BlockSig": { + "Type": 2, + "Data": "mPI9h7jWDM41Uj9bj+9nA2y77x11yoRPwo9ve7ipMvpCwRA/6R7vVi7vmQ1w5J4yFB7XQj2kY5oALoFDMXi/lOZE9mxjmhDcUexQV299ncS3Iu86xPvuQqxKuG5aUvMT" + }, + "ForkSignaling": 0 + }, + "cbor_hex": "8d4300e807815860913118b7f66ab8752c5d1f244f25be799facda7efa43d9f8ee714280e60e22e637cebf27d9509c587a6da4732068abeb17c4b74257142d5c59108c82a51ec380aee7358542a18799d3e71ed63a8aa1e25d20dc174f83865ef158e3c12b34c635838182004b76616c69642070726f6f66586092c2f9941e13453744349f7a1b13d65280ee442959c894e22f06640281bb2b12acf92dd5b70e74d206f78a0a4d1fd8370c7c2a296847168dce331f17b3b333acf05926d4fedc0232b7dbe22bb20b4bf27f3ca3a4dc21c4dbfa6b35a882160fe1818358200000000000000000000000000000000000000000000000000000000000000000010182d82a5827000171a0e402200415babd05d73610230b8d6ccf576ce6b922bc72c6c8cf1318f081d7bc345be1d82a5827000171a0e402204d4d6c22d37162341c67b685fb2a09d5feea80e40e28b3128115cc5bb67443494300386504d82a5827000171a0e40220bfb0ae1311e15522f03b15f297cabd614647aa323cc1dcf0be9a861711e24a7cd82a5827000171a0e402201670ffe5c544e4ba9a3a2f30310cf1d9ab1ef24c9feded6108fe02408d55de82d82a5827000171a0e40220430aca3a8ee913094cb90fb98d024ed2c780b77f1d618de3dcf965e8edc09d4c586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0001870458610298f23d87b8d60cce35523f5b8fef67036cbbef1d75ca844fc28f6f7bb8a932fa42c1103fe91eef562eef990d70e49e32141ed7423da4639a002e81433178bf94e644f66c639a10dc51ec50576f7d9dc4b722ef3ac4fbee42ac4ab86e5a52f31300", + "cid": "bafy2bzaceaaaojy4z4yn3rqodznemaul3rgddocgb4zfx4xh3qhke2kdpssjo" + }, + { + "block": { + "Miner": "t01000", + "Ticket": { + "VRFProof": "haG/qPeztxhCz+dyChgBoGAvUN3WXV5QYZF86IIcxjtxZdGQiLUIkAefEPqRFLBQA61dPpf/bK40YU2QBEGncneAl9FTwUf5QdQCoBgRlJXQ5qSOk0uQiszsuLZyj14t" + }, + "EPostProof": { + "Proofs": [ + { + "RegisteredProof": 0, + "ProofBytes": "dmFsaWQgcHJvb2Y=" + } + ], + "PostRand": "ueyZOnCA2GtdmhLnxrlY0BcoFOYFadXBK3w4zB2gmIMJWYdOaZijGSPk9oK8yQBACBIq6Uf05aHCTSByqKiiSEz6ZSGo9BEg5GnrgsIjcufnE4KMW46uUvBVEgfve80G", + "Candidates": [ + { + "Partial": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "SectorID": 1, + "ChallengeIndex": 1 + } + ] + }, + "Parents": [ + { + "/": "bafy2bzaceaaaojy4z4yn3rqodznemaul3rgddocgb4zfx4xh3qhke2kdpssjo" + }, + { + "/": "bafy2bzacedeinl3sa2l6jn2pkzxsprchg6ptexoa3a7nw6jtipekrgjswvxdk" + } + ], + "ParentWeight": "18123", + "Height": 5, + "ParentStateRoot": { + "/": "bafy2bzacecpqhczshnbpf32ejrmm5ruh3bcl2ktkbto2j3omluctuklbgcsey" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacealhb77fyvcojou2hixtamim6hm2whxsjsp633lbbd7aeqenkxpie" + }, + "Messages": { + "/": "bafy2bzaceafcdqjwrpz3uwhn532crplao4zgjn4dif2siptleefxoemf6mblc" + }, + "BLSAggregate": { + "Type": 2, + "Data": "wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + }, + "Timestamp": 100125, + "BlockSig": { + "Type": 2, + "Data": "mUOCo4AHRIXCd6KeYeKpX4XfRVYu/06k0jlL+i7tmjKmOxNilv0/SC8vQZ2xEHNbBjhJjoDU/9G/2wD9HmWlTZd0TKHQ5VfSMG84BxIYla9+VbL0QNc+RYYe+IvjDVho" + }, + "ForkSignaling": 0 + }, + "cbor_hex": "8d4300e80781586085a1bfa8f7b3b71842cfe7720a1801a0602f50ddd65d5e5061917ce8821cc63b7165d19088b50890079f10fa9114b05003ad5d3e97ff6cae34614d900441a772778097d153c147f941d402a018119495d0e6a48e934b908accecb8b6728f5e2d838182004b76616c69642070726f6f665860b9ec993a7080d86b5d9a12e7c6b958d0172814e60569d5c12b7c38cc1da098830959874e6998a31923e4f682bcc9004008122ae947f4e5a1c24d2072a8a8a2484cfa6521a8f41120e469eb82c22372e7e713828c5b8eae52f0551207ef7bcd06818358200000000000000000000000000000000000000000000000000000000000000000010182d82a5827000171a0e402200007271ccf30ddc60e1e5a46028bdc4c31b8460f325bf2e7dc0ea269437ca497d82a5827000171a0e40220c886af720697e4b74f566f27c447379f325dc0d83edb793343c8a89932b56e35430046cb05d82a5827000171a0e402209f038b323b42f2ef444c58cec687d844bd2a6a0cdda4edcc5d053a296130a44cd82a5827000171a0e402201670ffe5c544e4ba9a3a2f30310cf1d9ab1ef24c9feded6108fe02408d55de82d82a5827000171a0e402200a21c1368bf3ba58edeef428bd60773264b7834175243e6b210b771185f302b1586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0001871d586102994382a380074485c277a29e61e2a95f85df45562eff4ea4d2394bfa2eed9a32a63b136296fd3f482f2f419db110735b0638498e80d4ffd1bfdb00fd1e65a54d97744ca1d0e557d2306f3807121895af7e55b2f440d73e45861ef88be30d586800", + "cid": "bafy2bzaceamjpc7ubuuyc6t64i3r6rmq2mfyf2dehqrglti7rinvatj4llkzm" + } +] \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/message_signing.json b/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/message_signing.json new file mode 100644 index 0000000000..637c4e0ab7 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/message_signing.json @@ -0,0 +1,42 @@ +[ + { + "Unsigned": { + "Version": 0, + "To": "t099999", + "From": "t3r4mni4ncwaa5bnr5jz3hvrbuiupy2oqf5u65zg5nkrldgg7ubskkvaa554v7kdzl5ughslh7gct7s4fjhpya", + "Nonce": 55, + "Value": "1", + "GasPrice": "0", + "GasLimit": 1, + "Method": 0, + "Params": null + }, + "Cid": "bafy2bzacecjixgx2mvr4zijdrnha2vmjxlmxavhwci66imamkqo35o5fpnbrw", + "CidHexBytes": "0171a0e40220928b9afa6563cca1238b4e0d5589bad97054f6123de4300c541dbebba57b431b", + "PrivateKey": "P8zKGOLIElfX/nEReFZK30fSNIdOeQenO8qG9j3E/mA=", + "Signature": { + "Type": 2, + "Data": "sjJBddDeRxebEpDlc2moOpWFcZy10sxIj7p7lLkYFV7ao60nN9DFwH3DXh+SkYHCFRDey5A5LSRrjmE0OsLsoIjBZgpfXGFGT6bV5fIBGDydJ2WKqOlqzrEkhq4/0Pwd" + } + }, + { + "Unsigned": { + "Version": 0, + "To": "t099999", + "From": "t3v5sb37hecmsm6ybo4g2pdkwj6omvo7rvspcxeghm7wxp5mj3nn3a7zxitdgtlgham47ifotobljjdulurogq", + "Nonce": 55, + "Value": "1", + "GasPrice": "0", + "GasLimit": 1, + "Method": 0, + "Params": null + }, + "Cid": "bafy2bzaceazgfk2m4v4zpimgqkknsfj7qcy3h2eyiibbkguz22uhxnecpwpta", + "CidHexBytes": "0171a0e402203262ab4ce57997a1868294d9153f80b1b3e8984202151a99d6a87bb4827d9f30", + "PrivateKey": "6UEWLG7I8oz2YnreMbE5A3iMyHOZjqEIEspLrMuBPDI=", + "Signature": { + "Type": 2, + "Data": "qfu5DhjGsTXuq2bUADUE2dclCA5MgqgszvvCPP/6n45oKunog/5k/qzMOXmpp0ynAh8L9CPGs5TjPefXBvbRTVJ1WRJagV1AYVfG7ujNDHMuQh0khhdfjSXZEAXSfMLT" + } + } +] diff --git a/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/unsigned_messages.json b/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/unsigned_messages.json new file mode 100644 index 0000000000..59ebb7ef79 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/extern/serialization-vectors/unsigned_messages.json @@ -0,0 +1,296 @@ +[ + { + "message": { + "Version": 0, + "To": "t013389068808970846986", + "From": "t2ch7krq7l35i74rebqbjdsp3ucl47t24e3juxjfa", + "Nonce": 11658068477141177407, + "Value": "11416382733294334924", + "GasPrice": "5210983352187082620", + "GasLimit": 7284457589948619162, + "Method": 11471309754226496341, + "Params": "v4RpPG9ZhuXLZcyTLCDh4DuoP7nVtvxhd3/ZRQICtBI=" + }, + "hex_cbor": "89004b008a86e1bfcbe4e1e7b901550211fea8c3ebdf51fe44818052393f7412f9f9eb841ba1c9c7834b2dd43f49009e6f239bfde973cc4900485121bff595d77c1b651797955649199a1b9f324771a124d3555820bf84693c6f5986e5cb65cc932c20e1e03ba83fb9d5b6fc61777fd9450202b412" + }, + { + "message": { + "Version": 0, + "To": "t03832874859695014541", + "From": "t1pyfq7dg6sq65acyomqvzvbgwni4zllglqffw5dy", + "Nonce": 17894947808754847462, + "Value": "2336524996408783450", + "GasPrice": "4555274658731024958", + "GasLimit": 6482596810555773759, + "Method": 1513517541386354487, + "Params": "LvA/+JCxFtFmwcUKCHkWertTbleiNRccmRO2YU4c3/Q=" + }, + "hex_cbor": "89004a008d8596858aecc6983555017e0b0f8cde943dd00b0e642b9a84d66a3995accb1bf857a03876fccee64900206d011ad3c4325a49003f37962ad000623e1b59f6cf73f341d33f1b1501182f57a7ff3758202ef03ff890b116d166c1c50a0879167abb536e57a235171c9913b6614e1cdff4" + }, + { + "message": { + "Version": 0, + "To": "t07806671100947809543", + "From": "t1cyg66djxytxhzdq7ynoqfxk7xinp6xsejbeufli", + "Nonce": 15726415710470574326, + "Value": "7445614829779086639", + "GasPrice": "7390413385876731229", + "GasLimit": 6548519544910854473, + "Method": 14454435380330863563, + "Params": "CcgEueeeWoR0qYZUd8PXiBfdIW1sXdgMYEwa6ZByBnk=" + }, + "hex_cbor": "89004a00878ab5d293c0b7ab6c5501160def0d37c4ee7c8e1fc35d02dd5fba1aff5e441bda3f73c43cb890f649006754233d375ced2f4900669005d18079755d1b5ae103d49f1d39491bc898786541759bcb582009c804b9e79e5a8474a9865477c3d78817dd216d6c5dd80c604c1ae990720679" + }, + { + "message": { + "Version": 0, + "To": "t02154560952017581553", + "From": "t16n7vrq5humzoqll7zg4yw6dta645tuakcoalp6y", + "Nonce": 15588571783605307901, + "Value": "3476369076493661495", + "GasPrice": "13677671167026193283", + "GasLimit": 2531499896285806282, + "Method": 13608858569283704761, + "Params": "CeKs6Z49oyosiY2wpw6neCJXs312jNCFWPzVy8Xcybs=" + }, + "hex_cbor": "89004a00f1ebbdffd3b8a2f31d5501f37f58c3a7a332e82d7fc9b98b787307b9d9d00a1bd855bb720578c9fd4900303e8b41a88eb5374900bdd0d9758132e3831b2321b1be430dbeca1bbcdc60c414af97b9582009e2ace99e3da32a2c898db0a70ea7782257b37d768cd08558fcd5cbc5dcc9bb" + }, + { + "message": { + "Version": 0, + "To": "t07840455359962565480", + "From": "t1awsiuji4wpbxpzslg36f3wnfxzi4o5gq67tz2mi", + "Nonce": 7259033473108024785, + "Value": "4938896623558237654", + "GasPrice": "15772564500769413673", + "GasLimit": 2384886871371271863, + "Method": 9140863599983255209, + "Params": "LNw8yn3onIxKW3qeSLkef3kxumcExeR5/gTitg1NHcs=" + }, + "hex_cbor": "89004a00e89681ffbf93b9e76c550105a48a251cb3c377e64b36fc5dd9a5be51c774d01b64bd447bd9461dd14900448a7c4fcd909dd64900dae367d8c94c1a291b2118d1f94d93ceb71b7edadf03894cdea958202cdc3cca7de89c8c4a5b7a9e48b91e7f7931ba6704c5e479fe04e2b60d4d1dcb" + }, + { + "message": { + "Version": 0, + "To": "t016323823421156475669", + "From": "t14mb3j32uuwajy5b2mliz63isp6zl5xkppzyuhfy", + "Nonce": 5433761484740407072, + "Value": "16697536397875723426", + "GasPrice": "14680071226922488587", + "GasLimit": 3247611972277692347, + "Method": 2062042162400776130, + "Params": "cj81Un7MKVkHX6sZnM09z8KEzTJggzwlV5KfRXyJWEM=" + }, + "hex_cbor": "89004b009586efd1a0ddf7c4e2015501e303b4ef54a5809c743a62d19f6d127fb2bedd4f1b4b689947f426af204900e7b990e2f389bca24900cbba1700a625d30b1b2d11d5e1d7eae7bb1b1c9dd86be9c6cfc25820723f35527ecc2959075fab199ccd3dcfc284cd3260833c2557929f457c895843" + }, + { + "message": { + "Version": 0, + "To": "t01020310244991269625", + "From": "t1dzdmyzzdy6q5elobj63eokzv2xnwsp4vm5l6aka", + "Nonce": 13801415015494088514, + "Value": "5206279589327648562", + "GasPrice": "12191252486160305284", + "GasLimit": 8663655281210548398, + "Method": 4477572038606617645, + "Params": "nGYfgfEqDwNn433vBtnrkU6kGsEHhXExV6a1HHxKbgk=" + }, + "hex_cbor": "89004a00f9f5958bb1d8b7940e55011e46cc6723c7a1d22dc14fb6472b35d5db693f951bbf8879d564447742490048406bb3d33db7324900a930078b4caecc841b783b7c9384fde0ae1b3e23880bc15e7c2d58209c661f81f12a0f0367e37def06d9eb914ea41ac10785713157a6b51c7c4a6e09" + }, + { + "message": { + "Version": 0, + "To": "t017422814465637515751", + "From": "t1svd45rkcfpsyqedvvhuv77yvllvu5ygmygjlvka", + "Nonce": 7513202630092755205, + "Value": "9197252879814148676", + "GasPrice": "13407169184082324715", + "GasLimit": 3391459310341080152, + "Method": 1313782793266575600, + "Params": "A3u9ouavmFpPthn120DSdFSBkE2/KdxPVnbThiYiBaQ=" + }, + "hex_cbor": "89004b00e783f2dea4ae91e5f10155019547cec5422be5881075a9e95fff155aeb4ee0cc1b684441fc4435910549007fa334c3dac2c2444900ba0fd556b4ca6ceb1b2f10e246271244581b123b7e7d60acb8f05820037bbda2e6af985a4fb619f5db40d2745481904dbf29dc4f5676d386262205a4" + }, + { + "message": { + "Version": 0, + "To": "t017411500490521185325", + "From": "t1mrret5liwh46qde6qhaxrmcwil7jawjeqdijwfq", + "Nonce": 14324710588575616807, + "Value": "10528211970185902072", + "GasPrice": "5810359608201510699", + "GasLimit": 4150572571990551478, + "Method": 6203584036735357589, + "Params": "Lrr+MSRTDh0XHBxGsA47YrwQ40g6TASKadWi9Sn5rjU=" + }, + "hex_cbor": "89004b00ad98b880a3ee84d1f1015501646249f568b1f9e80c9e81c178b05642fe9059241bc6cb98627e538f274900921bb9018af237f8490050a28b477020ff2b1b3999cbc377f9ebb61b56178ed03be5129558202ebafe3124530e1d171c1c46b00e3b62bc10e3483a4c048a69d5a2f529f9ae35" + }, + { + "message": { + "Version": 0, + "To": "t01902762716708433834", + "From": "t1ly3ynedw74p4q3ytdnb4stjdkiodrl54moeyxea", + "Nonce": 14857502780229415327, + "Value": "3001273522196893515", + "GasPrice": "7497561247630821085", + "GasLimit": 6298573618200002291, + "Method": 6788076268171610837, + "Params": "1gCARDcKrT17hNKPeQLIkumBhi+0wRHWzG5WP8r10Yk=" + }, + "hex_cbor": "89004a00aadf8deac093feb31a55015e37869076ff1fc86f131b43c94d23521c38afbc1bce30740f68f3f19f490029a6aa5df454cf4b4900680cb03b1ec506dd1b57690755a0753ef31b5e341766b0a0cad55820d6008044370aad3d7b84d28f7902c892e981862fb4c111d6cc6e563fcaf5d189" + }, + { + "message": { + "Version": 0, + "To": "t013241953094381299116", + "From": "t1uqexvn66gj4lxkbvmrgposwrlxbyd655o2nayyi", + "Nonce": 15058303905176171282, + "Value": "5658730261436603476", + "GasPrice": "12582980597242372521", + "GasLimit": 304849130194029080, + "Method": 3215623805900737890, + "Params": "TF3jzIBrL8IsqGxBn1na1qFTqHo/fAgYlEvHzxBJViE=" + }, + "hex_cbor": "89004b00accbed97e3c5b7e2b7015501a4097ab7de3278bba835644cf74ad15dc381fbbd1bd0f9d79e93e7331249004e87d93108ae9c544900ae9fba2f8a43a1a91b043b0aab334d4a181b2ca030d07a00cd6258204c5de3cc806b2fc22ca86c419f59dad6a153a87a3f7c0818944bc7cf10495621" + }, + { + "message": { + "Version": 0, + "To": "t012894086468139855586", + "From": "t1dwwjod7vw62jzw2eva7gtxohaidjhgh6w2rofui", + "Nonce": 2650434461542759538, + "Value": "9388362994582083202", + "GasPrice": "12199567756512175851", + "GasLimit": 5906091373423752240, + "Method": 6259838894762694668, + "Params": "n5AGPeZSdo3cZpPmNIyB8pvHR1K5kOPko6NvzVwkoDk=" + }, + "hex_cbor": "89004b00e2dd96a5bbeabff8b20155011dac970ff5b7b49cdb44a83e69ddc702069398fe1b24c83c19a4b5bc724900824a2a66e27cd6824900a94d923d0c37a6eb1b51f6a6cff3ebf4301b56df6a4f0981180c58209f90063de652768ddc6693e6348c81f29bc74752b990e3e4a3a36fcd5c24a039" + }, + { + "message": { + "Version": 0, + "To": "t08848011971582042020", + "From": "t1slswisymmkfulmvl3jynrnwqi27tkvmsgzhztvy", + "Nonce": 2258285282172144483, + "Value": "9186039444302359918", + "GasPrice": "5283787488163612528", + "GasLimit": 7317510937304607984, + "Method": 7062874609806913965, + "Params": "ibAIT0RcN0hc1DyErUoSz4e3p3bfjTYrf2JR5REv5EE=" + }, + "hex_cbor": "89004a00a4bfb4b4a6809de57a550192e5644b0c628b45b2abda70d8b6d046bf3555921b1f570a7fcd5d0b6349007f7b5e34725e6d6e49004953c8b9cca547701b658d056d7a13acf01b62045f0972aab1ad582089b0084f445c37485cd43c84ad4a12cf87b7a776df8d362b7f6251e5112fe441" + }, + { + "message": { + "Version": 0, + "To": "t017001436207406598236", + "From": "t1e3vymxcdqfkqwz6e6wnxxx6ayuml3vxi5gef4xa", + "Nonce": 2783837848253290986, + "Value": "6828906388692990073", + "GasPrice": "12074759331928579047", + "GasLimit": 8249737539214836660, + "Method": 14365964813264657028, + "Params": "Tj68x7NVTwyTps+6rFjME4OyFJQZxy1iBQUAj4tRDF8=" + }, + "hex_cbor": "89004b00dc90bdaff384cff8eb01550126eb865c4381550b67c4f59b7bdfc0c518bdd6e81b26a22dc6096cd9ea49005ec5262dee70f8794900a79229a337ef9be71b727cf4953b1b03b41bc75e28e22e669a8458204e3ebcc7b3554f0c93a6cfbaac58cc1383b2149419c72d620505008f8b510c5f" + }, + { + "message": { + "Version": 0, + "To": "t08190521071294029470", + "From": "t1bgqopgk64ywpprka4citgi62aldclyaegvwvx6y", + "Nonce": 2351973351885345277, + "Value": "12875132054430426205", + "GasPrice": "13183915647165133202", + "GasLimit": 2095316695814612399, + "Method": 1431578561611763739, + "Params": "ph9EEZfJznp5tWYsl4Xc0rhqOQnNjU0Y9AXUNrbZIKU=" + }, + "hex_cbor": "89004a009ebdd49ecef0a4d571550109a0e7995ee62cf7c540e0913323da02c625e0041b20a3e34d604f91fd4900b2ada8635c92245d4900b6f6ad6e01fdf1921b1d140f6ef1f9a5af1b13ddfd1df0ef101b5820a61f441197c9ce7a79b5662c9785dcd2b86a3909cd8d4d18f405d436b6d920a5" + }, + { + "message": { + "Version": 0, + "To": "t03432166294462646070", + "From": "t1aizqgl2klzkzffwu35rufyuzefke2i6ndbewuhi", + "Nonce": 1329052725775789099, + "Value": "11460467607133957158", + "GasPrice": "10619154450692967225", + "GasLimit": 253864613405588675, + "Method": 2831671877034034504, + "Params": "MdJgU8s3TUeHOTTIYmxoArrMFvbtH5vHSJsrbfy0BZI=" + }, + "hex_cbor": "89004a00b68e8fbcf7a1e0d02f55010233032f4a5e559296d4df6342e29921544d23cd1b1271be6997a16c2b49009f0bc2918b172c264900935ed0b5d0900b391b0385e8855714fcc31b274c1e91bf13c548582031d26053cb374d47873934c8626c6802bacc16f6ed1f9bc7489b2b6dfcb40592" + }, + { + "message": { + "Version": 0, + "To": "t016095392736240416130", + "From": "t1mzposcnsd2tc66yu5i3kajtrh5pvwohdjvitcey", + "Nonce": 10599216310610898629, + "Value": "18156332997987115811", + "GasPrice": "11197374033232148890", + "GasLimit": 8699413646009026630, + "Method": 9801068698403975252, + "Params": "wheM9jgNAZ6xJ2ssMWyrYY94pnpNQBS+7zCLb1kBq34=" + }, + "hex_cbor": "89004b0082eb8ca0aacd94afdf015501665ee909b21ea62f7b14ea36a026713f5f5b38e31b9317fb13d37d2ec54900fbf840aa50b9a32349009b65105b63fc399a1b78ba869e9c8dc8461b8804640d8b91b0545820c2178cf6380d019eb1276b2c316cab618f78a67a4d4014beef308b6f5901ab7e" + }, + { + "message": { + "Version": 0, + "To": "t05892979989249169419", + "From": "t1x7xvs6oorrrlefyzn6wlbvaibzj3a2fyt4hsmvq", + "Nonce": 11279671523822037692, + "Value": "9772790049211981834", + "GasPrice": "883878775519579412", + "GasLimit": 7488695136490415251, + "Method": 16398325880447472757, + "Params": "yZz2UIanfcrW1aY4ByRiF6GBmPmNay1ShCvIzd1ZAwY=" + }, + "hex_cbor": "89004a008bb0bafdbec284e4515501bfef5979ce8c62b217196facb0d4080e53b068b81b9c89717d18806abc4900879fecc573c0a00a49000c442b10375a0d141b67ed308cc1b4e4931be3928e81972a94755820c99cf65086a77dcad6d5a63807246217a18198f98d6b2d52842bc8cddd590306" + }, + { + "message": { + "Version": 0, + "To": "t015381054695529705304", + "From": "t1ez743nvc4j7qfirwnmxbh4qdqwha3iyalnq4rya", + "Nonce": 5622736039048946235, + "Value": "16742784398161772708", + "GasPrice": "4559617121003297017", + "GasLimit": 2182971286425511142, + "Method": 6963678923887998479, + "Params": "f1QblN4pmBCkkf0R6wrFephgRmAqb98kCXgQsZzQ+Ig=" + }, + "hex_cbor": "89004b00d8de9baf8df89ebad5015501267fcdb6a2e27f02a2366b2e13f203858e0da3001b4e07f8a3114ca23b4900e85a51b3fb6280a449003f47039d1930d8f91b1e4b78d1b24524e61b60a3f5160c37f60f58207f541b94de299810a491fd11eb0ac57a986046602a6fdf24097810b19cd0f888" + }, + { + "message": { + "Version": 0, + "To": "t012569094584653648978", + "From": "t17dvtgkop7cqgi6myjne5kzvrnsbg5wnowjphhwy", + "Nonce": 6496185520788301878, + "Value": "6202417319134868039", + "GasPrice": "12793645932586974114", + "GasLimit": 4029284056746876795, + "Method": 15045045355813860701, + "Params": "IvyVkiuf9uZU7xWLao1iHpseC4bzBjGBTJEGTk8oQsY=" + }, + "hex_cbor": "89004b00d2a8c4d4e49d99b7ae015501f8eb3329cff8a06479984b49d566b16c826ed9ae1b5a271650199f68364900561369b09fc3b2474900b18c293129f7bba21b37eae480658adf7b1bd0cabd09feecf55d582022fc95922b9ff6e654ef158b6a8d621e9b1e0b86f30631814c91064e4f2842c6" + }, + { + "message": { + "Version": 0, + "To": "t011515639353459277841", + "From": "t1kvar5z3q7dwrfxjqsnuqpq5qsd7mvh2xypblwta", + "Nonce": 12663853165144576657, + "Value": "13594064579734367591", + "GasPrice": "11665215272543958717", + "GasLimit": 4688591007166616406, + "Method": 9799772402436471351, + "Params": "cQYUSJhpKoKWa4R/jgzjke/Yekv3ejqKb66RlHCLBpc=" + }, + "hex_cbor": "89004b009180cc83ac9ff1e79f01550155411ee770f8ed12dd30936907c3b090feca9f571bafbf0b5b942612914900bca7d1b5f8c96d674900a1e32b7c4471b6bd1b411138ae0741d3561b87ffc9141ee6fa3758207106144898692a82966b847f8e0ce391efd87a4bf77a3a8a6fae9194708b0697" + } +] diff --git a/vendor/github.com/filecoin-project/lotus/gen/main.go b/vendor/github.com/filecoin-project/lotus/gen/main.go new file mode 100644 index 0000000000..01cd756f78 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/gen/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "fmt" + "os" + + gen "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/hello" + "github.com/filecoin-project/lotus/paychmgr" +) + +func main() { + err := gen.WriteTupleEncodersToFile("./chain/types/cbor_gen.go", "types", + types.BlockHeader{}, + types.Ticket{}, + types.ElectionProof{}, + types.Message{}, + types.SignedMessage{}, + types.MsgMeta{}, + types.Actor{}, + types.MessageReceipt{}, + types.BlockMsg{}, + types.ExpTipSet{}, + types.BeaconEntry{}, + ) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + err = gen.WriteMapEncodersToFile("./paychmgr/cbor_gen.go", "paychmgr", + paychmgr.VoucherInfo{}, + paychmgr.ChannelInfo{}, + ) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + err = gen.WriteMapEncodersToFile("./api/cbor_gen.go", "api", + api.PaymentInfo{}, + api.SealedRef{}, + api.SealedRefs{}, + api.SealTicket{}, + api.SealSeed{}, + ) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + err = gen.WriteTupleEncodersToFile("./node/hello/cbor_gen.go", "hello", + hello.HelloMessage{}, + hello.LatencyMessage{}, + ) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + err = gen.WriteTupleEncodersToFile("./chain/blocksync/cbor_gen.go", "blocksync", + blocksync.BlockSyncRequest{}, + blocksync.BlockSyncResponse{}, + blocksync.BSTipSet{}, + ) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + +} diff --git a/vendor/github.com/filecoin-project/lotus/genesis/types.go b/vendor/github.com/filecoin-project/lotus/genesis/types.go new file mode 100644 index 0000000000..41d8a413c2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/genesis/types.go @@ -0,0 +1,70 @@ +package genesis + +import ( + "encoding/json" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/ipfs/go-cid" + "github.com/libp2p/go-libp2p-core/peer" +) + +type ActorType string + +const ( + TAccount ActorType = "account" + TMultisig ActorType = "multisig" +) + +type PreSeal struct { + CommR cid.Cid + CommD cid.Cid + SectorID abi.SectorNumber + Deal market.DealProposal + ProofType abi.RegisteredSealProof +} + +type Miner struct { + Owner address.Address + Worker address.Address + PeerId peer.ID //nolint:golint + + MarketBalance abi.TokenAmount + PowerBalance abi.TokenAmount + + SectorSize abi.SectorSize + + Sectors []*PreSeal +} + +type AccountMeta struct { + Owner address.Address // bls / secpk +} + +func (am *AccountMeta) ActorMeta() json.RawMessage { + out, err := json.Marshal(am) + if err != nil { + panic(err) + } + return out +} + +type MultisigMeta struct { + // TODO +} + +type Actor struct { + Type ActorType + Balance abi.TokenAmount + + Meta json.RawMessage +} + +type Template struct { + Accounts []Actor + Miners []Miner + + NetworkName string + Timestamp uint64 `json:",omitempty"` +} diff --git a/vendor/github.com/filecoin-project/lotus/go.mod b/vendor/github.com/filecoin-project/lotus/go.mod new file mode 100644 index 0000000000..1591639e5b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/go.mod @@ -0,0 +1,129 @@ +module github.com/filecoin-project/lotus + +go 1.14 + +require ( + contrib.go.opencensus.io/exporter/jaeger v0.1.0 + contrib.go.opencensus.io/exporter/prometheus v0.1.0 + github.com/BurntSushi/toml v0.3.1 + github.com/GeertJohan/go.rice v1.0.0 + github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect + github.com/coreos/go-systemd/v22 v22.0.0 + github.com/docker/go-units v0.4.0 + github.com/drand/drand v0.9.2-0.20200616080806-a94e9c1636a4 + github.com/drand/kyber v1.1.0 + github.com/fatih/color v1.8.0 + github.com/filecoin-project/chain-validation v0.0.6-0.20200615191232-6be1a8c6ed09 + github.com/filecoin-project/filecoin-ffi v0.26.1-0.20200508175440-05b30afeb00d + github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef + github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2 + github.com/filecoin-project/go-bitfield v0.0.2-0.20200629135455-587b27927d38 + github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 + github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 + github.com/filecoin-project/go-data-transfer v0.3.0 + github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5 + github.com/filecoin-project/go-fil-markets v0.3.2-0.20200702145639-4034a18364e4 + github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24 + github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 + github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 + github.com/filecoin-project/go-statestore v0.1.0 + github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b + github.com/filecoin-project/sector-storage v0.0.0-20200630180318-4c1968f62a8f + github.com/filecoin-project/specs-actors v0.6.2-0.20200702170846-2cd72643a5cf + github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea + github.com/filecoin-project/storage-fsm v0.0.0-20200625160832-379a4655b044 + github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 + github.com/go-kit/kit v0.10.0 + github.com/go-ole/go-ole v1.2.4 // indirect + github.com/google/uuid v1.1.1 + github.com/gorilla/mux v1.7.4 + github.com/gorilla/websocket v1.4.2 + github.com/hashicorp/go-multierror v1.1.0 + github.com/hashicorp/golang-lru v0.5.4 + github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d + github.com/ipfs/go-bitswap v0.2.8 + github.com/ipfs/go-block-format v0.0.2 + github.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834 + github.com/ipfs/go-cid v0.0.6 + github.com/ipfs/go-cidutil v0.0.2 + github.com/ipfs/go-datastore v0.4.4 + github.com/ipfs/go-ds-badger2 v0.1.0 + github.com/ipfs/go-ds-leveldb v0.4.2 + github.com/ipfs/go-ds-measure v0.1.0 + github.com/ipfs/go-filestore v1.0.0 + github.com/ipfs/go-fs-lock v0.0.1 + github.com/ipfs/go-graphsync v0.0.6-0.20200504202014-9d5f2c26a103 + github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f + github.com/ipfs/go-ipfs-blockstore v1.0.0 + github.com/ipfs/go-ipfs-chunker v0.0.5 + github.com/ipfs/go-ipfs-ds-help v1.0.0 + github.com/ipfs/go-ipfs-exchange-interface v0.0.1 + github.com/ipfs/go-ipfs-exchange-offline v0.0.1 + github.com/ipfs/go-ipfs-files v0.0.8 + github.com/ipfs/go-ipfs-http-client v0.0.5 + github.com/ipfs/go-ipfs-routing v0.1.0 + github.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf + github.com/ipfs/go-ipld-format v0.2.0 + github.com/ipfs/go-log v1.0.4 + github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 + github.com/ipfs/go-merkledag v0.3.1 + github.com/ipfs/go-path v0.0.7 + github.com/ipfs/go-unixfs v0.2.4 + github.com/ipfs/interface-go-ipfs-core v0.2.3 + github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae + github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e + github.com/kelseyhightower/envconfig v1.4.0 + github.com/lib/pq v1.2.0 + github.com/libp2p/go-eventbus v0.2.1 + github.com/libp2p/go-libp2p v0.10.0 + github.com/libp2p/go-libp2p-connmgr v0.2.4 + github.com/libp2p/go-libp2p-core v0.6.0 + github.com/libp2p/go-libp2p-discovery v0.4.0 + github.com/libp2p/go-libp2p-kad-dht v0.8.1 + github.com/libp2p/go-libp2p-mplex v0.2.3 + github.com/libp2p/go-libp2p-peer v0.2.0 + github.com/libp2p/go-libp2p-peerstore v0.2.6 + github.com/libp2p/go-libp2p-pubsub v0.3.2 + github.com/libp2p/go-libp2p-quic-transport v0.5.0 + github.com/libp2p/go-libp2p-record v0.1.2 + github.com/libp2p/go-libp2p-routing-helpers v0.2.3 + github.com/libp2p/go-libp2p-secio v0.2.2 + github.com/libp2p/go-libp2p-swarm v0.2.7 + github.com/libp2p/go-libp2p-tls v0.1.3 + github.com/libp2p/go-libp2p-yamux v0.2.8 + github.com/libp2p/go-maddr-filter v0.1.0 + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/mitchellh/go-homedir v1.1.0 + github.com/multiformats/go-base32 v0.0.3 + github.com/multiformats/go-multiaddr v0.2.2 + github.com/multiformats/go-multiaddr-dns v0.2.0 + github.com/multiformats/go-multiaddr-net v0.1.5 + github.com/multiformats/go-multibase v0.0.3 + github.com/multiformats/go-multihash v0.0.13 + github.com/opentracing/opentracing-go v1.1.0 + github.com/stretchr/objx v0.2.0 // indirect + github.com/stretchr/testify v1.6.1 + github.com/syndtr/goleveldb v1.0.0 + github.com/urfave/cli/v2 v2.2.0 + github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba + github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d + github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 + github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d + go.opencensus.io v0.22.3 + go.uber.org/dig v1.8.0 // indirect + go.uber.org/fx v1.9.0 + go.uber.org/multierr v1.5.0 + go.uber.org/zap v1.15.0 + go4.org v0.0.0-20190313082347-94abd6928b1d // indirect + golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 + golang.org/x/time v0.0.0-20191024005414-555d28b269f0 + golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 + google.golang.org/api v0.25.0 // indirect + launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect +) + +replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v1.18.0 + +replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi diff --git a/vendor/github.com/filecoin-project/lotus/go.sum b/vendor/github.com/filecoin-project/lotus/go.sum new file mode 100644 index 0000000000..0f334363a8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/go.sum @@ -0,0 +1,1825 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +contrib.go.opencensus.io/exporter/jaeger v0.1.0 h1:WNc9HbA38xEQmsI40Tjd/MNU/g8byN2Of7lwIjv0Jdc= +contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= +contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= +contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee h1:8doiS7ib3zi6/K172oDhSKU0dJ/miJramo9NITOMyZQ= +github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee/go.mod h1:W0GbEAA4uFNYOGG2cJpmFJ04E6SD1NLELPYZB57/7AY= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/Stebalien/go-bitfield v0.0.0-20180330043415-076a62f9ce6e/go.mod h1:3oM7gXIttpYDAJXpVNnSCiUMYBLIZ6cb1t+Ip982MRo= +github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= +github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0 h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/benbjohnson/clock v1.0.1/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.0.2 h1:Z0CN0Yb4ig9sGPXkvAQcGJfnrrMQ5QYLCMPRi9iD7YE= +github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= +github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f h1:BOaYiTvg8p9vBUXpklC22XSK/mifLF7lG9jtmYYi3Tc= +github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= +github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg= +github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= +github.com/dgraph-io/badger/v2 v2.0.3 h1:inzdf6VF/NZ+tJ8RwwYMjJMvsOALTHYdozn0qSl6XJI= +github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= +github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po= +github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/drand/bls12-381 v0.3.2 h1:RImU8Wckmx8XQx1tp1q04OV73J9Tj6mmpQLYDP7V1XE= +github.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y= +github.com/drand/drand v0.9.2-0.20200616080806-a94e9c1636a4 h1:wEpu4hGFF0m0uDq/gxT9Ca/HWek0tvsMqsyPpLBWJ/E= +github.com/drand/drand v0.9.2-0.20200616080806-a94e9c1636a4/go.mod h1:Bu8QYdU0YdB2ZQZezHxabmOIciddiwLRnyV4nuZ2HQE= +github.com/drand/kyber v1.0.1-0.20200110225416-8de27ed8c0e2/go.mod h1:UpXoA0Upd1N9l4TvRPHr1qAUBBERj6JQ/mnKI3BPEmw= +github.com/drand/kyber v1.0.2 h1:dHjtWJZJdn3zBBZ9pqLsLfcR9ScvDvSqzS1sWA8seao= +github.com/drand/kyber v1.0.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= +github.com/drand/kyber v1.1.0 h1:uBfD8gwpVufr+7Dvbxi4jGQ+qoMCO5tRfhYPyn+Tpqk= +github.com/drand/kyber v1.1.0/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= +github.com/drand/kyber-bls12381 v0.1.0 h1:/P4C65VnyEwxzR5ZYYVMNzY1If+aYBrdUU5ukwh7LQw= +github.com/drand/kyber-bls12381 v0.1.0/go.mod h1:N1emiHpm+jj7kMlxEbu3MUyOiooTgNySln564cgD9mk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/go-sysinfo v1.3.0 h1:eb2XFGTMlSwG/yyU9Y8jVAYLIzU2sFzWXwo2gmetyrE= +github.com/elastic/go-sysinfo v1.3.0/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= +github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= +github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= +github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= +github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY= +github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= +github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= +github.com/filecoin-project/chain-validation v0.0.6-0.20200615191232-6be1a8c6ed09 h1:GuiNSEZ9nc05LUpKhABw/SO6t9wqCfsJX1D0ByWQjkc= +github.com/filecoin-project/chain-validation v0.0.6-0.20200615191232-6be1a8c6ed09/go.mod h1:HEJn6kOXMNhCNBYNTO/lrEI7wSgqCOR6hN5ecfYUnC8= +github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= +github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= +github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef h1:Wi5E+P1QfHP8IF27eUiTx5vYfqQZwfPxzq3oFEq8w8U= +github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef/go.mod h1:SrA+pWVoUivqKOfC+ckVYbx41hWz++HxJcrlmHNnebU= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2 h1:jamfsxfK0Q9yCMHt8MPWx7Aa/O9k2Lve8eSc6FILYGQ= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= +github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= +github.com/filecoin-project/go-bitfield v0.0.2-0.20200518150651-562fdb554b6e h1:gkG/7G+iKy4He+IiQNeQn+nndFznb/vCoOR8iRQsm60= +github.com/filecoin-project/go-bitfield v0.0.2-0.20200518150651-562fdb554b6e/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= +github.com/filecoin-project/go-bitfield v0.0.2-0.20200629135455-587b27927d38 h1:B2gUde2DlfCb5YMYNVems2orobxC3KhrX3migym1IOQ= +github.com/filecoin-project/go-bitfield v0.0.2-0.20200629135455-587b27927d38/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= +github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= +github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= +github.com/filecoin-project/go-data-transfer v0.3.0 h1:BwBrrXu9Unh9JjjX4GAc5FfzUNioor/aATIjfc7JTBg= +github.com/filecoin-project/go-data-transfer v0.3.0/go.mod h1:cONglGP4s/d+IUQw5mWZrQK+FQATQxr3AXzi4dRh0l4= +github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5 h1:yvQJCW9mmi9zy+51xA01Ea2X7/dL7r8eKDPuGUjRmbo= +github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= +github.com/filecoin-project/go-fil-markets v0.3.2-0.20200702145639-4034a18364e4 h1:VqNmKGy4/ryzo/TqevSa1kancc3hSdws7sl/NCTZzT0= +github.com/filecoin-project/go-fil-markets v0.3.2-0.20200702145639-4034a18364e4/go.mod h1:UY+/zwNXHN73HcrN6HxNDpv6KKM6ehqfCuE9vK9khF8= +github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24 h1:Jc7vkplmZYVuaEcSXGHDwefvZIdoyyaoGDLqSr8Svms= +github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24/go.mod h1:j6zV//WXIIY5kky873Q3iIKt/ViOE8rcijovmpxrXzM= +github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= +github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= +github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h1:A256QonvzRaknIIAuWhe/M2dpV2otzs3NBhi5TWa/UA= +github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9 h1:k9qVR9ItcziSB2rxtlkN/MDWNlbsI6yzec+zjUatLW0= +github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-statemachine v0.0.0-20200612181802-4eb3d0c68eba h1:GEWb/6KQyNZt4jm8fgVcIFPH0ElAGXfHM59ZSiqPTvY= +github.com/filecoin-project/go-statemachine v0.0.0-20200612181802-4eb3d0c68eba/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= +github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIiWBRilQjQ+5IiwdQ= +github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= +github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= +github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= +github.com/filecoin-project/sector-storage v0.0.0-20200615154852-728a47ab99d6/go.mod h1:M59QnAeA/oV+Z8oHFLoNpGMv0LZ8Rll+vHVXX7GirPM= +github.com/filecoin-project/sector-storage v0.0.0-20200625154333-98ef8e4ef246 h1:NfYQRmVRe0LzlNbK5Ket3vbBOwFD5TvtcNtfo/Sd8mg= +github.com/filecoin-project/sector-storage v0.0.0-20200625154333-98ef8e4ef246/go.mod h1:8f0hWDzzIi1hKs4IVKH9RnDsO4LEHVz8BNat0okDOuY= +github.com/filecoin-project/sector-storage v0.0.0-20200630180318-4c1968f62a8f h1:EHKqNJNIcYggqfrd5nu7SV1KR93ReZygfdSV0w/jefQ= +github.com/filecoin-project/sector-storage v0.0.0-20200630180318-4c1968f62a8f/go.mod h1:r12d7tsmJKz8QDGoCvl65Ay2al6mOgDqxAGUxbyrgMs= +github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= +github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= +github.com/filecoin-project/specs-actors v0.6.0/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= +github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= +github.com/filecoin-project/specs-actors v0.6.2-0.20200702170846-2cd72643a5cf h1:2ERozAZteHYef3tVLVJRepzYieLtJdxvfXNUel19CeU= +github.com/filecoin-project/specs-actors v0.6.2-0.20200702170846-2cd72643a5cf/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= +github.com/filecoin-project/specs-storage v0.1.0 h1:PkDgTOT5W5Ao7752onjDl4QSv+sgOVdJbvFjOnD5w94= +github.com/filecoin-project/specs-storage v0.1.0/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= +github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h1:iixjULRQFPn7Q9KlIqfwLJnlAXO10bbkI+xy5GKGdLY= +github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= +github.com/filecoin-project/storage-fsm v0.0.0-20200625160832-379a4655b044 h1:i4oMhv1kx/MAUxRN4EM5tag5fI1uagrwQwINgKrzUt4= +github.com/filecoin-project/storage-fsm v0.0.0-20200625160832-379a4655b044/go.mod h1:JD7fmV1BYADDcy4EYQnqFH/rUzXsh0Je0jXarCjZqSk= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF6M5KiVP0= +github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968 h1:s+PDl6lozQ+dEUtUtQnO7+A2iPG3sK1pI4liU+jxn90= +github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/status v1.0.3 h1:WkVBY59mw7qUNTr/bLwO7J2vesJ0rQ2C3tMXrTd3w5M= +github.com/gogo/status v1.0.3/go.mod h1:SavQ51ycCLnc7dGyJxp8YAmudx8xqiVrRf+6IXRsugc= +github.com/gogo/status v1.1.0 h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= +github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o= +github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/gxed/go-shellwords v1.0.3/go.mod h1:N7paucT91ByIjmVJHhvoarjoQnmsi3Jd3vH7VqgtMxQ= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE= +github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099 h1:vQqOW42RRM5LoM/1K5dK940VipLqpH8lEVGrMz+mNjU= +github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099/go.mod h1:WVPCl0HO/0RAL5+vBH2GMxBomlxBF70MAS78+Lu1//k= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= +github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hodgesds/perf-utils v0.0.8/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitswap v0.0.3/go.mod h1:jadAZYsP/tcRMl47ZhFxhaNuDQoXawT8iHMg+iFoQbg= +github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis= +github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= +github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= +github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-bitswap v0.2.8 h1:5tQrbyyRS3DkzvcM5n+bVjdSAHLgvH7D+1LopndhUII= +github.com/ipfs/go-bitswap v0.2.8/go.mod h1:2Yjog0GMdH8+AsxkE0DI9D2mANaUTxbVVav0pPoZoug= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-blockservice v0.0.3/go.mod h1:/NNihwTi6V2Yr6g8wBI+BSwPuURpBRMtYNGrlxZ8KuI= +github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= +github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= +github.com/ipfs/go-blockservice v0.1.3 h1:9XgsPMwwWJSC9uVr2pMDsW2qFTBSkxpGMhmna8mIjPM= +github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834 h1:hFJoI1D2a3MqiNkSb4nKwrdkhCngUxUTFNwVwovZX2s= +github.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4-0.20191112011718-79e75dffeb10/go.mod h1:/BYOuUoxkE+0f6tGzlzMvycuN+5l35VOR4Bpg2sCmds= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00 h1:QN88Q0kT2QiDaLxpR/SDsqOBtNIEF/F3n96gSDUimkA= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6 h1:go0y+GcDOGeJIV01FeBsta4FHngoA4Wz7KMeLkXAhMs= +github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cidutil v0.0.2 h1:CNOboQf1t7Qp0nuNh8QMmhJs0+Q//bRL1axtCnIB1Yo= +github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.0/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8= +github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= +github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= +github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= +github.com/ipfs/go-ds-badger v0.2.3 h1:J27YvAcpuA5IvZUbeBxOcQgqnYHUPxoygc6QxxkodZ4= +github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= +github.com/ipfs/go-ds-badger2 v0.1.0 h1:784py6lXkwlVF+K6XSuqmdMgy5l8GI6k60ngBokb9Fg= +github.com/ipfs/go-ds-badger2 v0.1.0/go.mod h1:pbR1p817OZbdId9EvLOhKBgUVTM3BMCSTan78lDDVaw= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= +github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ds-leveldb v0.4.2 h1:QmQoAJ9WkPMUfBLnu1sBVy0xWWlJPg0m4kRAiJL9iaw= +github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= +github.com/ipfs/go-ds-measure v0.1.0 h1:vE4TyY4aeLeVgnnPBC5QzKIjKrqzha0NCujTfgvVbVQ= +github.com/ipfs/go-ds-measure v0.1.0/go.mod h1:1nDiFrhLlwArTME1Ees2XaBOl49OoCgd2A3f8EchMSY= +github.com/ipfs/go-filestore v1.0.0 h1:QR7ekKH+q2AGiWDc7W2Q0qHuYSRZGUJqUn0GsegEPb0= +github.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPiFOdcuu9SM= +github.com/ipfs/go-fs-lock v0.0.1 h1:XHX8uW4jQBYWHj59XXcjg7BHlHxV9ZOYs6Y43yb7/l0= +github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y= +github.com/ipfs/go-graphsync v0.0.6-0.20200504202014-9d5f2c26a103 h1:SD+bXod/pOWKJCGj0tG140ht8Us5k+3JBcHw0PVYTho= +github.com/ipfs/go-graphsync v0.0.6-0.20200504202014-9d5f2c26a103/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= +github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= +github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= +github.com/ipfs/go-hamt-ipld v0.1.1-0.20200501020327-d53d20a7063e h1:Klv6s+kbuhh0JVpGFmFK2t6AtZxJfAnVneQHh1DlFOo= +github.com/ipfs/go-hamt-ipld v0.1.1-0.20200501020327-d53d20a7063e/go.mod h1:giiPqWYCnRBYpNTsJ/EX1ojldX5kTXrXYckSJQ7ko9M= +github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f h1:mchhWiYYUSoCuE3wDfRCo8cho5kqSoxkgnOtGcnNMZw= +github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f/go.mod h1:phOFBB7W73N9dg1glcb1fQ9HtQFDUpeyJgatW8ns0bw= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= +github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blockstore v1.0.0 h1:pmFp5sFYsYVvMOp9X01AK3s85usVcLvkBTRsN6SnfUA= +github.com/ipfs/go-ipfs-blockstore v1.0.0/go.mod h1:knLVdhVU9L7CC4T+T4nvGdeUIPAXlnd9zmXfp+9MIjU= +github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= +github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= +github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= +github.com/ipfs/go-ipfs-cmds v0.1.0 h1:0CEde9EcxByej8+L6d1PST57J4ambRPyCTjLG5Ymou8= +github.com/ipfs/go-ipfs-cmds v0.1.0/go.mod h1:TiK4e7/V31tuEb8YWDF8lN3qrnDH+BS7ZqWIeYJlAs8= +github.com/ipfs/go-ipfs-config v0.0.11 h1:5/4nas2CQXiKr2/MLxU24GDGTBvtstQIQezuk7ltOQQ= +github.com/ipfs/go-ipfs-config v0.0.11/go.mod h1:wveA8UT5ywN26oKStByzmz1CO6cXwLKKM6Jn/Hfw08I= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g= +github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.7/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= +github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA= +github.com/ipfs/go-ipfs-http-client v0.0.5 h1:niW5M0qqa0O/VRCAzr3f5Y7i3MjTpf0lhpkisjRtHR8= +github.com/ipfs/go-ipfs-http-client v0.0.5/go.mod h1:8EKP9RGUrUex4Ff86WhnKU7seEBOtjdgXlY9XHYvYMw= +github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= +github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= +github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= +github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= +github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= +github.com/ipfs/go-ipld-cbor v0.0.1/go.mod h1:RXHr8s4k0NE0TKhnrxqZC9M888QfsBN9rhS5NjfKzY8= +github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5-0.20200204214505-252690b78669/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf h1:PRCy+w3GocY77CBEwTprp6hn7PLiEU1YToKe7B+1FVk= +github.com/ipfs/go-ipld-cbor v0.0.5-0.20200428170625-a0bd04d3cbdf/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= +github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs= +github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA= +github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I= +github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= +github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= +github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= +github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log/v2 v2.0.1/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 h1:3bijxqzQ1O9yg7gd7Aqk80oaEvsJ+uXw0zSvi2qR3Jw= +github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA= +github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= +github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= +github.com/ipfs/go-merkledag v0.3.1 h1:3UqWINBEr3/N+r6OwgFXAddDP/8zpQX/8J7IGVOCqRQ= +github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-path v0.0.3/go.mod h1:zIRQUez3LuQIU25zFjC2hpBTHimWx7VK5bjZgRLbbdo= +github.com/ipfs/go-path v0.0.7 h1:H06hKMquQ0aYtHiHryOMLpQC1qC3QwXwkahcEVD51Ho= +github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= +github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= +github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN1EJOjc= +github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= +github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= +github.com/ipfs/go-unixfs v0.0.4/go.mod h1:eIo/p9ADu/MFOuyxzwU+Th8D6xoxU//r590vUpWyfz8= +github.com/ipfs/go-unixfs v0.2.1/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k= +github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo= +github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipfs/interface-go-ipfs-core v0.2.3 h1:E6uQ+1fJjkxJWlL9lAE72a5FWeyeeNL3GitLy8+jq3Y= +github.com/ipfs/interface-go-ipfs-core v0.2.3/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s= +github.com/ipfs/iptb v1.4.0 h1:YFYTrCkLMRwk/35IMyC6+yjoQSHTEcNcefBStLJzgvo= +github.com/ipfs/iptb v1.4.0/go.mod h1:1rzHpCYtNp87/+hTxG5TfCVn/yMY3dKnLn8tBiMfdmg= +github.com/ipfs/iptb-plugins v0.2.1 h1:au4HWn9/pRPbkxA08pDx2oRAs4cnbgQWgV0teYXuuGA= +github.com/ipfs/iptb-plugins v0.2.1/go.mod h1:QXMbtIWZ+jRsW8a4h13qAKU7jcM7qaittO8wOsTP0Rs= +github.com/ipld/go-car v0.1.1-0.20200429200904-c222d793c339/go.mod h1:eajxljm6I8o3LitnFeVEmucwZmz7+yLSiKce9yYMefg= +github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae h1:OV9dxl8iPMCOD8Vi/hvFwRh3JWPXqmkYSVxWr9JnEzM= +github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae/go.mod h1:2mvxpu4dKRnuH3mj5u6KW/tmRSCcXvy/KYiJ4nC6h4c= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e h1:ZISbJlM0urTANR9KRfRaqlBmyOj5uUtxs2r4Up9IXsA= +github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1 h1:K1Ysr7kgIlo7YQkPqdkA6H7BVdIugvuAz7OQUTJxLdE= +github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= +github.com/jackpal/gateway v1.0.4/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c h1:uUx61FiAa1GI6ZmVd2wf2vULeQZIKG66eybjNXKYCz4= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1 h1:qBCV/RLV02TSfQa7tFmxTihnG+u+7JXByOkhlkR5rmQ= +github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 h1:Iy7Ifq2ysilWU4QlCx/97OoI4xT1IV7i8byT/EyIT/M= +github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f h1:qET3Wx0v8tMtoTOQnsJXVvqvCopSf48qobR6tcJuDHo= +github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= +github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= +github.com/libp2p/go-conn-security-multistream v0.0.1/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= +github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= +github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= +github.com/libp2p/go-eventbus v0.0.2/go.mod h1:Hr/yGlwxA/stuLnpMiu82lpNKpvRy3EaJxPu40XYOwk= +github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= +github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= +github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.0.2/go.mod h1:Qu8bWqFXiocPloabFGUcVG4kk94fLvfC8mWTDdFC9wE= +github.com/libp2p/go-libp2p v0.0.30/go.mod h1:XWT8FGHlhptAv1+3V/+J5mEpzyui/5bvFsNuWYs611A= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= +github.com/libp2p/go-libp2p v0.3.1/go.mod h1:e6bwxbdYH1HqWTz8faTChKGR0BjPc8p+6SyP8GTTR7Y= +github.com/libp2p/go-libp2p v0.4.0/go.mod h1:9EsEIf9p2UDuwtPd0DwJsAl0qXVxgAnuDGRvHbfATfI= +github.com/libp2p/go-libp2p v0.6.0/go.mod h1:mfKWI7Soz3ABX+XEBR61lGbg+ewyMtJHVt043oWeqwg= +github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= +github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= +github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= +github.com/libp2p/go-libp2p v0.8.2/go.mod h1:NQDA/F/qArMHGe0J7sDScaKjW8Jh4y/ozQqBbYJ+BnA= +github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM= +github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ= +github.com/libp2p/go-libp2p v0.10.0 h1:7ooOvK1wi8eLpyTppy8TeH43UHy5uI75GAHGJxenUi0= +github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8= +github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= +github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= +github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= +github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= +github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= +github.com/libp2p/go-libp2p-autonat v0.2.3 h1:w46bKK3KTOUWDe5mDYMRjJu1uryqBp8HCNDp/TWMqKw= +github.com/libp2p/go-libp2p-autonat v0.2.3/go.mod h1:2U6bNWCNsAG9LEbwccBDQbjzQ8Krdjge1jLTE9rdoMM= +github.com/libp2p/go-libp2p-autonat-svc v0.1.0/go.mod h1:fqi8Obl/z3R4PFVLm8xFtZ6PBL9MlV/xumymRFkKq5A= +github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-blankhost v0.1.3/go.mod h1:KML1//wiKR8vuuJO0y3LUd1uLv+tlkGTAr3jC0S5cLg= +github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= +github.com/libp2p/go-libp2p-blankhost v0.1.6 h1:CkPp1/zaCrCnBo0AdsQA0O1VkUYoUOtyHOnoa8gKIcE= +github.com/libp2p/go-libp2p-blankhost v0.1.6/go.mod h1:jONCAJqEP+Z8T6EQviGL4JsQcLx1LgTGtVqFNY8EMfQ= +github.com/libp2p/go-libp2p-circuit v0.0.1/go.mod h1:Dqm0s/BiV63j8EEAs8hr1H5HudqvCAeXxDyic59lCwE= +github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-circuit v0.1.1/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-circuit v0.1.3/go.mod h1:Xqh2TjSy8DD5iV2cCOMzdynd6h8OTBGoV1AWbWor3qM= +github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= +github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= +github.com/libp2p/go-libp2p-circuit v0.2.2 h1:87RLabJ9lrhoiSDDZyCJ80ZlI5TLJMwfyoGAaWXzWqA= +github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= +github.com/libp2p/go-libp2p-circuit v0.2.3 h1:3Uw1fPHWrp1tgIhBz0vSOxRUmnKL8L/NGUyEd5WfSGM= +github.com/libp2p/go-libp2p-circuit v0.2.3/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= +github.com/libp2p/go-libp2p-connmgr v0.1.1/go.mod h1:wZxh8veAmU5qdrfJ0ZBLcU8oJe9L82ciVP/fl1VHjXk= +github.com/libp2p/go-libp2p-connmgr v0.2.3/go.mod h1:Gqjg29zI8CwXX21zRxy6gOg8VYu3zVerJRt2KyktzH4= +github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= +github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= +github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= +github.com/libp2p/go-libp2p-core v0.0.6/go.mod h1:0d9xmaYAVY5qmbp/fcgxHT3ZJsLjYeYPMJAUKpaCHrE= +github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= +github.com/libp2p/go-libp2p-core v0.2.3/go.mod h1:GqhyQqyIAPsxFYXHMjfXgMv03lxsvM0mFzuYA9Ib42A= +github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= +github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= +github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.2/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= +github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= +github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.5.7 h1:QK3xRwFxqd0Xd9bSZL+8yZ8ncZZbl6Zngd/+Y+A6sgQ= +github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.6.0 h1:u03qofNYTBN+yVg08PuAKylZogVf0xcTEeM8skGf+ak= +github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= +github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= +github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ= +github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI= +github.com/libp2p/go-libp2p-discovery v0.0.5/go.mod h1:YtF20GUxjgoKZ4zmXj8j3Nb2TUSBHFlOCetzYdbZL5I= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= +github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= +github.com/libp2p/go-libp2p-discovery v0.4.0 h1:dK78UhopBk48mlHtRCzbdLm3q/81g77FahEBTjcqQT8= +github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4= +github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= +github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= +github.com/libp2p/go-libp2p-kad-dht v0.2.1/go.mod h1:k7ONOlup7HKzQ68dE6lSnp07cdxdkmnRa+6B4Fh9/w0= +github.com/libp2p/go-libp2p-kad-dht v0.8.1 h1:PS/mgLSzFqH5lS3PnnxcqsIrHy+qbQ5GkhzcrT12LyA= +github.com/libp2p/go-libp2p-kad-dht v0.8.1/go.mod h1:u3rbYbp3CSraAHD5s81CJ3hHozKTud/UOXfAgh93Gek= +github.com/libp2p/go-libp2p-kbucket v0.2.1/go.mod h1:/Rtu8tqbJ4WQ2KTCOMJhggMukOLNLNPY1EtEWWLxUvc= +github.com/libp2p/go-libp2p-kbucket v0.4.2 h1:wg+VPpCtY61bCasGRexCuXOmEmdKjN+k1w+JtTwu9gA= +github.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFPnXzAZCCBBS70lytY= +github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= +github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= +github.com/libp2p/go-libp2p-mplex v0.2.3 h1:2zijwaJvpdesST2MXpI5w9wWFRgYtMcpRX7rrw0jmOo= +github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= +github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= +github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= +github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= +github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= +github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= +github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= +github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= +github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= +github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= +github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw= +github.com/libp2p/go-libp2p-peerstore v0.2.4 h1:jU9S4jYN30kdzTpDAR7SlHUD+meDUjTODh4waLWF1ws= +github.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U= +github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= +github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= +github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= +github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= +github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= +github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= +github.com/libp2p/go-libp2p-pubsub v0.3.2 h1:k3cJm5JW5mjaWZkobS50sJLJWaB2mBi0HW4eRlE8mSo= +github.com/libp2p/go-libp2p-pubsub v0.3.2/go.mod h1:Uss7/Cfz872KggNb+doCVPHeCDmXB7z500m/R8DaAUk= +github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= +github.com/libp2p/go-libp2p-quic-transport v0.5.0 h1:BUN1lgYNUrtv4WLLQ5rQmC9MCJ6uEXusezGvYRNoJXE= +github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= +github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= +github.com/libp2p/go-libp2p-record v0.1.2 h1:M50VKzWnmUrk/M5/Dz99qO9Xh4vs8ijsK+7HkJvRP+0= +github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= +github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= +github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE= +github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= +github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= +github.com/libp2p/go-libp2p-secio v0.0.1/go.mod h1:IdG6iQybdcYmbTzxp4J5dwtUEDTOvZrT0opIDVNPrJs= +github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= +github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= +github.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg= +github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= +github.com/libp2p/go-libp2p-swarm v0.0.1/go.mod h1:mh+KZxkbd3lQnveQ3j2q60BM1Cw2mX36XXQqwfPOShs= +github.com/libp2p/go-libp2p-swarm v0.0.6/go.mod h1:s5GZvzg9xXe8sbeESuFpjt8CJPTCa8mhEusweJqyFy8= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-swarm v0.2.1/go.mod h1:x07b4zkMFo2EvgPV2bMTlNmdQc8i+74Jjio7xGvsTgU= +github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= +github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= +github.com/libp2p/go-libp2p-swarm v0.2.4/go.mod h1:/xIpHFPPh3wmSthtxdGbkHZ0OET1h/GGZes8Wku/M5Y= +github.com/libp2p/go-libp2p-swarm v0.2.7 h1:4lV/sf7f0NuVqunOpt1I11+Z54+xp+m0eeAvxj/LyRc= +github.com/libp2p/go-libp2p-swarm v0.2.7/go.mod h1:ZSJ0Q+oq/B1JgfPHJAT2HTall+xYRNYp1xs4S2FBWKA= +github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU= +github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= +github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= +github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= +github.com/libp2p/go-libp2p-transport v0.0.4/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= +github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= +github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m+JmZCe5RUXG10UMEx4kWe9Ipj5c= +github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= +github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4= +github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= +github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= +github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= +github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= +github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= +github.com/libp2p/go-libp2p-yamux v0.2.8 h1:0s3ELSLu2O7hWKfX1YjzudBKCP0kZ+m9e2+0veXzkn4= +github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= +github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-maddr-filter v0.1.0 h1:4ACqZKw8AqiuJfwFGq1CYDFugfXTOos+qQ3DETkhtCE= +github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= +github.com/libp2p/go-mplex v0.0.1/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.1.2 h1:qOg1s+WdGLlpkrczDqmhYzyk3vCfsQ8+RxRTQjOZWwI= +github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= +github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= +github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= +github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= +github.com/libp2p/go-netroute v0.1.2 h1:UHhB35chwgvcRI392znJA3RCBtZ3MpE3ahNCN5MR4Xg= +github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.5 h1:pQkejVhF0xp08D4CQUcw8t+BFJeXowja6RVcb5p++EA= +github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.1/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M= +github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= +github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= +github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ= +github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= +github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-tcp-transport v0.0.1/go.mod h1:mnjg0o0O5TmXUaUIanYPUqkW4+u6mK0en8rlpA6BBTs= +github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= +github.com/libp2p/go-tcp-transport v0.2.0 h1:YoThc549fzmNJIh7XjHVtMIFaEDRtIrtWciG5LyYAPo= +github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= +github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= +github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.0.1/go.mod h1:p3bKjDWHEgtuKKj+2OdPYs5dAPIjtpQGHF2tJfGz7Ww= +github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-ws-transport v0.1.2/go.mod h1:dsh2Ld8F+XNmzpkaAijmg5Is+e9l6/1tK/6VFOdN69Y= +github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= +github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw= +github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.6/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.3.7 h1:v40A1eSPJDIZwz2AvrV3cxpTZEGDP11QJbukmEhYyQI= +github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= +github.com/lucas-clemente/quic-go v0.16.0 h1:jJw36wfzGJhmOhAOaOC2lS36WgeqXQszH47A7spo1LI= +github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= +github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= +github.com/marten-seemann/qtls v0.9.1 h1:O0YKQxNVPaiFgMng0suWEOY2Sb4LT2sRn9Qimq3Z1IQ= +github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee/go.mod h1:Evt/EIne46u9PtQbeTx2NTcqURpr5K4SvKtGmBuDPN8= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= +github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= +github.com/multiformats/go-multiaddr v0.2.2 h1:XZLDTszBIJe6m0zF6ITBrEcZR73OPUhCBBS9rYAuUzI= +github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.1.0/go.mod h1:01k2RAqtoXIuPa3DCavAE9/6jc6nM0H3EgZyfUhN2oY= +github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= +github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= +github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.1.5 h1:QoRKvu0xHN1FCFJcMQLbG/yQE2z441L5urvG3+qyz7g= +github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.2 h1:2pAgScmS1g9XjH7EtAfNhTuyrWYEWcxy0G5Wo85hWDA= +github.com/multiformats/go-multibase v0.0.2/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= +github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.7/go.mod h1:XuKXPp8VHcTygube3OWZC+aZrA+H1IhmjoCDtJc7PXM= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI= +github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c h1:5bFTChQxSKNwy8ALwOebjekYExl9HTT9urdawqC95tA= +github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 h1:0R5mDLI66Qw13qN80TRz85zthQ2nf2+uDyiV23w6c3Q= +github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02/go.mod h1:JNdpVEzCpXBgIiv4ds+TzhN1hrtxq6ClLrTlT9OQRSc= +github.com/opentracing-contrib/go-grpc v0.0.0-20191001143057-db30781987df h1:vdYtBU6zvL7v+Tr+0xFM/qhahw/EvY8DMMunZHKH6eE= +github.com/opentracing-contrib/go-grpc v0.0.0-20191001143057-db30781987df/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 h1:QsgXACQhd9QJhEmRumbsMQQvBtmdS0mafoVEBplWXEg= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= +github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= +github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/node_exporter v1.0.0-rc.0.0.20200428091818-01054558c289/go.mod h1:FGbBv5OPKjch+jNUJmEQpMZytIdyW0NdBtWFcfSKusc= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.0 h1:jhMy6QXfi3y2HEzFoyuCj40z4OZIIHHPtFyCMftmvKA= +github.com/prometheus/procfs v0.1.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sercand/kuberesolver v2.1.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ= +github.com/sercand/kuberesolver v2.4.0+incompatible h1:WE2OlRf6wjLxHwNkkFLQGaZcVLEXjMjBPjjEU5vksH8= +github.com/sercand/kuberesolver v2.4.0+incompatible/go.mod h1:lWF3GL0xptCB/vCiJPl/ZshwPsX/n4Y7u0CW9E7aQIQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= +github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/siebenmann/go-kstat v0.0.0-20160321171754-d34789b79745/go.mod h1:G81aIFAMS9ECrwBYR9YxhlPjWgrItd+Kje78O6+uqm8= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a/go.mod h1:LeFCbQYJ3KJlPs/FvPz2dy1tkpxyeNESVyCNNzRXFR0= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-client-go v2.23.1+incompatible h1:uArBYHQR0HqLFFAypI7RsWTzPSj/bDpmZZuQjMLSg1A= +github.com/uber/jaeger-client-go v2.23.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v1.5.1-0.20181102163054-1fc5c315e03c/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= +github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= +github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5 h1:EYxr08r8x6r/5fLEAMMkida1BVgxVXE4LfZv/XV+znU= +github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5/go.mod h1:c98fKi5B9u8OsKGiWHLRKus6ToQ1Tubeow44ECO1uxY= +github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= +github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= +github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= +github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba h1:X4n8JG2e2biEZZXdBKt9HX7DN3bYGFUqljqqy0DqgnY= +github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CHQnYnQUEPydYCwuy8lmTHfGmdw9TKrhWV0xLx8l0oM= +github.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200206220010-03c9665e2a66/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501014322-5f9941ef88e0/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= +github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d h1:Y25auOnuZb/GuJvqMflRSDWBz8/HBRME8fiD+H8zLfs= +github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= +github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/go-smux-multiplex v3.0.16+incompatible/go.mod h1:34LEDbeKFZInPUrAG+bjuJmUXONGdEFW7XL0SpTY1y4= +github.com/whyrusleeping/go-smux-multistream v2.0.2+incompatible/go.mod h1:dRWHHvc4HDQSHh9gbKEBbUZ+f2Q8iZTPG3UOGYODxSQ= +github.com/whyrusleeping/go-smux-yamux v2.0.8+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= +github.com/whyrusleeping/go-smux-yamux v2.0.9+incompatible/go.mod h1:6qHUzBXUbB9MXmw3AUdB52L8sEb/hScCqOdW2kj/wuI= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d h1:wnjWu1N8UTNf2zzF5FWlEyNNbNw5GMVHaHaaLdvdTdA= +github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d/go.mod h1:g7ckxrjiFh8mi1AY7ox23PZD0g6QU/TxW3U3unX7I3A= +github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= +github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= +github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= +go.dedis.ch/kyber/v3 v3.0.9 h1:i0ZbOQocHUjfFasBiUql5zVeC7u/vahFd96DFA8UOWk= +go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg= +go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= +go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= +go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo= +go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI= +go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/fx v1.9.0 h1:7OAz8ucp35AU8eydejpYG7QrbE8rLKzGhHbZlJi5LYY= +go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= +go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= +go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org v0.0.0-20190313082347-94abd6928b1d h1:JkRdGP3zvTtTbabWSAC6n67ka30y7gOzWAah4XYJSfw= +go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476 h1:E7ct1C6/33eOdrGZKMoyntcEvs2dwZnDe30crG5vpYU= +golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566 h1:OXjomkWHhzUx4+HldlJ2TsMxJdWgEo5CTtspD1wdhdk= +golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.3.2 h1:iTp+3yyl/KOtxa/d1/JUE0GGSoR6FuW5udver22iwpw= +google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA= +google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8= +google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/vendor/github.com/filecoin-project/lotus/lib/addrutil/parse.go b/vendor/github.com/filecoin-project/lotus/lib/addrutil/parse.go new file mode 100644 index 0000000000..f9ee04c3f7 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/addrutil/parse.go @@ -0,0 +1,89 @@ +package addrutil + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/libp2p/go-libp2p-core/peer" + ma "github.com/multiformats/go-multiaddr" + madns "github.com/multiformats/go-multiaddr-dns" +) + +// ParseAddresses is a function that takes in a slice of string peer addresses +// (multiaddr + peerid) and returns a slice of properly constructed peers +func ParseAddresses(ctx context.Context, addrs []string) ([]peer.AddrInfo, error) { + // resolve addresses + maddrs, err := resolveAddresses(ctx, addrs) + if err != nil { + return nil, err + } + + return peer.AddrInfosFromP2pAddrs(maddrs...) +} + +const ( + dnsResolveTimeout = 10 * time.Second +) + +// resolveAddresses resolves addresses parallelly +func resolveAddresses(ctx context.Context, addrs []string) ([]ma.Multiaddr, error) { + ctx, cancel := context.WithTimeout(ctx, dnsResolveTimeout) + defer cancel() + + var maddrs []ma.Multiaddr + var wg sync.WaitGroup + resolveErrC := make(chan error, len(addrs)) + + maddrC := make(chan ma.Multiaddr) + + for _, addr := range addrs { + maddr, err := ma.NewMultiaddr(addr) + if err != nil { + return nil, err + } + + // check whether address ends in `ipfs/Qm...` + if _, last := ma.SplitLast(maddr); last.Protocol().Code == ma.P_IPFS { + maddrs = append(maddrs, maddr) + continue + } + wg.Add(1) + go func(maddr ma.Multiaddr) { + defer wg.Done() + raddrs, err := madns.Resolve(ctx, maddr) + if err != nil { + resolveErrC <- err + return + } + // filter out addresses that still doesn't end in `ipfs/Qm...` + found := 0 + for _, raddr := range raddrs { + if _, last := ma.SplitLast(raddr); last != nil && last.Protocol().Code == ma.P_IPFS { + maddrC <- raddr + found++ + } + } + if found == 0 { + resolveErrC <- fmt.Errorf("found no ipfs peers at %s", maddr) + } + }(maddr) + } + go func() { + wg.Wait() + close(maddrC) + }() + + for maddr := range maddrC { + maddrs = append(maddrs, maddr) + } + + select { + case err := <-resolveErrC: + return nil, err + default: + } + + return maddrs, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/bufbstore/buf_bstore.go b/vendor/github.com/filecoin-project/lotus/lib/bufbstore/buf_bstore.go new file mode 100644 index 0000000000..4b430828b3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/bufbstore/buf_bstore.go @@ -0,0 +1,146 @@ +package bufbstore + +import ( + "context" + "os" + + block "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + ds "github.com/ipfs/go-datastore" + bstore "github.com/ipfs/go-ipfs-blockstore" + logging "github.com/ipfs/go-log/v2" +) + +var log = logging.Logger("bufbs") + +type BufferedBS struct { + read bstore.Blockstore + write bstore.Blockstore +} + +func NewBufferedBstore(base bstore.Blockstore) *BufferedBS { + buf := bstore.NewBlockstore(ds.NewMapDatastore()) + if os.Getenv("LOTUS_DISABLE_VM_BUF") == "iknowitsabadidea" { + log.Warn("VM BLOCKSTORE BUFFERING IS DISABLED") + buf = base + } + + return &BufferedBS{ + read: base, + write: buf, + } +} + +func NewTieredBstore(r bstore.Blockstore, w bstore.Blockstore) *BufferedBS { + return &BufferedBS{ + read: r, + write: w, + } +} + +var _ (bstore.Blockstore) = &BufferedBS{} + +func (bs *BufferedBS) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + a, err := bs.read.AllKeysChan(ctx) + if err != nil { + return nil, err + } + + b, err := bs.write.AllKeysChan(ctx) + if err != nil { + return nil, err + } + + out := make(chan cid.Cid) + go func() { + defer close(out) + for a != nil || b != nil { + select { + case val, ok := <-a: + if !ok { + a = nil + } else { + select { + case out <- val: + case <-ctx.Done(): + return + } + } + case val, ok := <-b: + if !ok { + b = nil + } else { + select { + case out <- val: + case <-ctx.Done(): + return + } + } + } + } + }() + + return out, nil +} + +func (bs *BufferedBS) DeleteBlock(c cid.Cid) error { + if err := bs.read.DeleteBlock(c); err != nil { + return err + } + + return bs.write.DeleteBlock(c) +} + +func (bs *BufferedBS) Get(c cid.Cid) (block.Block, error) { + if out, err := bs.read.Get(c); err != nil { + if err != bstore.ErrNotFound { + return nil, err + } + } else { + return out, nil + } + + return bs.write.Get(c) +} + +func (bs *BufferedBS) GetSize(c cid.Cid) (int, error) { + panic("nyi") +} + +func (bs *BufferedBS) Put(blk block.Block) error { + has, err := bs.read.Has(blk.Cid()) + if err != nil { + return err + } + + if has { + return nil + } + + return bs.write.Put(blk) +} + +func (bs *BufferedBS) Has(c cid.Cid) (bool, error) { + has, err := bs.read.Has(c) + if err != nil { + return false, err + } + if has { + return true, nil + } + + return bs.write.Has(c) +} + +func (bs *BufferedBS) HashOnRead(hor bool) { + bs.read.HashOnRead(hor) + bs.write.HashOnRead(hor) +} + +func (bs *BufferedBS) PutMany(blks []block.Block) error { + return bs.write.PutMany(blks) +} + +func (bs *BufferedBS) Read() bstore.Blockstore { + return bs.read +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/increadtimeout/incrt.go b/vendor/github.com/filecoin-project/lotus/lib/increadtimeout/incrt.go new file mode 100644 index 0000000000..0b9c65d4df --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/increadtimeout/incrt.go @@ -0,0 +1,73 @@ +package incrt + +import ( + "io" + "time" + + logging "github.com/ipfs/go-log/v2" +) + +var log = logging.Logger("incrt") + +var now = time.Now + +type ReaderDeadline interface { + Read([]byte) (int, error) + SetReadDeadline(time.Time) error +} + +type incrt struct { + rd ReaderDeadline + + waitPerByte time.Duration + wait time.Duration + maxWait time.Duration +} + +// New creates an Incremental Reader Timeout, with minimum sustained speed of +// minSpeed bytes per second and with maximum wait of maxWait +func New(rd ReaderDeadline, minSpeed int64, maxWait time.Duration) io.Reader { + return &incrt{ + rd: rd, + waitPerByte: time.Second / time.Duration(minSpeed), + wait: maxWait, + maxWait: maxWait, + } +} + +type errNoWait struct{} + +func (err errNoWait) Error() string { + return "wait time exceeded" +} +func (err errNoWait) Timeout() bool { + return true +} + +func (crt *incrt) Read(buf []byte) (int, error) { + start := now() + if crt.wait == 0 { + return 0, errNoWait{} + } + + err := crt.rd.SetReadDeadline(start.Add(crt.wait)) + if err != nil { + log.Debugf("unable to set deadline: %+v", err) + } + + n, err := crt.rd.Read(buf) + + _ = crt.rd.SetReadDeadline(time.Time{}) + if err == nil { + dur := now().Sub(start) + crt.wait -= dur + crt.wait += time.Duration(n) * crt.waitPerByte + if crt.wait < 0 { + crt.wait = 0 + } + if crt.wait > crt.maxWait { + crt.wait = crt.maxWait + } + } + return n, err +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/ipfsbstore/ipfsbstore.go b/vendor/github.com/filecoin-project/lotus/lib/ipfsbstore/ipfsbstore.go new file mode 100644 index 0000000000..33110e2953 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/ipfsbstore/ipfsbstore.go @@ -0,0 +1,119 @@ +package ipfsbstore + +import ( + "bytes" + "context" + "io/ioutil" + + "golang.org/x/xerrors" + + "github.com/multiformats/go-multiaddr" + "github.com/multiformats/go-multihash" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + blockstore "github.com/ipfs/go-ipfs-blockstore" + httpapi "github.com/ipfs/go-ipfs-http-client" + iface "github.com/ipfs/interface-go-ipfs-core" + "github.com/ipfs/interface-go-ipfs-core/options" + "github.com/ipfs/interface-go-ipfs-core/path" +) + +type IpfsBstore struct { + ctx context.Context + api iface.CoreAPI +} + +func NewIpfsBstore(ctx context.Context) (*IpfsBstore, error) { + api, err := httpapi.NewLocalApi() + if err != nil { + return nil, xerrors.Errorf("getting local ipfs api: %w", err) + } + + return &IpfsBstore{ + ctx: ctx, + api: api, + }, nil +} + +func NewRemoteIpfsBstore(ctx context.Context, maddr multiaddr.Multiaddr) (*IpfsBstore, error) { + api, err := httpapi.NewApi(maddr) + if err != nil { + return nil, xerrors.Errorf("getting remote ipfs api: %w", err) + } + + return &IpfsBstore{ + ctx: ctx, + api: api, + }, nil +} + +func (i *IpfsBstore) DeleteBlock(cid cid.Cid) error { + return xerrors.Errorf("not supported") +} + +func (i *IpfsBstore) Has(cid cid.Cid) (bool, error) { + _, err := i.api.Block().Stat(i.ctx, path.IpldPath(cid)) + if err != nil { + return false, xerrors.Errorf("getting ipfs block: %w", err) + } + + return true, nil +} + +func (i *IpfsBstore) Get(cid cid.Cid) (blocks.Block, error) { + rd, err := i.api.Block().Get(i.ctx, path.IpldPath(cid)) + if err != nil { + return nil, xerrors.Errorf("getting ipfs block: %w", err) + } + + data, err := ioutil.ReadAll(rd) + if err != nil { + return nil, err + } + + return blocks.NewBlockWithCid(data, cid) +} + +func (i *IpfsBstore) GetSize(cid cid.Cid) (int, error) { + st, err := i.api.Block().Stat(i.ctx, path.IpldPath(cid)) + if err != nil { + return 0, xerrors.Errorf("getting ipfs block: %w", err) + } + + return st.Size(), nil +} + +func (i *IpfsBstore) Put(block blocks.Block) error { + mhd, err := multihash.Decode(block.Cid().Hash()) + if err != nil { + return err + } + + _, err = i.api.Block().Put(i.ctx, bytes.NewReader(block.RawData()), + options.Block.Hash(mhd.Code, mhd.Length), + options.Block.Format(cid.CodecToStr[block.Cid().Type()])) + return err +} + +func (i *IpfsBstore) PutMany(blocks []blocks.Block) error { + // TODO: could be done in parallel + + for _, block := range blocks { + if err := i.Put(block); err != nil { + return err + } + } + + return nil +} + +func (i *IpfsBstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + return nil, xerrors.Errorf("not supported") +} + +func (i *IpfsBstore) HashOnRead(enabled bool) { + return // TODO: We could technically support this, but.. +} + +var _ blockstore.Blockstore = &IpfsBstore{} diff --git a/vendor/github.com/filecoin-project/lotus/lib/lotuslog/levels.go b/vendor/github.com/filecoin-project/lotus/lib/lotuslog/levels.go new file mode 100644 index 0000000000..ae3959568e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/lotuslog/levels.go @@ -0,0 +1,21 @@ +package lotuslog + +import ( + "os" + + logging "github.com/ipfs/go-log/v2" +) + +func SetupLogLevels() { + if _, set := os.LookupEnv("GOLOG_LOG_LEVEL"); !set { + _ = logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("dht", "ERROR") + _ = logging.SetLogLevel("swarm2", "WARN") + _ = logging.SetLogLevel("bitswap", "WARN") + //_ = logging.SetLogLevel("pubsub", "WARN") + _ = logging.SetLogLevel("connmgr", "WARN") + _ = logging.SetLogLevel("advmgr", "DEBUG") + _ = logging.SetLogLevel("stores", "DEBUG") + _ = logging.SetLogLevel("nat", "INFO") + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/nullreader/reader.go b/vendor/github.com/filecoin-project/lotus/lib/nullreader/reader.go new file mode 100644 index 0000000000..3c0a856ca4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/nullreader/reader.go @@ -0,0 +1,10 @@ +package nullreader + +type Reader struct{} + +func (Reader) Read(out []byte) (int, error) { + for i := range out { + out[i] = 0 + } + return len(out), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/parmap/parmap.go b/vendor/github.com/filecoin-project/lotus/lib/parmap/parmap.go new file mode 100644 index 0000000000..dcf0ef3c8e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/parmap/parmap.go @@ -0,0 +1,88 @@ +package parmap + +import ( + "reflect" + "sync" +) + +// MapArr transforms map into slice of map values +func MapArr(in interface{}) interface{} { + rin := reflect.ValueOf(in) + rout := reflect.MakeSlice(reflect.SliceOf(rin.Type().Elem()), rin.Len(), rin.Len()) + var i int + + it := rin.MapRange() + for it.Next() { + rout.Index(i).Set(it.Value()) + i++ + } + + return rout.Interface() +} + +// KMapArr transforms map into slice of map keys +func KMapArr(in interface{}) interface{} { + rin := reflect.ValueOf(in) + rout := reflect.MakeSlice(reflect.SliceOf(rin.Type().Key()), rin.Len(), rin.Len()) + var i int + + it := rin.MapRange() + for it.Next() { + rout.Index(i).Set(it.Key()) + i++ + } + + return rout.Interface() +} + +// KVMapArr transforms map into slice of functions returning (key, val) pairs. +// map[A]B => []func()(A, B) +func KVMapArr(in interface{}) interface{} { + rin := reflect.ValueOf(in) + + t := reflect.FuncOf([]reflect.Type{}, []reflect.Type{ + rin.Type().Key(), + rin.Type().Elem(), + }, false) + + rout := reflect.MakeSlice(reflect.SliceOf(t), rin.Len(), rin.Len()) + var i int + + it := rin.MapRange() + for it.Next() { + k := it.Key() + v := it.Value() + + rout.Index(i).Set(reflect.MakeFunc(t, func(args []reflect.Value) (results []reflect.Value) { + return []reflect.Value{k, v} + })) + i++ + } + + return rout.Interface() +} + +func Par(concurrency int, arr interface{}, f interface{}) { + throttle := make(chan struct{}, concurrency) + var wg sync.WaitGroup + + varr := reflect.ValueOf(arr) + l := varr.Len() + + rf := reflect.ValueOf(f) + + wg.Add(l) + for i := 0; i < l; i++ { + throttle <- struct{}{} + + go func(i int) { + defer wg.Done() + defer func() { + <-throttle + }() + rf.Call([]reflect.Value{varr.Index(i)}) + }(i) + } + + wg.Wait() +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/peermgr/peermgr.go b/vendor/github.com/filecoin-project/lotus/lib/peermgr/peermgr.go new file mode 100644 index 0000000000..490f2b2294 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/peermgr/peermgr.go @@ -0,0 +1,169 @@ +package peermgr + +import ( + "context" + "sync" + "time" + + "github.com/filecoin-project/lotus/metrics" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "go.opencensus.io/stats" + "go.uber.org/fx" + + host "github.com/libp2p/go-libp2p-core/host" + net "github.com/libp2p/go-libp2p-core/network" + peer "github.com/libp2p/go-libp2p-core/peer" + dht "github.com/libp2p/go-libp2p-kad-dht" + + logging "github.com/ipfs/go-log/v2" +) + +var log = logging.Logger("peermgr") + +const ( + MaxFilPeers = 32 + MinFilPeers = 12 +) + +type MaybePeerMgr struct { + fx.In + + Mgr *PeerMgr `optional:"true"` +} + +type PeerMgr struct { + bootstrappers []peer.AddrInfo + + // peerLeads is a set of peers we hear about through the network + // and who may be good peers to connect to for expanding our peer set + //peerLeads map[peer.ID]time.Time // TODO: unused + + peersLk sync.Mutex + peers map[peer.ID]time.Duration + + maxFilPeers int + minFilPeers int + + expanding chan struct{} + + h host.Host + dht *dht.IpfsDHT + + notifee *net.NotifyBundle +} + +func NewPeerMgr(h host.Host, dht *dht.IpfsDHT, bootstrap dtypes.BootstrapPeers) *PeerMgr { + pm := &PeerMgr{ + h: h, + dht: dht, + bootstrappers: bootstrap, + + peers: make(map[peer.ID]time.Duration), + expanding: make(chan struct{}, 1), + + maxFilPeers: MaxFilPeers, + minFilPeers: MinFilPeers, + } + + pm.notifee = &net.NotifyBundle{ + DisconnectedF: func(_ net.Network, c net.Conn) { + pm.Disconnect(c.RemotePeer()) + }, + } + + h.Network().Notify(pm.notifee) + + return pm +} + +func (pmgr *PeerMgr) AddFilecoinPeer(p peer.ID) { + pmgr.peersLk.Lock() + defer pmgr.peersLk.Unlock() + pmgr.peers[p] = time.Duration(0) +} + +func (pmgr *PeerMgr) GetPeerLatency(p peer.ID) (time.Duration, bool) { + pmgr.peersLk.Lock() + defer pmgr.peersLk.Unlock() + dur, ok := pmgr.peers[p] + return dur, ok +} + +func (pmgr *PeerMgr) SetPeerLatency(p peer.ID, latency time.Duration) { + pmgr.peersLk.Lock() + defer pmgr.peersLk.Unlock() + if _, ok := pmgr.peers[p]; ok { + pmgr.peers[p] = latency + } + +} + +func (pmgr *PeerMgr) Disconnect(p peer.ID) { + if pmgr.h.Network().Connectedness(p) == net.NotConnected { + pmgr.peersLk.Lock() + defer pmgr.peersLk.Unlock() + delete(pmgr.peers, p) + } +} + +func (pmgr *PeerMgr) Run(ctx context.Context) { + tick := time.NewTicker(time.Second * 5) + for { + select { + case <-tick.C: + pcount := pmgr.getPeerCount() + if pcount < pmgr.minFilPeers { + pmgr.expandPeers() + } else if pcount > pmgr.maxFilPeers { + log.Debug("peer count about threshold: %d > %d", pcount, pmgr.maxFilPeers) + } + stats.Record(ctx, metrics.PeerCount.M(int64(pmgr.getPeerCount()))) + } + } +} + +func (pmgr *PeerMgr) getPeerCount() int { + pmgr.peersLk.Lock() + defer pmgr.peersLk.Unlock() + return len(pmgr.peers) +} + +func (pmgr *PeerMgr) expandPeers() { + select { + case pmgr.expanding <- struct{}{}: + default: + return + } + + go func() { + ctx, cancel := context.WithTimeout(context.TODO(), time.Second*30) + defer cancel() + + pmgr.doExpand(ctx) + + <-pmgr.expanding + }() +} + +func (pmgr *PeerMgr) doExpand(ctx context.Context) { + pcount := pmgr.getPeerCount() + if pcount == 0 { + if len(pmgr.bootstrappers) == 0 { + log.Warn("no peers connected, and no bootstrappers configured") + return + } + + log.Info("connecting to bootstrap peers") + for _, bsp := range pmgr.bootstrappers { + if err := pmgr.h.Connect(ctx, bsp); err != nil { + log.Warnf("failed to connect to bootstrap peer: %s", err) + } + } + return + } + + // if we already have some peers and need more, the dht is really good at connecting to most peers. Use that for now until something better comes along. + if err := pmgr.dht.Bootstrap(ctx); err != nil { + log.Warnf("dht bootstrapping failed: %s", err) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/sigs/bls/bls_bench_test.go b/vendor/github.com/filecoin-project/lotus/lib/sigs/bls/bls_bench_test.go new file mode 100644 index 0000000000..a6c0339121 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/sigs/bls/bls_bench_test.go @@ -0,0 +1,38 @@ +package bls + +import ( + "crypto/rand" + "github.com/filecoin-project/go-address" + "testing" +) + +func BenchmarkBLSSign(b *testing.B) { + signer := blsSigner{} + for i := 0; i < b.N; i++ { + b.StopTimer() + pk, _ := signer.GenPrivate() + randMsg := make([]byte, 32) + rand.Read(randMsg) + b.StartTimer() + + _, _ = signer.Sign(pk, randMsg) + } +} + +func BenchmarkBLSVerify(b *testing.B) { + signer := blsSigner{} + for i := 0; i < b.N; i++ { + b.StopTimer() + randMsg := make([]byte, 32) + rand.Read(randMsg) + + priv, _ := signer.GenPrivate() + pk, _ := signer.ToPublic(priv) + addr, _ := address.NewBLSAddress(pk) + sig, _ := signer.Sign(priv, randMsg) + + b.StartTimer() + + _ = signer.Verify(sig, addr, randMsg) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/sigs/bls/init.go b/vendor/github.com/filecoin-project/lotus/lib/sigs/bls/init.go new file mode 100644 index 0000000000..66a5ade81f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/sigs/bls/init.go @@ -0,0 +1,54 @@ +package bls + +import ( + "fmt" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/crypto" + + ffi "github.com/filecoin-project/filecoin-ffi" + + "github.com/filecoin-project/lotus/lib/sigs" +) + +type blsSigner struct{} + +func (blsSigner) GenPrivate() ([]byte, error) { + pk := ffi.PrivateKeyGenerate() + return pk[:], nil +} + +func (blsSigner) ToPublic(priv []byte) ([]byte, error) { + var pk ffi.PrivateKey + copy(pk[:], priv) + pub := ffi.PrivateKeyPublicKey(pk) + return pub[:], nil +} + +func (blsSigner) Sign(p []byte, msg []byte) ([]byte, error) { + var pk ffi.PrivateKey + copy(pk[:], p) + sig := ffi.PrivateKeySign(pk, msg) + return sig[:], nil +} + +func (blsSigner) Verify(sig []byte, a address.Address, msg []byte) error { + + var pubk ffi.PublicKey + copy(pubk[:], a.Payload()) + pubkeys := []ffi.PublicKey{pubk} + digests := []ffi.Message{msg} + + var s ffi.Signature + copy(s[:], sig) + + if !ffi.HashVerify(&s, digests, pubkeys) { + return fmt.Errorf("bls signature failed to verify") + } + + return nil +} + +func init() { + sigs.RegisterSignature(crypto.SigTypeBLS, blsSigner{}) +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/sigs/doc.go b/vendor/github.com/filecoin-project/lotus/lib/sigs/doc.go new file mode 100644 index 0000000000..ca3093f395 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/sigs/doc.go @@ -0,0 +1,9 @@ +// Package sigs allows for signing, verifying signatures and key generation +// using key types selected by package user. +// +// For support of secp256k1 import: +// _ "github.com/filecoin-project/lotus/lib/sigs/secp" +// +// For support of Filecoin BLS import: +// _ "github.com/filecoin-project/lotus/lib/sigs/bls" +package sigs diff --git a/vendor/github.com/filecoin-project/lotus/lib/sigs/secp/init.go b/vendor/github.com/filecoin-project/lotus/lib/sigs/secp/init.go new file mode 100644 index 0000000000..1285b19b6f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/sigs/secp/init.go @@ -0,0 +1,59 @@ +package secp + +import ( + "fmt" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-crypto" + crypto2 "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/minio/blake2b-simd" + + "github.com/filecoin-project/lotus/lib/sigs" +) + +type secpSigner struct{} + +func (secpSigner) GenPrivate() ([]byte, error) { + priv, err := crypto.GenerateKey() + if err != nil { + return nil, err + } + return priv, nil +} + +func (secpSigner) ToPublic(pk []byte) ([]byte, error) { + return crypto.PublicKey(pk), nil +} + +func (secpSigner) Sign(pk []byte, msg []byte) ([]byte, error) { + b2sum := blake2b.Sum256(msg) + sig, err := crypto.Sign(pk, b2sum[:]) + if err != nil { + return nil, err + } + + return sig, nil +} + +func (secpSigner) Verify(sig []byte, a address.Address, msg []byte) error { + b2sum := blake2b.Sum256(msg) + pubk, err := crypto.EcRecover(b2sum[:], sig) + if err != nil { + return err + } + + maybeaddr, err := address.NewSecp256k1Address(pubk) + if err != nil { + return err + } + + if a != maybeaddr { + return fmt.Errorf("signature did not match") + } + + return nil +} + +func init() { + sigs.RegisterSignature(crypto2.SigTypeSecp256k1, secpSigner{}) +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/sigs/sigs.go b/vendor/github.com/filecoin-project/lotus/lib/sigs/sigs.go new file mode 100644 index 0000000000..4a4fd7340a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/sigs/sigs.go @@ -0,0 +1,112 @@ +package sigs + +import ( + "context" + "fmt" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/crypto" + "go.opencensus.io/trace" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types" +) + +// Sign takes in signature type, private key and message. Returns a signature for that message. +// Valid sigTypes are: "secp256k1" and "bls" +func Sign(sigType crypto.SigType, privkey []byte, msg []byte) (*crypto.Signature, error) { + sv, ok := sigs[sigType] + if !ok { + return nil, fmt.Errorf("cannot sign message with signature of unsupported type: %v", sigType) + } + + sb, err := sv.Sign(privkey, msg) + if err != nil { + return nil, err + } + return &crypto.Signature{ + Type: sigType, + Data: sb, + }, nil +} + +// Verify verifies signatures +func Verify(sig *crypto.Signature, addr address.Address, msg []byte) error { + if sig == nil { + return xerrors.Errorf("signature is nil") + } + + if addr.Protocol() == address.ID { + return fmt.Errorf("must resolve ID addresses before using them to verify a signature") + } + + sv, ok := sigs[sig.Type] + if !ok { + return fmt.Errorf("cannot verify signature of unsupported type: %v", sig.Type) + } + + return sv.Verify(sig.Data, addr, msg) +} + +// Generate generates private key of given type +func Generate(sigType crypto.SigType) ([]byte, error) { + sv, ok := sigs[sigType] + if !ok { + return nil, fmt.Errorf("cannot generate private key of unsupported type: %v", sigType) + } + + return sv.GenPrivate() +} + +// ToPublic converts private key to public key +func ToPublic(sigType crypto.SigType, pk []byte) ([]byte, error) { + sv, ok := sigs[sigType] + if !ok { + return nil, fmt.Errorf("cannot generate public key of unsupported type: %v", sigType) + } + + return sv.ToPublic(pk) +} + +func CheckBlockSignature(ctx context.Context, blk *types.BlockHeader, worker address.Address) error { + _, span := trace.StartSpan(ctx, "checkBlockSignature") + defer span.End() + + if blk.IsValidated() { + return nil + } + + if blk.BlockSig == nil { + return xerrors.New("block signature not present") + } + + sigb, err := blk.SigningBytes() + if err != nil { + return xerrors.Errorf("failed to get block signing bytes: %w", err) + } + + err = Verify(blk.BlockSig, worker, sigb) + if err == nil { + blk.SetValidated() + } + + return err +} + +// SigShim is used for introducing signature functions +type SigShim interface { + GenPrivate() ([]byte, error) + ToPublic(pk []byte) ([]byte, error) + Sign(pk []byte, msg []byte) ([]byte, error) + Verify(sig []byte, a address.Address, msg []byte) error +} + +var sigs map[crypto.SigType]SigShim + +// RegisterSignature should be only used during init +func RegisterSignature(typ crypto.SigType, vs SigShim) { + if sigs == nil { + sigs = make(map[crypto.SigType]SigShim) + } + sigs[typ] = vs +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/tracing/setup.go b/vendor/github.com/filecoin-project/lotus/lib/tracing/setup.go new file mode 100644 index 0000000000..141683b393 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/tracing/setup.go @@ -0,0 +1,34 @@ +package tracing + +import ( + "os" + + "contrib.go.opencensus.io/exporter/jaeger" + logging "github.com/ipfs/go-log/v2" + "go.opencensus.io/trace" +) + +var log = logging.Logger("tracing") + +func SetupJaegerTracing(serviceName string) *jaeger.Exporter { + + if _, ok := os.LookupEnv("LOTUS_JAEGER"); !ok { + return nil + } + agentEndpointURI := os.Getenv("LOTUS_JAEGER") + + je, err := jaeger.NewExporter(jaeger.Options{ + AgentEndpoint: agentEndpointURI, + ServiceName: serviceName, + }) + if err != nil { + log.Errorw("Failed to create the Jaeger exporter", "error", err) + return nil + } + + trace.RegisterExporter(je) + trace.ApplyConfig(trace.Config{ + DefaultSampler: trace.AlwaysSample(), + }) + return je +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit.go b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit.go new file mode 100644 index 0000000000..5686a0f9af --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit.go @@ -0,0 +1,116 @@ +package ulimit + +// from go-ipfs + +import ( + "fmt" + "os" + "strconv" + "syscall" + + logging "github.com/ipfs/go-log" +) + +var log = logging.Logger("ulimit") + +var ( + supportsFDManagement = false + + // getlimit returns the soft and hard limits of file descriptors counts + getLimit func() (uint64, uint64, error) + // set limit sets the soft and hard limits of file descriptors counts + setLimit func(uint64, uint64) error +) + +// minimum file descriptor limit before we complain +const minFds = 2048 + +// default max file descriptor limit. +const maxFds = 16 << 10 + +// userMaxFDs returns the value of IPFS_FD_MAX +func userMaxFDs() uint64 { + // check if the IPFS_FD_MAX is set up and if it does + // not have a valid fds number notify the user + if val := os.Getenv("IPFS_FD_MAX"); val != "" { + fds, err := strconv.ParseUint(val, 10, 64) + if err != nil { + log.Errorf("bad value for IPFS_FD_MAX: %s", err) + return 0 + } + return fds + } + return 0 +} + +// ManageFdLimit raise the current max file descriptor count +// of the process based on the IPFS_FD_MAX value +func ManageFdLimit() (changed bool, newLimit uint64, err error) { + if !supportsFDManagement { + return false, 0, nil + } + + targetLimit := uint64(maxFds) + userLimit := userMaxFDs() + if userLimit > 0 { + targetLimit = userLimit + } + + soft, hard, err := getLimit() + if err != nil { + return false, 0, err + } + + if targetLimit <= soft { + return false, 0, nil + } + + // the soft limit is the value that the kernel enforces for the + // corresponding resource + // the hard limit acts as a ceiling for the soft limit + // an unprivileged process may only set it's soft limit to a + // alue in the range from 0 up to the hard limit + err = setLimit(targetLimit, targetLimit) + switch err { + case nil: + newLimit = targetLimit + case syscall.EPERM: + // lower limit if necessary. + if targetLimit > hard { + targetLimit = hard + } + + // the process does not have permission so we should only + // set the soft value + err = setLimit(targetLimit, hard) + if err != nil { + err = fmt.Errorf("error setting ulimit wihout hard limit: %s", err) + break + } + newLimit = targetLimit + + // Warn on lowered limit. + + if newLimit < userLimit { + err = fmt.Errorf( + "failed to raise ulimit to IPFS_FD_MAX (%d): set to %d", + userLimit, + newLimit, + ) + break + } + + if userLimit == 0 && newLimit < minFds { + err = fmt.Errorf( + "failed to raise ulimit to minimum %d: set to %d", + minFds, + newLimit, + ) + break + } + default: + err = fmt.Errorf("error setting: ulimit: %s", err) + } + + return newLimit > 0, newLimit, err +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_freebsd.go b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_freebsd.go new file mode 100644 index 0000000000..7e50436f3d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_freebsd.go @@ -0,0 +1,36 @@ +// +build freebsd + +package ulimit + +import ( + "errors" + "math" + + unix "golang.org/x/sys/unix" +) + +func init() { + supportsFDManagement = true + getLimit = freebsdGetLimit + setLimit = freebsdSetLimit +} + +func freebsdGetLimit() (uint64, uint64, error) { + rlimit := unix.Rlimit{} + err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) + if (rlimit.Cur < 0) || (rlimit.Max < 0) { + return 0, 0, errors.New("invalid rlimits") + } + return uint64(rlimit.Cur), uint64(rlimit.Max), err +} + +func freebsdSetLimit(soft uint64, max uint64) error { + if (soft > math.MaxInt64) || (max > math.MaxInt64) { + return errors.New("invalid rlimits") + } + rlimit := unix.Rlimit{ + Cur: int64(soft), + Max: int64(max), + } + return unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_test.go b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_test.go new file mode 100644 index 0000000000..1e7fc7d165 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_test.go @@ -0,0 +1,84 @@ +// +build !windows + +package ulimit + +import ( + "fmt" + "os" + "strings" + "syscall" + "testing" +) + +func TestManageFdLimit(t *testing.T) { + t.Log("Testing file descriptor count") + if _, _, err := ManageFdLimit(); err != nil { + t.Errorf("Cannot manage file descriptors") + } + + if maxFds != uint64(16<<10) { + t.Errorf("Maximum file descriptors default value changed") + } +} + +func TestManageInvalidNFds(t *testing.T) { + t.Logf("Testing file descriptor invalidity") + var err error + if err = os.Unsetenv("IPFS_FD_MAX"); err != nil { + t.Fatal("Cannot unset the IPFS_FD_MAX env variable") + } + + rlimit := syscall.Rlimit{} + if err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { + t.Fatal("Cannot get the file descriptor count") + } + + value := rlimit.Max + rlimit.Cur + if err = os.Setenv("IPFS_FD_MAX", fmt.Sprintf("%d", value)); err != nil { + t.Fatal("Cannot set the IPFS_FD_MAX env variable") + } + + t.Logf("setting ulimit to %d, max %d, cur %d", value, rlimit.Max, rlimit.Cur) + + if changed, new, err := ManageFdLimit(); err == nil { + t.Errorf("ManageFdLimit should return an error: changed %t, new: %d", changed, new) + } else if err != nil { + flag := strings.Contains(err.Error(), + "failed to raise ulimit to IPFS_FD_MAX") + if !flag { + t.Error("ManageFdLimit returned unexpected error", err) + } + } + + // unset all previous operations + if err = os.Unsetenv("IPFS_FD_MAX"); err != nil { + t.Fatal("Cannot unset the IPFS_FD_MAX env variable") + } +} + +func TestManageFdLimitWithEnvSet(t *testing.T) { + t.Logf("Testing file descriptor manager with IPFS_FD_MAX set") + var err error + if err = os.Unsetenv("IPFS_FD_MAX"); err != nil { + t.Fatal("Cannot unset the IPFS_FD_MAX env variable") + } + + rlimit := syscall.Rlimit{} + if err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { + t.Fatal("Cannot get the file descriptor count") + } + + value := rlimit.Max - rlimit.Cur + 1 + if err = os.Setenv("IPFS_FD_MAX", fmt.Sprintf("%d", value)); err != nil { + t.Fatal("Cannot set the IPFS_FD_MAX env variable") + } + + if _, _, err = ManageFdLimit(); err != nil { + t.Errorf("Cannot manage file descriptor count") + } + + // unset all previous operations + if err = os.Unsetenv("IPFS_FD_MAX"); err != nil { + t.Fatal("Cannot unset the IPFS_FD_MAX env variable") + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_unix.go b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_unix.go new file mode 100644 index 0000000000..a351236dcb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lib/ulimit/ulimit_unix.go @@ -0,0 +1,27 @@ +// +build darwin linux netbsd openbsd + +package ulimit + +import ( + unix "golang.org/x/sys/unix" +) + +func init() { + supportsFDManagement = true + getLimit = unixGetLimit + setLimit = unixSetLimit +} + +func unixGetLimit() (uint64, uint64, error) { + rlimit := unix.Rlimit{} + err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) + return rlimit.Cur, rlimit.Max, err +} + +func unixSetLimit(soft uint64, max uint64) error { + rlimit := unix.Rlimit{ + Cur: soft, + Max: max, + } + return unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/api.go b/vendor/github.com/filecoin-project/lotus/lotuspond/api.go new file mode 100644 index 0000000000..169cec1dee --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/api.go @@ -0,0 +1,138 @@ +package main + +import ( + "crypto/rand" + "io" + "io/ioutil" + "os" + "sync" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc" + + "github.com/filecoin-project/lotus/node/repo" +) + +type NodeState int + +const ( + NodeUnknown = iota + NodeRunning + NodeStopped +) + +type api struct { + cmds int32 + running map[int32]*runningNode + runningLk sync.Mutex + genesis string +} + +type nodeInfo struct { + Repo string + ID int32 + APIPort int32 + State NodeState + + FullNode string // only for storage nodes + Storage bool +} + +func (api *api) Nodes() []nodeInfo { + api.runningLk.Lock() + out := make([]nodeInfo, 0, len(api.running)) + for _, node := range api.running { + out = append(out, node.meta) + } + + api.runningLk.Unlock() + + return out +} + +func (api *api) TokenFor(id int32) (string, error) { + api.runningLk.Lock() + defer api.runningLk.Unlock() + + rnd, ok := api.running[id] + if !ok { + return "", xerrors.New("no running node with this ID") + } + + r, err := repo.NewFS(rnd.meta.Repo) + if err != nil { + return "", err + } + + t, err := r.APIToken() + if err != nil { + return "", err + } + + return string(t), nil +} + +func (api *api) FullID(id int32) (int32, error) { + api.runningLk.Lock() + defer api.runningLk.Unlock() + + stor, ok := api.running[id] + if !ok { + return 0, xerrors.New("storage node not found") + } + + if !stor.meta.Storage { + return 0, xerrors.New("node is not a storage node") + } + + for id, n := range api.running { + if n.meta.Repo == stor.meta.FullNode { + return id, nil + } + } + return 0, xerrors.New("node not found") +} + +func (api *api) CreateRandomFile(size int64) (string, error) { + tf, err := ioutil.TempFile(os.TempDir(), "pond-random-") + if err != nil { + return "", err + } + + _, err = io.CopyN(tf, rand.Reader, size) + if err != nil { + return "", err + } + + if err := tf.Close(); err != nil { + return "", err + } + + return tf.Name(), nil +} + +func (api *api) Stop(node int32) error { + api.runningLk.Lock() + nd, ok := api.running[node] + api.runningLk.Unlock() + + if !ok { + return nil + } + + nd.stop() + return nil +} + +type client struct { + Nodes func() []nodeInfo +} + +func apiClient() (*client, error) { + c := &client{} + if _, err := jsonrpc.NewClient("ws://"+listenAddr+"/rpc/v0", "Pond", c, nil); err != nil { + return nil, err + } + return c, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/.gitignore b/vendor/github.com/filecoin-project/lotus/lotuspond/front/.gitignore new file mode 100644 index 0000000000..4d29575de8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/package-lock.json b/vendor/github.com/filecoin-project/lotus/lotuspond/front/package-lock.json new file mode 100644 index 0000000000..8df204f2e3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/package-lock.json @@ -0,0 +1,13255 @@ +{ + "name": "front", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "101": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/101/-/101-1.6.3.tgz", + "integrity": "sha512-4dmQ45yY0Dx24Qxp+zAsNLlMF6tteCyfVzgbulvSyC7tCyd3V8sW76sS0tHq8NpcbXfWTKasfyfzU1Kd86oKzw==", + "requires": { + "clone": "^1.0.2", + "deep-eql": "^0.1.3", + "keypather": "^1.10.2" + } + }, + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.3.tgz", + "integrity": "sha512-oDpASqKFlbspQfzAE7yaeTmdljSH2ADIvBlb0RwbStltTuWa0+7CCI1fYVINNv9saHPa1W7oaKeuNuKj+RQCvA==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.0", + "@babel/helpers": "^7.4.3", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "@babel/generator": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", + "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", + "requires": { + "@babel/types": "^7.5.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz", + "integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==", + "requires": { + "@babel/types": "^7.3.0", + "esutils": "^2.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.5.tgz", + "integrity": "sha512-ZsxkyYiRA7Bg+ZTRpPvB6AbOFKTFFK4LrvTet8lInm0V468MWCaSYJE+I7v2z2r8KNLtYiV+K5kTCnR7dvyZjg==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-member-expression-to-functions": "^7.5.5", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5", + "@babel/helper-split-export-declaration": "^7.4.4" + } + }, + "@babel/helper-define-map": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", + "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", + "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "requires": { + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", + "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==" + }, + "@babel/helper-regex": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", + "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", + "requires": { + "lodash": "^4.17.13" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", + "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "requires": { + "@babel/helper-member-expression-to-functions": "^7.5.5", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz", + "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==", + "requires": { + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", + "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==" + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.0.tgz", + "integrity": "sha512-t2ECPNOXsIeK1JxJNKmgbzQtoG27KIlVE61vTqX0DKR9E9sZlVVxWUtEW9D5FlZ8b8j7SBNCHY47GgPKCKlpPg==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.4.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.4.0.tgz", + "integrity": "sha512-d08TLmXeK/XbgCo7ZeZ+JaeZDtDai/2ctapTRsWWkkmy7G/cqz8DQN/HlWG7RR4YmfXxmExsbU3SuCjlM7AtUg==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.4.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-decorators": "^7.2.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", + "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz", + "integrity": "sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", + "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz", + "integrity": "sha512-38QdqVoXdHUQfTpZo3rQwqQdWtCn5tMv4uV6r2RMfTqNBuv4ZBhz79SfaQWKTVmxHjeFv/DnXVC/+agHCklYWA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz", + "integrity": "sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", + "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz", + "integrity": "sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", + "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.5.5.tgz", + "integrity": "sha512-82A3CLRRdYubkG85lKwhZB0WZoHxLGsJdux/cOVaJCJpvYFl1LVzAIFyRsa7CvXqW8rBM4Zf3Bfn8PHt5DP0Sg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } + } + }, + "@babel/plugin-transform-classes": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", + "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz", + "integrity": "sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", + "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", + "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.0.tgz", + "integrity": "sha512-C4ZVNejHnfB22vI2TYN4RUp2oCmq6cSEAg4RygSvYZUECRqUu9O4PMEMNJ4wsemaRGg27BbgYctG4BZh+AgIHw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", + "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz", + "integrity": "sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ==", + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", + "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz", + "integrity": "sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg==", + "requires": { + "regexp-tree": "^0.1.6" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", + "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "requires": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.5.0.tgz", + "integrity": "sha512-c5Ba8cpybZFp1Izkf2sWGuNjOxoQ32tFgBvvYvwGhi4+9f6vGiSK9Gex4uVuO/Va6YJFu41aAh1MzMjUWkp0IQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz", + "integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz", + "integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==", + "requires": { + "@babel/helper-builder-react-jsx": "^7.3.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz", + "integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.5.0.tgz", + "integrity": "sha512-58Q+Jsy4IDCZx7kqEZuSDdam/1oW8OdDX8f+Loo6xyxdfg1yF0GE2XNJQSTZCaMol93+FBzpWiPEwtbMloAcPg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", + "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "requires": { + "regenerator-transform": "^0.14.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", + "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.3.tgz", + "integrity": "sha512-7Q61bU+uEI7bCUFReT1NKn7/X6sDQsZ7wL1sJ9IYMAO7cI+eg6x9re1cEw2fCRMbbTVyoeUKWSV1M6azEfKCfg==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", + "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.5.5.tgz", + "integrity": "sha512-pehKf4m640myZu5B2ZviLaiBlxMCjSZ1qTEO459AXKX5GnPueyulJeCqZFs1nz/Ya2dDzXQ1NxZ/kKNWyD4h6w==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.5.5", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-typescript": "^7.2.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", + "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/preset-env": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.5.5.tgz", + "integrity": "sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-dynamic-import": "^7.5.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.5.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.5.0", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.5.5", + "@babel/plugin-transform-classes": "^7.5.5", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.5.0", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.5.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.5.0", + "@babel/plugin-transform-modules-commonjs": "^7.5.0", + "@babel/plugin-transform-modules-systemjs": "^7.5.0", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.5.5", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.5.5", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "@babel/preset-react": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", + "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0" + } + }, + "@babel/preset-typescript": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz", + "integrity": "sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.3.2" + } + }, + "@babel/runtime": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz", + "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", + "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.5.5", + "@babel/types": "^7.5.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } + } + }, + "@babel/types": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + } + }, + "@csstools/convert-colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", + "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==" + }, + "@csstools/normalize.css": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-9.0.1.tgz", + "integrity": "sha512-6It2EVfGskxZCQhuykrfnALg7oVeiI6KclWSmGDqB0AiInVrTGB9Jp9i4/Ad21u9Jde/voVQz6eFX/eSg/UsPA==" + }, + "@hapi/address": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.0.0.tgz", + "integrity": "sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==" + }, + "@hapi/hoek": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-6.2.4.tgz", + "integrity": "sha512-HOJ20Kc93DkDVvjwHyHawPwPkX44sIrbXazAUDiUXaY2R9JwQGo2PhFfnQtdrsIe4igjG2fPgMra7NYw7qhy0A==" + }, + "@hapi/joi": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.0.tgz", + "integrity": "sha512-n6kaRQO8S+kepUTbXL9O/UOL788Odqs38/VOfoCrATDtTvyfiO3fgjlSRaNkHabpTLgM7qru9ifqXlXbXk8SeQ==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/marker": "1.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/marker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@hapi/marker/-/marker-1.0.0.tgz", + "integrity": "sha512-JOfdekTXnJexfE8PyhZFyHvHjt81rBFSAbTIRAhF2vv/2Y1JzoKsGqxH/GpZJoF7aEfYok8JVcAHmSz1gkBieA==" + }, + "@hapi/topo": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.2.tgz", + "integrity": "sha512-r+aumOqJ5QbD6aLPJWqVjMAPsx5pZKz+F5yPqXZ/WWG9JTtHbQqlzrJoknJ0iJxLj9vlXtmpSdjlkszseeG8OA==", + "requires": { + "@hapi/hoek": "8.x.x" + }, + "dependencies": { + "@hapi/hoek": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.0.2.tgz", + "integrity": "sha512-O6o6mrV4P65vVccxymuruucb+GhP2zl9NLCG8OdoFRS8BEGw3vwpPp20wpAtpbQQxz1CEUtmxJGgWhjq1XA3qw==" + } + } + }, + "@jest/console": { + "version": "24.7.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz", + "integrity": "sha512-iNhtIy2M8bXlAOULWVTUxmnelTLFneTNEkHCgPmgd+zNwy9zVddJ6oS5rZ9iwoscNdT5mMwUd0C51v/fSlzItg==", + "requires": { + "@jest/source-map": "^24.3.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + } + }, + "@jest/core": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.8.0.tgz", + "integrity": "sha512-R9rhAJwCBQzaRnrRgAdVfnglUuATXdwTRsYqs6NMdVcAl5euG8LtWDe+fVkN27YfKVBW61IojVsXKaOmSnqd/A==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.8.0", + "@jest/test-result": "^24.8.0", + "@jest/transform": "^24.8.0", + "@jest/types": "^24.8.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.8.0", + "jest-config": "^24.8.0", + "jest-haste-map": "^24.8.0", + "jest-message-util": "^24.8.0", + "jest-regex-util": "^24.3.0", + "jest-resolve-dependencies": "^24.8.0", + "jest-runner": "^24.8.0", + "jest-runtime": "^24.8.0", + "jest-snapshot": "^24.8.0", + "jest-util": "^24.8.0", + "jest-validate": "^24.8.0", + "jest-watcher": "^24.8.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "@jest/environment": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.8.0.tgz", + "integrity": "sha512-vlGt2HLg7qM+vtBrSkjDxk9K0YtRBi7HfRFaDxoRtyi+DyVChzhF20duvpdAnKVBV6W5tym8jm0U9EfXbDk1tw==", + "requires": { + "@jest/fake-timers": "^24.8.0", + "@jest/transform": "^24.8.0", + "@jest/types": "^24.8.0", + "jest-mock": "^24.8.0" + } + }, + "@jest/fake-timers": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.8.0.tgz", + "integrity": "sha512-2M4d5MufVXwi6VzZhJ9f5S/wU4ud2ck0kxPof1Iz3zWx6Y+V2eJrES9jEktB6O3o/oEyk+il/uNu9PvASjWXQw==", + "requires": { + "@jest/types": "^24.8.0", + "jest-message-util": "^24.8.0", + "jest-mock": "^24.8.0" + } + }, + "@jest/reporters": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.8.0.tgz", + "integrity": "sha512-eZ9TyUYpyIIXfYCrw0UHUWUvE35vx5I92HGMgS93Pv7du+GHIzl+/vh8Qj9MCWFK/4TqyttVBPakWMOfZRIfxw==", + "requires": { + "@jest/environment": "^24.8.0", + "@jest/test-result": "^24.8.0", + "@jest/transform": "^24.8.0", + "@jest/types": "^24.8.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.1.1", + "jest-haste-map": "^24.8.0", + "jest-resolve": "^24.8.0", + "jest-runtime": "^24.8.0", + "jest-util": "^24.8.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.2.1", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + }, + "dependencies": { + "jest-resolve": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", + "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "requires": { + "@jest/types": "^24.8.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/source-map": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.3.0.tgz", + "integrity": "sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==", + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/test-result": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.8.0.tgz", + "integrity": "sha512-+YdLlxwizlfqkFDh7Mc7ONPQAhA4YylU1s529vVM1rsf67vGZH/2GGm5uO8QzPeVyaVMobCQ7FTxl38QrKRlng==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/types": "^24.8.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.8.0.tgz", + "integrity": "sha512-OzL/2yHyPdCHXEzhoBuq37CE99nkme15eHkAzXRVqthreWZamEMA0WoetwstsQBCXABhczpK03JNbc4L01vvLg==", + "requires": { + "@jest/test-result": "^24.8.0", + "jest-haste-map": "^24.8.0", + "jest-runner": "^24.8.0", + "jest-runtime": "^24.8.0" + } + }, + "@jest/transform": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.8.0.tgz", + "integrity": "sha512-xBMfFUP7TortCs0O+Xtez2W7Zu1PLH9bvJgtraN1CDST6LBM/eTOZ9SfwS/lvV8yOfcDpFmwf9bq5cYbXvqsvA==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.8.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.8.0", + "jest-regex-util": "^24.3.0", + "jest-util": "^24.8.0", + "micromatch": "^3.1.10", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@jest/types": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.8.0.tgz", + "integrity": "sha512-g17UxVr2YfBtaMUxn9u/4+siG1ptg9IGYAYwvpwn61nBg779RXnjE/m7CxYcIzEt0AbHZZAHSEZNhkE2WxURVg==", + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^12.0.9" + } + }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig==" + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz", + "integrity": "sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ==" + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz", + "integrity": "sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w==" + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz", + "integrity": "sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w==" + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.1.tgz", + "integrity": "sha512-p6z6JJroP989jHWcuraeWpzdejehTmLUpyC9smhTBWyPN0VVGe2phbYxpPTV7Vh8XzmFrcG55idrnfWn/2oQEw==" + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz", + "integrity": "sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w==" + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz", + "integrity": "sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw==" + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz", + "integrity": "sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw==" + }, + "@svgr/babel-preset": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.1.tgz", + "integrity": "sha512-rPFKLmyhlh6oeBv3j2vEAj2nd2QbWqpoJLKzBLjwQVt+d9aeXajVaPNEqrES2spjXKR4OxfgSs7U0NtmAEkr0Q==", + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^4.2.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^4.2.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^4.2.0", + "@svgr/babel-plugin-svg-dynamic-title": "^4.3.1", + "@svgr/babel-plugin-svg-em-dimensions": "^4.2.0", + "@svgr/babel-plugin-transform-react-native-svg": "^4.2.0", + "@svgr/babel-plugin-transform-svg-component": "^4.2.0" + } + }, + "@svgr/core": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-4.3.2.tgz", + "integrity": "sha512-N+tP5CLFd1hP9RpO83QJPZY3NL8AtrdqNbuhRgBkjE/49RnMrrRsFm1wY8pueUfAGvzn6tSXUq29o6ah8RuR5w==", + "requires": { + "@svgr/plugin-jsx": "^4.3.2", + "camelcase": "^5.3.1", + "cosmiconfig": "^5.2.1" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz", + "integrity": "sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg==", + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@svgr/plugin-jsx": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.2.tgz", + "integrity": "sha512-+1GW32RvmNmCsOkMoclA/TppNjHPLMnNZG3/Ecscxawp051XJ2MkO09Hn11VcotdC2EPrDfT8pELGRo+kbZ1Eg==", + "requires": { + "@babel/core": "^7.4.5", + "@svgr/babel-preset": "^4.3.1", + "@svgr/hast-util-to-babel-ast": "^4.3.2", + "svg-parser": "^2.0.0" + }, + "dependencies": { + "@babel/core": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", + "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==", + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helpers": "^7.5.5", + "@babel/parser": "^7.5.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "@svgr/plugin-svgo": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz", + "integrity": "sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==", + "requires": { + "cosmiconfig": "^5.2.1", + "merge-deep": "^3.0.2", + "svgo": "^1.2.2" + } + }, + "@svgr/webpack": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.1.0.tgz", + "integrity": "sha512-d09ehQWqLMywP/PT/5JvXwPskPK9QCXUjiSkAHehreB381qExXf5JFCBWhfEyNonRbkIneCeYM99w+Ud48YIQQ==", + "requires": { + "@babel/core": "^7.1.6", + "@babel/plugin-transform-react-constant-elements": "^7.0.0", + "@babel/preset-env": "^7.1.6", + "@babel/preset-react": "^7.0.0", + "@svgr/core": "^4.1.0", + "@svgr/plugin-jsx": "^4.1.0", + "@svgr/plugin-svgo": "^4.0.3", + "loader-utils": "^1.1.0" + } + }, + "@types/babel__core": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.2.tgz", + "integrity": "sha512-cfCCrFmiGY/yq0NuKNxIQvZFy9kY/1immpSpTngOnyIbD4+eJOG5mxphhHDv3CHL9GltO4GcKr54kGBg3RNdbg==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", + "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", + "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==" + }, + "@types/istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" + }, + "@types/yargs": { + "version": "12.0.12", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-12.0.12.tgz", + "integrity": "sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.6.0.tgz", + "integrity": "sha512-U224c29E2lo861TQZs6GSmyC0OYeRNg6bE9UVIiFBxN2MlA0nq2dCrgIVyyRbC05UOcrgf2Wk/CF2gGOPQKUSQ==", + "requires": { + "@typescript-eslint/parser": "1.6.0", + "@typescript-eslint/typescript-estree": "1.6.0", + "requireindex": "^1.2.0", + "tsutils": "^3.7.0" + } + }, + "@typescript-eslint/parser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.6.0.tgz", + "integrity": "sha512-VB9xmSbfafI+/kI4gUK3PfrkGmrJQfh0N4EScT1gZXSZyUxpsBirPL99EWZg9MmPG0pzq/gMtgkk7/rAHj4aQw==", + "requires": { + "@typescript-eslint/typescript-estree": "1.6.0", + "eslint-scope": "^4.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.6.0.tgz", + "integrity": "sha512-A4CanUwfaG4oXobD5y7EXbsOHjCwn8tj1RDd820etpPAjH+Icjc2K9e/DQM1Hac5zH2BSy+u6bjvvF2wwREvYA==", + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + } + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", + "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==" + }, + "acorn-dynamic-import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" + }, + "acorn-globals": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", + "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + } + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==" + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" + }, + "address": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", + "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==" + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==" + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" + }, + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-args": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-args/-/assert-args-1.2.1.tgz", + "integrity": "sha1-QEEDoUUqMv53iYgR5U5ZCoqTc70=", + "requires": { + "101": "^1.2.0", + "compound-subject": "0.0.1", + "debug": "^2.2.0", + "get-prototype-of": "0.0.0", + "is-capitalized": "^1.0.0", + "is-class": "0.0.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=" + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "autoprefixer": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz", + "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==", + "requires": { + "browserslist": "^4.6.3", + "caniuse-lite": "^1.0.30000980", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.17", + "postcss-value-parser": "^4.0.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz", + "integrity": "sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==" + } + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "requires": { + "ast-types-flow": "0.0.7" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "babel-eslint": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz", + "integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "babel-extract-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", + "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", + "requires": { + "babylon": "^6.18.0" + } + }, + "babel-jest": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.8.0.tgz", + "integrity": "sha512-+5/kaZt4I9efoXzPlZASyK/lN9qdRKmmUav9smVc0ruPQD7IsfucQ87gpOE8mn2jbDuS6M/YOW6n3v9ZoIfgnw==", + "requires": { + "@jest/transform": "^24.8.0", + "@jest/types": "^24.8.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.6.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + } + }, + "babel-loader": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", + "integrity": "sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==", + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "util.promisify": "^1.0.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + } + }, + "babel-plugin-jest-hoist": { + "version": "24.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.6.0.tgz", + "integrity": "sha512-3pKNH6hMt9SbOv0F3WVmy5CWQ4uogS3k0GY5XLyQHJ9EGpAT9XWkFd2ZiXXtkwFHdAHa5j7w7kfxSP5lAIwu7w==", + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-plugin-macros": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz", + "integrity": "sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==", + "requires": { + "@babel/runtime": "^7.4.2", + "cosmiconfig": "^5.2.0", + "resolve": "^1.10.0" + } + }, + "babel-plugin-named-asset-import": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.2.tgz", + "integrity": "sha512-CxwvxrZ9OirpXQ201Ec57OmGhmI8/ui/GwTDy0hSp6CmRvgRC0pSair6Z04Ck+JStA0sMPZzSJ3uE4n17EXpPQ==" + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "requires": { + "babel-plugin-syntax-object-rest-spread": "^6.8.0", + "babel-runtime": "^6.26.0" + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "babel-preset-jest": { + "version": "24.6.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz", + "integrity": "sha512-pdZqLEdmy1ZK5kyRUfvBb2IfTPb2BUvIJczlPspS8fWmBQslNNDBqVfh7BW5leOVJMDZKzjD8XEyABTk6gQ5yw==", + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.6.0" + } + }, + "babel-preset-react-app": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-9.0.0.tgz", + "integrity": "sha512-YVsDA8HpAKklhFLJtl9+AgaxrDaor8gGvDFlsg1ByOS0IPGUovumdv4/gJiAnLcDmZmKlH6+9sVOz4NVW7emAg==", + "requires": { + "@babel/core": "7.4.3", + "@babel/plugin-proposal-class-properties": "7.4.0", + "@babel/plugin-proposal-decorators": "7.4.0", + "@babel/plugin-proposal-object-rest-spread": "7.4.3", + "@babel/plugin-syntax-dynamic-import": "7.2.0", + "@babel/plugin-transform-classes": "7.4.3", + "@babel/plugin-transform-destructuring": "7.4.3", + "@babel/plugin-transform-flow-strip-types": "7.4.0", + "@babel/plugin-transform-react-constant-elements": "7.2.0", + "@babel/plugin-transform-react-display-name": "7.2.0", + "@babel/plugin-transform-runtime": "7.4.3", + "@babel/preset-env": "7.4.3", + "@babel/preset-react": "7.0.0", + "@babel/preset-typescript": "7.3.3", + "@babel/runtime": "7.4.3", + "babel-plugin-dynamic-import-node": "2.2.0", + "babel-plugin-macros": "2.5.1", + "babel-plugin-transform-react-remove-prop-types": "0.4.24" + }, + "dependencies": { + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.3.tgz", + "integrity": "sha512-xC//6DNSSHVjq8O2ge0dyYlhshsH4T7XdCVoxbi5HzLYWfsC5ooFlJjrXk8RcAT+hjHAK9UjBXdylzSoDK3t4g==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.3.tgz", + "integrity": "sha512-PUaIKyFUDtG6jF5DUJOfkBdwAS/kFFV3XFk7Nn0a6vR7ZT8jYw5cGtIlat77wcnd0C6ViGqo/wyNf4ZHytF/nQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.4.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.0", + "@babel/helper-split-export-declaration": "^7.4.0", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.3.tgz", + "integrity": "sha512-rVTLLZpydDFDyN4qnXdzwoVpk1oaXHIvPEOkOLyr88o7oHxVc/LyrnDx+amuBWGOwUb7D1s/uLsKBNTx08htZg==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-react-constant-elements": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.2.0.tgz", + "integrity": "sha512-YYQFg6giRFMsZPKUM9v+VcHOdfSQdz9jHCx3akAi3UYgyjndmdYGSXylQ/V+HswQt4fL8IklchD9HTsaOCrWQQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/preset-env": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.3.tgz", + "integrity": "sha512-FYbZdV12yHdJU5Z70cEg0f6lvtpZ8jFSDakTm7WXeJbLXh4R0ztGEu/SW7G1nJ2ZvKwDhz8YrbA84eYyprmGqw==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.4.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.0", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.4.0", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.4.0", + "@babel/plugin-transform-classes": "^7.4.3", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.4.3", + "@babel/plugin-transform-dotall-regex": "^7.4.3", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.3", + "@babel/plugin-transform-function-name": "^7.4.3", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.4.3", + "@babel/plugin-transform-modules-systemjs": "^7.4.0", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.2", + "@babel/plugin-transform-new-target": "^7.4.0", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.4.3", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.3", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.2.0", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.3", + "@babel/types": "^7.4.0", + "browserslist": "^4.5.2", + "core-js-compat": "^3.0.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.2.0.tgz", + "integrity": "sha512-fP899ELUnTaBcIzmrW7nniyqqdYWrWuJUyPWHxFa/c7r7hS6KC8FscNfLlBNIoPSc55kYMGEEKjPjJGCLbE1qA==", + "requires": { + "object.assign": "^4.1.0" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "base-x": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz", + "integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "blakejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=" + }, + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "borc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.1.tgz", + "integrity": "sha512-vPLLC2/gS0QN4O3cnPh+8jLshkMMD4qIfs+B1TPGPh30WrtcfItaO6j4k9alsqu/hIgKi8dVdmMvTcbq4tIF7A==", + "requires": { + "bignumber.js": "^9.0.0", + "commander": "^2.15.0", + "ieee754": "^1.1.8", + "iso-url": "~0.4.4", + "json-text-sequence": "~0.1.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==" + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + } + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz", + "integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==", + "requires": { + "caniuse-lite": "^1.0.30000984", + "electron-to-chromium": "^1.3.191", + "node-releases": "^1.1.25" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "requires": { + "base-x": "^3.0.2" + } + }, + "bser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", + "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "cacache": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, + "caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000985", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000985.tgz", + "integrity": "sha512-1ngiwkgqAYPG0JSSUp3PUDGPKKY59EK7NrGGX+VOxaKCNzRbNc7uXMny+c3VJfZxtoK3wSImTvG9T9sXiTw2+w==" + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "requires": { + "rsvp": "^4.8.4" + } + }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.2.0.tgz", + "integrity": "sha512-u5ElzokS8A1pm9vM3/iDgTcI3xqHxuCao94Oz8etI3cf0Tio0p8izkDYbTIn09uP3yUUr6+veaE6IkjnTYS46g==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "chokidar": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "dependencies": { + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "optional": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + } + } + }, + "chownr": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", + "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==" + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cids": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.1.tgz", + "integrity": "sha512-qEM4j2GKE/BiT6WdUi6cfW8dairhSLTUE8tIdxJG6SvY33Mp/UPjw+xcO0n1zsllgo72BupzKF/44v+Bg8YPPg==", + "requires": { + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "~0.5.1", + "multihashes": "~0.4.14" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-json": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", + "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==" + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "clone-deep": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", + "requires": { + "for-own": "^0.1.3", + "is-plain-object": "^2.0.1", + "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", + "shallow-clone": "^0.1.2" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "compound-subject": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/compound-subject/-/compound-subject-0.0.1.tgz", + "integrity": "sha1-JxVUaYoVrmCLHfyv0wt7oeqJLEs=" + }, + "compressible": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", + "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "requires": { + "mime-db": ">= 1.40.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "confusing-browser-globals": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.7.tgz", + "integrity": "sha512-cgHI1azax5ATrZ8rJ+ODDML9Fvu67PimB6aNxBrc/QwSaDaM9eTfIEUHx3bBLJJ82ioSb+/5zfsMCCEJax3ByQ==" + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.1.tgz", + "integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==" + }, + "core-js-compat": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.1.4.tgz", + "integrity": "sha512-Z5zbO9f1d0YrJdoaQhphVAnKPimX92D6z8lCGphH89MNRxlL1prI9ExJPqVwP0/kgkQCv8c4GJGT8X16yUncOg==", + "requires": { + "browserslist": "^4.6.2", + "core-js-pure": "3.1.4", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "core-js-pure": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.1.4.tgz", + "integrity": "sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css-blank-pseudo": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz", + "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" + }, + "css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "requires": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + } + }, + "css-has-pseudo": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz", + "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^5.0.0-rc.4" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "css-loader": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", + "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", + "requires": { + "camelcase": "^5.2.0", + "icss-utils": "^4.1.0", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.14", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^2.0.6", + "postcss-modules-scope": "^2.1.0", + "postcss-modules-values": "^2.0.0", + "postcss-value-parser": "^3.3.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + } + } + }, + "css-prefers-color-scheme": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", + "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==", + "requires": { + "postcss": "^7.0.5" + } + }, + "css-select": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", + "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^2.1.2", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "css-to-react-native": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.3.1.tgz", + "integrity": "sha512-yO+oEx1Lf+hDKasqQRVrAvzMCz825Huh1VMlEEDlRWyAhFb/FWb6I0KpEF1PkyKQ7NEdcx9d5M2ZEWgJAsgPvQ==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^3.3.0" + } + }, + "css-tree": { + "version": "1.0.0-alpha.33", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.33.tgz", + "integrity": "sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w==", + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.5.3" + } + }, + "css-unit-converter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=" + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + }, + "cssdb": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz", + "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "requires": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "requires": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + } + }, + "cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=" + }, + "cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=" + }, + "cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "requires": { + "postcss": "^7.0.0" + } + }, + "cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" + }, + "csso": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", + "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", + "requires": { + "css-tree": "1.0.0-alpha.29" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", + "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", + "requires": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + } + }, + "mdn-data": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", + "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==" + } + } + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "requires": { + "cssom": "0.3.x" + } + }, + "cyclist": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" + }, + "damerau-levenshtein": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz", + "integrity": "sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "requires": { + "type-detect": "0.1.1" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delimit-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", + "integrity": "sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "diff-sequences": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", + "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", + "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" + }, + "dotenv-expand": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", + "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=" + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "electron-to-chromium": { + "version": "1.3.200", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.200.tgz", + "integrity": "sha512-PUurrpyDA74MuAjJRD+79ss5BqJlU3mdArRbuu4wO/dt6jc3Ic/6BDmFJxkdwbfq39cHf/XKm2vW98XSvut9Dg==" + }, + "elliptic": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", + "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "eslint-config-react-app": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-4.0.1.tgz", + "integrity": "sha512-ZsaoXUIGsK8FCi/x4lT2bZR5mMkL/Kgj+Lnw690rbvvUr/uiwgFiD8FcfAhkCycm7Xte6O5lYz4EqMx2vX7jgw==", + "requires": { + "confusing-browser-globals": "^1.0.7" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "eslint-loader": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.2.tgz", + "integrity": "sha512-rA9XiXEOilLYPOIInvVH5S/hYfyTPyxag6DZhoQOduM+3TkghAEQ3VcFO8VnX4J4qg/UIBzp72aOf/xvYmpmsg==", + "requires": { + "loader-fs-cache": "^1.0.0", + "loader-utils": "^1.0.2", + "object-assign": "^4.0.1", + "object-hash": "^1.1.4", + "rimraf": "^2.6.1" + } + }, + "eslint-module-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-flowtype": { + "version": "2.50.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.1.tgz", + "integrity": "sha512-9kRxF9hfM/O6WGZcZPszOVPd2W0TLHBtceulLTsGfwMPtiCCLnCW0ssRiOOiXyqrCA20pm1iXdXm7gQeN306zQ==", + "requires": { + "lodash": "^4.17.10" + } + }, + "eslint-plugin-import": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz", + "integrity": "sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==", + "requires": { + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.3.0", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "read-pkg-up": "^2.0.0", + "resolve": "^1.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "requires": { + "pify": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz", + "integrity": "sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==", + "requires": { + "aria-query": "^3.0.0", + "array-includes": "^3.0.3", + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.2", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^7.0.2", + "has": "^1.0.3", + "jsx-ast-utils": "^2.0.1" + } + }, + "eslint-plugin-react": { + "version": "7.12.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz", + "integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==", + "requires": { + "array-includes": "^3.0.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.0.1", + "object.fromentries": "^2.0.0", + "prop-types": "^15.6.2", + "resolve": "^1.9.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-plugin-react-hooks": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.6.0.tgz", + "integrity": "sha512-lHBVRIaz5ibnIgNG07JNiAuBUeKhEf8l4etNx5vfAEwqQ5tcuK3jV9yjmopPgQDagQb7HwIuQVsE3IVcGrRnag==" + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", + "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "requires": { + "eslint-visitor-keys": "^1.0.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==" + }, + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exec-sh": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==" + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "expect": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.8.0.tgz", + "integrity": "sha512-/zYvP8iMDrzaaxHVa724eJBCKqSHmO0FA7EDkBiRHxg6OipmMn1fN+C8T9L9K8yr7UONkOifu6+LLH+z76CnaA==", + "requires": { + "@jest/types": "^24.8.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.8.0", + "jest-matcher-utils": "^24.8.0", + "jest-message-util": "^24.8.0", + "jest-regex-util": "^24.3.0" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "requires": { + "bser": "^2.0.0" + } + }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + } + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==" + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=" + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", + "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "requires": { + "debug": "^3.2.6" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "fork-ts-checker-webpack-plugin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-1.1.1.tgz", + "integrity": "sha512-gqWAEMLlae/oeVnN6RWCAhesOJMswAN1MaKNqhhjXHV5O0/rTUjWI4UbgQHdlrVbCnb+xLotXmJbBlC66QmpFw==", + "requires": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^2.0.4", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.6.tgz", + "integrity": "sha512-vfmKZp3XPM36DNF0qhW+Cdxk7xm7gTEHY1clv1Xq1arwRQuKZgAhw+NZNWbJBtuaNxzNXwhfdPYRrvIbjfS33A==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", + "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==" + }, + "get-prototype-of": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/get-prototype-of/-/get-prototype-of-0.0.0.tgz", + "integrity": "sha1-mHcr0QcW0W3rSzIlFsRp78oorEQ=" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + } + } + }, + "graceful-fs": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" + }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, + "gzip-size": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", + "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==", + "requires": { + "duplexer": "^0.1.1", + "pify": "^3.0.0" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" + }, + "handlebars": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "harmony-reflect": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.1.tgz", + "integrity": "sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" + }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" + }, + "hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=" + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + } + } + }, + "html-webpack-plugin": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.5.tgz", + "integrity": "sha512-y5l4lGxOW3pz3xBTFdfB9rnnrWRPVxlAhX6nrBYIcW+2k2zC3mSp/3DxlWVCMBfnO6UAnoF8OcFn0IMy6kaKAQ==", + "requires": { + "html-minifier": "^3.5.20", + "loader-utils": "^1.1.0", + "lodash": "^4.17.11", + "pretty-error": "^2.1.1", + "tapable": "^1.1.0", + "util.promisify": "1.0.0" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "requires": { + "postcss": "^7.0.14" + } + }, + "identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", + "requires": { + "harmony-reflect": "^1.4.6" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "immer": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", + "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==" + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "requires": { + "import-from": "^2.1.0" + } + }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "inquirer": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", + "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" + }, + "ipld-dag-cbor": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/ipld-dag-cbor/-/ipld-dag-cbor-0.15.0.tgz", + "integrity": "sha512-wc9nrDtV4Le76UUhG4LXX57NVi5d7JS2kLid2nOYZAcr0SFhiXZL2ZyV3bfmNohO50KvgPEessSaBBSm9bflGA==", + "requires": { + "borc": "^2.1.0", + "cids": "~0.7.0", + "is-circular": "^1.0.2", + "multicodec": "~0.5.0", + "multihashing-async": "~0.7.0" + } + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, + "is-capitalized": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-capitalized/-/is-capitalized-1.0.0.tgz", + "integrity": "sha1-TIRktNkdPk7rRIid0s2PGwrEwTY=" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-circular": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-circular/-/is-circular-1.0.2.tgz", + "integrity": "sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA==" + }, + "is-class": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/is-class/-/is-class-0.0.4.tgz", + "integrity": "sha1-4FdFFwW7NOOePjNZjJOpg3KWtzY=" + }, + "is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "requires": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "is-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.0.0.tgz", + "integrity": "sha512-F/pJIk8QD6OX5DNhRB7hWamLsUilmkDGho48KbgZ6xg/lmAZXHxzXQ91jzB3yRSw5kdQGGGc4yz8HYhTYIMWPg==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "iso-url": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.6.tgz", + "integrity": "sha512-YQO7+aIe6l1aSJUKOx+Vrv08DlhZeLFIVfehG2L29KLSEb9RszqPXilxJRVpp57px36BddKR5ZsebacO5qG0tg==" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==" + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "requires": { + "handlebars": "^4.1.2" + } + }, + "iterable-backoff": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/iterable-backoff/-/iterable-backoff-0.1.0.tgz", + "integrity": "sha512-7FeWGM9u6wB2a3x5cv8zHnuAYu6WYUYtayYcNXJfe17zL6NjR8OfalqmXNBm3AeTADHgLkByhnIrzm0DU2qFCA==" + }, + "jest": { + "version": "24.7.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.7.1.tgz", + "integrity": "sha512-AbvRar5r++izmqo5gdbAjTeA6uNRGoNRuj5vHB0OnDXo2DXWZJVuaObiGgtlvhKb+cWy2oYbQSfxv7Q7GjnAtA==", + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.7.1" + }, + "dependencies": { + "jest-cli": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.8.0.tgz", + "integrity": "sha512-+p6J00jSMPQ116ZLlHJJvdf8wbjNbZdeSX9ptfHX06/MSNaXmKihQzx5vQcw0q2G6JsdVkUIdWbOWtSnaYs3yA==", + "requires": { + "@jest/core": "^24.8.0", + "@jest/test-result": "^24.8.0", + "@jest/types": "^24.8.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.8.0", + "jest-util": "^24.8.0", + "jest-validate": "^24.8.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^12.0.2" + } + } + } + }, + "jest-changed-files": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.8.0.tgz", + "integrity": "sha512-qgANC1Yrivsq+UrLXsvJefBKVoCsKB0Hv+mBb6NMjjZ90wwxCDmU3hsCXBya30cH+LnPYjwgcU65i6yJ5Nfuug==", + "requires": { + "@jest/types": "^24.8.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.8.0.tgz", + "integrity": "sha512-Czl3Nn2uEzVGsOeaewGWoDPD8GStxCpAe0zOYs2x2l0fZAgPbCr3uwUkgNKV3LwE13VXythM946cd5rdGkkBZw==", + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.8.0", + "@jest/types": "^24.8.0", + "babel-jest": "^24.8.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.8.0", + "jest-environment-node": "^24.8.0", + "jest-get-type": "^24.8.0", + "jest-jasmine2": "^24.8.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.8.0", + "jest-util": "^24.8.0", + "jest-validate": "^24.8.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.8.0", + "realpath-native": "^1.1.0" + }, + "dependencies": { + "jest-resolve": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", + "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "requires": { + "@jest/types": "^24.8.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + } + } + }, + "jest-diff": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.8.0.tgz", + "integrity": "sha512-wxetCEl49zUpJ/bvUmIFjd/o52J+yWcoc5ZyPq4/W1LUKGEhRYDIbP1KcF6t+PvqNrGAFk4/JhtxDq/Nnzs66g==", + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.3.0", + "jest-get-type": "^24.8.0", + "pretty-format": "^24.8.0" + } + }, + "jest-docblock": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.3.0.tgz", + "integrity": "sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==", + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.8.0.tgz", + "integrity": "sha512-NrwK9gaL5+XgrgoCsd9svsoWdVkK4gnvyhcpzd6m487tXHqIdYeykgq3MKI1u4I+5Zf0tofr70at9dWJDeb+BA==", + "requires": { + "@jest/types": "^24.8.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.8.0", + "jest-util": "^24.8.0", + "pretty-format": "^24.8.0" + } + }, + "jest-environment-jsdom": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.8.0.tgz", + "integrity": "sha512-qbvgLmR7PpwjoFjM/sbuqHJt/NCkviuq9vus9NBn/76hhSidO+Z6Bn9tU8friecegbJL8gzZQEMZBQlFWDCwAQ==", + "requires": { + "@jest/environment": "^24.8.0", + "@jest/fake-timers": "^24.8.0", + "@jest/types": "^24.8.0", + "jest-mock": "^24.8.0", + "jest-util": "^24.8.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-jsdom-fourteen": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-0.1.0.tgz", + "integrity": "sha512-4vtoRMg7jAstitRzL4nbw83VmGH8Rs13wrND3Ud2o1fczDhMUF32iIrNKwYGgeOPUdfvZU4oy8Bbv+ni1fgVCA==", + "requires": { + "jest-mock": "^24.5.0", + "jest-util": "^24.5.0", + "jsdom": "^14.0.0" + }, + "dependencies": { + "jsdom": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.1.0.tgz", + "integrity": "sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng==", + "requires": { + "abab": "^2.0.0", + "acorn": "^6.0.4", + "acorn-globals": "^4.3.0", + "array-equal": "^1.0.0", + "cssom": "^0.3.4", + "cssstyle": "^1.1.1", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.0", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.1.3", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.5.0", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^6.1.2", + "xml-name-validator": "^3.0.0" + } + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==" + }, + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "jest-environment-node": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.8.0.tgz", + "integrity": "sha512-vIGUEScd1cdDgR6sqn2M08sJTRLQp6Dk/eIkCeO4PFHxZMOgy+uYLPMC4ix3PEfM5Au/x3uQ/5Tl0DpXXZsJ/Q==", + "requires": { + "@jest/environment": "^24.8.0", + "@jest/fake-timers": "^24.8.0", + "@jest/types": "^24.8.0", + "jest-mock": "^24.8.0", + "jest-util": "^24.8.0" + } + }, + "jest-get-type": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.8.0.tgz", + "integrity": "sha512-RR4fo8jEmMD9zSz2nLbs2j0zvPpk/KCEz3a62jJWbd2ayNo0cb+KFRxPHVhE4ZmgGJEQp0fosmNz84IfqM8cMQ==" + }, + "jest-haste-map": { + "version": "24.8.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.8.1.tgz", + "integrity": "sha512-SwaxMGVdAZk3ernAx2Uv2sorA7jm3Kx+lR0grp6rMmnY06Kn/urtKx1LPN2mGTea4fCT38impYT28FfcLUhX0g==", + "requires": { + "@jest/types": "^24.8.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.4.0", + "jest-util": "^24.8.0", + "jest-worker": "^24.6.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "dependencies": { + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "optional": true + } + } + } + } + }, + "jest-jasmine2": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.8.0.tgz", + "integrity": "sha512-cEky88npEE5LKd5jPpTdDCLvKkdyklnaRycBXL6GNmpxe41F0WN44+i7lpQKa/hcbXaQ+rc9RMaM4dsebrYong==", + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.8.0", + "@jest/test-result": "^24.8.0", + "@jest/types": "^24.8.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.8.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.8.0", + "jest-matcher-utils": "^24.8.0", + "jest-message-util": "^24.8.0", + "jest-runtime": "^24.8.0", + "jest-snapshot": "^24.8.0", + "jest-util": "^24.8.0", + "pretty-format": "^24.8.0", + "throat": "^4.0.0" + } + }, + "jest-leak-detector": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.8.0.tgz", + "integrity": "sha512-cG0yRSK8A831LN8lIHxI3AblB40uhv0z+SsQdW3GoMMVcK+sJwrIIyax5tu3eHHNJ8Fu6IMDpnLda2jhn2pD/g==", + "requires": { + "pretty-format": "^24.8.0" + } + }, + "jest-matcher-utils": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.8.0.tgz", + "integrity": "sha512-lex1yASY51FvUuHgm0GOVj7DCYEouWSlIYmCW7APSqB9v8mXmKSn5+sWVF0MhuASG0bnYY106/49JU1FZNl5hw==", + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.8.0", + "jest-get-type": "^24.8.0", + "pretty-format": "^24.8.0" + } + }, + "jest-message-util": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.8.0.tgz", + "integrity": "sha512-p2k71rf/b6ns8btdB0uVdljWo9h0ovpnEe05ZKWceQGfXYr4KkzgKo3PBi8wdnd9OtNh46VpNIJynUn/3MKm1g==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.8.0", + "@jest/types": "^24.8.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-mock": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.8.0.tgz", + "integrity": "sha512-6kWugwjGjJw+ZkK4mDa0Df3sDlUTsV47MSrT0nGQ0RBWJbpODDQ8MHDVtGtUYBne3IwZUhtB7elxHspU79WH3A==", + "requires": { + "@jest/types": "^24.8.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==" + }, + "jest-regex-util": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.3.0.tgz", + "integrity": "sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==" + }, + "jest-resolve": { + "version": "24.7.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.7.1.tgz", + "integrity": "sha512-Bgrc+/UUZpGJ4323sQyj85hV9d+ANyPNu6XfRDUcyFNX1QrZpSoM0kE4Mb2vZMAYTJZsBFzYe8X1UaOkOELSbw==", + "requires": { + "@jest/types": "^24.7.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.8.0.tgz", + "integrity": "sha512-hyK1qfIf/krV+fSNyhyJeq3elVMhK9Eijlwy+j5jqmZ9QsxwKBiP6qukQxaHtK8k6zql/KYWwCTQ+fDGTIJauw==", + "requires": { + "@jest/types": "^24.8.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.8.0" + } + }, + "jest-runner": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.8.0.tgz", + "integrity": "sha512-utFqC5BaA3JmznbissSs95X1ZF+d+4WuOWwpM9+Ak356YtMhHE/GXUondZdcyAAOTBEsRGAgH/0TwLzfI9h7ow==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.8.0", + "@jest/test-result": "^24.8.0", + "@jest/types": "^24.8.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.8.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.8.0", + "jest-jasmine2": "^24.8.0", + "jest-leak-detector": "^24.8.0", + "jest-message-util": "^24.8.0", + "jest-resolve": "^24.8.0", + "jest-runtime": "^24.8.0", + "jest-util": "^24.8.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + }, + "dependencies": { + "jest-resolve": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", + "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "requires": { + "@jest/types": "^24.8.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + } + } + }, + "jest-runtime": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.8.0.tgz", + "integrity": "sha512-Mq0aIXhvO/3bX44ccT+czU1/57IgOMyy80oM0XR/nyD5zgBcesF84BPabZi39pJVA6UXw+fY2Q1N+4BiVUBWOA==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.8.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.8.0", + "@jest/types": "^24.8.0", + "@types/yargs": "^12.0.2", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.8.0", + "jest-haste-map": "^24.8.0", + "jest-message-util": "^24.8.0", + "jest-mock": "^24.8.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.8.0", + "jest-snapshot": "^24.8.0", + "jest-util": "^24.8.0", + "jest-validate": "^24.8.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^12.0.2" + }, + "dependencies": { + "jest-resolve": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", + "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "requires": { + "@jest/types": "^24.8.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + } + } + }, + "jest-serializer": { + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.4.0.tgz", + "integrity": "sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==" + }, + "jest-snapshot": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.8.0.tgz", + "integrity": "sha512-5ehtWoc8oU9/cAPe6fez6QofVJLBKyqkY2+TlKTOf0VllBB/mqUNdARdcjlZrs9F1Cv+/HKoCS/BknT0+tmfPg==", + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.8.0", + "chalk": "^2.0.1", + "expect": "^24.8.0", + "jest-diff": "^24.8.0", + "jest-matcher-utils": "^24.8.0", + "jest-message-util": "^24.8.0", + "jest-resolve": "^24.8.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.8.0", + "semver": "^5.5.0" + }, + "dependencies": { + "jest-resolve": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.8.0.tgz", + "integrity": "sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==", + "requires": { + "@jest/types": "^24.8.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "jest-util": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.8.0.tgz", + "integrity": "sha512-DYZeE+XyAnbNt0BG1OQqKy/4GVLPtzwGx5tsnDrFcax36rVE3lTA5fbvgmbVPUZf9w77AJ8otqR4VBbfFJkUZA==", + "requires": { + "@jest/console": "^24.7.1", + "@jest/fake-timers": "^24.8.0", + "@jest/source-map": "^24.3.0", + "@jest/test-result": "^24.8.0", + "@jest/types": "^24.8.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "jest-validate": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.8.0.tgz", + "integrity": "sha512-+/N7VOEMW1Vzsrk3UWBDYTExTPwf68tavEPKDnJzrC6UlHtUDU/fuEdXqFoHzv9XnQ+zW6X3qMZhJ3YexfeLDA==", + "requires": { + "@jest/types": "^24.8.0", + "camelcase": "^5.0.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.8.0", + "leven": "^2.1.0", + "pretty-format": "^24.8.0" + } + }, + "jest-watch-typeahead": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.3.0.tgz", + "integrity": "sha512-+uOtlppt9ysST6k6ZTqsPI0WNz2HLa8bowiZylZoQCQaAVn7XsVmHhZREkz73FhKelrFrpne4hQQjdq42nFEmA==", + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.4.1", + "jest-watcher": "^24.3.0", + "slash": "^2.0.0", + "string-length": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "jest-watcher": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.8.0.tgz", + "integrity": "sha512-SBjwHt5NedQoVu54M5GEx7cl7IGEFFznvd/HNT8ier7cCAx/Qgu9ZMlaTQkvK22G1YOpcWBLQPFSImmxdn3DAw==", + "requires": { + "@jest/test-result": "^24.8.0", + "@jest/types": "^24.8.0", + "@types/yargs": "^12.0.9", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.8.0", + "string-length": "^2.0.0" + } + }, + "jest-worker": { + "version": "24.6.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.6.0.tgz", + "integrity": "sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ==", + "requires": { + "merge-stream": "^1.0.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-rpc-peer": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/json-rpc-peer/-/json-rpc-peer-0.15.5.tgz", + "integrity": "sha512-jZUNbRmcMXTpAnp1WGY9o85IfdGLKp75lBFYOIgpKOT9ZwKDHQOc3UmxOJUUg1bBfI7D1dltR3FSA6D0ZpPMpw==", + "requires": { + "@babel/runtime": "7.0.0-rc.1", + "json-rpc-protocol": "^0.12.0", + "lodash": "^4.17.4" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-rc.1.tgz", + "integrity": "sha512-Nifv2kwP/nwR39cAOasNxzjYfpeuf/ZbZNtQz5eYxWTC9yHARU9wItFnAwz1GTZ62MU+AtSjzZPMbLK5Q9hmbg==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, + "json-rpc-protocol": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/json-rpc-protocol/-/json-rpc-protocol-0.12.0.tgz", + "integrity": "sha512-zev0tw+eiKgMkUbP+JWfVfWiYxFz9IxUhThsrAfTzgfQI7slwaeH1/9esvR/E/Yt8x+kVQY67rSh1ap9BQBvog==", + "requires": { + "make-error": "^1.3.0" + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json-text-sequence": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", + "integrity": "sha1-py8hfcSvxGKf/1/rME3BvVGi89I=", + "requires": { + "delimit-stream": "0.1.0" + } + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonrpc-websocket-client": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsonrpc-websocket-client/-/jsonrpc-websocket-client-0.5.0.tgz", + "integrity": "sha512-kZtVAANjBpFjzZrZQm3qenOJ1lQfhemHKto+ZH2ubn58C8+f9B3XJPWKPMt4AG1jzh1/08CzsKMhEfuMmWyuvQ==", + "requires": { + "isomorphic-ws": "^4.0.1", + "iterable-backoff": "^0.1.0", + "json-rpc-peer": "^0.15.0", + "lodash": "^4.17.4", + "make-error": "^1.3.0", + "promise-toolbox": "^0.12.1", + "ws": "^6.0.0" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jsx-ast-utils": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz", + "integrity": "sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ==", + "requires": { + "array-includes": "^3.0.3", + "object.assign": "^4.1.0" + } + }, + "keypather": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/keypather/-/keypather-1.10.2.tgz", + "integrity": "sha1-4ESWMtSz5RbyHMAUznxWRP3c5hQ=", + "requires": { + "101": "^1.0.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, + "last-call-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "requires": { + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "requires": { + "invert-kv": "^2.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "loader-fs-cache": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.2.tgz", + "integrity": "sha512-70IzT/0/L+M20jUlEqZhZyArTU6VKLRTYRDAYN26g4jfzpJqjipLL3/hgYpySqI9PwsVRHHFja0LfEmsx9X2Cw==", + "requires": { + "find-cache-dir": "^0.1.1", + "mkdirp": "0.5.1" + }, + "dependencies": { + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "requires": { + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "requires": { + "find-up": "^1.0.0" + } + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=" + }, + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + }, + "loglevel": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz", + "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==" + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "requires": { + "tmpl": "1.0.x" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + } + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-deep": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", + "integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==", + "requires": { + "arr-union": "^3.1.0", + "clone-deep": "^0.2.4", + "kind-of": "^3.0.2" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "merge2": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "microevent.ts": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", + "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "requires": { + "mime-db": "1.40.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "mini-create-react-context": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", + "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", + "requires": { + "@babel/runtime": "^7.4.0", + "gud": "^1.0.0", + "tiny-warning": "^1.0.2" + } + }, + "mini-css-extract-plugin": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz", + "integrity": "sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw==", + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=" + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multibase": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.0.tgz", + "integrity": "sha512-R9bNLQhbD7MsitPm1NeY7w9sDgu6d7cuj25snAWH7k5PSNPSwIQQBpcpj8jx1W96dLbdigZqmUWOdQRMnAmgjA==", + "requires": { + "base-x": "3.0.4" + } + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "multicodec": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.5.tgz", + "integrity": "sha512-1kOifvwAqp9IdiiTKmpK2tS+LY6GHZdKpk3S2EvW4T32vlwDyA3hJoZtGauzqdedUPVNGChnTksEotVOCVlC+Q==", + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.15.tgz", + "integrity": "sha512-G/Smj1GWqw1RQP3dRuRRPe3oyLqvPqUaEDIaoi7JF7Loxl4WAWvhJNk84oyDEodSucv0MmSW/ZT0RKUrsIFD3g==", + "requires": { + "bs58": "^4.0.1", + "varint": "^5.0.0" + } + }, + "multihashing-async": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multihashing-async/-/multihashing-async-0.7.0.tgz", + "integrity": "sha512-SCbfl3f+DzJh+/5piukga9ofIOxwfT05t8R4jfzZIJ88YE9zU9+l3K2X+XB19MYyxqvyK9UJRNWbmQpZqQlbRA==", + "requires": { + "blakejs": "^1.1.0", + "buffer": "^5.2.1", + "err-code": "^1.1.2", + "js-sha3": "~0.8.0", + "multihashes": "~0.4.13", + "murmurhash3js-revisited": "^3.0.0" + }, + "dependencies": { + "buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, + "murmurhash3js-revisited": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz", + "integrity": "sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g==" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" + }, + "node-notifier": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "node-releases": { + "version": "1.1.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.26.tgz", + "integrity": "sha512-fZPsuhhUHMTlfkhDLGtfY80DSJTjOcx+qD1j5pqPkuhUHVS7xHZIg9EE4DHK8O3f0zTxXHX5VIkDG8pu98/wfQ==", + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + } + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "nwsapi": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", + "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.fromentries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", + "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.11.0", + "function-bind": "^1.1.1", + "has": "^1.0.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "opn": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", + "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + } + } + }, + "optimize-css-assets-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", + "requires": { + "cssnano": "^4.1.0", + "last-call-webpack-plugin": "^3.0.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=" + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" + }, + "parallel-transform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "requires": { + "no-case": "^2.2.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + }, + "dependencies": { + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + } + } + }, + "parse-asn1": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "requires": { + "pify": "^3.0.0" + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + } + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" + }, + "pnp-webpack-plugin": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.2.1.tgz", + "integrity": "sha512-W6GctK7K2qQiVR+gYSv/Gyt6jwwIH4vwdviFqx+Y2jAtVf5eZyYIDf5Ac2NCDMBiX5yWscBLZElPTsyA1UtVVA==", + "requires": { + "ts-pnp": "^1.0.0" + } + }, + "portfinder": { + "version": "1.0.21", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.21.tgz", + "integrity": "sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA==", + "requires": { + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", + "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-attribute-case-insensitive": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.1.tgz", + "integrity": "sha512-L2YKB3vF4PetdTIthQVeT+7YiSzMoNMLLYxPXXppOOP7NoazEAy45sh2LvJ8leCQjfBcfkYQs8TtCcQjeZTp8A==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-browser-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-2.0.0.tgz", + "integrity": "sha512-xGG0UvoxwBc4Yx4JX3gc0RuDl1kc4bVihCzzk6UC72YPfq5fu3c717Nu8Un3nvnq1BJ31gBnFXIG/OaUTnpHgA==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-calc": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.1.tgz", + "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", + "requires": { + "css-unit-converter": "^1.1.1", + "postcss": "^7.0.5", + "postcss-selector-parser": "^5.0.0-rc.4", + "postcss-value-parser": "^3.3.1" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-color-functional-notation": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", + "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-gray": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz", + "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-hex-alpha": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", + "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", + "requires": { + "postcss": "^7.0.14", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-color-mod-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", + "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", + "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "requires": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-custom-media": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", + "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", + "requires": { + "postcss": "^7.0.14" + } + }, + "postcss-custom-properties": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", + "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", + "requires": { + "postcss": "^7.0.17", + "postcss-values-parser": "^2.0.1" + } + }, + "postcss-custom-selectors": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", + "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-dir-pseudo-class": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", + "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-double-position-gradients": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz", + "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==", + "requires": { + "postcss": "^7.0.5", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-env-function": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", + "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-flexbugs-fixes": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", + "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-focus-visible": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", + "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-focus-within": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", + "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-font-variant": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.0.tgz", + "integrity": "sha512-M8BFYKOvCrI2aITzDad7kWuXXTm0YhGdP9Q8HanmN4EF1Hmcgs1KK5rSHylt/lUJe8yLxiSwWAHdScoEiIxztg==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-gap-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", + "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-image-set-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", + "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-initial": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.1.tgz", + "integrity": "sha512-I2Sz83ZSHybMNh02xQDK609lZ1/QOyYeuizCjzEhlMgeV/HcDJapQiH4yTqLjZss0X6/6VvKFXUeObaHpJoINw==", + "requires": { + "lodash.template": "^4.5.0", + "postcss": "^7.0.2" + } + }, + "postcss-lab-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", + "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", + "requires": { + "@csstools/convert-colors": "^1.4.0", + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "requires": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + } + }, + "postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "postcss-logical": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", + "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-media-minmax": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", + "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "requires": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + } + }, + "postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "requires": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "requires": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", + "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^3.3.1" + } + }, + "postcss-modules-scope": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz", + "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==", + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", + "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^7.0.6" + } + }, + "postcss-nesting": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.0.tgz", + "integrity": "sha512-WSsbVd5Ampi3Y0nk/SKr5+K34n52PqMqEfswu6RtU4r7wA8vSD+gM8/D9qq4aJkHImwn1+9iEFTbjoWsQeqtaQ==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-normalize": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-7.0.1.tgz", + "integrity": "sha512-NOp1fwrG+6kVXWo7P9SizCHX6QvioxFD/hZcI2MLxPmVnFJFC0j0DDpIuNw2tUDeCFMni59gCVgeJ1/hYhj2OQ==", + "requires": { + "@csstools/normalize.css": "^9.0.1", + "browserslist": "^4.1.1", + "postcss": "^7.0.2", + "postcss-browser-comments": "^2.0.0" + } + }, + "postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "requires": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "requires": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "requires": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-overflow-shorthand": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", + "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-page-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", + "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-place": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", + "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", + "requires": { + "postcss": "^7.0.2", + "postcss-values-parser": "^2.0.0" + } + }, + "postcss-preset-env": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.6.0.tgz", + "integrity": "sha512-I3zAiycfqXpPIFD6HXhLfWXIewAWO8emOKz+QSsxaUZb9Dp8HbF5kUf+4Wy/AxR33o+LRoO8blEWCHth0ZsCLA==", + "requires": { + "autoprefixer": "^9.4.9", + "browserslist": "^4.4.2", + "caniuse-lite": "^1.0.30000939", + "css-blank-pseudo": "^0.1.4", + "css-has-pseudo": "^0.10.0", + "css-prefers-color-scheme": "^3.1.1", + "cssdb": "^4.3.0", + "postcss": "^7.0.14", + "postcss-attribute-case-insensitive": "^4.0.1", + "postcss-color-functional-notation": "^2.0.1", + "postcss-color-gray": "^5.0.0", + "postcss-color-hex-alpha": "^5.0.2", + "postcss-color-mod-function": "^3.0.3", + "postcss-color-rebeccapurple": "^4.0.1", + "postcss-custom-media": "^7.0.7", + "postcss-custom-properties": "^8.0.9", + "postcss-custom-selectors": "^5.1.2", + "postcss-dir-pseudo-class": "^5.0.0", + "postcss-double-position-gradients": "^1.0.0", + "postcss-env-function": "^2.0.2", + "postcss-focus-visible": "^4.0.0", + "postcss-focus-within": "^3.0.0", + "postcss-font-variant": "^4.0.0", + "postcss-gap-properties": "^2.0.0", + "postcss-image-set-function": "^3.0.1", + "postcss-initial": "^3.0.0", + "postcss-lab-function": "^2.0.1", + "postcss-logical": "^3.0.0", + "postcss-media-minmax": "^4.0.0", + "postcss-nesting": "^7.0.0", + "postcss-overflow-shorthand": "^2.0.0", + "postcss-page-break": "^2.0.0", + "postcss-place": "^4.0.1", + "postcss-pseudo-class-any-link": "^6.0.0", + "postcss-replace-overflow-wrap": "^3.0.0", + "postcss-selector-matches": "^4.0.0", + "postcss-selector-not": "^4.0.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", + "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", + "requires": { + "postcss": "^7.0.2", + "postcss-selector-parser": "^5.0.0-rc.3" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "requires": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "requires": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + } + }, + "postcss-replace-overflow-wrap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", + "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", + "requires": { + "postcss": "^7.0.2" + } + }, + "postcss-safe-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", + "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-selector-matches": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", + "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-not": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz", + "integrity": "sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ==", + "requires": { + "balanced-match": "^1.0.0", + "postcss": "^7.0.2" + } + }, + "postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "requires": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + } + }, + "postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "requires": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "postcss-values-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", + "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "pretty-bytes": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.2.0.tgz", + "integrity": "sha512-ujANBhiUsl9AhREUDUEY1GPOharMGm8x8juS7qOHybcLi7XsKfrYQ88hSly1l2i0klXHTDYrlL8ihMCG55Dc3w==" + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "pretty-format": { + "version": "24.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.8.0.tgz", + "integrity": "sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw==", + "requires": { + "@jest/types": "^24.8.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + } + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "promise": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", + "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", + "requires": { + "asap": "~2.0.6" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "promise-toolbox": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/promise-toolbox/-/promise-toolbox-0.12.1.tgz", + "integrity": "sha512-fvsSG1kxs+xDJFwmN3WgPpAdikJvaoYkcLs1xrLRHYE2luzNVfroLrx2WzIhhsGjLsbNBu+983503IRf/n9MWA==", + "requires": { + "make-error": "^1.3.2" + } + }, + "prompts": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.1.0.tgz", + "integrity": "sha512-+x5TozgqYdOwWsQFZizE/Tra3fKvAoy037kOyU6cgz84n8f6zxngLOV4O32kTwt9FcLCxAqw0P/c8rOr9y+Gfg==", + "requires": { + "kleur": "^3.0.2", + "sisteransi": "^1.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "psl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz", + "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + } + } + }, + "react": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", + "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" + } + }, + "react-app-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.1.tgz", + "integrity": "sha512-LbVpT1NdzTdDDs7xEZdebjDrqsvKi5UyVKUQqtTYYNyC1JJYVAwNQWe4ybWvoT2V2WW9PGVO2u5Y6aVj4ER/Ow==", + "requires": { + "core-js": "3.0.1", + "object-assign": "4.1.1", + "promise": "8.0.2", + "raf": "3.4.1", + "regenerator-runtime": "0.13.2", + "whatwg-fetch": "3.0.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" + } + } + }, + "react-cristal": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/react-cristal/-/react-cristal-0.0.12.tgz", + "integrity": "sha512-1aerLtjDv+59omo4BC7z6gxBpN4+4H2/2/Q1tDObLNwJcWCO5/Gq12IjVQ4FjYh1BLBtuBZe0HalIbVAFVPzqg==" + }, + "react-dev-utils": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.0.1.tgz", + "integrity": "sha512-pnaeMo/Pxel8aZpxk1WwxT3uXxM3tEwYvsjCYn5R7gNxjhN1auowdcLDzFB8kr7rafAj2rxmvfic/fbac5CzwQ==", + "requires": { + "@babel/code-frame": "7.0.0", + "address": "1.0.3", + "browserslist": "4.5.4", + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "1.0.5", + "filesize": "3.6.1", + "find-up": "3.0.0", + "fork-ts-checker-webpack-plugin": "1.1.1", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.0.0", + "immer": "1.10.0", + "inquirer": "6.2.2", + "is-root": "2.0.0", + "loader-utils": "1.2.3", + "opn": "5.4.0", + "pkg-up": "2.0.0", + "react-error-overlay": "^5.1.6", + "recursive-readdir": "2.2.2", + "shell-quote": "1.6.1", + "sockjs-client": "1.3.0", + "strip-ansi": "5.2.0", + "text-table": "0.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "browserslist": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.5.4.tgz", + "integrity": "sha512-rAjx494LMjqKnMPhFkuLmLp8JWEX0o8ADTGeAbOqaF+XCvYLreZrG5uVjnPBlAQ8REZK4pzXGvp0bWgrFtKaag==", + "requires": { + "caniuse-lite": "^1.0.30000955", + "electron-to-chromium": "^1.3.122", + "node-releases": "^1.1.13" + } + }, + "inquirer": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", + "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.0.0", + "through": "^2.3.6" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "react-dom": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", + "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" + } + }, + "react-error-overlay": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.6.tgz", + "integrity": "sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==" + }, + "react-is": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", + "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" + }, + "react-router": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.0.1.tgz", + "integrity": "sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.3.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.0.1.tgz", + "integrity": "sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.0.1", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, + "react-scripts": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.0.1.tgz", + "integrity": "sha512-LKEjBhVpEB+c312NeJhzF+NATxF7JkHNr5GhtwMeRS1cMeLElMeIu8Ye7WGHtDP7iz7ra4ryy48Zpo6G/cwWUw==", + "requires": { + "@babel/core": "7.4.3", + "@svgr/webpack": "4.1.0", + "@typescript-eslint/eslint-plugin": "1.6.0", + "@typescript-eslint/parser": "1.6.0", + "babel-eslint": "10.0.1", + "babel-jest": "^24.8.0", + "babel-loader": "8.0.5", + "babel-plugin-named-asset-import": "^0.3.2", + "babel-preset-react-app": "^9.0.0", + "camelcase": "^5.2.0", + "case-sensitive-paths-webpack-plugin": "2.2.0", + "css-loader": "2.1.1", + "dotenv": "6.2.0", + "dotenv-expand": "4.2.0", + "eslint": "^5.16.0", + "eslint-config-react-app": "^4.0.1", + "eslint-loader": "2.1.2", + "eslint-plugin-flowtype": "2.50.1", + "eslint-plugin-import": "2.16.0", + "eslint-plugin-jsx-a11y": "6.2.1", + "eslint-plugin-react": "7.12.4", + "eslint-plugin-react-hooks": "^1.5.0", + "file-loader": "3.0.1", + "fs-extra": "7.0.1", + "fsevents": "2.0.6", + "html-webpack-plugin": "4.0.0-beta.5", + "identity-obj-proxy": "3.0.0", + "is-wsl": "^1.1.0", + "jest": "24.7.1", + "jest-environment-jsdom-fourteen": "0.1.0", + "jest-resolve": "24.7.1", + "jest-watch-typeahead": "0.3.0", + "mini-css-extract-plugin": "0.5.0", + "optimize-css-assets-webpack-plugin": "5.0.1", + "pnp-webpack-plugin": "1.2.1", + "postcss-flexbugs-fixes": "4.1.0", + "postcss-loader": "3.0.0", + "postcss-normalize": "7.0.1", + "postcss-preset-env": "6.6.0", + "postcss-safe-parser": "4.0.1", + "react-app-polyfill": "^1.0.1", + "react-dev-utils": "^9.0.1", + "resolve": "1.10.0", + "sass-loader": "7.1.0", + "semver": "6.0.0", + "style-loader": "0.23.1", + "terser-webpack-plugin": "1.2.3", + "ts-pnp": "1.1.2", + "url-loader": "1.1.2", + "webpack": "4.29.6", + "webpack-dev-server": "3.2.1", + "webpack-manifest-plugin": "2.0.4", + "workbox-webpack-plugin": "4.2.0" + } + }, + "react-tooltip": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.11.1.tgz", + "integrity": "sha512-YCMVlEC2KuHIzOQhPplTK5jmBBwoL+PYJJdJKXj7M/h7oevupd/QSVq6z5U7/ehIGXyHsAqvwpdxexDfyQ0o3A==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "requires": { + "util.promisify": "^1.0.0" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "requires": { + "minimatch": "3.0.4" + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + }, + "regenerator-transform": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", + "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp-tree": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.11.tgz", + "integrity": "sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg==" + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" + }, + "regexpu-core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", + "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==" + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "renderkid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", + "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" + }, + "rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rpc-websockets": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-4.5.1.tgz", + "integrity": "sha512-OoXnJAJ6tz2WC56l0SsWFHF0hrqVQk86aZ/bCQfKx5s5GvCWUW/xNVEUHyh6RwHIgEnSnKq00fTbRD8E9Yw3Dw==", + "requires": { + "@babel/runtime": "^7.4.5", + "assert-args": "^1.2.1", + "babel-runtime": "^6.26.0", + "circular-json": "^0.5.9", + "eventemitter3": "^3.1.2", + "uuid": "^3.3.2", + "ws": "^5.2.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", + "integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "requires": { + "aproba": "^1.1.1" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + } + }, + "sass-loader": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", + "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" + } + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "requires": { + "xmlchars": "^2.1.1" + } + }, + "scheduler": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", + "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "selfsigned": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz", + "integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==", + "requires": { + "node-forge": "0.7.5" + } + }, + "semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serialize-javascript": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", + "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==" + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "requires": { + "is-buffer": "^1.0.2" + } + }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=" + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "requires": { + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" + } + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "sisteransi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.2.tgz", + "integrity": "sha512-ZcYcZcT69nSLAR2oLN2JwNmLkJEKGooFMCdvOkFrToUt/WfcRWqhIg4P4KwY4dmLbuyXIx4o4YmPsvMRJYJd/w==" + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==" + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + }, + "dependencies": { + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "sockjs-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", + "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" + }, + "spdy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.0.tgz", + "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", + "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", + "requires": { + "babel-extract-comments": "^1.0.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + } + }, + "styled-components": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-3.4.10.tgz", + "integrity": "sha512-TA8ip8LoILgmSAFd3r326pKtXytUUGu5YWuqZcOQVwVVwB6XqUMn4MHW2IuYJ/HAD81jLrdQed8YWfLSG1LX4Q==", + "requires": { + "buffer": "^5.0.3", + "css-to-react-native": "^2.0.3", + "fbjs": "^0.8.16", + "hoist-non-react-statics": "^2.5.0", + "prop-types": "^15.5.4", + "react-is": "^16.3.1", + "stylis": "^3.5.0", + "stylis-rule-sheet": "^0.0.10", + "supports-color": "^3.2.3" + }, + "dependencies": { + "buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "requires": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "dependencies": { + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "requires": { + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + } + } + }, + "stylis": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", + "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==" + }, + "stylis-rule-sheet": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", + "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "svg-parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.1.tgz", + "integrity": "sha512-8eUnCsU2sc2hyfvjK++zi5u24a2UQIB2DK9GY/cprGlaDr7SIhm9F0m9CkGYOnOgrK3iTUSnJ7M1DTLqqZt96g==" + }, + "svgo": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz", + "integrity": "sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==", + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.33", + "csso": "^3.5.1", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "table": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.4.tgz", + "integrity": "sha512-IIfEAUx5QlODLblLrGTTLJA7Tk0iLSGBvgY8essPRVNGHAzThujww1YqHLs6h3HfTg55h++RzLHH5Xw/rfv+mg==", + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "terser": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", + "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", + "requires": { + "commander": "^2.19.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.10" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "terser-webpack-plugin": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz", + "integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==", + "requires": { + "cacache": "^11.0.2", + "find-cache-dir": "^2.0.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "terser": "^3.16.1", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==" + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "requires": { + "setimmediate": "^1.0.4" + } + }, + "timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" + }, + "tiny-invariant": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.6.tgz", + "integrity": "sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=" + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "ts-pnp": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.2.tgz", + "integrity": "sha512-f5Knjh7XCyRIzoC/z1Su1yLLRrPrFCgtUAh/9fCSP6NKbATwpOL1+idQVXQokK9GRFURn/jYPGPfegIctwunoA==" + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, + "tsutils": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz", + "integrity": "sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==", + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "ua-parser-js": { + "version": "0.7.20", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz", + "integrity": "sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==" + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==" + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==" + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "requires": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" + } + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "varint": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", + "integrity": "sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "vendors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz", + "integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==" + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "requires": { + "makeerror": "1.0.x" + } + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "webpack": { + "version": "4.29.6", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.6.tgz", + "integrity": "sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw==", + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.0.5", + "acorn-dynamic-import": "^4.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chrome-trace-event": "^1.0.0", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.0", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "micromatch": "^3.1.8", + "mkdirp": "~0.5.0", + "neo-async": "^2.5.0", + "node-libs-browser": "^2.0.0", + "schema-utils": "^1.0.0", + "tapable": "^1.1.0", + "terser-webpack-plugin": "^1.1.0", + "watchpack": "^1.5.0", + "webpack-sources": "^1.3.0" + } + }, + "webpack-dev-middleware": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz", + "integrity": "sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA==", + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.2", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + } + }, + "webpack-dev-server": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.2.1.tgz", + "integrity": "sha512-sjuE4mnmx6JOh9kvSbPYw3u/6uxCLHNWfhWaIPwcXWsvWOPN+nc5baq4i9jui3oOBRXGonK9+OI0jVkaz6/rCw==", + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^4.1.1", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "^0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.2.0", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "schema-utils": "^1.0.0", + "selfsigned": "^1.9.1", + "semver": "^5.6.0", + "serve-index": "^1.7.2", + "sockjs": "0.3.19", + "sockjs-client": "1.3.0", + "spdy": "^4.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.5.1", + "webpack-log": "^2.0.0", + "yargs": "12.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + }, + "decamelize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", + "requires": { + "xregexp": "4.0.0" + } + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "yargs": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", + "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", + "requires": { + "cliui": "^4.0.0", + "decamelize": "^2.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^10.1.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-manifest-plugin": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.0.4.tgz", + "integrity": "sha512-nejhOHexXDBKQOj/5v5IZSfCeTO3x1Dt1RZEcGfBSul891X/eLIcIVH31gwxPDdsi2Z8LKKFGpM4w9+oTBOSCg==", + "requires": { + "fs-extra": "^7.0.0", + "lodash": ">=3.5 <5", + "tapable": "^1.0.0" + } + }, + "webpack-sources": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", + "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "workbox-background-sync": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz", + "integrity": "sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-broadcast-update": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz", + "integrity": "sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-build": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-4.3.1.tgz", + "integrity": "sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw==", + "requires": { + "@babel/runtime": "^7.3.4", + "@hapi/joi": "^15.0.0", + "common-tags": "^1.8.0", + "fs-extra": "^4.0.2", + "glob": "^7.1.3", + "lodash.template": "^4.4.0", + "pretty-bytes": "^5.1.0", + "stringify-object": "^3.3.0", + "strip-comments": "^1.0.2", + "workbox-background-sync": "^4.3.1", + "workbox-broadcast-update": "^4.3.1", + "workbox-cacheable-response": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-expiration": "^4.3.1", + "workbox-google-analytics": "^4.3.1", + "workbox-navigation-preload": "^4.3.1", + "workbox-precaching": "^4.3.1", + "workbox-range-requests": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1", + "workbox-streams": "^4.3.1", + "workbox-sw": "^4.3.1", + "workbox-window": "^4.3.1" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "workbox-cacheable-response": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz", + "integrity": "sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-core": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-4.3.1.tgz", + "integrity": "sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg==" + }, + "workbox-expiration": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-4.3.1.tgz", + "integrity": "sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-google-analytics": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz", + "integrity": "sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg==", + "requires": { + "workbox-background-sync": "^4.3.1", + "workbox-core": "^4.3.1", + "workbox-routing": "^4.3.1", + "workbox-strategies": "^4.3.1" + } + }, + "workbox-navigation-preload": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz", + "integrity": "sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-precaching": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-4.3.1.tgz", + "integrity": "sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-range-requests": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz", + "integrity": "sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-routing": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-4.3.1.tgz", + "integrity": "sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-strategies": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-4.3.1.tgz", + "integrity": "sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-streams": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-4.3.1.tgz", + "integrity": "sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "workbox-sw": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-4.3.1.tgz", + "integrity": "sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==" + }, + "workbox-webpack-plugin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-4.2.0.tgz", + "integrity": "sha512-YZsiA+y/ns/GdWRaBsfYv8dln1ebWtGnJcTOg1ppO0pO1tScAHX0yGtHIjndxz3L/UUhE8b0NQE9KeLNwJwA5A==", + "requires": { + "@babel/runtime": "^7.0.0", + "json-stable-stringify": "^1.0.1", + "workbox-build": "^4.2.0" + } + }, + "workbox-window": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-4.3.1.tgz", + "integrity": "sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg==", + "requires": { + "workbox-core": "^4.3.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "requires": { + "errno": "~0.1.7" + } + }, + "worker-rpc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", + "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", + "requires": { + "microevent.ts": "~0.1.1" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "xmlchars": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.1.1.tgz", + "integrity": "sha512-7hew1RPJ1iIuje/Y01bGD/mXokXxegAgVS+e+E0wSi2ILHQkYAH1+JXARwTjZSM4Z4Z+c73aKspEcqj+zPPL/w==" + }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "xterm": { + "version": "3.14.5", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-3.14.5.tgz", + "integrity": "sha512-DVmQ8jlEtL+WbBKUZuMxHMBgK/yeIZwkXB81bH+MGaKKnJGYwA+770hzhXPfwEIokK9On9YIFPRleVp/5G7z9g==" + }, + "xterm-addon-attach": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xterm-addon-attach/-/xterm-addon-attach-0.1.0.tgz", + "integrity": "sha512-vImYAP+AVoW/gnr4CIESrOr2MplzNxnrPX4YEkdk0EEkBOg3Pwnndu1xy7HnY0XZsfGRz7rfn71sAXfJDGLvUQ==" + }, + "xterm-addon-fit": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.1.0.tgz", + "integrity": "sha512-DzYThnR5rXYX7JrOZ8rHGMU36BiTwYNFUOhhNwrDSFvoUR2MgwQrfA/JrqLE62KRj0D8bkRR7+xe7qGBp1O4Rw==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + }, + "dependencies": { + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + } + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/package.json b/vendor/github.com/filecoin-project/lotus/lotuspond/front/package.json new file mode 100644 index 0000000000..c9e6ac7696 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/package.json @@ -0,0 +1,44 @@ +{ + "name": "front", + "version": "0.1.0", + "private": true, + "dependencies": { + "borc": "^2.1.1", + "cids": "^0.7.1", + "ipld-dag-cbor": "^0.15.0", + "jsonrpc-websocket-client": "^0.5.0", + "multihashes": "^0.4.15", + "react": "^16.8.6", + "react-cristal": "^0.0.12", + "react-dom": "^16.8.6", + "react-router-dom": "^5.0.1", + "react-scripts": "3.0.1", + "react-tooltip": "^3.11.1", + "rpc-websockets": "^4.5.1", + "styled-components": "^3.3.3", + "xterm": "^3.14.5", + "xterm-addon-attach": "^0.1.0", + "xterm-addon-fit": "^0.1.0" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/public/index.html b/vendor/github.com/filecoin-project/lotus/lotuspond/front/public/index.html new file mode 100644 index 0000000000..d0709c0166 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/public/index.html @@ -0,0 +1,14 @@ + + + + + + + + Lotus Pond + + + +
    + + diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/public/manifest.json b/vendor/github.com/filecoin-project/lotus/lotuspond/front/public/manifest.json new file mode 100644 index 0000000000..1f2f141faf --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Address.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Address.js new file mode 100644 index 0000000000..7ca2ea888a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Address.js @@ -0,0 +1,148 @@ +import React from 'react' +import CID from 'cids' +import ReactTooltip from 'react-tooltip' +import * as multihash from "multihashes" +import State from "./State" +import methods from "./chain/methods.json" +import Fil from "./Fil"; + +function truncAddr(addr, len) { + if (!addr) { + return "" + } + if (addr.length > len) { + return {addr.substr(0, len - 3) + '..'} + } + return addr +} + +let sheet = document.createElement('style') +document.body.appendChild(sheet); + +class Address extends React.Component { + constructor(props) { + super(props) + + this.openState = this.openState.bind(this) + + this.state = {balance: -2} + this.refresh = this.refresh.bind(this) + } + + componentDidMount() { + this.refresh() + if(!this.props.ts) { + this.updates = setInterval(this.refresh, 2050) + this.props.client.on('close', () => clearInterval(this.updates)) + } + } + + componentWillUnmount() { + clearInterval(this.updates) + } + + async refresh() { + let balance = 0 + let actor = {} + let actorInfo + let minerInfo + let nonce + + try { + balance = await this.props.client.call('Filecoin.WalletBalance', [this.props.addr]) + actor = await this.props.client.call('Filecoin.StateGetActor', [this.props.addr, (this.props.ts || {}).Cids]) + + actorInfo = await this.actorInfo(actor) + if(this.props.miner) { + minerInfo = await this.props.client.call('Filecoin.StateMinerPower', [this.props.addr, (this.props.ts || {}).Cids]) + } + if(this.props.nonce) { + nonce = await this.props.client.call('Filecoin.MpoolGetNonce', [this.props.addr]) + } + } catch (err) { + console.log(err) + balance = -1 + } + this.setState({balance, actor, actorInfo, minerInfo, nonce}) + } + + openState() { + this.props.mountWindow((onClose) => ) + } + + async actorInfo(actor) { + const c = new CID(actor.Code['/']) + const mh = multihash.decode(c.multihash) // TODO: check identity + + let method = + if(this.props.method !== undefined && mh.digest.toString()) { + method = .{methods[mh.digest.toString()][this.props.method]} + } + + let info = ({mh.digest.toString()}{method}) + switch(mh.digest.toString()) { + case 'paych': + const actstate = await this.props.client.call('Filecoin.StateReadState', [actor, (this.props.ts || {}).Cids]) + info = ({mh.digest.toString()}{method} to
    ) + } + + return info + } + + addColl = async () => { + const coll = await this.props.client.call('Filecoin.StatePledgeCollateral', [null]) + this.props.addN(this.props.addr, coll) + } + + render() { + let add20k = + if(this.props.addN) { + add20k =   this.props.addN(this.props.addr, 200000)}>[+200k] + if (this.props.add10k) { + add20k = {add20k}  this.props.addN(this.props.addr, 2000000)}>[+2M] + add20k = {add20k}  this.props.addN(this.props.addr, 20000000)}>[+20M] + add20k = {add20k}  this.addColl()}>[+C] + } + } + let addr = truncAddr(this.props.addr, this.props.short ? 12 : 17) + + let actInfo = (?) + if(this.state.balance >= 0) { + actInfo = this.state.actorInfo + addr = {addr} + } + + addr = sheet.sheet.insertRule(`.pondaddr-${this.props.addr}, .pondaddr-${this.props.addr} * { color: #11ee11 !important; }`, 0)} + onMouseLeave={() => sheet.sheet.deleteRule(0)} + >{addr} + + let nonce = + if(this.props.nonce) { + nonce =  Nc:{this.state.nonce}{nonce} + } + + let balance = : {{this.state.balance} + if(this.props.nobalance) { + balance = + } + if(this.props.short) { + actInfo = {actInfo}: {this.state.balance} + balance = + } + + let transfer = + if(this.props.transfer) { + transfer =  {this.props.transfer}FIL + } + + let minerInfo = + if(this.state.minerInfo) { + minerInfo =  Power: {this.state.minerInfo.MinerPower} ({this.state.minerInfo.MinerPower/this.state.minerInfo.TotalPower*100}%) + } + + return {addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo} + } +} + +export default Address diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.css b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.css new file mode 100644 index 0000000000..7c58b720ed --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.css @@ -0,0 +1,232 @@ +.Index { + width: 100vw; + height: 100vh; + background: #1a1a1a; + color: #f0f0f0; + font-family: monospace; + + display: grid; + grid-template-columns: auto 40vw auto; + grid-template-rows: auto auto auto 3em; + grid-template-areas: + ". . ." + ". main ." + ". . ." + "footer footer footer"; +} + +.Index-footer { + background: #2a2a2a; + grid-area: footer; +} + +.Index-footer > div { + padding-left: 0.7em; + padding-top: 0.7em; +} + +.Index-nodes { + grid-area: main; + background: #2a2a2a; +} + +.Index-node { + margin: 5px; + padding: 15px; + background: #1f1f1f; +} + +.Index-addwrap { + margin-top: 5px; +} + +/* SingleNode */ + + +.SingleNode-connecting { + width: 100vw; + height: 100vh; + + background: #1a1a1a; + color: #ffffff; + font-family: monospace; + + display: grid; + grid-template-columns: auto min-content auto; + grid-template-rows: auto min-content auto; + grid-template-areas: + ". . ." + ". main ." + ". . ." +} + +.SingleNode-connecting > div { + grid-area: main; + padding: 15px; + white-space: nowrap; + background: #2a2a2a; +} + + + +/*****/ + +a:link { + color: #50f020; +} + +a:visited { + color: #50f020; +} + +a:hover { + color: #30a00a; +} + +.Button { + display: inline-block; + padding: 15px; + background: #1f1f1f; + margin-left: 5px; +} + +.Window { + background: #2a2a2a !important; + color: #e0e0e0; +} + +.Window b { + color: #f0f0f0; +} + +.Window > :first-child > :nth-child(2)::before { + background: #f0f0f0; +} + +.Window > :first-child > :nth-child(2)::after { + background: #f0f0f0; +} + +.Window a:link { + color: #30a015; +} + +.Window a:visited { + color: #30a015; +} + +/* POND */ + +.Pond-connecting { + width: 100vw; + height: 100vh; + + background: #1a1a1a; + color: #ffffff; + font-family: monospace; + + display: grid; + grid-template-columns: auto min-content auto; + grid-template-rows: auto min-content auto; + grid-template-areas: + ". . ." + ". main ." + ". . ." +} + +.App { + min-height: 100vh; + background: #1a1a1a; + font-family: monospace; +} + +.NodeList { + user-select: text; + font-family: monospace; + min-width: 40em; + display: inline-block; +} + +.FullNode { + user-select: text; + font-family: monospace; + min-width: 50em; + display: inline-block; +} + +.FullNode-voucher { + padding-left: 1em; +} + +.StorageNode { + user-select: text; + font-family: monospace; + min-width: 40em; + display: inline-block; +} + +.Block { + user-select: text; + font-family: monospace; + min-width: 60em; + display: inline-block; +} + +.State { + user-select: text; + font-family: monospace; + min-width: 40em; + display: inline-block; +} + +.Client { + user-select: text; + font-family: monospace; + display: inline-block; +} + +.CristalScroll { + display: flex; + min-width: 100%; + min-height: 100%; + overflow: auto; +} + +.Consensus { + font-family: monospace; +} + +.ChainExplorer { + font-family: monospace; + color: #d0d0d0; +} + +.ChainExplorer-at { + min-width: 40em; + background: #222222; +} + +.ChainExplorer-after { + background: #440000 +} + +.ChainExplorer-after:hover { + background: #770000 +} + +.ChainExplorer-before { + background: #444400 +} + +.ChainExplorer-before:hover { + background: #777700 +} + +.Logs { + width: 100%; + height: 100%; +} + +.Logs-window :nth-child(2) { + height: 100%; +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.js new file mode 100644 index 0000000000..4753697382 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.js @@ -0,0 +1,24 @@ +import React from 'react'; +import './App.css'; +import { BrowserRouter as Router, Route, Link } from "react-router-dom"; +import Pond from "./Pond"; +import SingleNode from "./SingleNode"; +import Index from "./NodeIndex"; + +class App extends React.Component { + constructor(props) { + super(props) + } + + render() { + return ( + + + + + + ) + } +} + +export default App diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.test.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.test.js new file mode 100644 index 0000000000..b63d6b53a2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import Pond from './Pond'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Block.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Block.js new file mode 100644 index 0000000000..44104d4830 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Block.js @@ -0,0 +1,87 @@ +import React from 'react'; +import {BlockLinks} from "./BlockLink"; +import Address from "./Address"; +import Window from "./Window"; + +class Block extends React.Component { + constructor(props) { + super(props) + + this.state = {} + + this.loadHeader() + } + + async loadHeader() { + const header = await this.props.conn.call('Filecoin.ChainGetBlock', [this.props.cid]) + let messages = await this.props.conn.call('Filecoin.ChainGetParentMessages', [this.props.cid]) + let receipts = await this.props.conn.call('Filecoin.ChainGetParentReceipts', [this.props.cid]) + + if (!messages) { + messages = [] + } + + + messages = messages.map((msg, k) => ({...msg.Message, cid: msg.Cid, receipt: receipts[k]})) + + messages = await Promise.all(messages.map(async (msg, i) => { + if (msg.receipt.ExitCode !== 0) { + let reply = await this.props.conn.call('Filecoin.StateReplay', [{Cids: [this.props.cid], Blocks: [header], Height: header.Height}, msg.Cid]) + if(!reply.Error) { + reply.Error = "reply: no error" + } + msg.Error = reply.Error + } + return msg + })) + + this.setState({header: header, messages: messages}) + } + + render() { + let content =
    Loading Block Info
    + if (this.state.header) { + let head = this.state.header + + const messages = this.state.messages.map((m, k) => ( +
    +
    +
     =>  +
    +  N{m.Nonce} +  {m.receipt.GasUsed}Gas + {m.receipt.ExitCode !== 0 ?  EXIT:{m.receipt.ExitCode} : } +
    + {m.receipt.ExitCode !== 0 ?
         Error: {m.Error}
    : } +
    + )) + + content = ( +
    +
    Height: {head.Height}
    +
    Parents:
    +
    Weight: {head.ParentWeight}
    +
    Miner: {
    }
    +
    Messages: {head.Messages['/']} {/*TODO: link to message explorer */}
    +
    Parent Receipts: {head.ParentMessageReceipts['/']}
    +
    + Parent State Root: {head.ParentStateRoot['/']} +  
    +  
    +  
    +  
    +  
    +
    +
    ----
    +
    {messages}
    +
    + ) + } + + return ( + {content} + ) + } +} + +export default Block \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/BlockLink.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/BlockLink.js new file mode 100644 index 0000000000..1d524999fe --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/BlockLink.js @@ -0,0 +1,41 @@ +import React from 'react'; +import Block from "./Block"; +import Address from "./Address"; + + +export class BlockLinks extends React.Component { + render() { + return this.props.cids.map((c, k) => { + let block + + if(this.props.blocks) { + block = this.props.blocks[k] + } + + return + }) + } +} + +class BlockLink extends React.Component { + constructor(props) { + super(props) + + this.openBlockViewer = this.openBlockViewer.bind(this) + } + + openBlockViewer() { + this.props.mountWindow((onClose) => ) + } + + render() { + let info = + if(this.props.block) { + info =  (by
    ) + } + + return {this.props.cid['/'].substr(-8)}{info} + } +} + +export default BlockLink \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ChainExplorer.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ChainExplorer.js new file mode 100644 index 0000000000..8957cb3d0f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ChainExplorer.js @@ -0,0 +1,178 @@ +import React from 'react'; +import {BlockLinks} from "./BlockLink"; +import Window from "./Window"; + +const rows = 32 + +class ChainExplorer extends React.Component { + fetching = [] + + constructor(props) { + super(props) + + this.update = this.update.bind(this) + this.scroll = this.scroll.bind(this) + + this.state = { + follow: true, + at: props.ts.Height, + highest: props.ts, + + cache: {[props.ts.Height]: props.ts}, + messages: {}, + } + } + + viewport() { + const base = this.state.at - this.state.at % rows + + return Array(rows).fill(0) + .map((_, k) => k + base) + .map(k => k > this.state.at ? k - rows : k) + } + + async componentDidMount() { + let msgcache = {} + await this.updateMessages(this.props.ts.Cids, msgcache) + this.setState(prev => ({messages: {...prev.messages, ...msgcache}})) + + setInterval(this.update, 1000) + } + + async updateMessages(cids, msgcache) { + const msgs = await Promise.all(cids.map(async cid => [cid['/'], await this.props.client.call('Filecoin.ChainGetParentMessages', [cid])])) + msgs.forEach(([cid, msg]) => msgcache[cid] = msg) + } + + async update() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) + if(tipset.Height > this.state.highest.Height) { + let msgcache = {} + await this.updateMessages(tipset.Cids, msgcache) + + this.setState(prev => ({highest: tipset, messages: {...prev.messages, ...msgcache}, cache: {...prev.cache, [tipset.Height]: tipset}})) + if(this.state.follow) { + this.setState({at: tipset.Height}) + } + } + + await this.fetchVisible() + } + + async fetch(h, base, cache, msgcache) { + //console.log(h, base, cache) + + if (this.fetching[h]) { + return cache[h] + } + this.fetching[h] = true + + if (h < 0) { + return + } + if(!base.Blocks) { + console.log("base for H is nil blk", h, base) + return + } + let cids = base.Blocks.map(b => (b.Parents || [])) + .reduce((acc, val) => { + let out = {...acc} + val.forEach(c => out[c['/']] = 8) + return out + }, {}) + cids = Object.keys(cids).map(k => ({'/': k})) + console.log("parents", cids) + + const blocks = await Promise.all(cids.map(cid => this.props.client.call('Filecoin.ChainGetBlock', [cid]))) + + if (!blocks[0]) { + return + } + + cache[h] = { + Height: blocks[0].Height, + Cids: cids, + Blocks: blocks, + } + + await this.updateMessages(cids, msgcache) + + return cache[h] + } + + async fetchVisible() { + await this.fetchN(this.state.at) + } + + async fetchN(top) { + if(!this.state.cache[top]) { + if(top === this.state.highest.Height) { + throw "fetchN broke (tipset not fetched)" + } + let h = top + rows > this.state.highest.Height ? this.state.highest.Height : top + rows + + await this.fetchN(h) + } + + let cache = {...this.state.cache} + let msgcache = {...this.state.messages} + + console.log("top", top) + + let parent = cache[top] + for(let i = 0; i < rows; i++) { + let newts = await this.fetch(top - i, parent, cache, msgcache) + parent = newts ? newts : parent + } + this.setState({cache: cache, messages: msgcache}) + } + + scroll(event) { + if(event.deltaY < 0 && this.state.at > 0) { + this.setState(prev => ({at: prev.at - 1, follow: false})) + } + if(event.deltaY > 0 && this.state.at < this.state.highest.Height) { + this.setState(prev => ({at: prev.at + 1, follow: prev.at + 1 === this.state.highest.Height})) + } + } + + render() { + const view = this.viewport() + + const content =
    {view.map(row => { + const base = this.state.at - this.state.at % rows + const className = row === this.state.at ? 'ChainExplorer-at' : (row < base ? 'ChainExplorer-after' : 'ChainExplorer-before') + let info = (fetching) + let h = {row} + if(this.state.cache[row]) { + const ts = this.state.cache[row] + + h = ts.Height + + let msgc = -1 + if(ts.Cids[0] && this.state.messages[ts.Cids[0]['/']]) { // TODO: get from all blks + msgc = this.state.messages[ts.Cids[0]['/']].length + } + if(msgc > 0) { + msgc = {msgc} + } + let time = '?' + if(this.state.cache[row - 1]){ + time = {ts.Blocks[0].Timestamp - this.state.cache[row - 1].Blocks[0].Timestamp}s + } + + info = + Msgs: {msgc} ΔT:{time} + + } + + return
    @{h} {info}
    + })}
    + + return ( + {content} + ) + } +} + +export default ChainExplorer \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Client.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Client.js new file mode 100644 index 0000000000..244f07bd88 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Client.js @@ -0,0 +1,228 @@ +import React from 'react' +import Address from './Address' +import Window from './Window' +import Fil from './Fil' + +const dealStates = [ + 'Unknown', + 'ProposalNotFound', + 'ProposalRejected', + 'ProposalAccepted', + 'Staged', + 'Sealing', + 'ProposalSigned', + 'Published', + 'Committed', + 'Active', + 'Failing', + 'Recovering', + 'Expired', + 'NotFound', + + 'Validating', + 'Transferring', + 'VerifyData', + 'Publishing', + 'Error' +] + +class Client extends React.Component { + constructor(props) { + super(props) + + this.state = { + miners: ['t0101'], + ask: { Price: '1000000000' }, // 2x min default ask to account for bin packing (could also do the math correctly below, but..) + + kbs: 1, + blocks: 12, + total: 36000, + miner: 't0101', + + deals: [], + + blockDelay: 10 + } + } + + async componentDidMount() { + let ver = await this.props.client.call('Filecoin.Version', []) + this.setState({ blockDelay: ver.BlockDelay }) + + this.getDeals() + setInterval(this.getDeals, 1325) + } + + getDeals = async () => { + let miners = await this.props.client.call('Filecoin.StateListMiners', [ + null + ]) + let deals = await this.props.client.call('Filecoin.ClientListDeals', []) + miners.sort() + this.setState({ deals, miners }) + } + + update = name => e => this.setState({ [name]: e.target.value }) + + makeDeal = async () => { + let perBlk = + ((this.state.ask.Price * this.state.kbs * 1000) / (1 << 30)) * 2 + + let file = await this.props.pondClient.call('Pond.CreateRandomFile', [ + this.state.kbs * 1000 + ]) // 1024 won't fit in 1k blocks :( + let cid = await this.props.client.call('Filecoin.ClientImport', [ + { + Path: file, + IsCar: false + } + ]) + let dealcid = await this.props.client.call('Filecoin.ClientStartDeal', [ + cid, + this.state.miner, + `${Math.round(perBlk)}`, + Number(this.state.blocks) + ]) + console.log('deal cid: ', dealcid) + } + + retrieve = deal => async () => { + console.log(deal) + let client = await this.props.client.call( + 'Filecoin.WalletDefaultAddress', + [] + ) + + let order = { + Root: deal.PieceRef, + Size: deal.Size, + // TODO: support offset + Total: String(deal.Size * 2), + + Client: client, + Miner: deal.Miner + } + + await this.props.client.call('Filecoin.ClientRetrieve', [ + order, + { + Path: '/dev/null', + IsCAR: false + } + ]) + } + + render() { + let perBlk = this.state.ask.Price * this.state.kbs * 1000 + let total = perBlk * this.state.blocks + let days = (this.state.blocks * this.state.blockDelay) / 60 / 60 / 24 + + let dealMaker = ( + + ) + + let deals = this.state.deals.map((deal, i) => ( +
    +
      +
    • + {i}. Proposal: {deal.ProposalCid['/'].substr(0, 18)}...{' '} +
      + : {dealStates[deal.State]} + {dealStates[deal.State] === 'Complete' ? ( + +   + + [Retrieve] + + + ) : ( + + )} +
        +
      • + Data: {deal.PieceRef['/']}, {deal.Size}B; Duration:{' '} + {deal.Duration}Blocks +
      • +
      • + Total: {deal.TotalPrice}FIL; Per Block:{' '} + + {Math.round((deal.TotalPrice / deal.Duration) * 100) / 100} + + FIL; PerMbyteByteBlock:{' '} + + {Math.round( + (deal.TotalPrice / deal.Duration / (deal.Size / 1000000)) * + 100 + ) / 100} + + FIL +
      • +
      +
    • +
    +
    + )) + + return ( + +
    +
    {dealMaker}
    +
    {deals}
    +
    +
    + ) + } +} + +export default Client diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ConnMgr.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ConnMgr.js new file mode 100644 index 0000000000..778d717f8f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/ConnMgr.js @@ -0,0 +1,126 @@ +import React from 'react'; +import Window from "./Window"; + +async function awaitReducer(prev, c) { + return {...await prev, ...await c} +} + +class ConnMgr extends React.Component { + constructor(props) { + super(props) + + this.connect = this.connect.bind(this) + this.connectAll = this.connectAll.bind(this) + this.connect1 = this.connect1.bind(this) + this.connectChain = this.connectChain.bind(this) + this.getActualState = this.getActualState.bind(this) + + this.state = {conns: {}, lock: true} + + this.getActualState() + setInterval(this.getActualState, 500) + } + + async getActualState() { + const nodes = this.props.nodes + let keys = Object.keys(nodes) + + const newConns = await keys.filter((_, i) => i > 0).filter(kfrom => this.props.nodes[kfrom].conn !== undefined).map(async (kfrom, i) => { + return keys.filter((_, j) => i >= j).filter(kto => this.props.nodes[kto].conn !== undefined).map(async kto => { + + const fromNd = this.props.nodes[kfrom] + const toNd = this.props.nodes[kto] + + const connectedness = await fromNd.conn.call('Filecoin.NetConnectedness', [toNd.peerid]) + + return {[`${kfrom},${kto}`]: connectedness === 1} + }).reduce(awaitReducer, Promise.resolve({})) + }).reduce(awaitReducer, Promise.resolve({})) + + this.setState({conns: newConns, lock: false}) + } + + async connect(action, from, to, noupdate) { + const fromNd = this.props.nodes[from] + const toNd = this.props.nodes[to] + + if (action) { + const toPeerInfo = await toNd.conn.call('Filecoin.NetAddrsListen', []) + + await fromNd.conn.call('Filecoin.NetConnect', [toPeerInfo]) + } else { + await fromNd.conn.call('Filecoin.NetDisconnect', [toNd.peerid]) + } + + if (!noupdate) + this.setState(prev => ({conns: {...prev.conns, [`${from},${to}`]: action}})) + } + + connectAll(discon) { + return () => { + const nodes = this.props.nodes + let keys = Object.keys(nodes) + + keys.filter((_, i) => i > 0).forEach((kfrom, i) => { + keys.filter((_, j) => i >= j).forEach((kto, i) => { + this.connect(!discon, kfrom, kto, true) + }) + }) + } + } + + connect1() { + const nodes = this.props.nodes + let keys = Object.keys(nodes) + + keys.filter((_, i) => i > 0).forEach((k, i) => { + this.connect(true, k, keys[0]) + }) + } + + connectChain() { + const nodes = this.props.nodes + let keys = Object.keys(nodes) + + keys.filter((_, i) => i > 0).forEach((k, i) => { + this.connect(true, k, keys[i]) + }) + } + + render() { + const nodes = this.props.nodes + let keys = Object.keys(nodes) + + const rows = keys.filter((_, i) => i > 0).map((k, i) => { + const cols = keys.filter((_, j) => i >= j).map((kt, i) => { + const checked = this.state.conns[`${k},${kt}`] === true + + return ( + + this.connect(e.target.checked, k, kt)}/> + + ) + }) + return ( + {k}{cols} + ) + }) + + return( + + + {keys.slice(0, -1).map((i) => ())} + {rows} +
    {i}
    +
    + + + + +
    +
    + ) + } +} + +export default ConnMgr \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Consensus.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Consensus.js new file mode 100644 index 0000000000..14b4dd6e21 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Consensus.js @@ -0,0 +1,69 @@ +import React from 'react'; +import {BlockLinks} from "./BlockLink"; +import Window from "./Window"; + +function styleForHDiff(max, act) { + switch (max - act) { + case 0: + return {background: '#004400'} + case 1: + return {background: '#aaaa00'} + default: + return {background: '#aa0000'} + } +} + +class Consensus extends React.Component { + constructor(props) { + super(props) + + this.state = { + maxH: -1, + tipsets: [] + } + + this.updateNodes = this.updateNodes.bind(this) + + setInterval(this.updateNodes, 333) + } + + async updateNodes() { + const nodes = this.props.nodes + let keys = Object.keys(nodes).filter(k => !nodes[k].Storage) + + const tipsets = await keys.map(async k => { + const tipset = await nodes[k].conn.call("Filecoin.ChainHead", []) + return [k, tipset] + }).reduce(async(p, i) => ([...await p, await i]), Promise.resolve([])) + + const maxH = tipsets.reduce((p, [_, i]) => Math.max(p, i.Height), -1) + + this.setState({maxH, tipsets}) + } + + render() { + return ( +
    +
    Max Height: {this.state.maxH}
    +
    + + + + + + {this.state.tipsets.map(([k, ts]) => { + return ( + + + + ) + })} + +
    NodeHeightTipSet
    {k}{ts.Height}
    +
    +
    +
    ) + } +} + +export default Consensus \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Fil.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Fil.js new file mode 100644 index 0000000000..85b26e9ec3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Fil.js @@ -0,0 +1,22 @@ +import React from "react"; + +function filStr(raw) { + if(typeof raw !== 'string') { + raw = String(raw) + } + if(raw.length < 19) { + raw = '0'.repeat(19 - raw.length).concat(raw) + } + + let out = raw.substring(0, raw.length - 18).concat('.', raw.substring(raw.length - 18, raw.length)).replace(/\.0+$|0+$/g, ''); + return out ? out : '0' +} + + +class Fil extends React.Component { + render() { + return filStr(this.props.children) + } +} + +export default Fil \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/FullNode.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/FullNode.js new file mode 100644 index 0000000000..f9ca779a59 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/FullNode.js @@ -0,0 +1,173 @@ +import React from 'react'; +import { BlockLinks } from "./BlockLink"; +import Address from "./Address"; +import ChainExplorer from "./ChainExplorer"; +import Client from "./Client"; +import Window from "./Window"; + +class FullNode extends React.Component { + constructor(props) { + super(props) + + this.state = {} + + this.loadInfo = this.loadInfo.bind(this) + this.newSecpAddr = this.newSecpAddr.bind(this) + this.newBLSAddr = this.newBLSAddr.bind(this) + this.startStorageMiner = this.startStorageMiner.bind(this) + this.explorer = this.explorer.bind(this) + this.client = this.client.bind(this) + this.stop = this.stop.bind(this) + + this.loadInfo() + let updates = setInterval(this.loadInfo, 2050) + this.props.client.on('close', () => clearInterval(updates)) + } + + async loadInfo() { + const id = await this.props.client.call("Filecoin.ID", []) + + const version = await this.props.client.call("Filecoin.Version", []) + + const peers = await this.props.client.call("Filecoin.NetPeers", []) + + const tipset = await this.props.client.call("Filecoin.ChainHead", []) + + let addrs = await this.props.client.call('Filecoin.WalletList', []) + let defaultAddr = "" + if (addrs.length > 0) { + defaultAddr = await this.props.client.call('Filecoin.WalletDefaultAddress', []) + } + let paychs = await this.props.client.call('Filecoin.PaychList', []) + if(!paychs) + paychs = [] + const vouchers = await Promise.all(paychs.map(paych => { + return this.props.client.call('Filecoin.PaychVoucherList', [paych]) + })) + + let mpoolPending = (await this.props.client.call('Filecoin.MpoolPending', [tipset.Cids])).length + + this.setState(() => ({ + id: id, + version: version, + peers: peers.length, + tipset: tipset, + + mpoolPending: mpoolPending, + + addrs: addrs, + paychs: paychs, + vouchers: vouchers, + + defaultAddr: defaultAddr, + })) + } + + async newSecpAddr() { + const t = 1 + await this.props.client.call("Filecoin.WalletNew", [t]) + this.loadInfo() + } + + async newBLSAddr() { + const t = 2 + await this.props.client.call("Filecoin.WalletNew", [t]) + this.loadInfo() + } + + startStorageMiner() { + this.props.spawnStorageNode(this.props.node.Repo, this.props.client) + } + + explorer() { + this.props.mountWindow((onClose) => ) + } + + client() { + this.props.mountWindow((onClose) => ) + } + + async stop() { + await this.props.stop() + } + + render() { + let runtime =
    + + if (this.state.id) { + let chainInfo =
    + if (this.state.tipset !== undefined) { + chainInfo = ( +
    + Head: { + + } H:{this.state.tipset.Height} Mp:{this.state.mpoolPending} [Explore] [Client] +
    + ) + } + + let storageMine = + + let addresses = this.state.addrs.map((addr) => { + let line =
    + if (this.state.defaultAddr === addr) { + line = {line} + } + return
    {line}
    + }) + let paychannels = this.state.paychs.map((addr, ak) => { + const line =
    + const vouchers = this.state.vouchers[ak].map(voucher => { + let extra = + if(voucher.Extra) { + extra = Verif: <
    > + } + + return
    + Voucher Nonce:{voucher.Nonce} Lane:{voucher.Lane} Amt:{voucher.Amount} TL:{voucher.TimeLock} MinCl:{voucher.MinCloseHeight} {extra} +
    + }) + return
    + {line} + {vouchers} +
    + }) + + runtime = ( +
    +
    {this.props.node.ID} - v{this.state.version.Version}, {this.state.id.substr(-8)}, {this.state.peers} peers
    +
    Repo: LOTUS_PATH={this.props.node.Repo}
    + {chainInfo} +
    + {storageMine} +
    +
    +
    Balances: [New [Secp256k1] [BLS]]
    +
    {addresses}
    +
    {paychannels}
    +
    + +
    + ) + } + + let nodeID = this.props.node.ID ? this.props.node.ID : '' + let nodePos = this.props.node.ID ? {x: this.props.node.ID*30, y: this.props.node.ID * 30} : 'center' + + return ( + +
    +
    + {runtime} +
    +
    +
    + ) + } +} + +export default FullNode \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Logs.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Logs.js new file mode 100644 index 0000000000..3bcf2bbaf6 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Logs.js @@ -0,0 +1,31 @@ +import React from 'react' +import { Terminal } from 'xterm'; +import { AttachAddon } from "xterm-addon-attach"; +import 'xterm/dist/xterm.css'; +import * as fit from 'xterm/lib/addons/fit/fit'; +import Window from "./Window"; + +class Logs extends React.Component { + constructor(props) { + super(props); + this.termRef = React.createRef() + this.winRef = React.createRef() + } + + async componentDidMount() { + Terminal.applyAddon(fit); + + this.terminal = new Terminal({convertEol: true, fontSize: 11}); + this.terminal.loadAddon(new AttachAddon(new WebSocket(`ws://127.0.0.1:2222/logs/${this.props.node}`), {bidirectional: false, inputUtf8: true})) + this.terminal.open(this.termRef.current) + setInterval(() => this.terminal.fit(), 200) + } + + render() { + return +
    + + } +} + +export default Logs diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeIndex.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeIndex.js new file mode 100644 index 0000000000..059d562f89 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeIndex.js @@ -0,0 +1,110 @@ +import React from 'react'; +import {Link} from "react-router-dom"; +import {Client} from "rpc-websockets"; + +class Index extends React.Component { + constructor(props) { + super(props) + + this.state = {rpcUrl: "ws://127.0.0.1:1234/rpc/v0", rpcToken: '', conns: {}, info: {}} + + const initialState = JSON.parse(window.localStorage.getItem('saved-nodes')) + if (initialState) { + this.state.nodes = initialState + } else { + this.state.nodes = [] + } + this.state.nodes.forEach((n, i) => this.connTo(i, n)) + } + + componentDidUpdate(prevProps, prevState, snapshot) { + window.localStorage.setItem('saved-nodes', JSON.stringify(this.state.nodes)) + //this.state.nodes.filter(i => [i, this.state.conns[i]]).forEach(([i, n]) => this.connTo(i, n)) + } + + componentWillUnmount() { + Object.keys(this.state.conns).forEach(c => this.state.conns[c].close()) + } + + async updateInfo(n) { + const conn = this.state.conns[n] + const head = await conn.call('Filecoin.ChainHead', []) + const peers = await conn.call('Filecoin.NetPeers', []) + + this.setState(p => ({info: {...p.info, [n]: {head, peers}}})) + } + + connTo = async (n, node) => { + const client = new Client(`${node.addr}?token=${node.token}`) + client.on('open', async () => { + this.setState(p => ({conns: {...p.conns, [n]: client}})) + setInterval(() => this.updateInfo(n), 1333) + }) + } + + onAdd = () => { + this.setState({addingNode: true}) + } + + update = (name) => (e) => this.setState({ [name]: e.target.value }) + + tokenOk = () => { + let m = this.state.rpcToken.match(/\.(.+)\./) + // TODO: eww + if(m && atob(m[1]) === '{"Allow":["read","write","sign","admin"]}') { + return ( + -Token OK- +
    + +
    +
    + ) + } + return -Expecting valid admin token- + } + + addNode = async () => { + this.setState(p => ({nodes: [...p.nodes, {addr: this.state.rpcUrl, token: this.state.rpcToken}], addingNode: true})) + } + + render() { + return ( +
    +
    +
    + { + this.state.nodes.map((node, i) => { + let info = [no conn] + if (this.state.info[i]) { + const ni = this.state.info[i] + info = H:{ni.head.Height}; Peers:{ni.peers.length} + } + + return
    + {i}. {node.addr} [OPEN UI] {info} +
    } + ) + } +
    + + +
    +
    +
    + Open Pond +
    +
    +
    + ) + } +} + +export default Index diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeList.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeList.js new file mode 100644 index 0000000000..78203929b4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/NodeList.js @@ -0,0 +1,198 @@ +import React from 'react'; +import FullNode from "./FullNode"; +import ConnMgr from "./ConnMgr"; +import Consensus from "./Consensus"; +import StorageNode from "./StorageNode"; +import {Client} from "rpc-websockets"; +import pushMessage from "./chain/send"; +import Logs from "./Logs"; +import StorageNodeInit from "./StorageNodeInit"; +import Window from "./Window"; + +const [NodeUnknown, NodeRunning, NodeStopped] = [0, 1, 2] + +class NodeList extends React.Component { + constructor(props) { + super(props) + this.state = { + existingLoaded: false, + nodes: {}, + + showConnMgr: false, + showConsensus: false, + } + + // This binding is necessary to make `this` work in the callback + this.spawnNode = this.spawnNode.bind(this) + this.spawnStorageNode = this.spawnStorageNode.bind(this) + this.connMgr = this.connMgr.bind(this) + this.consensus = this.consensus.bind(this) + this.transferNFrom1 = this.transferNFrom1.bind(this) + + this.getNodes() + } + + async mountNode(node) { + const token = await this.props.client.call('Pond.TokenFor', [node.ID]) + + const client = new Client(`ws://127.0.0.1:${node.ApiPort}/rpc/v0?token=${token}`) + client.on('open', async () => { + const id = await client.call("Filecoin.ID", []) + + this.setState(prev => ({ + nodes: { + ...prev.nodes, + [node.ID]: {...node, conn: client, peerid: id} + } + })) + + if (!node.Storage) { + this.props.mountWindow((onClose) => + ) + } else { + const fullId = await this.props.client.call('Pond.FullID', [node.ID]) + + this.props.mountWindow((onClose) => + ) + } + }) + } + + async getNodes() { + const nds = await this.props.client.call('Pond.Nodes') + const nodes = nds.reduce((o, i) => {o[i.ID] = i; return o}, {}) + console.log('nds', nodes) + + Object.keys(nodes).map(n => nodes[n]).filter(n => n.State === NodeRunning).forEach(n => this.mountNode(n)) + + this.setState({existingLoaded: true, nodes: nodes}) + } + + async transferNFrom1(to, n) { + const addrss = await this.state.nodes[1].conn.call('Filecoin.WalletList', []) + const [bestaddr, bal] = await addrss.map(async addr => { + let balance = 0 + try { + balance = await this.state.nodes[1].conn.call('Filecoin.WalletBalance', [addr]) + } catch { + balance = -1 + } + return [addr, balance] + }).reduce(async (c, n) => (await c)[1] > (await n)[1] ? await c : await n, Promise.resolve(['', -2])) + + await pushMessage(this.state.nodes[1].conn, bestaddr, { + To: to, + From: bestaddr, + Value: String(n), + }) + } + + async spawnNode() { + const node = await this.props.client.call('Pond.Spawn') + console.log(node) + await this.mountNode(node) + + this.setState(state => ({nodes: {...state.nodes, [node.ID]: node}})) + } + + async spawnStorageNode(fullRepo, fullConn) { + let nodePromise = this.props.client.call('Pond.SpawnStorage', [fullRepo]) + + this.props.mountWindow((onClose) => ) + let node = await nodePromise + await this.mountNode(node) + + //this.setState(state => ({nodes: {...state.nodes, [node.ID]: node}})) + } + + stopNode = (id, closeWindow) => async () => { + this.state.nodes[id].conn.close() + await this.props.client.call('Pond.Stop', [id]) + closeWindow() + this.setState(prev => ({ + nodes: { + ...prev.nodes, + [id]: {...(prev.nodes[id]), State: NodeStopped, conn: undefined} + } + })) + } + + startNode = (id) => async () => { + let node = await this.props.client.call('Pond.RestartNode', [Number(id)]) + await this.mountNode(node) + } + + connMgr() { + this.setState({showConnMgr: true}) + } + + consensus() { + this.setState({showConsensus: true}) + } + + render() { + let connMgr + if (this.state.showConnMgr) { + connMgr = () + } + + let consensus + if (this.state.showConsensus) { + consensus = () + } + + return ( + +
    +
    + + + +
    +
    + {Object.keys(this.state.nodes).map(n => { + const nd = this.state.nodes[n] + let type = "FULL" + if (nd.Storage) { + type = "STOR" + } + + let logs = "[logs]" + let info = "[CONNECTING..]" + if (nd.conn) { + info = {nd.peerid} + logs = this.props.mountWindow(cl => )}>[logs] + } + if (nd.State === NodeStopped) { + info = [stopped] [START] + } + + return
    + {n} {type} {logs} {info} +
    + })} +
    +
    +
    + {connMgr} + {consensus} +
    +
    + ); + } +} + +export default NodeList diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Pond.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Pond.js new file mode 100644 index 0000000000..2b58fd40d5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Pond.js @@ -0,0 +1,57 @@ +import React from 'react'; +import './App.css'; +import { Client } from 'rpc-websockets' +import NodeList from "./NodeList"; + + +class Pond extends React.Component { + constructor(props) { + super(props) + + const client = new Client('ws://127.0.0.1:2222/rpc/v0') + client.on('open', () => { + this.setState(() => ({client: client})) + }) + + this.state = { + windows: {}, + nextWindow: 0, + } + + this.mountWindow = this.mountWindow.bind(this) + } + + mountWindow(cb) { + const id = this.state.nextWindow + this.setState({nextWindow: id + 1}) + + const window = cb(() => { + this.setState(prev => ({windows: {...prev.windows, [id]: undefined}})) + }) + + this.setState(prev => ({windows: {...prev.windows, [id]: window}})) + } + + render() { + if (this.state.client === undefined) { + return ( +
    +
    +
    Connecting to Pond RPC
    +
    +
    + ) + } + + return ( +
    + +
    + {Object.keys(this.state.windows).map((w, i) =>
    {this.state.windows[w]}
    )} +
    +
    + ) + } +} + +export default Pond diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/SingleNode.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/SingleNode.js new file mode 100644 index 0000000000..a9da918f99 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/SingleNode.js @@ -0,0 +1,67 @@ +import React from 'react'; +import './App.css'; +import {Client} from "rpc-websockets"; +import FullNode from "./FullNode"; + +class SingleNode extends React.Component { + constructor(props) { + super(props) + + const nodes = JSON.parse(window.localStorage.getItem('saved-nodes')) + const node = nodes[this.props.match.params.node] + + const client = new Client(`${node.addr}?token=${node.token}`) + client.on('open', async () => { + this.setState(() => ({client: client})) + }) + + this.state = { + windows: {}, + nextWindow: 0, + + addr: node.addr + } + } + + mountWindow = (cb) => { + const id = this.state.nextWindow + this.setState({nextWindow: id + 1}) + + const window = cb(() => { + this.setState(prev => ({windows: {...prev.windows, [id]: undefined}})) + }) + + this.setState(prev => ({windows: {...prev.windows, [id]: window}})) + } + + render() { + if (this.state.client === undefined) { + return ( +
    +
    +
    Connecting to Node RPC:
    +
    {`${this.state.addr}?token=****`}
    +
    +
    + ) + } + + let node = + + return ( +
    + {node} +
    + {Object.keys(this.state.windows).map((w, i) =>
    {this.state.windows[w]}
    )} +
    +
    + ) + } +} + +export default SingleNode; diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/State.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/State.js new file mode 100644 index 0000000000..ade42f2e5e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/State.js @@ -0,0 +1,209 @@ +import React from 'react' +import Window from "./Window"; +import CID from "cids"; +import * as multihash from "multihashes"; +import code from "./chain/code"; +import Address from "./Address"; +import Fil from "./Fil"; + +class State extends React.Component { + byCode = { + [code.init]: InitState, + [code.power]: PowerState, + [code.market]: MarketState, + [code.miner]: MinerState, + } + + constructor(props) { + super(props) + + this.state = {Balance: -2, State: {}} + } + + async componentDidMount() { + const tipset = this.props.tipset || await this.props.client.call("Filecoin.ChainHead", []) + const actstate = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset.Cids]) + + const c = new CID(this.props.actor.Code['/']) + const mh = multihash.decode(c.multihash) + let code = mh.digest.toString() + + this.setState({...actstate, code: code}) + } + + render() { + let state + if(this.byCode[this.state.code]) { + const Stelem = this.byCode[this.state.code] + state = + } else { + state =
    {Object.keys(this.state.State || {}).map(k =>
    {k}: {JSON.stringify(this.state.State[k])}
    )}
    + } + + const content =
    +
    Balance: {this.state.Balance}
    +
    ---
    + {state} +
    + return + {content} + + } +} + +class InitState extends React.Component { + constructor(props) { + super(props) + + this.state = {actors: []} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + const actors = await this.props.client.call("Filecoin.StateListActors", [tipset.Cids]) + this.setState({actors: actors}) + } + + render() { + return this.state.actors.sort((a, b) => (Number(a.substr(1)) > Number(b.substr(1)))) + .map(addr =>
    ) + } +} + +class PowerState extends React.Component { + constructor(props) { + super(props) + + this.state = {actors: [], state: {State: {}}} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + const actors = await this.props.client.call("Filecoin.StateListMiners", [tipset.Cids]) + const state = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset.Cids]) + + this.setState({actors, state}) + } + + render() { + return
    +
    +
    Total Power: {this.state.state.State.TotalStorage}
    +
    +
    ---
    +
    {this.state.actors.sort((a, b) => (Number(a.substr(1)) > Number(b.substr(1)))) + .map(addr =>
    )}
    +
    + } +} + +class MarketState extends React.Component { + constructor(props) { + super(props) + this.state = {participants: {}, deals: []} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + const participants = await this.props.client.call("Filecoin.StateMarketParticipants", [tipset.Cids]) + const deals = await this.props.client.call("Filecoin.StateMarketDeals", [tipset.Cids]) + const state = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset.Cids]) + this.setState({participants, deals, nextDeal: state.State.NextDealID}) + } + + render() { + return
    +
    +
    Participants:
    + + + {Object.keys(this.state.participants).map(p => + + + + )} +
    AddressAvailableLocked
    {this.state.participants[p].Available}{this.state.participants[p].Locked}
    +
    +
    +
    ---
    +
    Deals ({this.state.nextDeal} Total):
    + + + {Object.keys(this.state.deals).map(d => + + + + + + + + )} +
    idStartedClientProviderSizePriceDuration
    {d}{this.state.deals[d].State.SectorStartEpoch || "No"}
    {this.state.deals[d].Proposal.PieceSize}B{this.state.deals[d].Proposal.StoragePricePerEpoch*(this.state.deals[d].Proposal.EndEpoch-this.state.deals[d].Proposal.StartEpoch)}{this.state.deals[d].Proposal.EndEpoch-this.state.deals[d].Proposal.StartEpoch}
    +
    +
    + } +} + +class MinerState extends React.Component { + constructor(props) { + super(props) + this.state = {state: {}, sectorSize: -1, worker: "", networkPower: 0, sectors: {}} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + + const state = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset.Cids]) + const sectorSize = await this.props.client.call("Filecoin.StateMinerSectorSize", [this.props.addr, tipset.Cids]) + const worker = await this.props.client.call("Filecoin.StateMinerWorker", [this.props.addr, tipset.Cids]) + + const tpow = await this.props.client.call("Filecoin.StateMinerPower", [this.props.addr, tipset.Cids]) + const networkPower = tpow.TotalPower + + let sectors = {} + + const sset = await this.props.client.call("Filecoin.StateMinerSectors", [this.props.addr, tipset.Cids]) || [] + const pset = await this.props.client.call("Filecoin.StateMinerProvingSet", [this.props.addr, tipset.Cids]) || [] + + sset.forEach(s => sectors[s.SectorID] = {...s, sectorSet: true}) + pset.forEach(s => sectors[s.SectorID] = {...(sectors[s.SectorID] || s), provingSet: true}) + + this.setState({state, sectorSize, worker, networkPower, sectors}) + } + + render() { + if (!this.state.worker) { + return (...) + } + + let state = this.state.state.State + + return
    +
    Worker:
    +
    Sector Size: {this.state.sectorSize/1024} KiB
    +
    Power: todoPower ({1/this.state.networkPower*100}%)
    +
    Election Period Start: {state.ElectionPeriodStart}
    +
    Slashed: {state.SlashedAt === 0 ? "NO" : state.SlashedAt}
    +
    +
    ----
    +
    Sectors:
    + + + + + + {Object.keys(this.state.sectors).map(sid => + + + + + + )} + +
    IDCommDCommRSectorSetProving
    {sid}{this.state.sectors[sid].CommD}{this.state.sectors[sid].CommR}{this.state.sectors[sid].sectorSet ? 'X' : ' '}{this.state.sectors[sid].provingSet ? 'X' : ' '}
    +
    +
    + } +} + +export default State \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNode.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNode.js new file mode 100644 index 0000000000..c4895c2ea2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNode.js @@ -0,0 +1,162 @@ +import React from 'react'; +import { Client } from 'rpc-websockets' +import Address from "./Address"; +import Window from "./Window"; + +const stateConnected = 'connected' +const stateConnecting = 'connecting' +const stateGettingToken = 'getting-token' + +let sealCodes = [ + "UndefinedSectorState", + "Empty", + "Packing", + "Unsealed", + "PreCommitting", + "WaitSeed", + "Committing", + "CommitWait", + "FinalizeSector", + "Proving", + + "SealFailed", + "PreCommitFailed", + "SealCommitFailed", + "CommitFailed", + "PackingFailed", + + "FailedUnrecoverable", + "Faulty", + "FaultReported", + "FaultedFinal", +] + +class StorageNode extends React.Component { + constructor(props) { + super(props) + + this.state = { + state: stateGettingToken, + id: "~", + + mining: false, + + statusCounts: [0, 0, 0, 0, 0] + } + + this.loadInfo = this.loadInfo.bind(this) + this.pledgeSector = this.pledgeSector.bind(this) + this.stop = this.stop.bind(this) + + this.connect() + } + + async connect() { + const token = await this.props.pondClient.call('Pond.TokenFor', [this.props.node.ID]) + + this.setState(() => ({ + state: stateConnecting, + token: token, + })) + + const client = new Client(`ws://127.0.0.1:${this.props.node.ApiPort}/rpc/v0?token=${token}`) + client.on('open', async () => { + this.setState(() => ({ + state: stateConnected, + client: client, + + version: {Version: "~version~"}, + id: "~peerid~", + peers: -1, + balances: [] + })) + + const id = await this.state.client.call("Filecoin.ID", []) + this.setState(() => ({id: id})) + + // this.props.onConnect(client, id) // TODO: dedupe connecting part + + let updates = setInterval(this.loadInfo, 1050) + client.on('close', () => clearInterval(updates)) + }) + + console.log(token) // todo: use + } + + async loadInfo() { + const version = await this.state.client.call("Filecoin.Version", []) + const peers = await this.state.client.call("Filecoin.NetPeers", []) + const actor = await this.state.client.call("Filecoin.ActorAddress", []) + + const stActor = await this.props.fullConn.call('Filecoin.StateGetActor', [actor, null]) + const actorState = await this.props.fullConn.call('Filecoin.StateReadState', [stActor, null]) + + this.setState({version: version, peers: peers.length, actor: actor, actorState: actorState}) + await this.stagedList() + } + + async stagedList() { + let stagedList = await this.state.client.call("Filecoin.SectorsList", []) + let staged = await stagedList + .map(sector => this.state.client.call("Filecoin.SectorsStatus", [sector])) + .reduce(async (p, n) => [...await p, await n], Promise.resolve([])) + + let statusCounts = staged.reduce((p, n) => p.map((e, i) => e + (i === n.State ? 1 : 0) ), [0, 0, 0, 0, 0]) + + this.setState({staged, statusCounts}) + } + + async pledgeSector() { + await this.state.client.call("Filecoin.PledgeSector", []) + } + + sealStaged = async () => { + await this.state.client.call("Filecoin.SectorsStagedSeal", []) + } + + async stop() { + await this.props.stop() + } + + render() { + let runtime =
    + if (this.state.actor) { + const pledgeSector = [Pledge Sector] + const sealStaged = [Seal Staged] + + runtime = ( +
    +
    v{this.state.version.Version}, {this.state.id.substr(-8)}, {this.state.peers} peers
    +
    Repo: LOTUS_STORAGE_PATH={this.props.node.Repo}
    +
    + {pledgeSector} {sealStaged} +
    +
    +
    +  EPS: {this.state.actorState.State.ElectionPeriodStart} +
    +
    {this.state.statusCounts.map((c, i) => {sealCodes[i]}: {c} | )}
    +
    + {this.state.staged ? this.state.staged.map((s, i) => ( +
    {s.SectorID} {sealCodes[s.State] || `unk ${s.State}`}
    + )) :
    } +
    + +
    + ) + } + + return +
    +
    + {runtime} +
    +
    +
    + } +} + +export default StorageNode \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNodeInit.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNodeInit.js new file mode 100644 index 0000000000..bd9d5390ab --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/StorageNodeInit.js @@ -0,0 +1,25 @@ +import React from 'react'; +import Window from "./Window"; + +class StorageNodeInit extends React.Component { + async componentDidMount() { + const info = await this.props.node + + this.props.onClose() + //this.props.mountWindow((onClose) => ) + } + + render() { + return +
    +
    + Waiting for init, make sure at least one miner is enabled +
    +
    +
    + } +} + +export default StorageNodeInit \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Window.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Window.js new file mode 100644 index 0000000000..b3dd4340f1 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/Window.js @@ -0,0 +1,15 @@ +import React from 'react' +import {Cristal} from "react-cristal"; + +class Window extends React.Component { + render() { + let props = {className: '', ...this.props} + props.className = `${props.className} Window` + + return + {this.props.children} + + } +} + +export default Window diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/code.json b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/code.json new file mode 100644 index 0000000000..098b402448 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/code.json @@ -0,0 +1,13 @@ +{ + "account": "fil/1/account", + "cron": "fil/1/cron", + "init": "fil/1/init", + "market": "fil/1/storagemarket", + "miner": "fil/1/storageminer", + "multisig": "fil/1/multisig", + "paych": "fil/1/paymentchannel", + "power": "fil/1/storagepower", + "reward": "fil/1/reward", + "system": "fil/1/system", + "verifreg": "fil/1/verifiedregistry" +} \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methodgen.go b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methodgen.go new file mode 100644 index 0000000000..3197803fe8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methodgen.go @@ -0,0 +1,85 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "os" + "reflect" + + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" + + "github.com/filecoin-project/specs-actors/actors/builtin" +) + +func main() { + if _, err := os.Stat("code.json"); err != nil { + panic(err) // note: must run in lotuspond/front/src/chain + } + + names := map[string]string{ + "system": "fil/1/system", + "init": "fil/1/init", + "cron": "fil/1/cron", + "account": "fil/1/account", + "power": "fil/1/storagepower", + "miner": "fil/1/storageminer", + "market": "fil/1/storagemarket", + "paych": "fil/1/paymentchannel", + "multisig": "fil/1/multisig", + "reward": "fil/1/reward", + "verifreg": "fil/1/verifiedregistry", + } + + { + b, err := json.MarshalIndent(names, "", " ") + if err != nil { + panic(err) + } + + if err := ioutil.WriteFile("code.json", b, 0664); err != nil { + panic(err) + } + } + + methods := map[cid.Cid]interface{}{ + // builtin.SystemActorCodeID: builtin.MethodsSystem - apparently it doesn't have methods + builtin.InitActorCodeID: builtin.MethodsInit, + builtin.CronActorCodeID: builtin.MethodsCron, + builtin.AccountActorCodeID: builtin.MethodsAccount, + builtin.StoragePowerActorCodeID: builtin.MethodsPower, + builtin.StorageMinerActorCodeID: builtin.MethodsMiner, + builtin.StorageMarketActorCodeID: builtin.MethodsMarket, + builtin.PaymentChannelActorCodeID: builtin.MethodsPaych, + builtin.MultisigActorCodeID: builtin.MethodsMultisig, + builtin.RewardActorCodeID: builtin.MethodsReward, + builtin.VerifiedRegistryActorCodeID: builtin.MethodsVerifiedRegistry, + } + + out := map[string][]string{} + for c, methods := range methods { + cmh, err := multihash.Decode(c.Hash()) + if err != nil { + panic(err) + } + + rt := reflect.TypeOf(methods) + nf := rt.NumField() + + out[string(cmh.Digest)] = append(out[string(cmh.Digest)], "Send") + for i := 0; i < nf; i++ { + out[string(cmh.Digest)] = append(out[string(cmh.Digest)], rt.Field(i).Name) + } + } + + { + b, err := json.MarshalIndent(out, "", " ") + if err != nil { + panic(err) + } + + if err := ioutil.WriteFile("methods.json", b, 0664); err != nil { + panic(err) + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methods.json b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methods.json new file mode 100644 index 0000000000..0d06587162 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/methods.json @@ -0,0 +1,98 @@ +{ + "fil/1/account": [ + "Send", + "Constructor", + "PubkeyAddress" + ], + "fil/1/cron": [ + "Send", + "Constructor", + "EpochTick" + ], + "fil/1/init": [ + "Send", + "Constructor", + "Exec" + ], + "fil/1/multisig": [ + "Send", + "Constructor", + "Propose", + "Approve", + "Cancel", + "AddSigner", + "RemoveSigner", + "SwapSigner", + "ChangeNumApprovalsThreshold" + ], + "fil/1/paymentchannel": [ + "Send", + "Constructor", + "UpdateChannelState", + "Settle", + "Collect" + ], + "fil/1/reward": [ + "Send", + "Constructor", + "AwardBlockReward", + "LastPerEpochReward", + "UpdateNetworkKPI" + ], + "fil/1/storagemarket": [ + "Send", + "Constructor", + "AddBalance", + "WithdrawBalance", + "PublishStorageDeals", + "VerifyDealsOnSectorProveCommit", + "OnMinerSectorsTerminate", + "ComputeDataCommitment", + "CronTick" + ], + "fil/1/storageminer": [ + "Send", + "Constructor", + "ControlAddresses", + "ChangeWorkerAddress", + "ChangePeerID", + "SubmitWindowedPoSt", + "PreCommitSector", + "ProveCommitSector", + "ExtendSectorExpiration", + "TerminateSectors", + "DeclareFaults", + "DeclareFaultsRecovered", + "OnDeferredCronEvent", + "CheckSectorProven", + "AddLockedFund", + "ReportConsensusFault", + "WithdrawBalance", + "ConfirmSectorProofsValid" + ], + "fil/1/storagepower": [ + "Send", + "Constructor", + "CreateMiner", + "DeleteMiner", + "OnSectorProveCommit", + "OnSectorTerminate", + "OnFaultBegin", + "OnFaultEnd", + "OnSectorModifyWeightDesc", + "EnrollCronEvent", + "OnEpochTickEnd", + "UpdatePledgeTotal", + "OnConsensusFault", + "SubmitPoRepForBulkVerify" + ], + "fil/1/verifiedregistry": [ + "Send", + "Constructor", + "AddVerifier", + "RemoveVerifier", + "AddVerifiedClient", + "UseBytes", + "RestoreBytes" + ] +} \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/send.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/send.js new file mode 100644 index 0000000000..9011aca5e4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/chain/send.js @@ -0,0 +1,42 @@ +import util from 'ipld-dag-cbor' +import { Buffer } from 'buffer' +import { Tagged } from 'borc' + +async function pushMessage(client, from, inmsg) { + if(!inmsg.GasLimit) { + inmsg.GasLimit = "10000" + } + if(!inmsg.GasPrice) { + inmsg.GasPrice = "0" + } + if(!inmsg.Params) { + inmsg.Params = "oA==" // 0b101_00000: empty cbor map: {} + } + if(!inmsg.Value) { + inmsg.Value = "0" + } + if(!inmsg.Method) { + inmsg.Method = 0 + } + +/* const msg = [ + inmsg.To, + inmsg.From, + + inmsg.Nonce, + + inmsg.Value, + + inmsg.GasPrice, + inmsg.GasLimit, + + inmsg.Method, + Buffer.from(inmsg.Params, 'base64'), + ]*/ + + console.log(inmsg) + + await client.call('Filecoin.MpoolPushMessage', [inmsg]) +} + +export default pushMessage diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.css b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.css new file mode 100644 index 0000000000..82ecd1213d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.css @@ -0,0 +1,18 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} + +input[type=text] { + -webkit-appearance: none; + appearance: none; +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.js b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.js new file mode 100644 index 0000000000..395b74997b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/front/src/index.js @@ -0,0 +1,6 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/main.go b/vendor/github.com/filecoin-project/lotus/lotuspond/main.go new file mode 100644 index 0000000000..fee36d86aa --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/main.go @@ -0,0 +1,162 @@ +package main + +import ( + "fmt" + "net/http" + "os" + "os/exec" + "path" + "strconv" + + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-jsonrpc" +) + +const listenAddr = "127.0.0.1:2222" + +type runningNode struct { + cmd *exec.Cmd + meta nodeInfo + + mux *outmux + stop func() +} + +var onCmd = &cli.Command{ + Name: "on", + Usage: "run a command on a given node", + Action: func(cctx *cli.Context) error { + client, err := apiClient() + if err != nil { + return err + } + + nd, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32) + if err != nil { + return err + } + + node := nodeByID(client.Nodes(), int(nd)) + var cmd *exec.Cmd + if !node.Storage { + cmd = exec.Command("./lotus", cctx.Args().Slice()[1:]...) + cmd.Env = []string{ + "LOTUS_PATH=" + node.Repo, + } + } else { + cmd = exec.Command("./lotus-storage-miner") + cmd.Env = []string{ + "LOTUS_STORAGE_PATH=" + node.Repo, + "LOTUS_PATH=" + node.FullNode, + } + } + + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + err = cmd.Run() + return err + }, +} + +var shCmd = &cli.Command{ + Name: "sh", + Usage: "spawn shell with node shell variables set", + Action: func(cctx *cli.Context) error { + client, err := apiClient() + if err != nil { + return err + } + + nd, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32) + if err != nil { + return err + } + + node := nodeByID(client.Nodes(), int(nd)) + shcmd := exec.Command("/bin/bash") + if !node.Storage { + shcmd.Env = []string{ + "LOTUS_PATH=" + node.Repo, + } + } else { + shcmd.Env = []string{ + "LOTUS_STORAGE_PATH=" + node.Repo, + "LOTUS_PATH=" + node.FullNode, + } + } + + shcmd.Env = append(os.Environ(), shcmd.Env...) + + shcmd.Stdin = os.Stdin + shcmd.Stdout = os.Stdout + shcmd.Stderr = os.Stderr + + fmt.Printf("Entering shell for Node %d\n", nd) + err = shcmd.Run() + fmt.Printf("Closed pond shell\n") + + return err + }, +} + +func nodeByID(nodes []nodeInfo, i int) nodeInfo { + for _, n := range nodes { + if n.ID == int32(i) { + return n + } + } + panic("no node with this id") +} + +func logHandler(api *api) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, req *http.Request) { + id, err := strconv.ParseInt(path.Base(req.URL.Path), 10, 32) + if err != nil { + panic(err) + } + + api.runningLk.Lock() + n := api.running[int32(id)] + api.runningLk.Unlock() + + n.mux.ServeHTTP(w, req) + } +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "run lotuspond daemon", + Action: func(cctx *cli.Context) error { + rpcServer := jsonrpc.NewServer() + a := &api{running: map[int32]*runningNode{}} + rpcServer.Register("Pond", a) + + http.Handle("/", http.FileServer(http.Dir("lotuspond/front/build"))) + http.HandleFunc("/app/", func(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, "lotuspond/front/build/index.html") + }) + + http.Handle("/rpc/v0", rpcServer) + http.HandleFunc("/logs/", logHandler(a)) + + fmt.Printf("Listening on http://%s\n", listenAddr) + return http.ListenAndServe(listenAddr, nil) + }, +} + +func main() { + app := &cli.App{ + Name: "pond", + Commands: []*cli.Command{ + runCmd, + shCmd, + onCmd, + }, + } + if err := app.Run(os.Args); err != nil { + panic(err) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/outmux.go b/vendor/github.com/filecoin-project/lotus/lotuspond/outmux.go new file mode 100644 index 0000000000..4060010782 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/outmux.go @@ -0,0 +1,127 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "net/http" + "strings" + + "github.com/gorilla/websocket" + "github.com/opentracing/opentracing-go/log" +) + +type outmux struct { + errpw *io.PipeWriter + outpw *io.PipeWriter + + errpr *io.PipeReader + outpr *io.PipeReader + + n uint64 + outs map[uint64]*websocket.Conn + + new chan *websocket.Conn + stop chan struct{} +} + +func newWsMux() *outmux { + out := &outmux{ + n: 0, + outs: map[uint64]*websocket.Conn{}, + new: make(chan *websocket.Conn), + stop: make(chan struct{}), + } + + out.outpr, out.outpw = io.Pipe() + out.errpr, out.errpw = io.Pipe() + + go out.run() + + return out +} + +func (m *outmux) msgsToChan(r *io.PipeReader, ch chan []byte) { + defer close(ch) + br := bufio.NewReader(r) + + for { + buf, _, err := br.ReadLine() + if err != nil { + return + } + out := make([]byte, len(buf)+1) + copy(out, buf) + out[len(out)-1] = '\n' + + select { + case ch <- out: + case <-m.stop: + return + } + } +} + +func (m *outmux) run() { + stdout := make(chan []byte) + stderr := make(chan []byte) + go m.msgsToChan(m.outpr, stdout) + go m.msgsToChan(m.errpr, stderr) + + for { + select { + case msg := <-stdout: + for k, out := range m.outs { + if err := out.WriteMessage(websocket.BinaryMessage, msg); err != nil { + out.Close() + fmt.Printf("outmux write failed: %s\n", err) + delete(m.outs, k) + } + } + case msg := <-stderr: + for k, out := range m.outs { + if err := out.WriteMessage(websocket.BinaryMessage, msg); err != nil { + out.Close() + fmt.Printf("outmux write failed: %s\n", err) + delete(m.outs, k) + } + } + case c := <-m.new: + m.n++ + m.outs[m.n] = c + case <-m.stop: + for _, out := range m.outs { + out.Close() + } + return + } + } +} + +var upgrader = websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func (m *outmux) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if !strings.Contains(r.Header.Get("Connection"), "Upgrade") { + fmt.Println("noupgrade") + w.WriteHeader(500) + return + } + + w.Header().Set("Access-Control-Allow-Origin", "*") + if r.Header.Get("Sec-WebSocket-Protocol") != "" { + w.Header().Set("Sec-WebSocket-Protocol", r.Header.Get("Sec-WebSocket-Protocol")) + } + + c, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Error(err) + w.WriteHeader(500) + return + } + + m.new <- c +} diff --git a/vendor/github.com/filecoin-project/lotus/lotuspond/spawn.go b/vendor/github.com/filecoin-project/lotus/lotuspond/spawn.go new file mode 100644 index 0000000000..ef0ebaeabb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/lotuspond/spawn.go @@ -0,0 +1,285 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "sync/atomic" + "time" + + "github.com/filecoin-project/lotus/chain/types" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" + "github.com/filecoin-project/lotus/genesis" +) + +func init() { + miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ + abi.RegisteredSealProof_StackedDrg2KiBV1: {}, + } +} + +func (api *api) Spawn() (nodeInfo, error) { + dir, err := ioutil.TempDir(os.TempDir(), "lotus-") + if err != nil { + return nodeInfo{}, err + } + + params := []string{"daemon", "--bootstrap=false"} + genParam := "--genesis=" + api.genesis + + id := atomic.AddInt32(&api.cmds, 1) + if id == 1 { + // preseal + + genMiner, err := address.NewIDAddress(genesis2.MinerStart) + if err != nil { + return nodeInfo{}, err + } + + sbroot := filepath.Join(dir, "preseal") + genm, ki, err := seed.PreSeal(genMiner, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, 2, sbroot, []byte("8"), nil, false) + if err != nil { + return nodeInfo{}, xerrors.Errorf("preseal failed: %w", err) + } + + if err := seed.WriteGenesisMiner(genMiner, sbroot, genm, ki); err != nil { + return nodeInfo{}, xerrors.Errorf("failed to write genminer info: %w", err) + } + params = append(params, "--import-key="+filepath.Join(dir, "preseal", "pre-seal-t01000.key")) + params = append(params, "--genesis-template="+filepath.Join(dir, "preseal", "genesis-template.json")) + + // Create template + + var template genesis.Template + template.Miners = append(template.Miners, *genm) + template.Accounts = append(template.Accounts, genesis.Actor{ + Type: genesis.TAccount, + Balance: types.FromFil(5000000), + Meta: (&genesis.AccountMeta{Owner: genm.Owner}).ActorMeta(), + }) + + tb, err := json.Marshal(&template) + if err != nil { + return nodeInfo{}, xerrors.Errorf("marshal genesis template: %w", err) + } + + if err := ioutil.WriteFile(filepath.Join(dir, "preseal", "genesis-template.json"), tb, 0664); err != nil { + return nodeInfo{}, xerrors.Errorf("write genesis template: %w", err) + } + + // make genesis + genf, err := ioutil.TempFile(os.TempDir(), "lotus-genesis-") + if err != nil { + return nodeInfo{}, err + } + + api.genesis = genf.Name() + genParam = "--lotus-make-genesis=" + api.genesis + + if err := genf.Close(); err != nil { + return nodeInfo{}, err + } + + } + + errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nodeInfo{}, err + } + logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nodeInfo{}, err + } + + mux := newWsMux() + confStr := fmt.Sprintf("[API]\nListenAddress = \"/ip4/127.0.0.1/tcp/%d/http\"\n", 2500+id) + + err = ioutil.WriteFile(filepath.Join(dir, "config.toml"), []byte(confStr), 0700) + if err != nil { + return nodeInfo{}, err + } + + cmd := exec.Command("./lotus", append(params, genParam)...) + + cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw) + cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw) + cmd.Env = append(os.Environ(), "LOTUS_PATH="+dir) + if err := cmd.Start(); err != nil { + return nodeInfo{}, err + } + + info := nodeInfo{ + Repo: dir, + ID: id, + APIPort: 2500 + id, + State: NodeRunning, + } + + api.runningLk.Lock() + api.running[id] = &runningNode{ + cmd: cmd, + meta: info, + + mux: mux, + stop: func() { + cmd.Process.Signal(os.Interrupt) + cmd.Process.Wait() + + api.runningLk.Lock() + api.running[id].meta.State = NodeStopped + api.runningLk.Unlock() + + //logfile.Close() + //errlogfile.Close() + + //close(mux.stop) + }, + } + api.runningLk.Unlock() + + time.Sleep(time.Millisecond * 750) // TODO: Something less terrible + + return info, nil +} + +func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) { + dir, err := ioutil.TempDir(os.TempDir(), "lotus-storage-") + if err != nil { + return nodeInfo{}, err + } + + errlogfile, err := os.OpenFile(dir+".err.log", os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nodeInfo{}, err + } + logfile, err := os.OpenFile(dir+".out.log", os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nodeInfo{}, err + } + + initArgs := []string{"init", "--nosync"} + if fullNodeRepo == api.running[1].meta.Repo { + presealPrefix := filepath.Join(fullNodeRepo, "preseal") + initArgs = []string{"init", "--actor=t01000", "--genesis-miner", "--pre-sealed-sectors=" + presealPrefix, "--pre-sealed-metadata=" + filepath.Join(presealPrefix, "pre-seal-t01000.json")} + } + + id := atomic.AddInt32(&api.cmds, 1) + cmd := exec.Command("./lotus-storage-miner", initArgs...) + cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile) + cmd.Stdout = io.MultiWriter(os.Stdout, logfile) + cmd.Env = append(os.Environ(), "LOTUS_STORAGE_PATH="+dir, "LOTUS_PATH="+fullNodeRepo) + if err := cmd.Run(); err != nil { + return nodeInfo{}, err + } + + time.Sleep(time.Millisecond * 300) + + mux := newWsMux() + + cmd = exec.Command("./lotus-storage-miner", "run", "--api", fmt.Sprintf("%d", 2500+id), "--nosync") + cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw) + cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw) + cmd.Env = append(os.Environ(), "LOTUS_STORAGE_PATH="+dir, "LOTUS_PATH="+fullNodeRepo) + if err := cmd.Start(); err != nil { + return nodeInfo{}, err + } + + info := nodeInfo{ + Repo: dir, + ID: id, + APIPort: 2500 + id, + State: NodeRunning, + + FullNode: fullNodeRepo, + Storage: true, + } + + api.runningLk.Lock() + api.running[id] = &runningNode{ + cmd: cmd, + meta: info, + + mux: mux, + stop: func() { + cmd.Process.Signal(os.Interrupt) + cmd.Process.Wait() + + api.runningLk.Lock() + api.running[id].meta.State = NodeStopped + api.runningLk.Unlock() + + //logfile.Close() + //errlogfile.Close() + + //close(mux.stop) + }, + } + api.runningLk.Unlock() + + time.Sleep(time.Millisecond * 750) // TODO: Something less terrible + + return info, nil +} + +func (api *api) RestartNode(id int32) (nodeInfo, error) { + api.runningLk.Lock() + defer api.runningLk.Unlock() + nd, ok := api.running[id] + + if !ok { + return nodeInfo{}, xerrors.New("node not found") + } + + if nd.meta.State != NodeStopped { + return nodeInfo{}, xerrors.New("node not stopped") + } + + var cmd *exec.Cmd + if nd.meta.Storage { + cmd = exec.Command("./lotus-storage-miner", "run", "--api", fmt.Sprintf("%d", 2500+id), "--nosync") + } else { + cmd = exec.Command("./lotus", "daemon", "--api", fmt.Sprintf("%d", 2500+id)) + } + + cmd.Stderr = nd.cmd.Stderr // recycle old vars + cmd.Stdout = nd.cmd.Stdout + cmd.Env = nd.cmd.Env + + if err := cmd.Start(); err != nil { + return nodeInfo{}, err + } + + nd.cmd = cmd + + nd.stop = func() { + cmd.Process.Signal(os.Interrupt) + cmd.Process.Wait() + + api.runningLk.Lock() + api.running[id].meta.State = NodeStopped + api.runningLk.Unlock() + + //logfile.Close() + //errlogfile.Close() + + //close(mux.stop) + } + + nd.meta.State = NodeRunning + + time.Sleep(time.Millisecond * 750) // TODO: Something less terrible + + return nd.meta, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/client.go b/vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/client.go new file mode 100644 index 0000000000..709254d494 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/client.go @@ -0,0 +1,101 @@ +package retrievaladapter + +import ( + "bytes" + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-fil-markets/shared" + "github.com/filecoin-project/specs-actors/actors/abi" + initactor "github.com/filecoin-project/specs-actors/actors/builtin/init" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/node/impl/full" + payapi "github.com/filecoin-project/lotus/node/impl/paych" + "github.com/filecoin-project/lotus/paychmgr" +) + +type retrievalClientNode struct { + chainapi full.ChainAPI + pmgr *paychmgr.Manager + payapi payapi.PaychAPI +} + +// NewRetrievalClientNode returns a new node adapter for a retrieval client that talks to the +// Lotus Node +func NewRetrievalClientNode(pmgr *paychmgr.Manager, payapi payapi.PaychAPI, chainapi full.ChainAPI) retrievalmarket.RetrievalClientNode { + return &retrievalClientNode{pmgr: pmgr, payapi: payapi, chainapi: chainapi} +} + +// GetOrCreatePaymentChannel sets up a new payment channel if one does not exist +// between a client and a miner and ensures the client has the given amount of +// funds available in the channel. +func (rcn *retrievalClientNode) GetOrCreatePaymentChannel(ctx context.Context, clientAddress address.Address, minerAddress address.Address, clientFundsAvailable abi.TokenAmount, tok shared.TipSetToken) (address.Address, cid.Cid, error) { + // TODO: respect the provided TipSetToken (a serialized TipSetKey) when + // querying the chain + return rcn.pmgr.GetPaych(ctx, clientAddress, minerAddress, clientFundsAvailable) +} + +// Allocate late creates a lane within a payment channel so that calls to +// CreatePaymentVoucher will automatically make vouchers only for the difference +// in total +func (rcn *retrievalClientNode) AllocateLane(paymentChannel address.Address) (uint64, error) { + return rcn.pmgr.AllocateLane(paymentChannel) +} + +// CreatePaymentVoucher creates a new payment voucher in the given lane for a +// given payment channel so that all the payment vouchers in the lane add up +// to the given amount (so the payment voucher will be for the difference) +func (rcn *retrievalClientNode) CreatePaymentVoucher(ctx context.Context, paymentChannel address.Address, amount abi.TokenAmount, lane uint64, tok shared.TipSetToken) (*paych.SignedVoucher, error) { + // TODO: respect the provided TipSetToken (a serialized TipSetKey) when + // querying the chain + voucher, err := rcn.payapi.PaychVoucherCreate(ctx, paymentChannel, amount, lane) + if err != nil { + return nil, err + } + return voucher, nil +} + +func (rcn *retrievalClientNode) GetChainHead(ctx context.Context) (shared.TipSetToken, abi.ChainEpoch, error) { + head, err := rcn.chainapi.ChainHead(ctx) + if err != nil { + return nil, 0, err + } + + return head.Key().Bytes(), head.Height(), nil +} + +// WaitForPaymentChannelAddFunds waits messageCID to appear on chain. If it doesn't appear within +// defaultMsgWaitTimeout it returns error +func (rcn *retrievalClientNode) WaitForPaymentChannelAddFunds(messageCID cid.Cid) error { + _, mr, err := rcn.chainapi.StateManager.WaitForMessage(context.TODO(), messageCID, build.MessageConfidence) + + if err != nil { + return err + } + if mr.ExitCode != exitcode.Ok { + return xerrors.Errorf("wait for payment channel to add funds failed. exit code: %d", mr.ExitCode) + } + return nil +} + +func (rcn *retrievalClientNode) WaitForPaymentChannelCreation(messageCID cid.Cid) (address.Address, error) { + _, mr, err := rcn.chainapi.StateManager.WaitForMessage(context.TODO(), messageCID, build.MessageConfidence) + + if err != nil { + return address.Undef, err + } + if mr.ExitCode != exitcode.Ok { + return address.Undef, xerrors.Errorf("payment channel creation failed. exit code: %d", mr.ExitCode) + } + var retval initactor.ExecReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(mr.Return)); err != nil { + return address.Undef, err + } + return retval.RobustAddress, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/provider.go b/vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/provider.go new file mode 100644 index 0000000000..6c425ccd8f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/markets/retrievaladapter/provider.go @@ -0,0 +1,81 @@ +package retrievaladapter + +import ( + "context" + "github.com/filecoin-project/sector-storage/storiface" + "io" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-fil-markets/shared" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/storage" +) + +type retrievalProviderNode struct { + miner *storage.Miner + sealer sectorstorage.SectorManager + full api.FullNode +} + +// NewRetrievalProviderNode returns a new node adapter for a retrieval provider that talks to the +// Lotus Node +func NewRetrievalProviderNode(miner *storage.Miner, sealer sectorstorage.SectorManager, full api.FullNode) retrievalmarket.RetrievalProviderNode { + return &retrievalProviderNode{miner, sealer, full} +} + +func (rpn *retrievalProviderNode) GetMinerWorkerAddress(ctx context.Context, miner address.Address, tok shared.TipSetToken) (address.Address, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return address.Undef, err + } + + mi, err := rpn.full.StateMinerInfo(ctx, miner, tsk) + return mi.Worker, err +} + +func (rpn *retrievalProviderNode) UnsealSector(ctx context.Context, sectorID uint64, offset uint64, length uint64) (io.ReadCloser, error) { + si, err := rpn.miner.GetSectorInfo(abi.SectorNumber(sectorID)) + if err != nil { + return nil, err + } + + mid, err := address.IDFromAddress(rpn.miner.Address()) + if err != nil { + return nil, err + } + + sid := abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(sectorID), + } + + r, w := io.Pipe() + go func() { + err := rpn.sealer.ReadPiece(ctx, w, sid, storiface.UnpaddedByteIndex(offset), abi.UnpaddedPieceSize(length), si.TicketValue, *si.CommD) + _ = w.CloseWithError(err) + }() + + return r, nil +} + +func (rpn *retrievalProviderNode) SavePaymentVoucher(ctx context.Context, paymentChannel address.Address, voucher *paych.SignedVoucher, proof []byte, expectedAmount abi.TokenAmount, tok shared.TipSetToken) (abi.TokenAmount, error) { + // TODO: respect the provided TipSetToken (a serialized TipSetKey) when + // querying the chain + added, err := rpn.full.PaychVoucherAdd(ctx, paymentChannel, voucher, proof, expectedAmount) + return added, err +} + +func (rpn *retrievalProviderNode) GetChainHead(ctx context.Context) (shared.TipSetToken, abi.ChainEpoch, error) { + head, err := rpn.full.ChainHead(ctx) + if err != nil { + return nil, 0, err + } + + return head.Key().Bytes(), head.Height(), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/markets/storageadapter/client.go b/vendor/github.com/filecoin-project/lotus/markets/storageadapter/client.go new file mode 100644 index 0000000000..863e527cb7 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/markets/storageadapter/client.go @@ -0,0 +1,437 @@ +package storageadapter + +// this file implements storagemarket.StorageClientNode + +import ( + "bytes" + "context" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/go-fil-markets/shared" + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + samarket "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multiaddr" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/market" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" + "github.com/filecoin-project/lotus/markets/utils" + "github.com/filecoin-project/lotus/node/impl/full" +) + +type ClientNodeAdapter struct { + full.StateAPI + full.ChainAPI + full.MpoolAPI + + sm *stmgr.StateManager + cs *store.ChainStore + fm *market.FundMgr + ev *events.Events +} + +type clientApi struct { + full.ChainAPI + full.StateAPI +} + +func NewClientNodeAdapter(state full.StateAPI, chain full.ChainAPI, mpool full.MpoolAPI, sm *stmgr.StateManager, cs *store.ChainStore, fm *market.FundMgr) storagemarket.StorageClientNode { + return &ClientNodeAdapter{ + StateAPI: state, + ChainAPI: chain, + MpoolAPI: mpool, + + sm: sm, + cs: cs, + fm: fm, + ev: events.NewEvents(context.TODO(), &clientApi{chain, state}), + } +} + +func (n *ClientNodeAdapter) ListStorageProviders(ctx context.Context, encodedTs shared.TipSetToken) ([]*storagemarket.StorageProviderInfo, error) { + tsk, err := types.TipSetKeyFromBytes(encodedTs) + if err != nil { + return nil, err + } + + addresses, err := n.StateListMiners(ctx, tsk) + if err != nil { + return nil, err + } + + var out []*storagemarket.StorageProviderInfo + + for _, addr := range addresses { + mi, err := n.StateMinerInfo(ctx, addr, tsk) + if err != nil { + return nil, err + } + + multiaddrs := make([]multiaddr.Multiaddr, 0, len(mi.Multiaddrs)) + for _, a := range mi.Multiaddrs { + maddr, err := multiaddr.NewMultiaddrBytes(a) + if err != nil { + return nil, err + } + multiaddrs = append(multiaddrs, maddr) + } + storageProviderInfo := utils.NewStorageProviderInfo(addr, mi.Worker, mi.SectorSize, mi.PeerId, multiaddrs) + out = append(out, &storageProviderInfo) + } + + return out, nil +} + +func (n *ClientNodeAdapter) VerifySignature(ctx context.Context, sig crypto.Signature, addr address.Address, input []byte, encodedTs shared.TipSetToken) (bool, error) { + addr, err := n.StateAccountKey(ctx, addr, types.EmptyTSK) + if err != nil { + return false, err + } + + err = sigs.Verify(&sig, addr, input) + return err == nil, err +} + +func (n *ClientNodeAdapter) ListClientDeals(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) ([]storagemarket.StorageDeal, error) { + tsk, err := types.TipSetKeyFromBytes(encodedTs) + if err != nil { + return nil, err + } + + allDeals, err := n.StateMarketDeals(ctx, tsk) + if err != nil { + return nil, err + } + + var out []storagemarket.StorageDeal + + for _, deal := range allDeals { + storageDeal := utils.FromOnChainDeal(deal.Proposal, deal.State) + if storageDeal.Client == addr { + out = append(out, storageDeal) + } + } + + return out, nil +} + +// Adds funds with the StorageMinerActor for a storage participant. Used by both providers and clients. +func (n *ClientNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) { + // (Provider Node API) + smsg, err := n.MpoolPushMessage(ctx, &types.Message{ + To: builtin.StorageMarketActorAddr, + From: addr, + Value: amount, + GasPrice: types.NewInt(0), + GasLimit: 1000000, + Method: builtin.MethodsMarket.AddBalance, + }) + if err != nil { + return cid.Undef, err + } + + return smsg.Cid(), nil +} + +func (n *ClientNodeAdapter) EnsureFunds(ctx context.Context, addr, wallet address.Address, amount abi.TokenAmount, ts shared.TipSetToken) (cid.Cid, error) { + return n.fm.EnsureAvailable(ctx, addr, wallet, amount) +} + +func (n *ClientNodeAdapter) GetBalance(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (storagemarket.Balance, error) { + tsk, err := types.TipSetKeyFromBytes(encodedTs) + if err != nil { + return storagemarket.Balance{}, err + } + + bal, err := n.StateMarketBalance(ctx, addr, tsk) + if err != nil { + return storagemarket.Balance{}, err + } + + return utils.ToSharedBalance(bal), nil +} + +// ValidatePublishedDeal validates that the provided deal has appeared on chain and references the same ClientDeal +// returns the Deal id if there is no error +func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal storagemarket.ClientDeal) (abi.DealID, error) { + log.Infow("DEAL ACCEPTED!") + + pubmsg, err := c.cs.GetMessage(*deal.PublishMessage) + if err != nil { + return 0, xerrors.Errorf("getting deal pubsish message: %w", err) + } + + mi, err := stmgr.StateMinerInfo(ctx, c.sm, c.cs.GetHeaviestTipSet(), deal.Proposal.Provider) + if err != nil { + return 0, xerrors.Errorf("getting miner worker failed: %w", err) + } + + fromid, err := c.StateLookupID(ctx, pubmsg.From, types.EmptyTSK) + if err != nil { + return 0, xerrors.Errorf("failed to resolve from msg ID addr: %w", err) + } + + if fromid != mi.Worker { + return 0, xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s", pubmsg.From, deal.Proposal.Provider) + } + + if pubmsg.To != builtin.StorageMarketActorAddr { + return 0, xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To) + } + + if pubmsg.Method != builtin.MethodsMarket.PublishStorageDeals { + return 0, xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method) + } + + var params samarket.PublishStorageDealsParams + if err := params.UnmarshalCBOR(bytes.NewReader(pubmsg.Params)); err != nil { + return 0, err + } + + dealIdx := -1 + for i, storageDeal := range params.Deals { + // TODO: make it less hacky + sd := storageDeal + eq, err := cborutil.Equals(&deal.ClientDealProposal, &sd) + if err != nil { + return 0, err + } + if eq { + dealIdx = i + break + } + } + + if dealIdx == -1 { + return 0, xerrors.Errorf("deal publish didn't contain our deal (message cid: %s)", deal.PublishMessage) + } + + // TODO: timeout + _, ret, err := c.sm.WaitForMessage(ctx, *deal.PublishMessage, build.MessageConfidence) + if err != nil { + return 0, xerrors.Errorf("waiting for deal publish message: %w", err) + } + if ret.ExitCode != 0 { + return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode) + } + + var res samarket.PublishStorageDealsReturn + if err := res.UnmarshalCBOR(bytes.NewReader(ret.Return)); err != nil { + return 0, err + } + + return res.IDs[dealIdx], nil +} + +func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider address.Address, dealId abi.DealID, cb storagemarket.DealSectorCommittedCallback) error { + checkFunc := func(ts *types.TipSet) (done bool, more bool, err error) { + sd, err := stmgr.GetStorageDeal(ctx, c.StateManager, dealId, ts) + + if err != nil { + // TODO: This may be fine for some errors + return false, false, xerrors.Errorf("client: failed to look up deal on chain: %w", err) + } + + if sd.State.SectorStartEpoch > 0 { + cb(nil) + return true, false, nil + } + + return false, true, nil + } + + called := func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error) { + defer func() { + if err != nil { + cb(xerrors.Errorf("handling applied event: %w", err)) + } + }() + + if msg == nil { + log.Error("timed out waiting for deal activation... what now?") + return false, nil + } + + sd, err := stmgr.GetStorageDeal(ctx, c.StateManager, abi.DealID(dealId), ts) + if err != nil { + return false, xerrors.Errorf("failed to look up deal on chain: %w", err) + } + + if sd.State.SectorStartEpoch < 1 { + return false, xerrors.Errorf("deal wasn't active: deal=%d, parentState=%s, h=%d", dealId, ts.ParentState(), ts.Height()) + } + + log.Infof("Storage deal %d activated at epoch %d", dealId, sd.State.SectorStartEpoch) + + cb(nil) + + return false, nil + } + + revert := func(ctx context.Context, ts *types.TipSet) error { + log.Warn("deal activation reverted; TODO: actually handle this!") + // TODO: Just go back to DealSealing? + return nil + } + + var sectorNumber abi.SectorNumber + var sectorFound bool + matchEvent := func(msg *types.Message) (bool, error) { + if msg.To != provider { + return false, nil + } + + switch msg.Method { + case builtin.MethodsMiner.PreCommitSector: + var params miner.SectorPreCommitInfo + if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { + return false, xerrors.Errorf("unmarshal pre commit: %w", err) + } + + for _, did := range params.DealIDs { + if did == abi.DealID(dealId) { + sectorNumber = params.SectorNumber + sectorFound = true + return false, nil + } + } + + return false, nil + case builtin.MethodsMiner.ProveCommitSector: + var params miner.ProveCommitSectorParams + if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { + return false, xerrors.Errorf("failed to unmarshal prove commit sector params: %w", err) + } + + if !sectorFound { + return false, nil + } + + if params.SectorNumber != sectorNumber { + return false, nil + } + + return true, nil + default: + return false, nil + } + } + + if err := c.ev.Called(checkFunc, called, revert, int(build.MessageConfidence+1), build.SealRandomnessLookbackLimit, matchEvent); err != nil { + return xerrors.Errorf("failed to set up called handler: %w", err) + } + + return nil +} + +func (n *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Address, proposal samarket.DealProposal) (*samarket.ClientDealProposal, error) { + // TODO: output spec signed proposal + buf, err := cborutil.Dump(&proposal) + if err != nil { + return nil, err + } + + signer, err = n.StateAccountKey(ctx, signer, types.EmptyTSK) + if err != nil { + return nil, err + } + + sig, err := n.Wallet.Sign(ctx, signer, buf) + if err != nil { + return nil, err + } + + return &samarket.ClientDealProposal{ + Proposal: proposal, + ClientSignature: *sig, + }, nil +} + +func (n *ClientNodeAdapter) GetDefaultWalletAddress(ctx context.Context) (address.Address, error) { + addr, err := n.Wallet.GetDefault() + return addr, err +} + +func (n *ClientNodeAdapter) ValidateAskSignature(ctx context.Context, ask *storagemarket.SignedStorageAsk, encodedTs shared.TipSetToken) (bool, error) { + tsk, err := types.TipSetKeyFromBytes(encodedTs) + if err != nil { + return false, err + } + + mi, err := n.StateMinerInfo(ctx, ask.Ask.Miner, tsk) + if err != nil { + return false, xerrors.Errorf("failed to get worker for miner in ask", err) + } + + sigb, err := cborutil.Dump(ask.Ask) + if err != nil { + return false, xerrors.Errorf("failed to re-serialize ask") + } + + ts, err := n.ChainGetTipSet(ctx, tsk) + if err != nil { + return false, xerrors.Errorf("failed to load tipset") + } + + m, err := n.StateManager.ResolveToKeyAddress(ctx, mi.Worker, ts) + + if err != nil { + return false, xerrors.Errorf("failed to resolve miner to key address") + } + + err = sigs.Verify(ask.Signature, m, sigb) + return err == nil, err +} + +func (n *ClientNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetToken, abi.ChainEpoch, error) { + head, err := n.ChainHead(ctx) + if err != nil { + return nil, 0, err + } + + return head.Key().Bytes(), head.Height(), nil +} + +func (n *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { + receipt, err := n.StateWaitMsg(ctx, mcid, build.MessageConfidence) + if err != nil { + return cb(0, nil, err) + } + return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) +} + +func (n *ClientNodeAdapter) GetMinerInfo(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*storagemarket.StorageProviderInfo, error) { + tsk, err := types.TipSetKeyFromBytes(encodedTs) + if err != nil { + return nil, err + } + mi, err := n.StateMinerInfo(ctx, addr, tsk) + if err != nil { + return nil, err + } + multiaddrs := make([]multiaddr.Multiaddr, 0, len(mi.Multiaddrs)) + for _, a := range mi.Multiaddrs { + maddr, err := multiaddr.NewMultiaddrBytes(a) + if err != nil { + return nil, err + } + multiaddrs = append(multiaddrs, maddr) + } + out := utils.NewStorageProviderInfo(addr, mi.Worker, mi.SectorSize, mi.PeerId, multiaddrs) + return &out, nil +} + +var _ storagemarket.StorageClientNode = &ClientNodeAdapter{} diff --git a/vendor/github.com/filecoin-project/lotus/markets/storageadapter/provider.go b/vendor/github.com/filecoin-project/lotus/markets/storageadapter/provider.go new file mode 100644 index 0000000000..338396675c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/markets/storageadapter/provider.go @@ -0,0 +1,348 @@ +package storageadapter + +// this file implements storagemarket.StorageProviderNode + +import ( + "bytes" + "context" + "io" + + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-fil-markets/shared" + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" + "github.com/filecoin-project/lotus/markets/utils" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/storage/sectorblocks" + sealing "github.com/filecoin-project/storage-fsm" +) + +var log = logging.Logger("provideradapter") + +type ProviderNodeAdapter struct { + api.FullNode + + // this goes away with the data transfer module + dag dtypes.StagingDAG + + secb *sectorblocks.SectorBlocks + ev *events.Events +} + +func NewProviderNodeAdapter(dag dtypes.StagingDAG, secb *sectorblocks.SectorBlocks, full api.FullNode) storagemarket.StorageProviderNode { + return &ProviderNodeAdapter{ + FullNode: full, + dag: dag, + secb: secb, + ev: events.NewEvents(context.TODO(), full), + } +} + +func (n *ProviderNodeAdapter) PublishDeals(ctx context.Context, deal storagemarket.MinerDeal) (cid.Cid, error) { + log.Info("publishing deal") + + mi, err := n.StateMinerInfo(ctx, deal.Proposal.Provider, types.EmptyTSK) + if err != nil { + return cid.Undef, err + } + + params, err := actors.SerializeParams(&market.PublishStorageDealsParams{ + Deals: []market.ClientDealProposal{deal.ClientDealProposal}, + }) + + if err != nil { + return cid.Undef, xerrors.Errorf("serializing PublishStorageDeals params failed: ", err) + } + + // TODO: We may want this to happen after fetching data + smsg, err := n.MpoolPushMessage(ctx, &types.Message{ + To: builtin.StorageMarketActorAddr, + From: mi.Worker, + Value: types.NewInt(0), + GasPrice: types.NewInt(0), + GasLimit: 1000000, + Method: builtin.MethodsMarket.PublishStorageDeals, + Params: params, + }) + if err != nil { + return cid.Undef, err + } + return smsg.Cid(), nil +} + +func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagemarket.MinerDeal, pieceSize abi.UnpaddedPieceSize, pieceData io.Reader) error { + _, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sealing.DealInfo{ + DealID: deal.DealID, + DealSchedule: sealing.DealSchedule{ + StartEpoch: deal.ClientDealProposal.Proposal.StartEpoch, + EndEpoch: deal.ClientDealProposal.Proposal.EndEpoch, + }, + }) + if err != nil { + return xerrors.Errorf("AddPiece failed: %s", err) + } + log.Warnf("New Deal: deal %d", deal.DealID) + + return nil +} + +func (n *ProviderNodeAdapter) VerifySignature(ctx context.Context, sig crypto.Signature, addr address.Address, input []byte, encodedTs shared.TipSetToken) (bool, error) { + addr, err := n.StateAccountKey(ctx, addr, types.EmptyTSK) + if err != nil { + return false, err + } + + err = sigs.Verify(&sig, addr, input) + return err == nil, err +} + +func (n *ProviderNodeAdapter) ListProviderDeals(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) ([]storagemarket.StorageDeal, error) { + tsk, err := types.TipSetKeyFromBytes(encodedTs) + if err != nil { + return nil, err + } + allDeals, err := n.StateMarketDeals(ctx, tsk) + if err != nil { + return nil, err + } + + var out []storagemarket.StorageDeal + + for _, deal := range allDeals { + sharedDeal := utils.FromOnChainDeal(deal.Proposal, deal.State) + if sharedDeal.Provider == addr { + out = append(out, sharedDeal) + } + } + + return out, nil +} + +func (n *ProviderNodeAdapter) GetMinerWorkerAddress(ctx context.Context, miner address.Address, tok shared.TipSetToken) (address.Address, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return address.Undef, err + } + + mi, err := n.StateMinerInfo(ctx, miner, tsk) + if err != nil { + return address.Address{}, err + } + return mi.Worker, nil +} + +func (n *ProviderNodeAdapter) SignBytes(ctx context.Context, signer address.Address, b []byte) (*crypto.Signature, error) { + signer, err := n.StateAccountKey(ctx, signer, types.EmptyTSK) + if err != nil { + return nil, err + } + + localSignature, err := n.WalletSign(ctx, signer, b) + if err != nil { + return nil, err + } + return localSignature, nil +} + +func (n *ProviderNodeAdapter) EnsureFunds(ctx context.Context, addr, wallet address.Address, amt abi.TokenAmount, encodedTs shared.TipSetToken) (cid.Cid, error) { + return n.MarketEnsureAvailable(ctx, addr, wallet, amt) +} + +// Adds funds with the StorageMinerActor for a storage participant. Used by both providers and clients. +func (n *ProviderNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) { + // (Provider Node API) + smsg, err := n.MpoolPushMessage(ctx, &types.Message{ + To: builtin.StorageMarketActorAddr, + From: addr, + Value: amount, + GasPrice: types.NewInt(0), + GasLimit: 1000000, + Method: builtin.MethodsMarket.AddBalance, + }) + if err != nil { + return cid.Undef, err + } + + return smsg.Cid(), nil +} + +func (n *ProviderNodeAdapter) GetBalance(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (storagemarket.Balance, error) { + tsk, err := types.TipSetKeyFromBytes(encodedTs) + if err != nil { + return storagemarket.Balance{}, err + } + + bal, err := n.StateMarketBalance(ctx, addr, tsk) + if err != nil { + return storagemarket.Balance{}, err + } + + return utils.ToSharedBalance(bal), nil +} + +func (n *ProviderNodeAdapter) LocatePieceForDealWithinSector(ctx context.Context, dealID abi.DealID, encodedTs shared.TipSetToken) (sectorID uint64, offset uint64, length uint64, err error) { + refs, err := n.secb.GetRefs(dealID) + if err != nil { + return 0, 0, 0, err + } + if len(refs) == 0 { + return 0, 0, 0, xerrors.New("no sector information for deal ID") + } + + // TODO: better strategy (e.g. look for already unsealed) + var best api.SealedRef + var bestSi sealing.SectorInfo + for _, r := range refs { + si, err := n.secb.Miner.GetSectorInfo(r.SectorID) + if err != nil { + return 0, 0, 0, xerrors.Errorf("getting sector info: %w", err) + } + if si.State == sealing.Proving { + best = r + bestSi = si + break + } + } + if bestSi.State == sealing.UndefinedSectorState { + return 0, 0, 0, xerrors.New("no sealed sector found") + } + return uint64(best.SectorID), best.Offset, uint64(best.Size), nil +} + +func (n *ProviderNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, cb storagemarket.DealSectorCommittedCallback) error { + checkFunc := func(ts *types.TipSet) (done bool, more bool, err error) { + sd, err := n.StateMarketStorageDeal(ctx, dealID, ts.Key()) + + if err != nil { + // TODO: This may be fine for some errors + return false, false, xerrors.Errorf("failed to look up deal on chain: %w", err) + } + + if sd.State.SectorStartEpoch > 0 { + cb(nil) + return true, false, nil + } + + return false, true, nil + } + + called := func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error) { + defer func() { + if err != nil { + cb(xerrors.Errorf("handling applied event: %w", err)) + } + }() + + if msg == nil { + log.Error("timed out waiting for deal activation... what now?") + return false, nil + } + + sd, err := n.StateMarketStorageDeal(ctx, abi.DealID(dealID), ts.Key()) + if err != nil { + return false, xerrors.Errorf("failed to look up deal on chain: %w", err) + } + + if sd.State.SectorStartEpoch < 1 { + return false, xerrors.Errorf("deal wasn't active: deal=%d, parentState=%s, h=%d", dealID, ts.ParentState(), ts.Height()) + } + + log.Infof("Storage deal %d activated at epoch %d", dealID, sd.State.SectorStartEpoch) + + cb(nil) + + return false, nil + } + + revert := func(ctx context.Context, ts *types.TipSet) error { + log.Warn("deal activation reverted; TODO: actually handle this!") + // TODO: Just go back to DealSealing? + return nil + } + + var sectorNumber abi.SectorNumber + var sectorFound bool + + matchEvent := func(msg *types.Message) (bool, error) { + if msg.To != provider { + return false, nil + } + + switch msg.Method { + case builtin.MethodsMiner.PreCommitSector: + var params miner.SectorPreCommitInfo + if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { + return false, xerrors.Errorf("unmarshal pre commit: %w", err) + } + + for _, did := range params.DealIDs { + if did == abi.DealID(dealID) { + sectorNumber = params.SectorNumber + sectorFound = true + return false, nil + } + } + + return false, nil + case builtin.MethodsMiner.ProveCommitSector: + var params miner.ProveCommitSectorParams + if err := params.UnmarshalCBOR(bytes.NewReader(msg.Params)); err != nil { + return false, xerrors.Errorf("failed to unmarshal prove commit sector params: %w", err) + } + + if !sectorFound { + return false, nil + } + + if params.SectorNumber != sectorNumber { + return false, nil + } + + return true, nil + default: + return false, nil + } + + } + + if err := n.ev.Called(checkFunc, called, revert, int(build.MessageConfidence+1), build.SealRandomnessLookbackLimit, matchEvent); err != nil { + return xerrors.Errorf("failed to set up called handler: %w", err) + } + + return nil +} + +func (n *ProviderNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetToken, abi.ChainEpoch, error) { + head, err := n.ChainHead(ctx) + if err != nil { + return nil, 0, err + } + + return head.Key().Bytes(), head.Height(), nil +} + +func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { + receipt, err := n.StateWaitMsg(ctx, mcid, build.MessageConfidence) + if err != nil { + return cb(0, nil, err) + } + return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) +} + +var _ storagemarket.StorageProviderNode = &ProviderNodeAdapter{} diff --git a/vendor/github.com/filecoin-project/lotus/markets/utils/converters.go b/vendor/github.com/filecoin-project/lotus/markets/utils/converters.go new file mode 100644 index 0000000000..4c7ab5c2df --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/markets/utils/converters.go @@ -0,0 +1,38 @@ +package utils + +import ( + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/multiformats/go-multiaddr" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-fil-markets/storagemarket" +) + +func NewStorageProviderInfo(address address.Address, miner address.Address, sectorSize abi.SectorSize, peer peer.ID, addrs []multiaddr.Multiaddr) storagemarket.StorageProviderInfo { + + return storagemarket.StorageProviderInfo{ + Address: address, + Worker: miner, + SectorSize: uint64(sectorSize), + PeerID: peer, + Addrs: addrs, + } +} + +func FromOnChainDeal(prop market.DealProposal, state market.DealState) storagemarket.StorageDeal { + return storagemarket.StorageDeal{ + DealProposal: prop, + DealState: state, + } +} + +func ToSharedBalance(bal api.MarketBalance) storagemarket.Balance { + return storagemarket.Balance{ + Locked: bal.Locked, + Available: big.Sub(bal.Escrow, bal.Locked), + } +} diff --git a/vendor/github.com/filecoin-project/lotus/metrics/metrics.go b/vendor/github.com/filecoin-project/lotus/metrics/metrics.go new file mode 100644 index 0000000000..0ef63de4f5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/metrics/metrics.go @@ -0,0 +1,102 @@ +package metrics + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" + + rpcmetrics "github.com/filecoin-project/go-jsonrpc/metrics" +) + +// Global Tags +var ( + Version, _ = tag.NewKey("version") + Commit, _ = tag.NewKey("commit") + PeerID, _ = tag.NewKey("peer_id") + FailureType, _ = tag.NewKey("failure_type") + MessageFrom, _ = tag.NewKey("message_from") + MessageTo, _ = tag.NewKey("message_to") + MessageNonce, _ = tag.NewKey("message_nonce") + ReceivedFrom, _ = tag.NewKey("received_from") +) + +// Measures +var ( + LotusInfo = stats.Int64("info", "Arbitrary counter to tag lotus info to", stats.UnitDimensionless) + ChainNodeHeight = stats.Int64("chain/node_height", "Current Height of the node", stats.UnitDimensionless) + ChainNodeWorkerHeight = stats.Int64("chain/node_worker_height", "Current Height of workers on the node", stats.UnitDimensionless) + MessageReceived = stats.Int64("message/received", "Counter for total received messages", stats.UnitDimensionless) + MessageValidationFailure = stats.Int64("message/failure", "Counter for message validation failures", stats.UnitDimensionless) + MessageValidationSuccess = stats.Int64("message/success", "Counter for message validation successes", stats.UnitDimensionless) + BlockReceived = stats.Int64("block/received", "Counter for total received blocks", stats.UnitDimensionless) + BlockValidationFailure = stats.Int64("block/failure", "Counter for block validation failures", stats.UnitDimensionless) + BlockValidationSuccess = stats.Int64("block/success", "Counter for block validation successes", stats.UnitDimensionless) + BlockValidationDurationMilliseconds = stats.Float64("block/validation_ms", "Duration for Block Validation in ms", stats.UnitMilliseconds) + PeerCount = stats.Int64("peer/count", "Current number of FIL peers", stats.UnitDimensionless) +) + +var ( + InfoView = &view.View{ + Name: "info", + Description: "Lotus node information", + Measure: LotusInfo, + Aggregation: view.LastValue(), + TagKeys: []tag.Key{Version, Commit}, + } + ChainNodeHeightView = &view.View{ + Measure: ChainNodeHeight, + Aggregation: view.LastValue(), + } + ChainNodeWorkerHeightView = &view.View{ + Measure: ChainNodeWorkerHeight, + Aggregation: view.LastValue(), + } + BlockReceivedView = &view.View{ + Measure: BlockReceived, + Aggregation: view.Count(), + } + BlockValidationFailureView = &view.View{ + Measure: BlockValidationFailure, + Aggregation: view.Count(), + TagKeys: []tag.Key{FailureType}, + } + BlockValidationSuccessView = &view.View{ + Measure: BlockValidationSuccess, + Aggregation: view.Count(), + } + BlockValidationDurationView = &view.View{ + Measure: BlockValidationDurationMilliseconds, + Aggregation: view.Sum(), + } + MessageReceivedView = &view.View{ + Measure: MessageReceived, + Aggregation: view.Count(), + } + MessageValidationFailureView = &view.View{ + Measure: MessageValidationFailure, + Aggregation: view.Count(), + TagKeys: []tag.Key{FailureType}, + } + MessageValidationSuccessView = &view.View{ + Measure: MessageValidationSuccess, + Aggregation: view.Count(), + } + PeerCountView = &view.View{ + Measure: PeerCount, + Aggregation: view.LastValue(), + } +) + +// DefaultViews is an array of OpenCensus views for metric gathering purposes +var DefaultViews = append([]*view.View{ + InfoView, + ChainNodeHeightView, + ChainNodeWorkerHeightView, + BlockReceivedView, + BlockValidationFailureView, + BlockValidationSuccessView, + BlockValidationDurationView, + MessageReceivedView, + MessageValidationFailureView, + MessageValidationSuccessView, + PeerCountView}, rpcmetrics.DefaultViews...) diff --git a/vendor/github.com/filecoin-project/lotus/miner/miner.go b/vendor/github.com/filecoin-project/lotus/miner/miner.go new file mode 100644 index 0000000000..c0747940e2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/miner/miner.go @@ -0,0 +1,578 @@ +package miner + +import ( + "bytes" + "context" + "fmt" + "sync" + "time" + + address "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/crypto" + lru "github.com/hashicorp/golang-lru" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + + logging "github.com/ipfs/go-log/v2" + "go.opencensus.io/trace" + "golang.org/x/xerrors" +) + +var log = logging.Logger("miner") + +// returns a callback reporting whether we mined a blocks in this round +type waitFunc func(ctx context.Context, baseTime uint64) (func(bool, error), error) + +func NewMiner(api api.FullNode, epp gen.WinningPoStProver, addr address.Address) *Miner { + arc, err := lru.NewARC(10000) + if err != nil { + panic(err) + } + + return &Miner{ + api: api, + epp: epp, + address: addr, + waitFunc: func(ctx context.Context, baseTime uint64) (func(bool, error), error) { + // Wait around for half the block time in case other parents come in + deadline := baseTime + build.PropagationDelaySecs + time.Sleep(time.Until(time.Unix(int64(deadline), 0))) + + return func(bool, error) {}, nil + }, + minedBlockHeights: arc, + } +} + +type Miner struct { + api api.FullNode + + epp gen.WinningPoStProver + + lk sync.Mutex + address address.Address + stop chan struct{} + stopping chan struct{} + + waitFunc waitFunc + + lastWork *MiningBase + + minedBlockHeights *lru.ARCCache +} + +func (m *Miner) Address() address.Address { + m.lk.Lock() + defer m.lk.Unlock() + + return m.address +} + +func (m *Miner) Start(ctx context.Context) error { + m.lk.Lock() + defer m.lk.Unlock() + if m.stop != nil { + return fmt.Errorf("miner already started") + } + m.stop = make(chan struct{}) + go m.mine(context.TODO()) + return nil +} + +func (m *Miner) Stop(ctx context.Context) error { + m.lk.Lock() + defer m.lk.Unlock() + + m.stopping = make(chan struct{}) + stopping := m.stopping + close(m.stop) + + select { + case <-stopping: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} + +func (m *Miner) niceSleep(d time.Duration) bool { + select { + case <-time.After(d): + return true + case <-m.stop: + return false + } +} + +func (m *Miner) mine(ctx context.Context) { + ctx, span := trace.StartSpan(ctx, "/mine") + defer span.End() + + var lastBase MiningBase + + for { + select { + case <-m.stop: + stopping := m.stopping + m.stop = nil + m.stopping = nil + close(stopping) + return + + default: + } + + prebase, err := m.GetBestMiningCandidate(ctx) + if err != nil { + log.Errorf("failed to get best mining candidate: %s", err) + m.niceSleep(time.Second * 5) + continue + } + + // Wait until propagation delay period after block we plan to mine on + onDone, err := m.waitFunc(ctx, prebase.TipSet.MinTimestamp()) + if err != nil { + log.Error(err) + continue + } + + base, err := m.GetBestMiningCandidate(ctx) + if err != nil { + log.Errorf("failed to get best mining candidate: %s", err) + continue + } + if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds { + log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds) + m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second) + continue + } + + b, err := m.mineOne(ctx, base) + if err != nil { + log.Errorf("mining block failed: %+v", err) + m.niceSleep(time.Second) + onDone(false, err) + continue + } + lastBase = *base + + onDone(b != nil, nil) + + if b != nil { + btime := time.Unix(int64(b.Header.Timestamp), 0) + if time.Now().Before(btime) { + if !m.niceSleep(time.Until(btime)) { + log.Warnf("received interrupt while waiting to broadcast block, will shutdown after block is sent out") + time.Sleep(time.Until(btime)) + } + } else { + log.Warnw("mined block in the past", "block-time", btime, + "time", time.Now(), "duration", time.Since(btime)) + } + + // TODO: should do better 'anti slash' protection here + blkKey := fmt.Sprintf("%d", b.Header.Height) + if _, ok := m.minedBlockHeights.Get(blkKey); ok { + log.Warnw("Created a block at the same height as another block we've created", "height", b.Header.Height, "miner", b.Header.Miner, "parents", b.Header.Parents) + continue + } + + m.minedBlockHeights.Add(blkKey, true) + if err := m.api.SyncSubmitBlock(ctx, b); err != nil { + log.Errorf("failed to submit newly mined block: %s", err) + } + } else { + base.NullRounds++ + + // Wait until the next epoch, plus the propagation delay, so a new tipset + // has enough time to form. + // + // See: https://github.com/filecoin-project/lotus/issues/1845 + nextRound := time.Unix(int64(base.TipSet.MinTimestamp()+build.BlockDelaySecs*uint64(base.NullRounds))+int64(build.PropagationDelaySecs), 0) + + select { + case <-time.After(time.Until(nextRound)): + case <-m.stop: + stopping := m.stopping + m.stop = nil + m.stopping = nil + close(stopping) + return + } + } + } +} + +type MiningBase struct { + TipSet *types.TipSet + NullRounds abi.ChainEpoch +} + +func (m *Miner) GetBestMiningCandidate(ctx context.Context) (*MiningBase, error) { + m.lk.Lock() + defer m.lk.Unlock() + + bts, err := m.api.ChainHead(ctx) + if err != nil { + return nil, err + } + + if m.lastWork != nil { + if m.lastWork.TipSet.Equals(bts) { + return m.lastWork, nil + } + + btsw, err := m.api.ChainTipSetWeight(ctx, bts.Key()) + if err != nil { + return nil, err + } + ltsw, err := m.api.ChainTipSetWeight(ctx, m.lastWork.TipSet.Key()) + if err != nil { + return nil, err + } + + if types.BigCmp(btsw, ltsw) <= 0 { + return m.lastWork, nil + } + } + + m.lastWork = &MiningBase{TipSet: bts} + return m.lastWork, nil +} + +func (m *Miner) hasPower(ctx context.Context, addr address.Address, ts *types.TipSet) (bool, error) { + mpower, err := m.api.StateMinerPower(ctx, addr, ts.Key()) + if err != nil { + return false, err + } + + return mpower.MinerPower.QualityAdjPower.GreaterThanEqual(power.ConsensusMinerMinPower), nil +} + +// mineOne attempts to mine a single block, and does so synchronously, if and +// only if we are eligible to mine. +// +// {hint/landmark}: This method coordinates all the steps involved in mining a +// block, including the condition of whether mine or not at all depending on +// whether we win the round or not. +// +// This method does the following: +// +// 1. +func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, error) { + log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.TipSet.Cids())) + start := time.Now() + + round := base.TipSet.Height() + base.NullRounds + 1 + + mbi, err := m.api.MinerGetBaseInfo(ctx, m.address, round, base.TipSet.Key()) + if err != nil { + return nil, xerrors.Errorf("failed to get mining base info: %w", err) + } + if mbi == nil { + return nil, nil + } + + tMBI := time.Now() + + beaconPrev := mbi.PrevBeaconEntry + + tDrand := time.Now() + bvals := mbi.BeaconEntries + + hasPower, err := m.hasPower(ctx, m.address, base.TipSet) + if err != nil { + return nil, xerrors.Errorf("checking if miner is slashed: %w", err) + } + if !hasPower { + // slashed or just have no power yet + return nil, nil + } + + tPowercheck := time.Now() + + log.Infof("Time delta between now and our mining base: %ds (nulls: %d)", uint64(time.Now().Unix())-base.TipSet.MinTimestamp(), base.NullRounds) + + rbase := beaconPrev + if len(bvals) > 0 { + rbase = bvals[len(bvals)-1] + } + + ticket, err := m.computeTicket(ctx, &rbase, base, len(bvals) > 0) + if err != nil { + return nil, xerrors.Errorf("scratching ticket failed: %w", err) + } + + winner, err := gen.IsRoundWinner(ctx, base.TipSet, round, m.address, rbase, mbi, m.api) + if err != nil { + return nil, xerrors.Errorf("failed to check if we win next round: %w", err) + } + + if winner == nil { + return nil, nil + } + + tTicket := time.Now() + + buf := new(bytes.Buffer) + if err := m.address.MarshalCBOR(buf); err != nil { + return nil, xerrors.Errorf("failed to marshal miner address: %w", err) + } + + rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, base.TipSet.Height()+base.NullRounds+1, buf.Bytes()) + if err != nil { + return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err) + } + + prand := abi.PoStRandomness(rand) + + tSeed := time.Now() + + postProof, err := m.epp.ComputeProof(ctx, mbi.Sectors, prand) + if err != nil { + return nil, xerrors.Errorf("failed to compute winning post proof: %w", err) + } + + // get pending messages early, + pending, err := m.api.MpoolPending(context.TODO(), base.TipSet.Key()) + if err != nil { + return nil, xerrors.Errorf("failed to get pending messages: %w", err) + } + + tPending := time.Now() + + // TODO: winning post proof + b, err := m.createBlock(base, m.address, ticket, winner, bvals, postProof, pending) + if err != nil { + return nil, xerrors.Errorf("failed to create block: %w", err) + } + + tCreateBlock := time.Now() + dur := tCreateBlock.Sub(start) + log.Infow("mined new block", "cid", b.Cid(), "height", b.Header.Height, "took", dur) + if dur > time.Second*time.Duration(build.BlockDelaySecs) { + log.Warn("CAUTION: block production took longer than the block delay. Your computer may not be fast enough to keep up") + + log.Warnw("tMinerBaseInfo ", "duration", tMBI.Sub(start)) + log.Warnw("tDrand ", "duration", tDrand.Sub(tMBI)) + log.Warnw("tPowercheck ", "duration", tPowercheck.Sub(tDrand)) + log.Warnw("tTicket ", "duration", tTicket.Sub(tPowercheck)) + log.Warnw("tSeed ", "duration", tSeed.Sub(tTicket)) + log.Warnw("tPending ", "duration", tPending.Sub(tSeed)) + log.Warnw("tCreateBlock ", "duration", tCreateBlock.Sub(tPending)) + } + + return b, nil +} + +func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase, haveNewEntries bool) (*types.Ticket, error) { + mi, err := m.api.StateMinerInfo(ctx, m.address, types.EmptyTSK) + if err != nil { + return nil, err + } + worker, err := m.api.StateAccountKey(ctx, mi.Worker, types.EmptyTSK) + if err != nil { + return nil, err + } + + buf := new(bytes.Buffer) + if err := m.address.MarshalCBOR(buf); err != nil { + return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) + } + + if !haveNewEntries { + buf.Write(base.TipSet.MinTicket().VRFProof) + } + + input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, base.TipSet.Height()+base.NullRounds+1-build.TicketRandomnessLookback, buf.Bytes()) + if err != nil { + return nil, err + } + + vrfOut, err := gen.ComputeVRF(ctx, m.api.WalletSign, worker, input) + if err != nil { + return nil, err + } + + return &types.Ticket{ + VRFProof: vrfOut, + }, nil +} + +func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, + eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []abi.PoStProof, pending []*types.SignedMessage) (*types.BlockMsg, error) { + msgs, err := SelectMessages(context.TODO(), m.api.StateGetActor, base.TipSet, pending) + if err != nil { + return nil, xerrors.Errorf("message filtering failed: %w", err) + } + + if len(msgs) > build.BlockMessageLimit { + log.Error("SelectMessages returned too many messages: ", len(msgs)) + msgs = msgs[:build.BlockMessageLimit] + } + + uts := base.TipSet.MinTimestamp() + build.BlockDelaySecs*(uint64(base.NullRounds)+1) + + nheight := base.TipSet.Height() + base.NullRounds + 1 + + // why even return this? that api call could just submit it for us + return m.api.MinerCreateBlock(context.TODO(), &api.BlockTemplate{ + Miner: addr, + Parents: base.TipSet.Key(), + Ticket: ticket, + Eproof: eproof, + BeaconValues: bvals, + Messages: msgs, + Epoch: nheight, + Timestamp: uts, + WinningPoStProof: wpostProof, + }) +} + +type actCacheEntry struct { + act *types.Actor + err error +} + +type cachedActorLookup struct { + tsk types.TipSetKey + cache map[address.Address]actCacheEntry + fallback ActorLookup +} + +func (c *cachedActorLookup) StateGetActor(ctx context.Context, a address.Address, tsk types.TipSetKey) (*types.Actor, error) { + if c.tsk == tsk { + e, has := c.cache[a] + if has { + return e.act, e.err + } + } + + e, err := c.fallback(ctx, a, tsk) + if c.tsk == tsk { + c.cache[a] = actCacheEntry{ + act: e, err: err, + } + } + return e, err +} + +type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) + +func countFrom(msgs []*types.SignedMessage, from address.Address) (out int) { + for _, msg := range msgs { + if msg.Message.From == from { + out++ + } + } + return out +} + +func SelectMessages(ctx context.Context, al ActorLookup, ts *types.TipSet, msgs []*types.SignedMessage) ([]*types.SignedMessage, error) { + al = (&cachedActorLookup{ + tsk: ts.Key(), + cache: map[address.Address]actCacheEntry{}, + fallback: al, + }).StateGetActor + + out := make([]*types.SignedMessage, 0, build.BlockMessageLimit) + inclNonces := make(map[address.Address]uint64) + inclBalances := make(map[address.Address]types.BigInt) + inclCount := make(map[address.Address]int) + + tooLowFundMsgs := 0 + tooHighNonceMsgs := 0 + + start := time.Now() + vmValid := time.Duration(0) + getbal := time.Duration(0) + + for _, msg := range msgs { + vmstart := time.Now() + + minGas := vm.PricelistByEpoch(ts.Height()).OnChainMessage(msg.ChainLength()) // TODO: really should be doing just msg.ChainLength() but the sync side of this code doesnt seem to have access to that + if err := msg.VMMessage().ValidForBlockInclusion(minGas.Total()); err != nil { + log.Warnf("invalid message in message pool: %s", err) + continue + } + + vmValid += time.Since(vmstart) + + // TODO: this should be in some more general 'validate message' call + if msg.Message.GasLimit > build.BlockGasLimit { + log.Warnf("message in mempool had too high of a gas limit (%d)", msg.Message.GasLimit) + continue + } + + if msg.Message.To == address.Undef { + log.Warnf("message in mempool had bad 'To' address") + continue + } + + from := msg.Message.From + + getBalStart := time.Now() + if _, ok := inclNonces[from]; !ok { + act, err := al(ctx, from, ts.Key()) + if err != nil { + log.Warnf("failed to check message sender balance, skipping message: %+v", err) + continue + } + + inclNonces[from] = act.Nonce + inclBalances[from] = act.Balance + } + getbal += time.Since(getBalStart) + + if inclBalances[from].LessThan(msg.Message.RequiredFunds()) { + tooLowFundMsgs++ + // todo: drop from mpool + continue + } + + if msg.Message.Nonce > inclNonces[from] { + tooHighNonceMsgs++ + continue + } + + if msg.Message.Nonce < inclNonces[from] { + log.Warnf("message in mempool has already used nonce (%d < %d), from %s, to %s, %s (%d pending for)", msg.Message.Nonce, inclNonces[from], msg.Message.From, msg.Message.To, msg.Cid(), countFrom(msgs, from)) + continue + } + + inclNonces[from] = msg.Message.Nonce + 1 + inclBalances[from] = types.BigSub(inclBalances[from], msg.Message.RequiredFunds()) + inclCount[from]++ + + out = append(out, msg) + if len(out) >= build.BlockMessageLimit { + break + } + } + + if tooLowFundMsgs > 0 { + log.Warnf("%d messages in mempool does not have enough funds", tooLowFundMsgs) + } + + if tooHighNonceMsgs > 0 { + log.Warnf("%d messages in mempool had too high nonce", tooHighNonceMsgs) + } + + sm := time.Now() + if sm.Sub(start) > time.Second { + log.Warnw("SelectMessages took a long time", + "duration", sm.Sub(start), + "vmvalidate", vmValid, + "getbalance", getbal, + "msgs", len(msgs)) + } + + return out, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/miner/miner_test.go b/vendor/github.com/filecoin-project/lotus/miner/miner_test.go new file mode 100644 index 0000000000..15cc41064d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/miner/miner_test.go @@ -0,0 +1,104 @@ +package miner + +import ( + "context" + "testing" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/types" +) + +func mustIDAddr(i uint64) address.Address { + a, err := address.NewIDAddress(i) + if err != nil { + panic(err) + } + + return a +} + +func TestMessageFiltering(t *testing.T) { + ctx := context.TODO() + a1 := mustIDAddr(1) + a2 := mustIDAddr(2) + + actors := map[address.Address]*types.Actor{ + a1: { + Nonce: 3, + Balance: types.NewInt(1200), + }, + a2: { + Nonce: 1, + Balance: types.NewInt(1000), + }, + } + + af := func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error) { + return actors[addr], nil + } + + msgs := []types.Message{ + { + From: a1, + To: a1, + Nonce: 3, + Value: types.NewInt(500), + GasLimit: 50, + GasPrice: types.NewInt(1), + }, + { + From: a1, + To: a1, + Nonce: 4, + Value: types.NewInt(500), + GasLimit: 50, + GasPrice: types.NewInt(1), + }, + { + From: a2, + To: a1, + Nonce: 1, + Value: types.NewInt(800), + GasLimit: 100, + GasPrice: types.NewInt(1), + }, + { + From: a2, + To: a1, + Nonce: 0, + Value: types.NewInt(800), + GasLimit: 100, + GasPrice: types.NewInt(1), + }, + { + From: a2, + To: a1, + Nonce: 2, + Value: types.NewInt(150), + GasLimit: (100), + GasPrice: types.NewInt(1), + }, + } + + outmsgs, err := SelectMessages(ctx, af, &types.TipSet{}, wrapMsgs(msgs)) + if err != nil { + t.Fatal(err) + } + + if len(outmsgs) != 3 { + t.Fatal("filtering didnt work as expected") + } + + m1 := outmsgs[2].Message + if m1.From != msgs[2].From || m1.Nonce != msgs[2].Nonce { + t.Fatal("filtering bad") + } +} + +func wrapMsgs(msgs []types.Message) []*types.SignedMessage { + var out []*types.SignedMessage + for _, m := range msgs { + out = append(out, &types.SignedMessage{Message: m}) + } + return out +} diff --git a/vendor/github.com/filecoin-project/lotus/miner/testminer.go b/vendor/github.com/filecoin-project/lotus/miner/testminer.go new file mode 100644 index 0000000000..1c8b0f67a4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/miner/testminer.go @@ -0,0 +1,43 @@ +package miner + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/gen" + lru "github.com/hashicorp/golang-lru" +) + +func NewTestMiner(nextCh <-chan func(bool, error), addr address.Address) func(api.FullNode, gen.WinningPoStProver) *Miner { + return func(api api.FullNode, epp gen.WinningPoStProver) *Miner { + arc, err := lru.NewARC(10000) + if err != nil { + panic(err) + } + + m := &Miner{ + api: api, + waitFunc: chanWaiter(nextCh), + epp: epp, + minedBlockHeights: arc, + address: addr, + } + + if err := m.Start(context.TODO()); err != nil { + panic(err) + } + return m + } +} + +func chanWaiter(next <-chan func(bool, error)) func(ctx context.Context, _ uint64) (func(bool, error), error) { + return func(ctx context.Context, _ uint64) (func(bool, error), error) { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case cb := <-next: + return cb, nil + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/builder.go b/vendor/github.com/filecoin-project/lotus/node/builder.go new file mode 100644 index 0000000000..2ffe889210 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/builder.go @@ -0,0 +1,520 @@ +package node + +import ( + "context" + "errors" + "time" + + blockstore "github.com/ipfs/go-ipfs-blockstore" + logging "github.com/ipfs/go-log" + ci "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p-core/routing" + dht "github.com/libp2p/go-libp2p-kad-dht" + "github.com/libp2p/go-libp2p-peerstore/pstoremem" + pubsub "github.com/libp2p/go-libp2p-pubsub" + record "github.com/libp2p/go-libp2p-record" + "github.com/multiformats/go-multiaddr" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-fil-markets/retrievalmarket/discovery" + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-fil-markets/storagemarket/impl/storedask" + + "github.com/filecoin-project/specs-actors/actors/runtime" + storage2 "github.com/filecoin-project/specs-storage/storage" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/beacon" + "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/market" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/metrics" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/lib/peermgr" + _ "github.com/filecoin-project/lotus/lib/sigs/bls" + _ "github.com/filecoin-project/lotus/lib/sigs/secp" + "github.com/filecoin-project/lotus/markets/storageadapter" + "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/hello" + "github.com/filecoin-project/lotus/node/impl" + "github.com/filecoin-project/lotus/node/impl/common" + "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/modules/lp2p" + "github.com/filecoin-project/lotus/node/modules/testing" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/paychmgr" + "github.com/filecoin-project/lotus/storage" + "github.com/filecoin-project/lotus/storage/sectorblocks" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/sector-storage/stores" + sealing "github.com/filecoin-project/storage-fsm" +) + +var log = logging.Logger("builder") + +// special is a type used to give keys to modules which +// can't really be identified by the returned type +type special struct{ id int } + +//nolint:golint +var ( + DefaultTransportsKey = special{0} // Libp2p option + DiscoveryHandlerKey = special{2} // Private type + AddrsFactoryKey = special{3} // Libp2p option + SmuxTransportKey = special{4} // Libp2p option + RelayKey = special{5} // Libp2p option + SecurityKey = special{6} // Libp2p option + BaseRoutingKey = special{7} // fx groups + multiret + NatPortMapKey = special{8} // Libp2p option + ConnectionManagerKey = special{9} // Libp2p option + AutoNATSvcKey = special{10} // Libp2p option +) + +type invoke int + +//nolint:golint +const ( + // libp2p + + PstoreAddSelfKeysKey = invoke(iota) + StartListeningKey + BootstrapKey + + // filecoin + SetGenesisKey + + RunHelloKey + RunBlockSyncKey + RunChainGraphsync + RunPeerMgrKey + + HandleIncomingBlocksKey + HandleIncomingMessagesKey + + RegisterClientValidatorKey + + // storage miner + GetParamsKey + HandleDealsKey + HandleRetrievalKey + RunSectorServiceKey + RegisterProviderValidatorKey + + // daemon + ExtractApiKey + HeadMetricsKey + RunPeerTaggerKey + + SetApiEndpointKey + + _nInvokes // keep this last +) + +type Settings struct { + // modules is a map of constructors for DI + // + // In most cases the index will be a reflect. Type of element returned by + // the constructor, but for some 'constructors' it's hard to specify what's + // the return type should be (or the constructor returns fx group) + modules map[interface{}]fx.Option + + // invokes are separate from modules as they can't be referenced by return + // type, and must be applied in correct order + invokes []fx.Option + + nodeType repo.RepoType + + Online bool // Online option applied + Config bool // Config option applied + +} + +func defaults() []Option { + return []Option{ + Override(new(helpers.MetricsCtx), context.Background), + Override(new(record.Validator), modules.RecordValidator), + Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(false)), + Override(new(dtypes.ShutdownChan), make(chan struct{})), + + // Filecoin modules + + } +} + +func libp2p() Option { + return Options( + Override(new(peerstore.Peerstore), pstoremem.NewPeerstore), + + Override(DefaultTransportsKey, lp2p.DefaultTransports), + + Override(new(lp2p.RawHost), lp2p.Host), + Override(new(host.Host), lp2p.RoutedHost), + Override(new(lp2p.BaseIpfsRouting), lp2p.DHTRouting(dht.ModeAuto)), + + Override(DiscoveryHandlerKey, lp2p.DiscoveryHandler), + Override(AddrsFactoryKey, lp2p.AddrsFactory(nil, nil)), + Override(SmuxTransportKey, lp2p.SmuxTransport(true)), + Override(RelayKey, lp2p.NoRelay()), + Override(SecurityKey, lp2p.Security(true, true)), + + Override(BaseRoutingKey, lp2p.BaseRouting), + Override(new(routing.Routing), lp2p.Routing), + + Override(NatPortMapKey, lp2p.NatPortMap), + + Override(ConnectionManagerKey, lp2p.ConnectionManager(50, 200, 20*time.Second, nil)), + Override(AutoNATSvcKey, lp2p.AutoNATService), + + Override(new(*dtypes.ScoreKeeper), lp2p.ScoreKeeper), + Override(new(*pubsub.PubSub), lp2p.GossipSub), + Override(new(*config.Pubsub), func(bs dtypes.Bootstrapper) *config.Pubsub { + return &config.Pubsub{ + Bootstrapper: bool(bs), + } + }), + + Override(PstoreAddSelfKeysKey, lp2p.PstoreAddSelfKeys), + Override(StartListeningKey, lp2p.StartListening(config.DefaultFullNode().Libp2p.ListenAddresses)), + ) +} + +func isType(t repo.RepoType) func(s *Settings) bool { + return func(s *Settings) bool { return s.nodeType == t } +} + +// Online sets up basic libp2p node +func Online() Option { + return Options( + // make sure that online is applied before Config. + // This is important because Config overrides some of Online units + func(s *Settings) error { s.Online = true; return nil }, + ApplyIf(func(s *Settings) bool { return s.Config }, + Error(errors.New("the Online option must be set before Config option")), + ), + + libp2p(), + + // common + + // Full node + + ApplyIf(isType(repo.FullNode), + // TODO: Fix offline mode + + Override(new(dtypes.BootstrapPeers), modules.BuiltinBootstrap), + Override(new(dtypes.DrandBootstrap), modules.DrandBootstrap), + Override(new(dtypes.DrandConfig), modules.BuiltinDrandConfig), + + Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages), + + Override(new(ffiwrapper.Verifier), ffiwrapper.ProofVerifier), + Override(new(runtime.Syscalls), vm.Syscalls), + Override(new(*store.ChainStore), modules.ChainStore), + Override(new(*stmgr.StateManager), stmgr.NewStateManager), + Override(new(*wallet.Wallet), wallet.NewWallet), + + Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker), + Override(new(dtypes.ChainGCBlockstore), modules.ChainGCBlockstore), + Override(new(dtypes.ChainExchange), modules.ChainExchange), + Override(new(dtypes.ChainBlockService), modules.ChainBlockservice), + Override(new(dtypes.ClientDAG), testing.MemoryClientDag), + + // Filecoin services + Override(new(*chain.Syncer), modules.NewSyncer), + Override(new(*blocksync.BlockSync), blocksync.NewBlockSyncClient), + Override(new(*messagepool.MessagePool), modules.MessagePool), + + Override(new(modules.Genesis), modules.ErrorGenesis), + Override(new(dtypes.AfterGenesisSet), modules.SetGenesis), + Override(SetGenesisKey, modules.DoSetGenesis), + + Override(new(dtypes.NetworkName), modules.NetworkName), + Override(new(*hello.Service), hello.NewHelloService), + Override(new(*blocksync.BlockSyncService), blocksync.NewBlockSyncService), + Override(new(*peermgr.PeerMgr), peermgr.NewPeerMgr), + + Override(new(dtypes.Graphsync), modules.Graphsync), + + Override(RunHelloKey, modules.RunHello), + Override(RunBlockSyncKey, modules.RunBlockSync), + Override(RunPeerMgrKey, modules.RunPeerMgr), + Override(HandleIncomingBlocksKey, modules.HandleIncomingBlocks), + + Override(new(*discovery.Local), modules.NewLocalDiscovery), + Override(new(retrievalmarket.PeerResolver), modules.RetrievalResolver), + + Override(new(retrievalmarket.RetrievalClient), modules.RetrievalClient), + Override(new(dtypes.ClientDealStore), modules.NewClientDealStore), + Override(new(dtypes.ClientDatastore), modules.NewClientDatastore), + Override(new(dtypes.ClientDataTransfer), modules.NewClientGraphsyncDataTransfer), + Override(new(dtypes.ClientRequestValidator), modules.NewClientRequestValidator), + Override(new(storagemarket.StorageClient), modules.StorageClient), + Override(new(storagemarket.StorageClientNode), storageadapter.NewClientNodeAdapter), + Override(RegisterClientValidatorKey, modules.RegisterClientValidator), + Override(new(beacon.RandomBeacon), modules.RandomBeacon), + + Override(new(*paychmgr.Store), paychmgr.NewStore), + Override(new(*paychmgr.Manager), paychmgr.NewManager), + Override(new(*market.FundMgr), market.NewFundMgr), + ), + + // Storage miner + ApplyIf(func(s *Settings) bool { return s.nodeType == repo.StorageMiner }, + Override(new(api.Common), From(new(common.CommonAPI))), + Override(new(sectorstorage.StorageAuth), modules.StorageAuth), + + Override(new(*stores.Index), stores.NewIndex), + Override(new(stores.SectorIndex), From(new(*stores.Index))), + Override(new(dtypes.MinerID), modules.MinerID), + Override(new(dtypes.MinerAddress), modules.MinerAddress), + Override(new(*ffiwrapper.Config), modules.ProofsConfig), + Override(new(stores.LocalStorage), From(new(repo.LockedRepo))), + Override(new(sealing.SectorIDCounter), modules.SectorIDCounter), + Override(new(*sectorstorage.Manager), modules.SectorStorage), + Override(new(ffiwrapper.Verifier), ffiwrapper.ProofVerifier), + + Override(new(sectorstorage.SectorManager), From(new(*sectorstorage.Manager))), + Override(new(storage2.Prover), From(new(sectorstorage.SectorManager))), + + Override(new(*sectorblocks.SectorBlocks), sectorblocks.NewSectorBlocks), + Override(new(*storage.Miner), modules.StorageMiner), + Override(new(dtypes.NetworkName), modules.StorageNetworkName), + + Override(new(dtypes.StagingBlockstore), modules.StagingBlockstore), + Override(new(dtypes.StagingDAG), modules.StagingDAG), + Override(new(dtypes.StagingGraphsync), modules.StagingGraphsync), + Override(new(retrievalmarket.RetrievalProvider), modules.RetrievalProvider), + Override(new(dtypes.ProviderDealStore), modules.NewProviderDealStore), + Override(new(dtypes.ProviderDataTransfer), modules.NewProviderDAGServiceDataTransfer), + Override(new(dtypes.ProviderRequestValidator), modules.NewProviderRequestValidator), + Override(new(dtypes.ProviderPieceStore), modules.NewProviderPieceStore), + Override(new(*storedask.StoredAsk), modules.NewStorageAsk), + Override(new(storagemarket.StorageProvider), modules.StorageProvider), + Override(new(storagemarket.StorageProviderNode), storageadapter.NewProviderNodeAdapter), + Override(RegisterProviderValidatorKey, modules.RegisterProviderValidator), + Override(HandleRetrievalKey, modules.HandleRetrieval), + Override(GetParamsKey, modules.GetParams), + Override(HandleDealsKey, modules.HandleDeals), + Override(new(gen.WinningPoStProver), storage.NewWinningPoStProver), + Override(new(*miner.Miner), modules.SetupBlockProducer), + + Override(new(dtypes.ConsiderOnlineStorageDealsConfigFunc), modules.NewConsiderOnlineStorageDealsConfigFunc), + Override(new(dtypes.SetConsiderOnlineStorageDealsConfigFunc), modules.NewSetConsideringOnlineStorageDealsFunc), + Override(new(dtypes.ConsiderOnlineRetrievalDealsConfigFunc), modules.NewConsiderOnlineRetrievalDealsConfigFunc), + Override(new(dtypes.SetConsiderOnlineRetrievalDealsConfigFunc), modules.NewSetConsiderOnlineRetrievalDealsConfigFunc), + Override(new(dtypes.StorageDealPieceCidBlocklistConfigFunc), modules.NewStorageDealPieceCidBlocklistConfigFunc), + Override(new(dtypes.SetStorageDealPieceCidBlocklistConfigFunc), modules.NewSetStorageDealPieceCidBlocklistConfigFunc), + Override(new(dtypes.ConsiderOfflineStorageDealsConfigFunc), modules.NewConsiderOfflineStorageDealsConfigFunc), + Override(new(dtypes.SetConsiderOfflineStorageDealsConfigFunc), modules.NewSetConsideringOfflineStorageDealsFunc), + Override(new(dtypes.ConsiderOfflineRetrievalDealsConfigFunc), modules.NewConsiderOfflineRetrievalDealsConfigFunc), + Override(new(dtypes.SetConsiderOfflineRetrievalDealsConfigFunc), modules.NewSetConsiderOfflineRetrievalDealsConfigFunc), + ), + ) +} + +func StorageMiner(out *api.StorageMiner) Option { + return Options( + ApplyIf(func(s *Settings) bool { return s.Config }, + Error(errors.New("the StorageMiner option must be set before Config option")), + ), + ApplyIf(func(s *Settings) bool { return s.Online }, + Error(errors.New("the StorageMiner option must be set before Online option")), + ), + + func(s *Settings) error { + s.nodeType = repo.StorageMiner + return nil + }, + + func(s *Settings) error { + resAPI := &impl.StorageMinerAPI{} + s.invokes[ExtractApiKey] = fx.Extract(resAPI) + *out = resAPI + return nil + }, + ) +} + +// Config sets up constructors based on the provided Config +func ConfigCommon(cfg *config.Common) Option { + return Options( + func(s *Settings) error { s.Config = true; return nil }, + Override(new(dtypes.APIEndpoint), func() (dtypes.APIEndpoint, error) { + return multiaddr.NewMultiaddr(cfg.API.ListenAddress) + }), + Override(SetApiEndpointKey, func(lr repo.LockedRepo, e dtypes.APIEndpoint) error { + return lr.SetAPIEndpoint(e) + }), + Override(new(sectorstorage.URLs), func(e dtypes.APIEndpoint) (sectorstorage.URLs, error) { + ip := cfg.API.RemoteListenAddress + + var urls sectorstorage.URLs + urls = append(urls, "http://"+ip+"/remote") // TODO: This makes no assumptions, and probably could... + return urls, nil + }), + ApplyIf(func(s *Settings) bool { return s.Online }, + Override(StartListeningKey, lp2p.StartListening(cfg.Libp2p.ListenAddresses)), + Override(ConnectionManagerKey, lp2p.ConnectionManager( + cfg.Libp2p.ConnMgrLow, + cfg.Libp2p.ConnMgrHigh, + time.Duration(cfg.Libp2p.ConnMgrGrace), + cfg.Libp2p.ProtectedPeers)), + Override(new(*pubsub.PubSub), lp2p.GossipSub), + Override(new(*config.Pubsub), &cfg.Pubsub), + + ApplyIf(func(s *Settings) bool { return len(cfg.Libp2p.BootstrapPeers) > 0 }, + Override(new(dtypes.BootstrapPeers), modules.ConfigBootstrap(cfg.Libp2p.BootstrapPeers)), + ), + ), + Override(AddrsFactoryKey, lp2p.AddrsFactory( + cfg.Libp2p.AnnounceAddresses, + cfg.Libp2p.NoAnnounceAddresses)), + ) +} + +func ConfigFullNode(c interface{}) Option { + cfg, ok := c.(*config.FullNode) + if !ok { + return Error(xerrors.Errorf("invalid config from repo, got: %T", c)) + } + + ipfsMaddr := cfg.Client.IpfsMAddr + useForRetrieval := cfg.Client.IpfsUseForRetrieval + return Options( + ConfigCommon(&cfg.Common), + If(cfg.Client.UseIpfs, + Override(new(dtypes.ClientBlockstore), modules.IpfsClientBlockstore(ipfsMaddr, useForRetrieval)), + ), + If(cfg.Metrics.HeadNotifs, + Override(HeadMetricsKey, metrics.SendHeadNotifs(cfg.Metrics.Nickname)), + ), + ) +} + +func ConfigStorageMiner(c interface{}) Option { + cfg, ok := c.(*config.StorageMiner) + if !ok { + return Error(xerrors.Errorf("invalid config from repo, got: %T", c)) + } + + return Options( + ConfigCommon(&cfg.Common), + + Override(new(sectorstorage.SealerConfig), cfg.Storage), + ) +} + +func Repo(r repo.Repo) Option { + return func(settings *Settings) error { + lr, err := r.Lock(settings.nodeType) + if err != nil { + return err + } + c, err := lr.Config() + if err != nil { + return err + } + + return Options( + Override(new(repo.LockedRepo), modules.LockedRepo(lr)), // module handles closing + + Override(new(dtypes.MetadataDS), modules.Datastore), + Override(new(dtypes.ChainBlockstore), modules.ChainBlockstore), + + Override(new(dtypes.ClientFilestore), modules.ClientFstore), + Override(new(dtypes.ClientBlockstore), modules.ClientBlockstore), + Override(new(dtypes.ClientDAG), modules.ClientDAG), + + Override(new(ci.PrivKey), lp2p.PrivKey), + Override(new(ci.PubKey), ci.PrivKey.GetPublic), + Override(new(peer.ID), peer.IDFromPublicKey), + + Override(new(types.KeyStore), modules.KeyStore), + + Override(new(*dtypes.APIAlg), modules.APISecret), + + ApplyIf(isType(repo.FullNode), ConfigFullNode(c)), + ApplyIf(isType(repo.StorageMiner), ConfigStorageMiner(c)), + )(settings) + } +} + +func FullAPI(out *api.FullNode) Option { + return func(s *Settings) error { + resAPI := &impl.FullNodeAPI{} + s.invokes[ExtractApiKey] = fx.Extract(resAPI) + *out = resAPI + return nil + } +} + +type StopFunc func(context.Context) error + +// New builds and starts new Filecoin node +func New(ctx context.Context, opts ...Option) (StopFunc, error) { + settings := Settings{ + modules: map[interface{}]fx.Option{}, + invokes: make([]fx.Option, _nInvokes), + nodeType: repo.FullNode, + } + + // apply module options in the right order + if err := Options(Options(defaults()...), Options(opts...))(&settings); err != nil { + return nil, xerrors.Errorf("applying node options failed: %w", err) + } + + // gather constructors for fx.Options + ctors := make([]fx.Option, 0, len(settings.modules)) + for _, opt := range settings.modules { + ctors = append(ctors, opt) + } + + // fill holes in invokes for use in fx.Options + for i, opt := range settings.invokes { + if opt == nil { + settings.invokes[i] = fx.Options() + } + } + + app := fx.New( + fx.Options(ctors...), + fx.Options(settings.invokes...), + + fx.NopLogger, + ) + + // TODO: we probably should have a 'firewall' for Closing signal + // on this context, and implement closing logic through lifecycles + // correctly + if err := app.Start(ctx); err != nil { + // comment fx.NopLogger few lines above for easier debugging + return nil, xerrors.Errorf("starting node: %w", err) + } + + return app.Stop, nil +} + +// In-memory / testing + +func Test() Option { + return Options( + Unset(RunPeerMgrKey), + Unset(new(*peermgr.PeerMgr)), + Override(new(beacon.RandomBeacon), testing.RandomBeacon), + ) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/config/def.go b/vendor/github.com/filecoin-project/lotus/node/config/def.go new file mode 100644 index 0000000000..dd80d4f759 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/config/def.go @@ -0,0 +1,161 @@ +package config + +import ( + "encoding" + "time" + + "github.com/ipfs/go-cid" + + sectorstorage "github.com/filecoin-project/sector-storage" +) + +// Common is common config between full node and miner +type Common struct { + API API + Libp2p Libp2p + Pubsub Pubsub +} + +// FullNode is a full node config +type FullNode struct { + Common + Client Client + Metrics Metrics +} + +// // Common + +// StorageMiner is a storage miner config +type StorageMiner struct { + Common + + Dealmaking DealmakingConfig + Storage sectorstorage.SealerConfig +} + +type DealmakingConfig struct { + ConsiderOnlineStorageDeals bool + ConsiderOfflineStorageDeals bool + ConsiderOnlineRetrievalDeals bool + ConsiderOfflineRetrievalDeals bool + PieceCidBlocklist []cid.Cid +} + +// API contains configs for API endpoint +type API struct { + ListenAddress string + RemoteListenAddress string + Timeout Duration +} + +// Libp2p contains configs for libp2p +type Libp2p struct { + ListenAddresses []string + AnnounceAddresses []string + NoAnnounceAddresses []string + BootstrapPeers []string + ProtectedPeers []string + + ConnMgrLow uint + ConnMgrHigh uint + ConnMgrGrace Duration +} + +type Pubsub struct { + Bootstrapper bool + DirectPeers []string + RemoteTracer string +} + +// // Full Node + +type Metrics struct { + Nickname string + HeadNotifs bool +} + +type Client struct { + UseIpfs bool + IpfsMAddr string + IpfsUseForRetrieval bool +} + +func defCommon() Common { + return Common{ + API: API{ + ListenAddress: "/ip4/127.0.0.1/tcp/1234/http", + Timeout: Duration(30 * time.Second), + }, + Libp2p: Libp2p{ + ListenAddresses: []string{ + "/ip4/0.0.0.0/tcp/0", + "/ip6/::/tcp/0", + }, + AnnounceAddresses: []string{}, + NoAnnounceAddresses: []string{}, + + ConnMgrLow: 150, + ConnMgrHigh: 180, + ConnMgrGrace: Duration(20 * time.Second), + }, + Pubsub: Pubsub{ + Bootstrapper: false, + DirectPeers: nil, + RemoteTracer: "/ip4/147.75.67.199/tcp/4001/p2p/QmTd6UvR47vUidRNZ1ZKXHrAFhqTJAD27rKL9XYghEKgKX", + }, + } + +} + +// DefaultFullNode returns the default config +func DefaultFullNode() *FullNode { + return &FullNode{ + Common: defCommon(), + } +} + +func DefaultStorageMiner() *StorageMiner { + cfg := &StorageMiner{ + Common: defCommon(), + + Storage: sectorstorage.SealerConfig{ + AllowPreCommit1: true, + AllowPreCommit2: true, + AllowCommit: true, + AllowUnseal: true, + }, + + Dealmaking: DealmakingConfig{ + ConsiderOnlineStorageDeals: true, + ConsiderOfflineStorageDeals: true, + ConsiderOnlineRetrievalDeals: true, + ConsiderOfflineRetrievalDeals: true, + PieceCidBlocklist: []cid.Cid{}, + }, + } + cfg.Common.API.ListenAddress = "/ip4/127.0.0.1/tcp/2345/http" + cfg.Common.API.RemoteListenAddress = "127.0.0.1:2345" + return cfg +} + +var _ encoding.TextMarshaler = (*Duration)(nil) +var _ encoding.TextUnmarshaler = (*Duration)(nil) + +// Duration is a wrapper type for time.Duration +// for decoding and encoding from/to TOML +type Duration time.Duration + +// UnmarshalText implements interface for TOML decoding +func (dur *Duration) UnmarshalText(text []byte) error { + d, err := time.ParseDuration(string(text)) + if err != nil { + return err + } + *dur = Duration(d) + return err +} + +func (dur Duration) MarshalText() ([]byte, error) { + d := time.Duration(dur) + return []byte(d.String()), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/config/load.go b/vendor/github.com/filecoin-project/lotus/node/config/load.go new file mode 100644 index 0000000000..b0786643ff --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/config/load.go @@ -0,0 +1,57 @@ +package config + +import ( + "bytes" + "fmt" + "io" + "os" + + "github.com/BurntSushi/toml" + "github.com/kelseyhightower/envconfig" + "golang.org/x/xerrors" +) + +// FromFile loads config from a specified file overriding defaults specified in +// the def parameter. If file does not exist or is empty defaults are assumed. +func FromFile(path string, def interface{}) (interface{}, error) { + file, err := os.Open(path) + switch { + case os.IsNotExist(err): + return def, nil + case err != nil: + return nil, err + } + + defer file.Close() //nolint:errcheck // The file is RO + return FromReader(file, def) +} + +// FromReader loads config from a reader instance. +func FromReader(reader io.Reader, def interface{}) (interface{}, error) { + cfg := def + _, err := toml.DecodeReader(reader, cfg) + if err != nil { + return nil, err + } + + err = envconfig.Process("LOTUS", cfg) + if err != nil { + return nil, fmt.Errorf("processing env vars overrides: %s", err) + } + + return cfg, nil +} + +func ConfigComment(t interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + _, _ = buf.WriteString("# Default config:\n") + e := toml.NewEncoder(buf) + if err := e.Encode(t); err != nil { + return nil, xerrors.Errorf("encoding config: %w", err) + } + b := buf.Bytes() + b = bytes.ReplaceAll(b, []byte("\n"), []byte("\n#")) + b = bytes.ReplaceAll(b, []byte("#["), []byte("[")) + return b, nil + +} diff --git a/vendor/github.com/filecoin-project/lotus/node/config/load_test.go b/vendor/github.com/filecoin-project/lotus/node/config/load_test.go new file mode 100644 index 0000000000..9abe8a54b7 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/config/load_test.go @@ -0,0 +1,63 @@ +package config + +import ( + "bytes" + "io/ioutil" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestDecodeNothing(t *testing.T) { + assert := assert.New(t) + + { + cfg, err := FromFile(os.DevNull, DefaultFullNode()) + assert.Nil(err, "error should be nil") + assert.Equal(DefaultFullNode(), cfg, + "config from empty file should be the same as default") + } + + { + cfg, err := FromFile("./does-not-exist.toml", DefaultFullNode()) + assert.Nil(err, "error should be nil") + assert.Equal(DefaultFullNode(), cfg, + "config from not exisiting file should be the same as default") + } +} + +func TestParitalConfig(t *testing.T) { + assert := assert.New(t) + cfgString := ` + [API] + Timeout = "10s" + ` + expected := DefaultFullNode() + expected.API.Timeout = Duration(10 * time.Second) + + { + cfg, err := FromReader(bytes.NewReader([]byte(cfgString)), DefaultFullNode()) + assert.NoError(err, "error should be nil") + assert.Equal(expected, cfg, + "config from reader should contain changes") + } + + { + f, err := ioutil.TempFile("", "config-*.toml") + fname := f.Name() + + assert.NoError(err, "tmp file shold not error") + _, err = f.WriteString(cfgString) + assert.NoError(err, "writing to tmp file should not error") + err = f.Close() + assert.NoError(err, "closing tmp file should not error") + defer os.Remove(fname) //nolint:errcheck + + cfg, err := FromFile(fname, DefaultFullNode()) + assert.Nil(err, "error should be nil") + assert.Equal(expected, cfg, + "config from reader should contain changes") + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/config/storage.go b/vendor/github.com/filecoin-project/lotus/node/config/storage.go new file mode 100644 index 0000000000..2c603df03a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/config/storage.go @@ -0,0 +1,51 @@ +package config + +import ( + "encoding/json" + "io" + "io/ioutil" + "os" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/sector-storage/stores" +) + +func StorageFromFile(path string, def *stores.StorageConfig) (*stores.StorageConfig, error) { + file, err := os.Open(path) + switch { + case os.IsNotExist(err): + if def == nil { + return nil, xerrors.Errorf("couldn't load storage config: %w", err) + } + return def, nil + case err != nil: + return nil, err + } + + defer file.Close() //nolint:errcheck // The file is RO + return StorageFromReader(file) +} + +func StorageFromReader(reader io.Reader) (*stores.StorageConfig, error) { + var cfg stores.StorageConfig + err := json.NewDecoder(reader).Decode(&cfg) + if err != nil { + return nil, err + } + + return &cfg, nil +} + +func WriteStorageFile(path string, config stores.StorageConfig) error { + b, err := json.MarshalIndent(config, "", " ") + if err != nil { + return xerrors.Errorf("marshaling storage config: %w", err) + } + + if err := ioutil.WriteFile(path, b, 0644); err != nil { + return xerrors.Errorf("persisting storage config (%s): %w", path, err) + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/fxlog.go b/vendor/github.com/filecoin-project/lotus/node/fxlog.go new file mode 100644 index 0000000000..d5d1a3e1f2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/fxlog.go @@ -0,0 +1,17 @@ +package node + +import ( + logging "github.com/ipfs/go-log/v2" + + "go.uber.org/fx" +) + +type debugPrinter struct { + l logging.StandardLogger +} + +func (p *debugPrinter) Printf(f string, a ...interface{}) { + p.l.Debugf(f, a...) +} + +var _ fx.Printer = new(debugPrinter) diff --git a/vendor/github.com/filecoin-project/lotus/node/hello/cbor_gen.go b/vendor/github.com/filecoin-project/lotus/node/hello/cbor_gen.go new file mode 100644 index 0000000000..8a4f9a1bca --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/hello/cbor_gen.go @@ -0,0 +1,266 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package hello + +import ( + "fmt" + "io" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +var lengthBufHelloMessage = []byte{132} + +func (t *HelloMessage) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufHelloMessage); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.HeaviestTipSet ([]cid.Cid) (slice) + if len(t.HeaviestTipSet) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.HeaviestTipSet was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.HeaviestTipSet))); err != nil { + return err + } + for _, v := range t.HeaviestTipSet { + if err := cbg.WriteCidBuf(scratch, w, v); err != nil { + return xerrors.Errorf("failed writing cid field t.HeaviestTipSet: %w", err) + } + } + + // t.HeaviestTipSetHeight (abi.ChainEpoch) (int64) + if t.HeaviestTipSetHeight >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.HeaviestTipSetHeight)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.HeaviestTipSetHeight-1)); err != nil { + return err + } + } + + // t.HeaviestTipSetWeight (big.Int) (struct) + if err := t.HeaviestTipSetWeight.MarshalCBOR(w); err != nil { + return err + } + + // t.GenesisHash (cid.Cid) (struct) + + if err := cbg.WriteCidBuf(scratch, w, t.GenesisHash); err != nil { + return xerrors.Errorf("failed to write cid field t.GenesisHash: %w", err) + } + + return nil +} + +func (t *HelloMessage) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.HeaviestTipSet ([]cid.Cid) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.HeaviestTipSet: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.HeaviestTipSet = make([]cid.Cid, extra) + } + + for i := 0; i < int(extra); i++ { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("reading cid field t.HeaviestTipSet failed: %w", err) + } + t.HeaviestTipSet[i] = c + } + + // t.HeaviestTipSetHeight (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.HeaviestTipSetHeight = abi.ChainEpoch(extraI) + } + // t.HeaviestTipSetWeight (big.Int) (struct) + + { + + if err := t.HeaviestTipSetWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.HeaviestTipSetWeight: %w", err) + } + + } + // t.GenesisHash (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.GenesisHash: %w", err) + } + + t.GenesisHash = c + + } + return nil +} + +var lengthBufLatencyMessage = []byte{130} + +func (t *LatencyMessage) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufLatencyMessage); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.TArrial (int64) (int64) + if t.TArrial >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.TArrial)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.TArrial-1)); err != nil { + return err + } + } + + // t.TSent (int64) (int64) + if t.TSent >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.TSent)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.TSent-1)); err != nil { + return err + } + } + return nil +} + +func (t *LatencyMessage) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.TArrial (int64) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.TArrial = int64(extraI) + } + // t.TSent (int64) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.TSent = int64(extraI) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/hello/hello.go b/vendor/github.com/filecoin-project/lotus/node/hello/hello.go new file mode 100644 index 0000000000..a2a5fbd4e6 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/hello/hello.go @@ -0,0 +1,183 @@ +package hello + +import ( + "context" + "time" + + "github.com/filecoin-project/specs-actors/actors/abi" + + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/host" + inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + protocol "github.com/libp2p/go-libp2p-core/protocol" + + cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/peermgr" +) + +const ProtocolID = "/fil/hello/1.0.0" + +var log = logging.Logger("hello") + +type HelloMessage struct { + HeaviestTipSet []cid.Cid + HeaviestTipSetHeight abi.ChainEpoch + HeaviestTipSetWeight big.Int + GenesisHash cid.Cid +} +type LatencyMessage struct { + TArrial int64 + TSent int64 +} + +type NewStreamFunc func(context.Context, peer.ID, ...protocol.ID) (inet.Stream, error) +type Service struct { + h host.Host + + cs *store.ChainStore + syncer *chain.Syncer + pmgr *peermgr.PeerMgr +} + +func NewHelloService(h host.Host, cs *store.ChainStore, syncer *chain.Syncer, pmgr peermgr.MaybePeerMgr) *Service { + if pmgr.Mgr == nil { + log.Warn("running without peer manager") + } + + return &Service{ + h: h, + + cs: cs, + syncer: syncer, + pmgr: pmgr.Mgr, + } +} + +func (hs *Service) HandleStream(s inet.Stream) { + + var hmsg HelloMessage + if err := cborutil.ReadCborRPC(s, &hmsg); err != nil { + log.Infow("failed to read hello message, disconnecting", "error", err) + _ = s.Conn().Close() + return + } + arrived := time.Now() + + log.Debugw("genesis from hello", + "tipset", hmsg.HeaviestTipSet, + "peer", s.Conn().RemotePeer(), + "hash", hmsg.GenesisHash) + + if hmsg.GenesisHash != hs.syncer.Genesis.Cids()[0] { + log.Warnf("other peer has different genesis! (%s)", hmsg.GenesisHash) + _ = s.Conn().Close() + return + } + go func() { + defer s.Close() //nolint:errcheck + + sent := time.Now() + msg := &LatencyMessage{ + TArrial: arrived.UnixNano(), + TSent: sent.UnixNano(), + } + if err := cborutil.WriteCborRPC(s, msg); err != nil { + log.Debugf("error while responding to latency: %v", err) + } + }() + + protos, err := hs.h.Peerstore().GetProtocols(s.Conn().RemotePeer()) + if err != nil { + log.Warnf("got error from peerstore.GetProtocols: %s", err) + } + if len(protos) == 0 { + log.Warn("other peer hasnt completed libp2p identify, waiting a bit") + // TODO: this better + time.Sleep(time.Millisecond * 300) + } + + ts, err := hs.syncer.FetchTipSet(context.Background(), s.Conn().RemotePeer(), types.NewTipSetKey(hmsg.HeaviestTipSet...)) + if err != nil { + log.Errorf("failed to fetch tipset from peer during hello: %+v", err) + return + } + + if ts.TipSet().Height() > 0 { + hs.h.ConnManager().TagPeer(s.Conn().RemotePeer(), "fcpeer", 10) + + // don't bother informing about genesis + log.Infof("Got new tipset through Hello: %s from %s", ts.Cids(), s.Conn().RemotePeer()) + hs.syncer.InformNewHead(s.Conn().RemotePeer(), ts) + } + if hs.pmgr != nil { + hs.pmgr.AddFilecoinPeer(s.Conn().RemotePeer()) + } + +} + +func (hs *Service) SayHello(ctx context.Context, pid peer.ID) error { + s, err := hs.h.NewStream(ctx, pid, ProtocolID) + if err != nil { + return err + } + + hts := hs.cs.GetHeaviestTipSet() + weight, err := hs.cs.Weight(ctx, hts) + if err != nil { + return err + } + + gen, err := hs.cs.GetGenesis() + if err != nil { + return err + } + + hmsg := &HelloMessage{ + HeaviestTipSet: hts.Cids(), + HeaviestTipSetHeight: hts.Height(), + HeaviestTipSetWeight: weight, + GenesisHash: gen.Cid(), + } + log.Debug("Sending hello message: ", hts.Cids(), hts.Height(), gen.Cid()) + + t0 := time.Now() + if err := cborutil.WriteCborRPC(s, hmsg); err != nil { + return err + } + + go func() { + defer s.Close() //nolint:errcheck + + lmsg := &LatencyMessage{} + _ = s.SetReadDeadline(time.Now().Add(10 * time.Second)) + err := cborutil.ReadCborRPC(s, lmsg) + if err != nil { + log.Infow("reading latency message", "error", err) + } + + t3 := time.Now() + lat := t3.Sub(t0) + // add to peer tracker + if hs.pmgr != nil { + hs.pmgr.SetPeerLatency(pid, lat) + } + + if err == nil { + if lmsg.TArrial != 0 && lmsg.TSent != 0 { + t1 := time.Unix(0, lmsg.TArrial) + t2 := time.Unix(0, lmsg.TSent) + offset := t0.Sub(t1) + t3.Sub(t2) + offset /= 2 + log.Infow("time offset", "offset", offset.Seconds(), "peerid", pid.String()) + } + } + }() + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/client/client.go b/vendor/github.com/filecoin-project/lotus/node/impl/client/client.go new file mode 100644 index 0000000000..6664414a33 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/client/client.go @@ -0,0 +1,571 @@ +package client + +import ( + "context" + "errors" + "fmt" + + "github.com/filecoin-project/go-fil-markets/pieceio" + basicnode "github.com/ipld/go-ipld-prime/node/basic" + "github.com/ipld/go-ipld-prime/traversal/selector" + "github.com/ipld/go-ipld-prime/traversal/selector/builder" + "github.com/multiformats/go-multiaddr" + + "io" + "os" + + "golang.org/x/xerrors" + + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-filestore" + chunker "github.com/ipfs/go-ipfs-chunker" + offline "github.com/ipfs/go-ipfs-exchange-offline" + files "github.com/ipfs/go-ipfs-files" + ipld "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-merkledag" + unixfile "github.com/ipfs/go-unixfs/file" + "github.com/ipfs/go-unixfs/importer/balanced" + ihelper "github.com/ipfs/go-unixfs/importer/helpers" + "github.com/ipld/go-car" + "github.com/libp2p/go-libp2p-core/peer" + "go.uber.org/fx" + + "github.com/filecoin-project/go-address" + rm "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/markets/utils" + "github.com/filecoin-project/lotus/node/impl/full" + "github.com/filecoin-project/lotus/node/impl/paych" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +const dealStartBuffer abi.ChainEpoch = 10000 // TODO: allow setting + +type API struct { + fx.In + + full.ChainAPI + full.StateAPI + full.WalletAPI + paych.PaychAPI + + SMDealClient storagemarket.StorageClient + RetDiscovery rm.PeerResolver + Retrieval rm.RetrievalClient + Chain *store.ChainStore + + LocalDAG dtypes.ClientDAG + Blockstore dtypes.ClientBlockstore + Filestore dtypes.ClientFilestore `optional:"true"` +} + +func calcDealExpiration(minDuration uint64, md *miner.DeadlineInfo, startEpoch abi.ChainEpoch) abi.ChainEpoch { + // Make sure we give some time for the miner to seal + minExp := startEpoch + abi.ChainEpoch(minDuration) + + // Align on miners ProvingPeriodBoundary + return minExp + miner.WPoStProvingPeriod - (minExp % miner.WPoStProvingPeriod) + (md.PeriodStart % miner.WPoStProvingPeriod) - 1 +} + +func (a *API) ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) { + exist, err := a.WalletHas(ctx, params.Wallet) + if err != nil { + return nil, xerrors.Errorf("failed getting addr from wallet: %w", params.Wallet) + } + if !exist { + return nil, xerrors.Errorf("provided address doesn't exist in wallet") + } + + mi, err := a.StateMinerInfo(ctx, params.Miner, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("failed getting peer ID: %w", err) + } + + multiaddrs := make([]multiaddr.Multiaddr, 0, len(mi.Multiaddrs)) + for _, a := range mi.Multiaddrs { + maddr, err := multiaddr.NewMultiaddrBytes(a) + if err != nil { + return nil, err + } + multiaddrs = append(multiaddrs, maddr) + } + + md, err := a.StateMinerProvingDeadline(ctx, params.Miner, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("failed getting peer ID: %w", err) + } + + rt, err := ffiwrapper.SealProofTypeFromSectorSize(mi.SectorSize) + if err != nil { + return nil, xerrors.Errorf("bad sector size: %w", err) + } + + if uint64(params.Data.PieceSize.Padded()) > uint64(mi.SectorSize) { + return nil, xerrors.New("data doesn't fit in a sector") + } + + providerInfo := utils.NewStorageProviderInfo(params.Miner, mi.Worker, mi.SectorSize, mi.PeerId, multiaddrs) + + dealStart := params.DealStartEpoch + if dealStart <= 0 { // unset, or explicitly 'epoch undefined' + ts, err := a.ChainHead(ctx) + if err != nil { + return nil, xerrors.Errorf("failed getting chain height: %w", err) + } + + dealStart = ts.Height() + dealStartBuffer + } + + result, err := a.SMDealClient.ProposeStorageDeal( + ctx, + params.Wallet, + &providerInfo, + params.Data, + dealStart, + calcDealExpiration(params.MinBlocksDuration, md, dealStart), + params.EpochPrice, + big.Zero(), + rt, + ) + + if err != nil { + return nil, xerrors.Errorf("failed to start deal: %w", err) + } + + return &result.ProposalCid, nil +} + +func (a *API) ClientListDeals(ctx context.Context) ([]api.DealInfo, error) { + deals, err := a.SMDealClient.ListLocalDeals(ctx) + if err != nil { + return nil, err + } + + out := make([]api.DealInfo, len(deals)) + for k, v := range deals { + out[k] = api.DealInfo{ + ProposalCid: v.ProposalCid, + State: v.State, + Message: v.Message, + Provider: v.Proposal.Provider, + + PieceCID: v.Proposal.PieceCID, + Size: uint64(v.Proposal.PieceSize.Unpadded()), + + PricePerEpoch: v.Proposal.StoragePricePerEpoch, + Duration: uint64(v.Proposal.Duration()), + DealID: v.DealID, + } + } + + return out, nil +} + +func (a *API) ClientGetDealInfo(ctx context.Context, d cid.Cid) (*api.DealInfo, error) { + v, err := a.SMDealClient.GetLocalDeal(ctx, d) + if err != nil { + return nil, err + } + + return &api.DealInfo{ + ProposalCid: v.ProposalCid, + State: v.State, + Message: v.Message, + Provider: v.Proposal.Provider, + PieceCID: v.Proposal.PieceCID, + Size: uint64(v.Proposal.PieceSize.Unpadded()), + PricePerEpoch: v.Proposal.StoragePricePerEpoch, + Duration: uint64(v.Proposal.Duration()), + DealID: v.DealID, + }, nil +} + +func (a *API) ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error) { + // TODO: check if we have the ENTIRE dag + + offExch := merkledag.NewDAGService(blockservice.New(a.Blockstore, offline.Exchange(a.Blockstore))) + _, err := offExch.Get(ctx, root) + if err == ipld.ErrNotFound { + return false, nil + } + if err != nil { + return false, err + } + return true, nil +} + +func (a *API) ClientFindData(ctx context.Context, root cid.Cid) ([]api.QueryOffer, error) { + peers, err := a.RetDiscovery.GetPeers(root) + if err != nil { + return nil, err + } + + out := make([]api.QueryOffer, len(peers)) + for k, p := range peers { + out[k] = a.makeRetrievalQuery(ctx, p, root, rm.QueryParams{}) + } + + return out, nil +} + +func (a *API) ClientMinerQueryOffer(ctx context.Context, payload cid.Cid, miner address.Address) (api.QueryOffer, error) { + mi, err := a.StateMinerInfo(ctx, miner, types.EmptyTSK) + if err != nil { + return api.QueryOffer{}, err + } + rp := rm.RetrievalPeer{ + Address: miner, + ID: mi.PeerId, + } + return a.makeRetrievalQuery(ctx, rp, payload, rm.QueryParams{}), nil +} + +func (a *API) makeRetrievalQuery(ctx context.Context, rp rm.RetrievalPeer, payload cid.Cid, qp rm.QueryParams) api.QueryOffer { + queryResponse, err := a.Retrieval.Query(ctx, rp, payload, qp) + if err != nil { + return api.QueryOffer{Err: err.Error(), Miner: rp.Address, MinerPeerID: rp.ID} + } + var errStr string + switch queryResponse.Status { + case rm.QueryResponseAvailable: + errStr = "" + case rm.QueryResponseUnavailable: + errStr = fmt.Sprintf("retrieval query offer was unavailable: %s", queryResponse.Message) + case rm.QueryResponseError: + errStr = fmt.Sprintf("retrieval query offer errored: %s", queryResponse.Message) + } + + return api.QueryOffer{ + Root: payload, + Size: queryResponse.Size, + MinPrice: queryResponse.PieceRetrievalPrice(), + PaymentInterval: queryResponse.MaxPaymentInterval, + PaymentIntervalIncrease: queryResponse.MaxPaymentIntervalIncrease, + Miner: queryResponse.PaymentAddress, // TODO: check + MinerPeerID: rp.ID, + Err: errStr, + } +} + +func (a *API) ClientImport(ctx context.Context, ref api.FileRef) (cid.Cid, error) { + + bufferedDS := ipld.NewBufferedDAG(ctx, a.LocalDAG) + nd, err := a.clientImport(ref, bufferedDS) + + if err != nil { + return cid.Undef, err + } + + return nd, nil +} + +func (a *API) ClientImportLocal(ctx context.Context, f io.Reader) (cid.Cid, error) { + file := files.NewReaderFile(f) + + bufferedDS := ipld.NewBufferedDAG(ctx, a.LocalDAG) + + params := ihelper.DagBuilderParams{ + Maxlinks: build.UnixfsLinksPerLevel, + RawLeaves: true, + CidBuilder: nil, + Dagserv: bufferedDS, + } + + db, err := params.New(chunker.NewSizeSplitter(file, int64(build.UnixfsChunkSize))) + if err != nil { + return cid.Undef, err + } + nd, err := balanced.Layout(db) + if err != nil { + return cid.Undef, err + } + + return nd.Cid(), bufferedDS.Commit() +} + +func (a *API) ClientListImports(ctx context.Context) ([]api.Import, error) { + if a.Filestore == nil { + return nil, errors.New("listing imports is not supported with in-memory dag yet") + } + next, err := filestore.ListAll(a.Filestore, false) + if err != nil { + return nil, err + } + + // TODO: make this less very bad by tracking root cids instead of using ListAll + + out := make([]api.Import, 0) + lowest := make([]uint64, 0) + for { + r := next() + if r == nil { + return out, nil + } + matched := false + for i := range out { + if out[i].FilePath == r.FilePath { + matched = true + if lowest[i] > r.Offset { + lowest[i] = r.Offset + out[i] = api.Import{ + Status: r.Status, + Key: r.Key, + FilePath: r.FilePath, + Size: r.Size, + } + } + break + } + } + if !matched { + out = append(out, api.Import{ + Status: r.Status, + Key: r.Key, + FilePath: r.FilePath, + Size: r.Size, + }) + lowest = append(lowest, r.Offset) + } + } +} + +func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error { + if order.MinerPeerID == "" { + mi, err := a.StateMinerInfo(ctx, order.Miner, types.EmptyTSK) + if err != nil { + return err + } + + order.MinerPeerID = peer.ID(mi.PeerId) + } + + if order.Size == 0 { + return xerrors.Errorf("cannot make retrieval deal for zero bytes") + } + + retrievalResult := make(chan error, 1) + + unsubscribe := a.Retrieval.SubscribeToEvents(func(event rm.ClientEvent, state rm.ClientDealState) { + if state.PayloadCID.Equals(order.Root) { + switch state.Status { + case rm.DealStatusCompleted: + retrievalResult <- nil + case rm.DealStatusRejected: + retrievalResult <- xerrors.Errorf("Retrieval Proposal Rejected: %s", state.Message) + case + rm.DealStatusDealNotFound, + rm.DealStatusErrored, + rm.DealStatusFailed: + retrievalResult <- xerrors.Errorf("Retrieval Error: %s", state.Message) + case + rm.DealStatusAccepted, + rm.DealStatusAwaitingAcceptance, + rm.DealStatusBlocksComplete, + rm.DealStatusFinalizing, + rm.DealStatusFundsNeeded, + rm.DealStatusFundsNeededLastPayment, + rm.DealStatusNew, + rm.DealStatusOngoing, + rm.DealStatusPaymentChannelAddingFunds, + rm.DealStatusPaymentChannelAllocatingLane, + rm.DealStatusPaymentChannelCreating, + rm.DealStatusPaymentChannelReady, + rm.DealStatusVerified: + return + default: + retrievalResult <- xerrors.Errorf("Unhandled Retrieval Status: %+v", state.Status) + } + } + }) + + ppb := types.BigDiv(order.Total, types.NewInt(order.Size)) + + _, err := a.Retrieval.Retrieve( + ctx, + order.Root, + rm.NewParamsV0(ppb, order.PaymentInterval, order.PaymentIntervalIncrease), + order.Total, + order.MinerPeerID, + order.Client, + order.Miner) + if err != nil { + return xerrors.Errorf("Retrieve failed: %w", err) + } + select { + case <-ctx.Done(): + return xerrors.New("Retrieval Timed Out") + case err := <-retrievalResult: + if err != nil { + return xerrors.Errorf("RetrieveUnixfs: %w", err) + } + } + + unsubscribe() + + // If ref is nil, it only fetches the data into the configured blockstore. + if ref == nil { + return nil + } + + if ref.IsCAR { + f, err := os.OpenFile(ref.Path, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + err = car.WriteCar(ctx, a.LocalDAG, []cid.Cid{order.Root}, f) + if err != nil { + return err + } + return f.Close() + } + + nd, err := a.LocalDAG.Get(ctx, order.Root) + if err != nil { + return xerrors.Errorf("ClientRetrieve: %w", err) + } + file, err := unixfile.NewUnixfsFile(ctx, a.LocalDAG, nd) + if err != nil { + return xerrors.Errorf("ClientRetrieve: %w", err) + } + return files.WriteTo(file, ref.Path) +} + +func (a *API) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) { + info := utils.NewStorageProviderInfo(miner, address.Undef, 0, p, nil) + signedAsk, err := a.SMDealClient.GetAsk(ctx, info) + if err != nil { + return nil, err + } + return signedAsk, nil +} + +func (a *API) ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) { + mi, err := a.StateMinerInfo(ctx, miner, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("failed checking miners sector size: %w", err) + } + + rt, err := ffiwrapper.SealProofTypeFromSectorSize(mi.SectorSize) + if err != nil { + return nil, xerrors.Errorf("bad sector size: %w", err) + } + + rdr, err := os.Open(inpath) + if err != nil { + return nil, err + } + + stat, err := rdr.Stat() + if err != nil { + return nil, err + } + + commP, pieceSize, err := pieceio.GeneratePieceCommitment(rt, rdr, uint64(stat.Size())) + + if err != nil { + return nil, xerrors.Errorf("computing commP failed: %w", err) + } + + return &api.CommPRet{ + Root: commP, + Size: pieceSize, + }, nil +} + +func (a *API) ClientGenCar(ctx context.Context, ref api.FileRef, outputPath string) error { + + bufferedDS := ipld.NewBufferedDAG(ctx, a.LocalDAG) + c, err := a.clientImport(ref, bufferedDS) + + if err != nil { + return err + } + + defer bufferedDS.Remove(ctx, c) //nolint:errcheck + ssb := builder.NewSelectorSpecBuilder(basicnode.Style.Any) + + // entire DAG selector + allSelector := ssb.ExploreRecursive(selector.RecursionLimitNone(), + ssb.ExploreAll(ssb.ExploreRecursiveEdge())).Node() + + f, err := os.Create(outputPath) + if err != nil { + return err + } + + sc := car.NewSelectiveCar(ctx, a.Blockstore, []car.Dag{{Root: c, Selector: allSelector}}) + if err = sc.Write(f); err != nil { + return err + } + + return f.Close() +} + +func (a *API) clientImport(ref api.FileRef, bufferedDS *ipld.BufferedDAG) (cid.Cid, error) { + f, err := os.Open(ref.Path) + if err != nil { + return cid.Undef, err + } + + stat, err := f.Stat() + if err != nil { + return cid.Undef, err + } + + file, err := files.NewReaderPathFile(ref.Path, f, stat) + if err != nil { + return cid.Undef, err + } + + if ref.IsCAR { + var store car.Store + if a.Filestore == nil { + store = a.Blockstore + } else { + store = (*filestore.Filestore)(a.Filestore) + } + result, err := car.LoadCar(store, file) + if err != nil { + return cid.Undef, err + } + + if len(result.Roots) != 1 { + return cid.Undef, xerrors.New("cannot import car with more than one root") + } + + return result.Roots[0], nil + } + + params := ihelper.DagBuilderParams{ + Maxlinks: build.UnixfsLinksPerLevel, + RawLeaves: true, + CidBuilder: nil, + Dagserv: bufferedDS, + NoCopy: true, + } + + db, err := params.New(chunker.NewSizeSplitter(file, int64(build.UnixfsChunkSize))) + if err != nil { + return cid.Undef, err + } + nd, err := balanced.Layout(db) + if err != nil { + return cid.Undef, err + } + + if err := bufferedDS.Commit(); err != nil { + return cid.Undef, err + } + + return nd.Cid(), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/common/common.go b/vendor/github.com/filecoin-project/lotus/node/impl/common/common.go new file mode 100644 index 0000000000..1d2695b6ee --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/common/common.go @@ -0,0 +1,146 @@ +package common + +import ( + "context" + "sort" + "strings" + + logging "github.com/ipfs/go-log/v2" + + "github.com/gbrlsnchs/jwt/v3" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + swarm "github.com/libp2p/go-libp2p-swarm" + ma "github.com/multiformats/go-multiaddr" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc/auth" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/lp2p" +) + +type CommonAPI struct { + fx.In + + APISecret *dtypes.APIAlg + Host host.Host + Router lp2p.BaseIpfsRouting + Sk *dtypes.ScoreKeeper + ShutdownChan dtypes.ShutdownChan +} + +type jwtPayload struct { + Allow []auth.Permission +} + +func (a *CommonAPI) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) { + var payload jwtPayload + if _, err := jwt.Verify([]byte(token), (*jwt.HMACSHA)(a.APISecret), &payload); err != nil { + return nil, xerrors.Errorf("JWT Verification failed: %w", err) + } + + return payload.Allow, nil +} + +func (a *CommonAPI) AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error) { + p := jwtPayload{ + Allow: perms, // TODO: consider checking validity + } + + return jwt.Sign(&p, (*jwt.HMACSHA)(a.APISecret)) +} + +func (a *CommonAPI) NetConnectedness(ctx context.Context, pid peer.ID) (network.Connectedness, error) { + return a.Host.Network().Connectedness(pid), nil +} +func (a *CommonAPI) NetPubsubScores(context.Context) ([]api.PubsubScore, error) { + scores := a.Sk.Get() + out := make([]api.PubsubScore, len(scores)) + i := 0 + for k, v := range scores { + out[i] = api.PubsubScore{ID: k, Score: v} + i++ + } + + sort.Slice(out, func(i, j int) bool { + return strings.Compare(string(out[i].ID), string(out[j].ID)) > 0 + }) + + return out, nil +} + +func (a *CommonAPI) NetPeers(context.Context) ([]peer.AddrInfo, error) { + conns := a.Host.Network().Conns() + out := make([]peer.AddrInfo, len(conns)) + + for i, conn := range conns { + out[i] = peer.AddrInfo{ + ID: conn.RemotePeer(), + Addrs: []ma.Multiaddr{ + conn.RemoteMultiaddr(), + }, + } + } + + return out, nil +} + +func (a *CommonAPI) NetConnect(ctx context.Context, p peer.AddrInfo) error { + if swrm, ok := a.Host.Network().(*swarm.Swarm); ok { + swrm.Backoff().Clear(p.ID) + } + + return a.Host.Connect(ctx, p) +} + +func (a *CommonAPI) NetAddrsListen(context.Context) (peer.AddrInfo, error) { + return peer.AddrInfo{ + ID: a.Host.ID(), + Addrs: a.Host.Addrs(), + }, nil +} + +func (a *CommonAPI) NetDisconnect(ctx context.Context, p peer.ID) error { + return a.Host.Network().ClosePeer(p) +} + +func (a *CommonAPI) NetFindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) { + return a.Router.FindPeer(ctx, p) +} + +func (a *CommonAPI) ID(context.Context) (peer.ID, error) { + return a.Host.ID(), nil +} + +func (a *CommonAPI) Version(context.Context) (api.Version, error) { + return api.Version{ + Version: build.UserVersion(), + APIVersion: build.APIVersion, + + BlockDelay: build.BlockDelaySecs, + }, nil +} + +func (a *CommonAPI) LogList(context.Context) ([]string, error) { + return logging.GetSubsystems(), nil +} + +func (a *CommonAPI) LogSetLevel(ctx context.Context, subsystem, level string) error { + return logging.SetLogLevel(subsystem, level) +} + +func (a *CommonAPI) Shutdown(ctx context.Context) error { + a.ShutdownChan <- struct{}{} + return nil +} + +func (a *CommonAPI) Closing(ctx context.Context) (<-chan struct{}, error) { + return make(chan struct{}), nil // relies on jsonrpc closing +} + +var _ api.Common = &CommonAPI{} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/full.go b/vendor/github.com/filecoin-project/lotus/node/impl/full.go new file mode 100644 index 0000000000..0091737c41 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/full.go @@ -0,0 +1,29 @@ +package impl + +import ( + logging "github.com/ipfs/go-log/v2" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/node/impl/client" + "github.com/filecoin-project/lotus/node/impl/common" + "github.com/filecoin-project/lotus/node/impl/full" + "github.com/filecoin-project/lotus/node/impl/market" + "github.com/filecoin-project/lotus/node/impl/paych" +) + +var log = logging.Logger("node") + +type FullNodeAPI struct { + common.CommonAPI + full.ChainAPI + client.API + full.MpoolAPI + market.MarketAPI + paych.PaychAPI + full.StateAPI + full.MsigAPI + full.WalletAPI + full.SyncAPI +} + +var _ api.FullNode = &FullNodeAPI{} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/full/chain.go b/vendor/github.com/filecoin-project/lotus/node/impl/full/chain.go new file mode 100644 index 0000000000..d5c8f385b8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/full/chain.go @@ -0,0 +1,507 @@ +package full + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "strconv" + "strings" + "sync" + + "github.com/filecoin-project/go-amt-ipld/v2" + commcid "github.com/filecoin-project/go-fil-commcid" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-hamt-ipld" + blockstore "github.com/ipfs/go-ipfs-blockstore" + offline "github.com/ipfs/go-ipfs-exchange-offline" + cbor "github.com/ipfs/go-ipld-cbor" + ipld "github.com/ipfs/go-ipld-format" + logging "github.com/ipfs/go-log" + "github.com/ipfs/go-merkledag" + "github.com/ipfs/go-path" + "github.com/ipfs/go-path/resolver" + mh "github.com/multiformats/go-multihash" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" +) + +var log = logging.Logger("fullnode") + +type ChainAPI struct { + fx.In + + WalletAPI + + Chain *store.ChainStore +} + +func (a *ChainAPI) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { + return a.Chain.SubHeadChanges(ctx), nil +} + +func (a *ChainAPI) ChainHead(context.Context) (*types.TipSet, error) { + return a.Chain.GetHeaviestTipSet(), nil +} + +func (a *ChainAPI) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) { + pts, err := a.Chain.LoadTipSet(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset key: %w", err) + } + + return a.Chain.GetRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy) +} + +func (a *ChainAPI) ChainGetBlock(ctx context.Context, msg cid.Cid) (*types.BlockHeader, error) { + return a.Chain.GetBlock(msg) +} + +func (a *ChainAPI) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) { + return a.Chain.LoadTipSet(key) +} + +func (a *ChainAPI) ChainGetBlockMessages(ctx context.Context, msg cid.Cid) (*api.BlockMessages, error) { + b, err := a.Chain.GetBlock(msg) + if err != nil { + return nil, err + } + + bmsgs, smsgs, err := a.Chain.MessagesForBlock(b) + if err != nil { + return nil, err + } + + cids := make([]cid.Cid, len(bmsgs)+len(smsgs)) + + for i, m := range bmsgs { + cids[i] = m.Cid() + } + + for i, m := range smsgs { + cids[i+len(bmsgs)] = m.Cid() + } + + return &api.BlockMessages{ + BlsMessages: bmsgs, + SecpkMessages: smsgs, + Cids: cids, + }, nil +} + +func (a *ChainAPI) ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*api.HeadChange, error) { + return a.Chain.GetPath(ctx, from, to) +} + +func (a *ChainAPI) ChainGetParentMessages(ctx context.Context, bcid cid.Cid) ([]api.Message, error) { + b, err := a.Chain.GetBlock(bcid) + if err != nil { + return nil, err + } + + // genesis block has no parent messages... + if b.Height == 0 { + return nil, nil + } + + // TODO: need to get the number of messages better than this + pts, err := a.Chain.LoadTipSet(types.NewTipSetKey(b.Parents...)) + if err != nil { + return nil, err + } + + cm, err := a.Chain.MessagesForTipset(pts) + if err != nil { + return nil, err + } + + var out []api.Message + for _, m := range cm { + out = append(out, api.Message{ + Cid: m.Cid(), + Message: m.VMMessage(), + }) + } + + return out, nil +} + +func (a *ChainAPI) ChainGetParentReceipts(ctx context.Context, bcid cid.Cid) ([]*types.MessageReceipt, error) { + b, err := a.Chain.GetBlock(bcid) + if err != nil { + return nil, err + } + + if b.Height == 0 { + return nil, nil + } + + // TODO: need to get the number of messages better than this + pts, err := a.Chain.LoadTipSet(types.NewTipSetKey(b.Parents...)) + if err != nil { + return nil, err + } + + cm, err := a.Chain.MessagesForTipset(pts) + if err != nil { + return nil, err + } + + var out []*types.MessageReceipt + for i := 0; i < len(cm); i++ { + r, err := a.Chain.GetParentReceipt(b, i) + if err != nil { + return nil, err + } + + out = append(out, r) + } + + return out, nil +} + +func (a *ChainAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return a.Chain.GetTipsetByHeight(ctx, h, ts, true) +} + +func (a *ChainAPI) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte, error) { + blk, err := a.Chain.Blockstore().Get(obj) + if err != nil { + return nil, xerrors.Errorf("blockstore get: %w", err) + } + + return blk.RawData(), nil +} + +func (a *ChainAPI) ChainHasObj(ctx context.Context, obj cid.Cid) (bool, error) { + return a.Chain.Blockstore().Has(obj) +} + +func (a *ChainAPI) ChainStatObj(ctx context.Context, obj cid.Cid, base cid.Cid) (api.ObjStat, error) { + bs := a.Chain.Blockstore() + bsvc := blockservice.New(bs, offline.Exchange(bs)) + + dag := merkledag.NewDAGService(bsvc) + + seen := cid.NewSet() + + var statslk sync.Mutex + var stats api.ObjStat + var collect = true + + walker := func(ctx context.Context, c cid.Cid) ([]*ipld.Link, error) { + if c.Prefix().MhType == uint64(commcid.FC_SEALED_V1) || c.Prefix().MhType == uint64(commcid.FC_UNSEALED_V1) { + return []*ipld.Link{}, nil + } + + nd, err := dag.Get(ctx, c) + if err != nil { + return nil, err + } + + if collect { + s := uint64(len(nd.RawData())) + statslk.Lock() + stats.Size = stats.Size + s + stats.Links = stats.Links + 1 + statslk.Unlock() + } + + return nd.Links(), nil + } + + if base != cid.Undef { + collect = false + if err := merkledag.Walk(ctx, walker, base, seen.Visit, merkledag.Concurrent()); err != nil { + return api.ObjStat{}, err + } + collect = true + } + + if err := merkledag.Walk(ctx, walker, obj, seen.Visit, merkledag.Concurrent()); err != nil { + return api.ObjStat{}, err + } + + return stats, nil +} + +func (a *ChainAPI) ChainSetHead(ctx context.Context, tsk types.TipSetKey) error { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return a.Chain.SetHead(ts) +} + +func (a *ChainAPI) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) { + genb, err := a.Chain.GetGenesis() + if err != nil { + return nil, err + } + + return types.NewTipSet([]*types.BlockHeader{genb}) +} + +func (a *ChainAPI) ChainTipSetWeight(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return a.Chain.Weight(ctx, ts) +} + +func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { + return func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { + if strings.HasPrefix(names[0], "@Ha:") { + addr, err := address.NewFromString(names[0][4:]) + if err != nil { + return nil, nil, xerrors.Errorf("parsing addr: %w", err) + } + + names[0] = "@H:" + string(addr.Bytes()) + } + + if strings.HasPrefix(names[0], "@Hi:") { + i, err := strconv.ParseInt(names[0][4:], 10, 64) + if err != nil { + return nil, nil, xerrors.Errorf("parsing int64: %w", err) + } + + ik := adt.IntKey(i) + + names[0] = "@H:" + ik.Key() + } + + if strings.HasPrefix(names[0], "@Hu:") { + i, err := strconv.ParseUint(names[0][4:], 10, 64) + if err != nil { + return nil, nil, xerrors.Errorf("parsing int64: %w", err) + } + + ik := adt.UIntKey(i) + + names[0] = "@H:" + ik.Key() + } + + if strings.HasPrefix(names[0], "@H:") { + cst := cbor.NewCborStore(bs) + + h, err := hamt.LoadNode(ctx, cst, nd.Cid(), hamt.UseTreeBitWidth(5)) + if err != nil { + return nil, nil, xerrors.Errorf("resolving hamt link: %w", err) + } + + var m interface{} + if err := h.Find(ctx, names[0][3:], &m); err != nil { + return nil, nil, xerrors.Errorf("resolve hamt: %w", err) + } + if c, ok := m.(cid.Cid); ok { + return &ipld.Link{ + Name: names[0][3:], + Cid: c, + }, names[1:], nil + } + + n, err := cbor.WrapObject(m, mh.SHA2_256, 32) + if err != nil { + return nil, nil, err + } + + if err := bs.Put(n); err != nil { + return nil, nil, xerrors.Errorf("put hamt val: %w", err) + } + + if len(names) == 1 { + return &ipld.Link{ + Name: names[0][3:], + Cid: n.Cid(), + }, nil, nil + } + + return resolveOnce(bs)(ctx, ds, n, names[1:]) + } + + if strings.HasPrefix(names[0], "@A:") { + a, err := amt.LoadAMT(ctx, cbor.NewCborStore(bs), nd.Cid()) + if err != nil { + return nil, nil, xerrors.Errorf("load amt: %w", err) + } + + idx, err := strconv.ParseUint(names[0][3:], 10, 64) + if err != nil { + return nil, nil, xerrors.Errorf("parsing amt index: %w", err) + } + + var m interface{} + if err := a.Get(ctx, idx, &m); err != nil { + return nil, nil, xerrors.Errorf("amt get: %w", err) + } + fmt.Printf("AG %T %v\n", m, m) + if c, ok := m.(cid.Cid); ok { + return &ipld.Link{ + Name: names[0][3:], + Cid: c, + }, names[1:], nil + } + + n, err := cbor.WrapObject(m, mh.SHA2_256, 32) + if err != nil { + return nil, nil, err + } + + if err := bs.Put(n); err != nil { + return nil, nil, xerrors.Errorf("put amt val: %w", err) + } + + if len(names) == 1 { + return &ipld.Link{ + Name: names[0][3:], + Size: 0, + Cid: n.Cid(), + }, nil, nil + } + + return resolveOnce(bs)(ctx, ds, n, names[1:]) + } + + if names[0] == "@state" { + var act types.Actor + if err := act.UnmarshalCBOR(bytes.NewReader(nd.RawData())); err != nil { + return nil, nil, xerrors.Errorf("unmarshaling actor struct for @state: %w", err) + } + + head, err := ds.Get(ctx, act.Head) + if err != nil { + return nil, nil, xerrors.Errorf("getting actor head for @state: %w", err) + } + + m, err := vm.DumpActorState(act.Code, head.RawData()) + if err != nil { + return nil, nil, err + } + + // a hack to workaround struct aliasing in refmt + ms := map[string]interface{}{} + { + mstr, err := json.Marshal(m) + if err != nil { + return nil, nil, err + } + if err := json.Unmarshal(mstr, &ms); err != nil { + return nil, nil, err + } + } + + n, err := cbor.WrapObject(ms, mh.SHA2_256, 32) + if err != nil { + return nil, nil, err + } + + if err := bs.Put(n); err != nil { + return nil, nil, xerrors.Errorf("put amt val: %w", err) + } + + if len(names) == 1 { + return &ipld.Link{ + Name: "state", + Size: 0, + Cid: n.Cid(), + }, nil, nil + } + + return resolveOnce(bs)(ctx, ds, n, names[1:]) + } + + return nd.ResolveLink(names) + } +} + +func (a *ChainAPI) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) { + ip, err := path.ParsePath(p) + if err != nil { + return nil, xerrors.Errorf("parsing path: %w", err) + } + + bs := a.Chain.Blockstore() + bsvc := blockservice.New(bs, offline.Exchange(bs)) + + dag := merkledag.NewDAGService(bsvc) + + r := &resolver.Resolver{ + DAG: dag, + ResolveOnce: resolveOnce(bs), + } + + node, err := r.ResolvePath(ctx, ip) + if err != nil { + return nil, err + } + + return &api.IpldObject{ + Cid: node.Cid(), + Obj: node, + }, nil +} + +func (a *ChainAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { + cm, err := a.Chain.GetCMessage(mc) + if err != nil { + return nil, err + } + + return cm.VMMessage(), nil +} + +func (a *ChainAPI) ChainExport(ctx context.Context, tsk types.TipSetKey) (<-chan []byte, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + r, w := io.Pipe() + out := make(chan []byte) + go func() { + defer w.Close() //nolint:errcheck // it is a pipe + if err := a.Chain.Export(ctx, ts, w); err != nil { + log.Errorf("chain export call failed: %s", err) + return + } + }() + + go func() { + defer close(out) + for { + buf := make([]byte, 4096) + n, err := r.Read(buf) + if err != nil && err != io.EOF { + log.Errorf("chain export pipe read failed: %s", err) + return + } + select { + case out <- buf[:n]: + case <-ctx.Done(): + log.Warnf("export writer failed: %s", ctx.Err()) + } + if err == io.EOF { + return + } + } + }() + + return out, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/full/mpool.go b/vendor/github.com/filecoin-project/lotus/node/impl/full/mpool.go new file mode 100644 index 0000000000..79e6d30bed --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/full/mpool.go @@ -0,0 +1,124 @@ +package full + +import ( + "context" + + "github.com/ipfs/go-cid" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +type MpoolAPI struct { + fx.In + + WalletAPI + + Chain *store.ChainStore + + Mpool *messagepool.MessagePool +} + +func (a *MpoolAPI) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + pending, mpts := a.Mpool.Pending() + + haveCids := map[cid.Cid]struct{}{} + for _, m := range pending { + haveCids[m.Cid()] = struct{}{} + } + + if ts == nil || mpts.Height() > ts.Height() { + return pending, nil + } + + for { + if mpts.Height() == ts.Height() { + if mpts.Equals(ts) { + return pending, nil + } + // different blocks in tipsets + + have, err := a.Mpool.MessagesForBlocks(ts.Blocks()) + if err != nil { + return nil, xerrors.Errorf("getting messages for base ts: %w", err) + } + + for _, m := range have { + haveCids[m.Cid()] = struct{}{} + } + } + + msgs, err := a.Mpool.MessagesForBlocks(ts.Blocks()) + if err != nil { + return nil, xerrors.Errorf(": %w", err) + } + + for _, m := range msgs { + if _, ok := haveCids[m.Cid()]; ok { + continue + } + + haveCids[m.Cid()] = struct{}{} + pending = append(pending, m) + } + + if mpts.Height() >= ts.Height() { + return pending, nil + } + + ts, err = a.Chain.LoadTipSet(ts.Parents()) + if err != nil { + return nil, xerrors.Errorf("loading parent tipset: %w", err) + } + } +} + +func (a *MpoolAPI) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) { + return a.Mpool.Push(smsg) +} + +func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message) (*types.SignedMessage, error) { + if msg.Nonce != 0 { + return nil, xerrors.Errorf("MpoolPushMessage expects message nonce to be 0, was %d", msg.Nonce) + } + + return a.Mpool.PushWithNonce(ctx, msg.From, func(from address.Address, nonce uint64) (*types.SignedMessage, error) { + msg.Nonce = nonce + if msg.From.Protocol() == address.ID { + log.Warnf("Push from ID address (%s), adjusting to %s", msg.From, from) + msg.From = from + } + + b, err := a.WalletBalance(ctx, msg.From) + if err != nil { + return nil, xerrors.Errorf("mpool push: getting origin balance: %w", err) + } + + if b.LessThan(msg.Value) { + return nil, xerrors.Errorf("mpool push: not enough funds: %s < %s", b, msg.Value) + } + + return a.WalletSignMessage(ctx, from, msg) + }) +} + +func (a *MpoolAPI) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) { + return a.Mpool.GetNonce(addr) +} + +func (a *MpoolAPI) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate, error) { + return a.Mpool.Updates(ctx) +} + +func (a *MpoolAPI) MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) { + return a.Mpool.EstimateGasPrice(ctx, nblocksincl, sender, gaslimit, tsk) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/full/multisig.go b/vendor/github.com/filecoin-project/lotus/node/impl/full/multisig.go new file mode 100644 index 0000000000..65e64e22f7 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/full/multisig.go @@ -0,0 +1,224 @@ +package full + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" + samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + + "github.com/ipfs/go-cid" + "github.com/minio/blake2b-simd" + "go.uber.org/fx" + "golang.org/x/xerrors" +) + +type MsigAPI struct { + fx.In + + WalletAPI WalletAPI + StateAPI StateAPI + MpoolAPI MpoolAPI +} + +func (a *MsigAPI) MsigCreate(ctx context.Context, req int64, addrs []address.Address, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) { + + lenAddrs := int64(len(addrs)) + + if lenAddrs < req { + return cid.Undef, xerrors.Errorf("cannot require signing of more addresses than provided for multisig") + } + + if req == 0 { + req = lenAddrs + } + + if src == address.Undef { + return cid.Undef, xerrors.Errorf("must provide source address") + } + + if gp == types.EmptyInt { + gp = types.NewInt(1) + } + + // Set up constructor parameters for multisig + msigParams := &samsig.ConstructorParams{ + Signers: addrs, + NumApprovalsThreshold: req, + } + + enc, actErr := actors.SerializeParams(msigParams) + if actErr != nil { + return cid.Undef, actErr + } + + // new actors are created by invoking 'exec' on the init actor with the constructor params + execParams := &init_.ExecParams{ + CodeCID: builtin.MultisigActorCodeID, + ConstructorParams: enc, + } + + enc, actErr = actors.SerializeParams(execParams) + if actErr != nil { + return cid.Undef, actErr + } + + // now we create the message to send this with + msg := types.Message{ + To: builtin.InitActorAddr, + From: src, + Method: builtin.MethodsInit.Exec, + Params: enc, + GasPrice: gp, + GasLimit: 1000000, + Value: val, + } + + // send the message out to the network + smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, &msg) + if err != nil { + return cid.Undef, err + } + + return smsg.Cid(), nil +} + +func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { + + if msig == address.Undef { + return cid.Undef, xerrors.Errorf("must provide a multisig address for proposal") + } + + if to == address.Undef { + return cid.Undef, xerrors.Errorf("must provide a target address for proposal") + } + + if amt.Sign() == -1 { + return cid.Undef, xerrors.Errorf("must provide a positive amount for proposed send") + } + + if src == address.Undef { + return cid.Undef, xerrors.Errorf("must provide source address") + } + + enc, actErr := actors.SerializeParams(&samsig.ProposeParams{ + To: to, + Value: amt, + Method: abi.MethodNum(method), + Params: params, + }) + if actErr != nil { + return cid.Undef, actErr + } + + msg := &types.Message{ + To: msig, + From: src, + Value: types.NewInt(0), + Method: builtin.MethodsMultisig.Propose, + Params: enc, + GasLimit: 100000, + GasPrice: types.NewInt(1), + } + + smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg) + if err != nil { + return cid.Undef, nil + } + + return smsg.Cid(), nil +} + +func (a *MsigAPI) MsigApprove(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { + return a.msigApproveOrCancel(ctx, api.MsigApprove, msig, txID, proposer, to, amt, src, method, params) +} + +func (a *MsigAPI) MsigCancel(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { + return a.msigApproveOrCancel(ctx, api.MsigCancel, msig, txID, proposer, to, amt, src, method, params) +} + +func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigProposeResponse, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) { + if msig == address.Undef { + return cid.Undef, xerrors.Errorf("must provide multisig address") + } + + if to == address.Undef { + return cid.Undef, xerrors.Errorf("must provide proposed target address") + } + + if amt.Sign() == -1 { + return cid.Undef, xerrors.Errorf("must provide the positive amount that was proposed") + } + + if src == address.Undef { + return cid.Undef, xerrors.Errorf("must provide source address") + } + + if proposer.Protocol() != address.ID { + proposerID, err := a.StateAPI.StateLookupID(ctx, proposer, types.EmptyTSK) + if err != nil { + return cid.Undef, err + } + proposer = proposerID + } + + p := samsig.ProposalHashData{ + Requester: proposer, + To: to, + Value: amt, + Method: abi.MethodNum(method), + Params: params, + } + + pser, err := p.Serialize() + if err != nil { + return cid.Undef, err + } + phash := blake2b.Sum256(pser) + + enc, err := actors.SerializeParams(&samsig.TxnIDParams{ + ID: samsig.TxnID(txID), + ProposalHash: phash[:], + }) + + if err != nil { + return cid.Undef, err + } + + var msigResponseMethod abi.MethodNum + + /* + We pass in a MsigProposeResponse instead of MethodNum to + tighten the possible inputs to just Approve and Cancel. + */ + switch operation { + case api.MsigApprove: + msigResponseMethod = builtin.MethodsMultisig.Approve + case api.MsigCancel: + msigResponseMethod = builtin.MethodsMultisig.Cancel + default: + return cid.Undef, xerrors.Errorf("Invalid operation for msigApproveOrCancel") + } + + msg := &types.Message{ + To: msig, + From: src, + Value: types.NewInt(0), + Method: msigResponseMethod, + Params: enc, + GasLimit: 100000, + GasPrice: types.NewInt(1), + } + + smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg) + if err != nil { + return cid.Undef, err + } + + return smsg.Cid(), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/full/state.go b/vendor/github.com/filecoin-project/lotus/node/impl/full/state.go new file mode 100644 index 0000000000..1792679444 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/full/state.go @@ -0,0 +1,840 @@ +package full + +import ( + "bytes" + "context" + "fmt" + "strconv" + + cid "github.com/ipfs/go-cid" + "github.com/ipfs/go-hamt-ipld" + cbor "github.com/ipfs/go-ipld-cbor" + cbg "github.com/whyrusleeping/cbor-gen" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-amt-ipld/v2" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/beacon" + "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/lib/bufbstore" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +type StateAPI struct { + fx.In + + // TODO: the wallet here is only needed because we have the MinerCreateBlock + // API attached to the state API. It probably should live somewhere better + Wallet *wallet.Wallet + + ProofVerifier ffiwrapper.Verifier + StateManager *stmgr.StateManager + Chain *store.ChainStore + Beacon beacon.RandomBeacon +} + +func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) { + return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState()) +} + +func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *abi.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, filter, filterOut) +} + +func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + var mas miner.State + _, err = a.StateManager.LoadActorState(ctx, addr, &mas, ts) + if err != nil { + return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) + } + + return stmgr.GetProvingSetRaw(ctx, a.StateManager, mas) +} + +func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return api.MinerInfo{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + mi, err := stmgr.StateMinerInfo(ctx, a.StateManager, ts, actor) + if err != nil { + return api.MinerInfo{}, err + } + return api.NewApiMinerInfo(mi), nil +} + +func (a *StateAPI) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) (*miner.Deadlines, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.GetMinerDeadlines(ctx, a.StateManager, ts, m) +} + +func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + var mas miner.State + _, err = a.StateManager.LoadActorState(ctx, addr, &mas, ts) + if err != nil { + return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) + } + + return miner.ComputeProvingPeriodDeadline(mas.ProvingPeriodStart, ts.Height()), nil +} + +func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.BitField, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.GetMinerFaults(ctx, a.StateManager, ts, addr) +} + +func (a *StateAPI) StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, endTsk types.TipSetKey) ([]*api.Fault, error) { + endTs, err := a.Chain.GetTipSetFromKey(endTsk) + if err != nil { + return nil, xerrors.Errorf("loading end tipset %s: %w", endTsk, err) + } + + cutoff := endTs.Height() - lookback + miners, err := stmgr.ListMinerActors(ctx, a.StateManager, endTs) + + if err != nil { + return nil, xerrors.Errorf("loading miners: %w", err) + } + + var allFaults []*api.Fault + + for _, m := range miners { + var mas miner.State + _, err := a.StateManager.LoadActorState(ctx, m, &mas, endTs) + if err != nil { + return nil, xerrors.Errorf("failed to load miner actor state %s: %w", m, err) + } + + err = mas.ForEachFaultEpoch(a.Chain.Store(ctx), func(faultStart abi.ChainEpoch, faults *abi.BitField) error { + if faultStart >= cutoff { + allFaults = append(allFaults, &api.Fault{ + Miner: m, + Epoch: faultStart, + }) + return nil + } + return nil + }) + + if err != nil { + return nil, xerrors.Errorf("failure when iterating over miner states: %w", err) + } + } + + return allFaults, nil +} + +func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.BitField, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.GetMinerRecoveries(ctx, a.StateManager, ts, addr) +} + +func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + m, net, err := stmgr.GetPower(ctx, a.StateManager, ts, addr) + if err != nil { + return nil, err + } + + return &api.MinerPower{ + MinerPower: m, + TotalPower: net, + }, nil +} + +func (a *StateAPI) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) { + /*ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + param, err := actors.SerializeParams(&actors.PledgeCollateralParams{Size: types.NewInt(0)}) + if err != nil { + return types.NewInt(0), err + } + + ret, aerr := a.StateManager.Call(ctx, &types.Message{ + From: actors.StoragePowerAddress, + To: actors.StoragePowerAddress, + Method: actors.SPAMethods.PledgeCollateralForSize, + + Params: param, + }, ts) + if aerr != nil { + return types.NewInt(0), xerrors.Errorf("failed to get miner worker addr: %w", err) + } + + if ret.MsgRct.ExitCode != 0 { + return types.NewInt(0), xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.MsgRct.ExitCode) + } + + return types.BigFromBytes(ret.Return), nil*/ + log.Error("TODO StatePledgeCollateral") + return big.Zero(), nil +} + +func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return a.StateManager.Call(ctx, msg, ts) +} + +func (a *StateAPI) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.Cid) (*api.InvocResult, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + m, r, err := a.StateManager.Replay(ctx, ts, mc) + if err != nil { + return nil, err + } + + var errstr string + if r.ActorErr != nil { + errstr = r.ActorErr.Error() + } + + return &api.InvocResult{ + Msg: m, + MsgRct: &r.MessageReceipt, + ExecutionTrace: r.ExecutionTrace, + Error: errstr, + Duration: r.Duration, + }, nil +} + +func (a *StateAPI) stateForTs(ctx context.Context, ts *types.TipSet) (*state.StateTree, error) { + if ts == nil { + ts = a.Chain.GetHeaviestTipSet() + } + + st, _, err := a.StateManager.TipSetState(ctx, ts) + if err != nil { + return nil, err + } + + buf := bufbstore.NewBufferedBstore(a.Chain.Blockstore()) + cst := cbor.NewCborStore(buf) + return state.LoadStateTree(cst, st) +} + +func (a *StateAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + state, err := a.stateForTs(ctx, ts) + if err != nil { + return nil, xerrors.Errorf("computing tipset state failed: %w", err) + } + + return state.GetActor(actor) +} + +func (a *StateAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + state, err := a.stateForTs(ctx, ts) + if err != nil { + return address.Undef, err + } + + return state.LookupID(addr) +} + +func (a *StateAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + return a.StateManager.ResolveToKeyAddress(ctx, addr, ts) +} + +func (a *StateAPI) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + state, err := a.stateForTs(ctx, ts) + if err != nil { + return nil, err + } + + act, err := state.GetActor(actor) + if err != nil { + return nil, err + } + + blk, err := state.Store.(*cbor.BasicIpldStore).Blocks.Get(act.Head) + if err != nil { + return nil, err + } + + oif, err := vm.DumpActorState(act.Code, blk.RawData()) + if err != nil { + return nil, err + } + + return &api.ActorState{ + Balance: act.Balance, + State: oif, + }, nil +} + +// This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner +func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) { + return stmgr.MinerGetBaseInfo(ctx, a.StateManager, a.Beacon, tsk, epoch, maddr, a.ProofVerifier) +} + +func (a *StateAPI) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate) (*types.BlockMsg, error) { + fblk, err := gen.MinerCreateBlock(ctx, a.StateManager, a.Wallet, bt) + if err != nil { + return nil, err + } + + var out types.BlockMsg + out.Header = fblk.Header + for _, msg := range fblk.BlsMessages { + out.BlsMessages = append(out.BlsMessages, msg.Cid()) + } + for _, msg := range fblk.SecpkMessages { + out.SecpkMessages = append(out.SecpkMessages, msg.Cid()) + } + + return &out, nil +} + +func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) { + ts, recpt, err := a.StateManager.WaitForMessage(ctx, msg, confidence) + if err != nil { + return nil, err + } + + var returndec interface{} + if recpt.ExitCode == 0 && len(recpt.Return) > 0 { + cmsg, err := a.Chain.GetCMessage(msg) + if err != nil { + return nil, xerrors.Errorf("failed to load message after successful receipt search: %w", err) + } + + vmsg := cmsg.VMMessage() + + t, err := stmgr.GetReturnType(ctx, a.StateManager, vmsg.To, vmsg.Method, ts) + if err != nil { + return nil, xerrors.Errorf("failed to get return type: %w", err) + } + + if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil { + return nil, err + } + + returndec = t + } + + return &api.MsgLookup{ + Receipt: *recpt, + ReturnDec: returndec, + TipSet: ts, + }, nil +} + +func (a *StateAPI) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLookup, error) { + ts, recpt, err := a.StateManager.SearchForMessage(ctx, msg) + if err != nil { + return nil, err + } + + if ts != nil { + return &api.MsgLookup{ + Receipt: *recpt, + TipSet: ts, + }, nil + } else { + return nil, nil + } +} + +func (a *StateAPI) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return a.StateManager.GetReceipt(ctx, msg, ts) +} + +func (a *StateAPI) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.ListMinerActors(ctx, a.StateManager, ts) +} + +func (a *StateAPI) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return a.StateManager.ListAllActors(ctx, ts) +} + +func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return api.MarketBalance{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return a.StateManager.MarketBalance(ctx, addr, ts) +} + +func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketBalance, error) { + out := map[string]api.MarketBalance{} + + var state market.State + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { + return nil, err + } + cst := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) + escrow, err := hamt.LoadNode(ctx, cst, state.EscrowTable, hamt.UseTreeBitWidth(5)) // todo: adt map + if err != nil { + return nil, err + } + locked, err := hamt.LoadNode(ctx, cst, state.LockedTable, hamt.UseTreeBitWidth(5)) + if err != nil { + return nil, err + } + + err = escrow.ForEach(ctx, func(k string, val interface{}) error { + cv := val.(*cbg.Deferred) + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + + var es abi.TokenAmount + if err := es.UnmarshalCBOR(bytes.NewReader(cv.Raw)); err != nil { + return err + } + var lk abi.TokenAmount + if err := locked.Find(ctx, k, &es); err != nil { + return err + } + + out[a.String()] = api.MarketBalance{ + Escrow: es, + Locked: lk, + } + return nil + }) + if err != nil { + return nil, err + } + return out, nil +} + +func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketDeal, error) { + out := map[string]api.MarketDeal{} + + var state market.State + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { + return nil, err + } + + blks := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) + da, err := amt.LoadAMT(ctx, blks, state.Proposals) + if err != nil { + return nil, err + } + + sa, err := amt.LoadAMT(ctx, blks, state.States) + if err != nil { + return nil, err + } + + if err := da.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { + var d market.DealProposal + if err := d.UnmarshalCBOR(bytes.NewReader(v.Raw)); err != nil { + return err + } + + var s market.DealState + if err := sa.Get(ctx, i, &s); err != nil { + if _, ok := err.(*amt.ErrNotFound); !ok { + return xerrors.Errorf("failed to get state for deal in proposals array: %w", err) + } + + s.SectorStartEpoch = -1 + } + out[strconv.FormatInt(int64(i), 10)] = api.MarketDeal{ + Proposal: d, + State: s, + } + return nil + }); err != nil { + return nil, err + } + return out, nil +} + +func (a *StateAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.GetStorageDeal(ctx, a.StateManager, dealId, ts) +} + +func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) { + cst := cbor.NewCborStore(a.Chain.Blockstore()) + + nh, err := hamt.LoadNode(ctx, cst, new, hamt.UseTreeBitWidth(5)) + if err != nil { + return nil, err + } + + oh, err := hamt.LoadNode(ctx, cst, old, hamt.UseTreeBitWidth(5)) + if err != nil { + return nil, err + } + + out := map[string]types.Actor{} + + err = nh.ForEach(ctx, func(k string, nval interface{}) error { + ncval := nval.(*cbg.Deferred) + var act types.Actor + + var ocval cbg.Deferred + + switch err := oh.Find(ctx, k, &ocval); err { + case nil: + if bytes.Equal(ocval.Raw, ncval.Raw) { + return nil // not changed + } + fallthrough + case hamt.ErrNotFound: + if err := act.UnmarshalCBOR(bytes.NewReader(ncval.Raw)); err != nil { + return err + } + + addr, err := address.NewFromBytes([]byte(k)) + if err != nil { + return xerrors.Errorf("address in state tree was not valid: %w", err) + } + + out[addr.String()] = act + default: + return err + } + + return nil + }) + if err != nil { + return nil, err + } + + return out, nil +} + +func (a *StateAPI) StateMinerSectorCount(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MinerSectors, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return api.MinerSectors{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.SectorSetSizes(ctx, a.StateManager, addr, ts) +} + +func (a *StateAPI) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return miner.SectorPreCommitOnChainInfo{}, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.PreCommitInfo(ctx, a.StateManager, maddr, n, ts) +} + +func (a *StateAPI) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + return stmgr.MinerSectorInfo(ctx, a.StateManager, maddr, n, ts) +} + +func (a *StateAPI) StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toheight abi.ChainEpoch) ([]cid.Cid, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + if ts == nil { + ts = a.Chain.GetHeaviestTipSet() + } + + if match.To == address.Undef && match.From == address.Undef { + return nil, xerrors.Errorf("must specify at least To or From in message filter") + } + + matchFunc := func(msg *types.Message) bool { + if match.From != address.Undef && match.From != msg.From { + return false + } + + if match.To != address.Undef && match.To != msg.To { + return false + } + + return true + } + + var out []cid.Cid + for ts.Height() >= toheight { + msgs, err := a.Chain.MessagesForTipset(ts) + if err != nil { + return nil, xerrors.Errorf("failed to get messages for tipset (%s): %w", ts.Key(), err) + } + + for _, msg := range msgs { + if matchFunc(msg.VMMessage()) { + out = append(out, msg.Cid()) + } + } + + if ts.Height() == 0 { + break + } + + next, err := a.Chain.LoadTipSet(ts.Parents()) + if err != nil { + return nil, xerrors.Errorf("loading next tipset: %w", err) + } + + ts = next + } + + return out, nil +} + +func (a *StateAPI) StateCompute(ctx context.Context, height abi.ChainEpoch, msgs []*types.Message, tsk types.TipSetKey) (*api.ComputeStateOutput, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + st, t, err := stmgr.ComputeState(ctx, a.StateManager, height, msgs, ts) + if err != nil { + return nil, err + } + + return &api.ComputeStateOutput{ + Root: st, + Trace: t, + }, nil +} + +func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + var st samsig.State + act, err := a.StateManager.LoadActorState(ctx, addr, &st, ts) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state: %w", err) + } + + if act.Code != builtin.MultisigActorCodeID { + return types.EmptyInt, fmt.Errorf("given actor was not a multisig") + } + + if st.UnlockDuration == 0 { + return act.Balance, nil + } + + offset := ts.Height() - st.StartEpoch + if offset > st.UnlockDuration { + return act.Balance, nil + } + + minBalance := types.BigDiv(st.InitialBalance, types.NewInt(uint64(st.UnlockDuration))) + minBalance = types.BigMul(minBalance, types.NewInt(uint64(offset))) + return types.BigSub(act.Balance, minBalance), nil +} + +var initialPledgeNum = types.NewInt(103) +var initialPledgeDen = types.NewInt(100) + +func (a *StateAPI) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, snum abi.SectorNumber, tsk types.TipSetKey) (types.BigInt, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + act, err := a.StateManager.GetActor(maddr, ts) + if err != nil { + return types.EmptyInt, err + } + + as := store.ActorStore(ctx, a.Chain.Blockstore()) + + var st miner.State + if err := as.Get(ctx, act.Head, &st); err != nil { + return types.EmptyInt, err + } + + precommit, found, err := st.GetPrecommittedSector(as, snum) + if err != nil { + return types.EmptyInt, err + } + + if !found { + return types.EmptyInt, xerrors.Errorf("no precommit found for sector %d", snum) + } + + var dealWeights market.VerifyDealsOnSectorProveCommitReturn + { + var err error + params, err := actors.SerializeParams(&market.VerifyDealsOnSectorProveCommitParams{ + DealIDs: precommit.Info.DealIDs, + SectorExpiry: precommit.Info.Expiration, + }) + if err != nil { + return types.EmptyInt, err + } + + ret, err := a.StateManager.Call(ctx, &types.Message{ + From: maddr, + To: builtin.StorageMarketActorAddr, + Method: builtin.MethodsMarket.VerifyDealsOnSectorProveCommit, + GasLimit: 100000000000, + GasPrice: types.NewInt(0), + Params: params, + }, ts) + if err != nil { + return types.EmptyInt, err + } + + if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret.MsgRct.Return)); err != nil { + return types.BigInt{}, err + } + } + + initialPledge := big.Zero() + { + ssize, err := precommit.Info.SealProof.SectorSize() + if err != nil { + return types.EmptyInt, err + } + + params, err := actors.SerializeParams(&power.OnSectorProveCommitParams{ + Weight: power.SectorStorageWeightDesc{ + SectorSize: ssize, + Duration: precommit.Info.Expiration - ts.Height(), // NB: not exactly accurate, but should always lead us to *over* estimate, not under + DealWeight: dealWeights.DealWeight, + VerifiedDealWeight: dealWeights.VerifiedDealWeight, + }, + }) + if err != nil { + return types.EmptyInt, err + } + + ret, err := a.StateManager.Call(ctx, &types.Message{ + From: maddr, + To: builtin.StoragePowerActorAddr, + Method: builtin.MethodsPower.OnSectorProveCommit, + GasLimit: 10000000000, + GasPrice: types.NewInt(0), + Params: params, + }, ts) + if err != nil { + return types.EmptyInt, err + } + + if err := initialPledge.UnmarshalCBOR(bytes.NewReader(ret.MsgRct.Return)); err != nil { + return types.BigInt{}, err + } + } + + return types.BigDiv(types.BigMul(initialPledge, initialPledgeNum), initialPledgeDen), nil +} + +func (a *StateAPI) StateMinerAvailableBalance(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (types.BigInt, error) { + ts, err := a.Chain.GetTipSetFromKey(tsk) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err) + } + + act, err := a.StateManager.GetActor(maddr, ts) + if err != nil { + return types.EmptyInt, err + } + + as := store.ActorStore(ctx, a.Chain.Blockstore()) + + var st miner.State + if err := as.Get(ctx, act.Head, &st); err != nil { + return types.EmptyInt, err + } + + vested, err := st.CheckVestedFunds(as, ts.Height()) + if err != nil { + return types.EmptyInt, err + } + + return types.BigAdd(st.GetAvailableBalance(act.Balance), vested), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/full/sync.go b/vendor/github.com/filecoin-project/lotus/node/impl/full/sync.go new file mode 100644 index 0000000000..c7c9baaafc --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/full/sync.go @@ -0,0 +1,102 @@ +package full + +import ( + "context" + + cid "github.com/ipfs/go-cid" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +type SyncAPI struct { + fx.In + + Syncer *chain.Syncer + PubSub *pubsub.PubSub + NetName dtypes.NetworkName +} + +func (a *SyncAPI) SyncState(ctx context.Context) (*api.SyncState, error) { + states := a.Syncer.State() + + out := &api.SyncState{} + + for i := range states { + ss := &states[i] + out.ActiveSyncs = append(out.ActiveSyncs, api.ActiveSync{ + Base: ss.Base, + Target: ss.Target, + Stage: ss.Stage, + Height: ss.Height, + Start: ss.Start, + End: ss.End, + Message: ss.Message, + }) + } + return out, nil +} + +func (a *SyncAPI) SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error { + // TODO: should we have some sort of fast path to adding a local block? + bmsgs, err := a.Syncer.ChainStore().LoadMessagesFromCids(blk.BlsMessages) + if err != nil { + return xerrors.Errorf("failed to load bls messages: %w", err) + } + + smsgs, err := a.Syncer.ChainStore().LoadSignedMessagesFromCids(blk.SecpkMessages) + if err != nil { + return xerrors.Errorf("failed to load secpk message: %w", err) + } + + fb := &types.FullBlock{ + Header: blk.Header, + BlsMessages: bmsgs, + SecpkMessages: smsgs, + } + + if err := a.Syncer.ValidateMsgMeta(fb); err != nil { + return xerrors.Errorf("provided messages did not match block: %w", err) + } + + ts, err := types.NewTipSet([]*types.BlockHeader{blk.Header}) + if err != nil { + return xerrors.Errorf("somehow failed to make a tipset out of a single block: %w", err) + } + if err := a.Syncer.Sync(ctx, ts); err != nil { + return xerrors.Errorf("sync to submitted block failed: %w", err) + } + + b, err := blk.Serialize() + if err != nil { + return xerrors.Errorf("serializing block for pubsub publishing failed: %w", err) + } + + // TODO: anything else to do here? + return a.PubSub.Publish(build.BlocksTopic(a.NetName), b) +} + +func (a *SyncAPI) SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) { + return a.Syncer.IncomingBlocks(ctx) +} + +func (a *SyncAPI) SyncMarkBad(ctx context.Context, bcid cid.Cid) error { + log.Warnf("Marking block %s as bad", bcid) + a.Syncer.MarkBad(bcid) + return nil +} + +func (a *SyncAPI) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) { + reason, ok := a.Syncer.CheckBadBlockCache(bcid) + if !ok { + return "", nil + } + + return reason, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/full/wallet.go b/vendor/github.com/filecoin-project/lotus/node/impl/full/wallet.go new file mode 100644 index 0000000000..8da8d30626 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/full/wallet.go @@ -0,0 +1,86 @@ +package full + +import ( + "context" + + "github.com/filecoin-project/lotus/lib/sigs" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/crypto" + + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + + "go.uber.org/fx" + "golang.org/x/xerrors" +) + +type WalletAPI struct { + fx.In + + StateManager *stmgr.StateManager + Wallet *wallet.Wallet +} + +func (a *WalletAPI) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) { + return a.Wallet.GenerateKey(typ) +} + +func (a *WalletAPI) WalletHas(ctx context.Context, addr address.Address) (bool, error) { + return a.Wallet.HasKey(addr) +} + +func (a *WalletAPI) WalletList(ctx context.Context) ([]address.Address, error) { + return a.Wallet.ListAddrs() +} + +func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) { + return a.StateManager.GetBalance(addr, nil) +} + +func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) { + keyAddr, err := a.StateManager.ResolveToKeyAddress(ctx, k, nil) + if err != nil { + return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr) + } + return a.Wallet.Sign(ctx, keyAddr, msg) +} + +func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, msg *types.Message) (*types.SignedMessage, error) { + mcid := msg.Cid() + + sig, err := a.WalletSign(ctx, k, mcid.Bytes()) + if err != nil { + return nil, xerrors.Errorf("failed to sign message: %w", err) + } + + return &types.SignedMessage{ + Message: *msg, + Signature: *sig, + }, nil +} + +func (a *WalletAPI) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) bool { + return sigs.Verify(sig, k, msg) == nil +} + +func (a *WalletAPI) WalletDefaultAddress(ctx context.Context) (address.Address, error) { + return a.Wallet.GetDefault() +} + +func (a *WalletAPI) WalletSetDefault(ctx context.Context, addr address.Address) error { + return a.Wallet.SetDefault(addr) +} + +func (a *WalletAPI) WalletExport(ctx context.Context, addr address.Address) (*types.KeyInfo, error) { + return a.Wallet.Export(addr) +} + +func (a *WalletAPI) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) { + return a.Wallet.Import(ki) +} + +func (a *WalletAPI) WalletDelete(ctx context.Context, addr address.Address) error { + return a.Wallet.DeleteKey(addr) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/market/market.go b/vendor/github.com/filecoin-project/lotus/node/impl/market/market.go new file mode 100644 index 0000000000..26d4a9edc2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/market/market.go @@ -0,0 +1,22 @@ +package market + +import ( + "context" + + "go.uber.org/fx" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/market" + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" +) + +type MarketAPI struct { + fx.In + + FMgr *market.FundMgr +} + +func (a *MarketAPI) MarketEnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) { + return a.FMgr.EnsureAvailable(ctx, addr, wallet, amt) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/paych/paych.go b/vendor/github.com/filecoin-project/lotus/node/impl/paych/paych.go new file mode 100644 index 0000000000..b08e07dbdf --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/paych/paych.go @@ -0,0 +1,258 @@ +package paych + +import ( + "context" + "fmt" + + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/ipfs/go-cid" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + full "github.com/filecoin-project/lotus/node/impl/full" + "github.com/filecoin-project/lotus/paychmgr" +) + +type PaychAPI struct { + fx.In + + full.MpoolAPI + full.WalletAPI + full.ChainAPI + + PaychMgr *paychmgr.Manager +} + +func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*api.ChannelInfo, error) { + ch, mcid, err := a.PaychMgr.GetPaych(ctx, from, to, ensureFunds) + if err != nil { + return nil, err + } + + return &api.ChannelInfo{ + Channel: ch, + ChannelMessage: mcid, + }, nil +} + +func (a *PaychAPI) PaychAllocateLane(ctx context.Context, ch address.Address) (uint64, error) { + return a.PaychMgr.AllocateLane(ch) +} + +func (a *PaychAPI) PaychNewPayment(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) { + amount := vouchers[len(vouchers)-1].Amount + + // TODO: Fix free fund tracking in PaychGet + // TODO: validate voucher spec before locking funds + ch, err := a.PaychGet(ctx, from, to, amount) + if err != nil { + return nil, err + } + + lane, err := a.PaychMgr.AllocateLane(ch.Channel) + if err != nil { + return nil, err + } + + svs := make([]*paych.SignedVoucher, len(vouchers)) + + for i, v := range vouchers { + sv, err := a.paychVoucherCreate(ctx, ch.Channel, paych.SignedVoucher{ + Amount: v.Amount, + Lane: uint64(lane), + + Extra: v.Extra, + TimeLockMin: v.TimeLockMin, + TimeLockMax: v.TimeLockMax, + MinSettleHeight: v.MinSettle, + }) + if err != nil { + return nil, err + } + + svs[i] = sv + } + + var pchCid *cid.Cid + if ch.ChannelMessage != cid.Undef { + pchCid = &ch.ChannelMessage + } + + return &api.PaymentInfo{ + Channel: ch.Channel, + ChannelMessage: pchCid, + Vouchers: svs, + }, nil +} + +func (a *PaychAPI) PaychList(ctx context.Context) ([]address.Address, error) { + return a.PaychMgr.ListChannels() +} + +func (a *PaychAPI) PaychStatus(ctx context.Context, pch address.Address) (*api.PaychStatus, error) { + ci, err := a.PaychMgr.GetChannelInfo(pch) + if err != nil { + return nil, err + } + return &api.PaychStatus{ + ControlAddr: ci.Control, + Direction: api.PCHDir(ci.Direction), + }, nil +} + +func (a *PaychAPI) PaychClose(ctx context.Context, addr address.Address) (cid.Cid, error) { + panic("TODO Settle logic") + + ci, err := a.PaychMgr.GetChannelInfo(addr) + if err != nil { + return cid.Undef, err + } + + nonce, err := a.MpoolGetNonce(ctx, ci.Control) + if err != nil { + return cid.Undef, err + } + + msg := &types.Message{ + To: addr, + From: ci.Control, + Value: types.NewInt(0), + Method: builtin.MethodsPaych.Settle, + Nonce: nonce, + + GasLimit: 10000, + GasPrice: types.NewInt(0), + } + + smsg, err := a.WalletSignMessage(ctx, ci.Control, msg) + if err != nil { + return cid.Undef, err + } + + if _, err := a.MpoolPush(ctx, smsg); err != nil { + return cid.Undef, err + } + + return smsg.Cid(), nil +} + +func (a *PaychAPI) PaychVoucherCheckValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) error { + return a.PaychMgr.CheckVoucherValid(ctx, ch, sv) +} + +func (a *PaychAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { + return a.PaychMgr.CheckVoucherSpendable(ctx, ch, sv, secret, proof) +} + +func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { + _ = a.PaychMgr.TrackInboundChannel(ctx, ch) // TODO: expose those calls + + return a.PaychMgr.AddVoucher(ctx, ch, sv, proof, minDelta) +} + +// PaychVoucherCreate creates a new signed voucher on the given payment channel +// with the given lane and amount. The value passed in is exactly the value +// that will be used to create the voucher, so if previous vouchers exist, the +// actual additional value of this voucher will only be the difference between +// the two. +func (a *PaychAPI) PaychVoucherCreate(ctx context.Context, pch address.Address, amt types.BigInt, lane uint64) (*paych.SignedVoucher, error) { + return a.paychVoucherCreate(ctx, pch, paych.SignedVoucher{Amount: amt, Lane: lane}) +} + +func (a *PaychAPI) paychVoucherCreate(ctx context.Context, pch address.Address, voucher paych.SignedVoucher) (*paych.SignedVoucher, error) { + ci, err := a.PaychMgr.GetChannelInfo(pch) + if err != nil { + return nil, xerrors.Errorf("get channel info: %w", err) + } + + nonce, err := a.PaychMgr.NextNonceForLane(ctx, pch, voucher.Lane) + if err != nil { + return nil, xerrors.Errorf("getting next nonce for lane: %w", err) + } + + sv := &voucher + sv.Nonce = nonce + + vb, err := sv.SigningBytes() + if err != nil { + return nil, err + } + + sig, err := a.WalletSign(ctx, ci.Control, vb) + if err != nil { + return nil, err + } + + sv.Signature = sig + + if _, err := a.PaychMgr.AddVoucher(ctx, pch, sv, nil, types.NewInt(0)); err != nil { + return nil, xerrors.Errorf("failed to persist voucher: %w", err) + } + + return sv, nil +} + +func (a *PaychAPI) PaychVoucherList(ctx context.Context, pch address.Address) ([]*paych.SignedVoucher, error) { + vi, err := a.PaychMgr.ListVouchers(ctx, pch) + if err != nil { + return nil, err + } + + out := make([]*paych.SignedVoucher, len(vi)) + for k, v := range vi { + out[k] = v.Voucher + } + + return out, nil +} + +func (a *PaychAPI) PaychVoucherSubmit(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (cid.Cid, error) { + ci, err := a.PaychMgr.GetChannelInfo(ch) + if err != nil { + return cid.Undef, err + } + + nonce, err := a.MpoolGetNonce(ctx, ci.Control) + if err != nil { + return cid.Undef, err + } + + if sv.Extra != nil || len(sv.SecretPreimage) > 0 { + return cid.Undef, fmt.Errorf("cant handle more advanced payment channel stuff yet") + } + + enc, err := actors.SerializeParams(&paych.UpdateChannelStateParams{ + Sv: *sv, + }) + if err != nil { + return cid.Undef, err + } + + msg := &types.Message{ + From: ci.Control, + To: ch, + Value: types.NewInt(0), + Nonce: nonce, + Method: builtin.MethodsPaych.UpdateChannelState, + Params: enc, + GasLimit: 100000, + GasPrice: types.NewInt(0), + } + + smsg, err := a.WalletSignMessage(ctx, ci.Control, msg) + if err != nil { + return cid.Undef, err + } + + if _, err := a.MpoolPush(ctx, smsg); err != nil { + return cid.Undef, err + } + + // TODO: should we wait for it...? + return smsg.Cid(), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/remoteworker.go b/vendor/github.com/filecoin-project/lotus/node/impl/remoteworker.go new file mode 100644 index 0000000000..b7cee83efb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/remoteworker.go @@ -0,0 +1,54 @@ +package impl + +import ( + "context" + "net/http" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-jsonrpc/auth" + "github.com/filecoin-project/specs-actors/actors/abi" + storage2 "github.com/filecoin-project/specs-storage/storage" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/sector-storage" +) + +type remoteWorker struct { + api.WorkerAPI + closer jsonrpc.ClientCloser +} + +func (r *remoteWorker) NewSector(ctx context.Context, sector abi.SectorID) error { + return xerrors.New("unsupported") +} + +func (r *remoteWorker) AddPiece(ctx context.Context, sector abi.SectorID, pieceSizes []abi.UnpaddedPieceSize, newPieceSize abi.UnpaddedPieceSize, pieceData storage2.Data) (abi.PieceInfo, error) { + return abi.PieceInfo{}, xerrors.New("unsupported") +} + +func connectRemoteWorker(ctx context.Context, fa api.Common, url string) (*remoteWorker, error) { + token, err := fa.AuthNew(ctx, []auth.Permission{"admin"}) + if err != nil { + return nil, xerrors.Errorf("creating auth token for remote connection: %w", err) + } + + headers := http.Header{} + headers.Add("Authorization", "Bearer "+string(token)) + + wapi, closer, err := client.NewWorkerRPC(url, headers) + if err != nil { + return nil, xerrors.Errorf("creating jsonrpc client: %w", err) + } + + return &remoteWorker{wapi, closer}, nil +} + +func (r *remoteWorker) Close() error { + r.closer() + return nil +} + +var _ sectorstorage.Worker = &remoteWorker{} diff --git a/vendor/github.com/filecoin-project/lotus/node/impl/storminer.go b/vendor/github.com/filecoin-project/lotus/node/impl/storminer.go new file mode 100644 index 0000000000..cf9b84388e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/impl/storminer.go @@ -0,0 +1,292 @@ +package impl + +import ( + "context" + "encoding/json" + "net/http" + "os" + "strconv" + + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + storagemarket "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-jsonrpc/auth" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/sector-storage/stores" + "github.com/filecoin-project/sector-storage/storiface" + "github.com/filecoin-project/specs-actors/actors/abi" + sealing "github.com/filecoin-project/storage-fsm" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/lotus/node/impl/common" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/storage" + "github.com/filecoin-project/lotus/storage/sectorblocks" +) + +type StorageMinerAPI struct { + common.CommonAPI + + ProofsConfig *ffiwrapper.Config + SectorBlocks *sectorblocks.SectorBlocks + + StorageProvider storagemarket.StorageProvider + Miner *storage.Miner + BlockMiner *miner.Miner + Full api.FullNode + StorageMgr *sectorstorage.Manager `optional:"true"` + *stores.Index + + ConsiderOnlineStorageDealsConfigFunc dtypes.ConsiderOnlineStorageDealsConfigFunc + SetConsiderOnlineStorageDealsConfigFunc dtypes.SetConsiderOnlineStorageDealsConfigFunc + ConsiderOnlineRetrievalDealsConfigFunc dtypes.ConsiderOnlineRetrievalDealsConfigFunc + SetConsiderOnlineRetrievalDealsConfigFunc dtypes.SetConsiderOnlineRetrievalDealsConfigFunc + StorageDealPieceCidBlocklistConfigFunc dtypes.StorageDealPieceCidBlocklistConfigFunc + SetStorageDealPieceCidBlocklistConfigFunc dtypes.SetStorageDealPieceCidBlocklistConfigFunc + ConsiderOfflineStorageDealsConfigFunc dtypes.ConsiderOfflineStorageDealsConfigFunc + SetConsiderOfflineStorageDealsConfigFunc dtypes.SetConsiderOfflineStorageDealsConfigFunc + ConsiderOfflineRetrievalDealsConfigFunc dtypes.ConsiderOfflineRetrievalDealsConfigFunc + SetConsiderOfflineRetrievalDealsConfigFunc dtypes.SetConsiderOfflineRetrievalDealsConfigFunc +} + +func (sm *StorageMinerAPI) ServeRemote(w http.ResponseWriter, r *http.Request) { + if !auth.HasPerm(r.Context(), nil, apistruct.PermAdmin) { + w.WriteHeader(401) + _ = json.NewEncoder(w).Encode(struct{ Error string }{"unauthorized: missing write permission"}) + return + } + + sm.StorageMgr.ServeHTTP(w, r) +} + +func (sm *StorageMinerAPI) WorkerStats(context.Context) (map[uint64]storiface.WorkerStats, error) { + return sm.StorageMgr.WorkerStats(), nil +} + +func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error) { + return sm.Miner.Address(), nil +} + +func (sm *StorageMinerAPI) MiningBase(ctx context.Context) (*types.TipSet, error) { + mb, err := sm.BlockMiner.GetBestMiningCandidate(ctx) + if err != nil { + return nil, err + } + return mb.TipSet, nil +} + +func (sm *StorageMinerAPI) ActorSectorSize(ctx context.Context, addr address.Address) (abi.SectorSize, error) { + mi, err := sm.Full.StateMinerInfo(ctx, addr, types.EmptyTSK) + if err != nil { + return 0, err + } + return mi.SectorSize, nil +} + +func (sm *StorageMinerAPI) PledgeSector(ctx context.Context) error { + return sm.Miner.PledgeSector() +} + +func (sm *StorageMinerAPI) SectorsStatus(ctx context.Context, sid abi.SectorNumber) (api.SectorInfo, error) { + info, err := sm.Miner.GetSectorInfo(sid) + if err != nil { + return api.SectorInfo{}, err + } + + deals := make([]abi.DealID, len(info.Pieces)) + for i, piece := range info.Pieces { + if piece.DealInfo == nil { + continue + } + deals[i] = piece.DealInfo.DealID + } + + log := make([]api.SectorLog, len(info.Log)) + for i, l := range info.Log { + log[i] = api.SectorLog{ + Kind: l.Kind, + Timestamp: l.Timestamp, + Trace: l.Trace, + Message: l.Message, + } + } + + return api.SectorInfo{ + SectorID: sid, + State: api.SectorState(info.State), + CommD: info.CommD, + CommR: info.CommR, + Proof: info.Proof, + Deals: deals, + Ticket: api.SealTicket{ + Value: info.TicketValue, + Epoch: info.TicketEpoch, + }, + Seed: api.SealSeed{ + Value: info.SeedValue, + Epoch: info.SeedEpoch, + }, + Retries: info.InvalidProofs, + + LastErr: info.LastErr, + Log: log, + }, nil +} + +// List all staged sectors +func (sm *StorageMinerAPI) SectorsList(context.Context) ([]abi.SectorNumber, error) { + sectors, err := sm.Miner.ListSectors() + if err != nil { + return nil, err + } + + out := make([]abi.SectorNumber, len(sectors)) + for i, sector := range sectors { + out[i] = sector.SectorNumber + } + return out, nil +} + +func (sm *StorageMinerAPI) StorageLocal(ctx context.Context) (map[stores.ID]string, error) { + return sm.StorageMgr.StorageLocal(ctx) +} + +func (sm *StorageMinerAPI) SectorsRefs(context.Context) (map[string][]api.SealedRef, error) { + // json can't handle cids as map keys + out := map[string][]api.SealedRef{} + + refs, err := sm.SectorBlocks.List() + if err != nil { + return nil, err + } + + for k, v := range refs { + out[strconv.FormatUint(k, 10)] = v + } + + return out, nil +} + +func (sm *StorageMinerAPI) StorageStat(ctx context.Context, id stores.ID) (stores.FsStat, error) { + return sm.StorageMgr.FsStat(ctx, id) +} + +func (sm *StorageMinerAPI) SectorsUpdate(ctx context.Context, id abi.SectorNumber, state api.SectorState) error { + return sm.Miner.ForceSectorState(ctx, id, sealing.SectorState(state)) +} + +func (sm *StorageMinerAPI) SectorRemove(ctx context.Context, id abi.SectorNumber) error { + return sm.Miner.RemoveSector(ctx, id) +} + +func (sm *StorageMinerAPI) WorkerConnect(ctx context.Context, url string) error { + w, err := connectRemoteWorker(ctx, sm, url) + if err != nil { + return xerrors.Errorf("connecting remote storage failed: %w", err) + } + + log.Infof("Connected to a remote worker at %s", url) + + return sm.StorageMgr.AddWorker(ctx, w) +} + +func (sm *StorageMinerAPI) MarketImportDealData(ctx context.Context, propCid cid.Cid, path string) error { + fi, err := os.Open(path) + if err != nil { + return xerrors.Errorf("failed to open file: %w", err) + } + defer fi.Close() //nolint:errcheck + + return sm.StorageProvider.ImportDataForDeal(ctx, propCid, fi) +} + +func (sm *StorageMinerAPI) MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error) { + return sm.StorageProvider.ListDeals(ctx) +} + +func (sm *StorageMinerAPI) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) { + return sm.StorageProvider.ListLocalDeals() +} + +func (sm *StorageMinerAPI) MarketSetAsk(ctx context.Context, price types.BigInt, duration abi.ChainEpoch, minPieceSize abi.PaddedPieceSize, maxPieceSize abi.PaddedPieceSize) error { + options := []storagemarket.StorageAskOption{ + storagemarket.MinPieceSize(minPieceSize), + storagemarket.MaxPieceSize(maxPieceSize), + } + + return sm.StorageProvider.SetAsk(price, duration, options...) +} + +func (sm *StorageMinerAPI) MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error) { + return sm.StorageProvider.GetAsk(), nil +} + +func (sm *StorageMinerAPI) DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error) { + return sm.StorageProvider.ListDeals(ctx) +} + +func (sm *StorageMinerAPI) DealsConsiderOnlineStorageDeals(ctx context.Context) (bool, error) { + return sm.ConsiderOnlineStorageDealsConfigFunc() +} + +func (sm *StorageMinerAPI) DealsSetConsiderOnlineStorageDeals(ctx context.Context, b bool) error { + return sm.SetConsiderOnlineStorageDealsConfigFunc(b) +} + +func (sm *StorageMinerAPI) DealsConsiderOnlineRetrievalDeals(ctx context.Context) (bool, error) { + return sm.ConsiderOnlineRetrievalDealsConfigFunc() +} + +func (sm *StorageMinerAPI) DealsSetConsiderOnlineRetrievalDeals(ctx context.Context, b bool) error { + return sm.SetConsiderOnlineRetrievalDealsConfigFunc(b) +} + +func (sm *StorageMinerAPI) DealsConsiderOfflineStorageDeals(ctx context.Context) (bool, error) { + return sm.ConsiderOfflineStorageDealsConfigFunc() +} + +func (sm *StorageMinerAPI) DealsSetConsiderOfflineStorageDeals(ctx context.Context, b bool) error { + return sm.SetConsiderOfflineStorageDealsConfigFunc(b) +} + +func (sm *StorageMinerAPI) DealsConsiderOfflineRetrievalDeals(ctx context.Context) (bool, error) { + return sm.ConsiderOfflineRetrievalDealsConfigFunc() +} + +func (sm *StorageMinerAPI) DealsSetConsiderOfflineRetrievalDeals(ctx context.Context, b bool) error { + return sm.SetConsiderOfflineRetrievalDealsConfigFunc(b) +} + +func (sm *StorageMinerAPI) DealsImportData(ctx context.Context, deal cid.Cid, fname string) error { + fi, err := os.Open(fname) + if err != nil { + return xerrors.Errorf("failed to open given file: %w", err) + } + defer fi.Close() //nolint:errcheck + + return sm.StorageProvider.ImportDataForDeal(ctx, deal, fi) +} + +func (sm *StorageMinerAPI) DealsPieceCidBlocklist(ctx context.Context) ([]cid.Cid, error) { + return sm.StorageDealPieceCidBlocklistConfigFunc() +} + +func (sm *StorageMinerAPI) DealsSetPieceCidBlocklist(ctx context.Context, cids []cid.Cid) error { + return sm.SetStorageDealPieceCidBlocklistConfigFunc(cids) +} + +func (sm *StorageMinerAPI) StorageAddLocal(ctx context.Context, path string) error { + if sm.StorageMgr == nil { + return xerrors.Errorf("no storage manager") + } + + return sm.StorageMgr.AddLocalStorage(ctx, path) +} + +var _ api.StorageMiner = &StorageMinerAPI{} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/chain.go b/vendor/github.com/filecoin-project/lotus/node/modules/chain.go new file mode 100644 index 0000000000..229a97cc4a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/chain.go @@ -0,0 +1,169 @@ +package modules + +import ( + "bytes" + "context" + + "github.com/ipfs/go-bitswap" + "github.com/ipfs/go-bitswap/network" + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-datastore" + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/ipld/go-car" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/routing" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/specs-actors/actors/runtime" + + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/beacon" + "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/repo" +) + +func ChainExchange(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt routing.Routing, bs dtypes.ChainGCBlockstore) dtypes.ChainExchange { + // prefix protocol for chain bitswap + // (so bitswap uses /chain/ipfs/bitswap/1.0.0 internally for chain sync stuff) + bitswapNetwork := network.NewFromIpfsHost(host, rt, network.Prefix("/chain")) + bitswapOptions := []bitswap.Option{bitswap.ProvideEnabled(false)} + exch := bitswap.New(helpers.LifecycleCtx(mctx, lc), bitswapNetwork, bs, bitswapOptions...) + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return exch.Close() + }, + }) + + return exch +} + +func MessagePool(lc fx.Lifecycle, sm *stmgr.StateManager, ps *pubsub.PubSub, ds dtypes.MetadataDS, nn dtypes.NetworkName) (*messagepool.MessagePool, error) { + mpp := messagepool.NewProvider(sm, ps) + mp, err := messagepool.New(mpp, ds, nn) + if err != nil { + return nil, xerrors.Errorf("constructing mpool: %w", err) + } + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return mp.Close() + }, + }) + return mp, nil +} + +func ChainBlockstore(lc fx.Lifecycle, mctx helpers.MetricsCtx, r repo.LockedRepo) (dtypes.ChainBlockstore, error) { + blocks, err := r.Datastore("/chain") + if err != nil { + return nil, err + } + + bs := blockstore.NewBlockstore(blocks) + cbs, err := blockstore.CachedBlockstore(helpers.LifecycleCtx(mctx, lc), bs, blockstore.DefaultCacheOpts()) + if err != nil { + return nil, err + } + + return blockstore.NewIdStore(cbs), nil +} + +func ChainGCBlockstore(bs dtypes.ChainBlockstore, gcl dtypes.ChainGCLocker) dtypes.ChainGCBlockstore { + return blockstore.NewGCBlockstore(bs, gcl) +} + +func ChainBlockservice(bs dtypes.ChainBlockstore, rem dtypes.ChainExchange) dtypes.ChainBlockService { + return blockservice.New(bs, rem) +} + +func ChainStore(lc fx.Lifecycle, bs dtypes.ChainBlockstore, ds dtypes.MetadataDS, syscalls runtime.Syscalls) *store.ChainStore { + chain := store.NewChainStore(bs, ds, syscalls) + + if err := chain.Load(); err != nil { + log.Warnf("loading chain state from disk: %s", err) + } + + return chain +} + +func ErrorGenesis() Genesis { + return func() (header *types.BlockHeader, e error) { + return nil, xerrors.New("No genesis block provided, provide the file with 'lotus daemon --genesis=[genesis file]'") + } +} + +func LoadGenesis(genBytes []byte) func(dtypes.ChainBlockstore) Genesis { + return func(bs dtypes.ChainBlockstore) Genesis { + return func() (header *types.BlockHeader, e error) { + c, err := car.LoadCar(bs, bytes.NewReader(genBytes)) + if err != nil { + return nil, xerrors.Errorf("loading genesis car file failed: %w", err) + } + if len(c.Roots) != 1 { + return nil, xerrors.New("expected genesis file to have one root") + } + root, err := bs.Get(c.Roots[0]) + if err != nil { + return nil, err + } + + h, err := types.DecodeBlock(root.RawData()) + if err != nil { + return nil, xerrors.Errorf("decoding block failed: %w", err) + } + return h, nil + } + } +} + +func DoSetGenesis(_ dtypes.AfterGenesisSet) {} + +func SetGenesis(cs *store.ChainStore, g Genesis) (dtypes.AfterGenesisSet, error) { + _, err := cs.GetGenesis() + if err == nil { + return dtypes.AfterGenesisSet{}, nil // already set, noop + } + if err != datastore.ErrNotFound { + return dtypes.AfterGenesisSet{}, xerrors.Errorf("getting genesis block failed: %w", err) + } + + genesis, err := g() + if err != nil { + return dtypes.AfterGenesisSet{}, xerrors.Errorf("genesis func failed: %w", err) + } + + return dtypes.AfterGenesisSet{}, cs.SetGenesis(genesis) +} + +func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, _ dtypes.AfterGenesisSet) (dtypes.NetworkName, error) { + ctx := helpers.LifecycleCtx(mctx, lc) + + netName, err := stmgr.GetNetworkName(ctx, stmgr.NewStateManager(cs), cs.GetHeaviestTipSet().ParentState()) + return netName, err +} + +func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, bsync *blocksync.BlockSync, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { + syncer, err := chain.NewSyncer(sm, bsync, h.ConnManager(), h.ID(), beacon, verifier) + if err != nil { + return nil, err + } + + lc.Append(fx.Hook{ + OnStart: func(_ context.Context) error { + syncer.Start() + return nil + }, + OnStop: func(_ context.Context) error { + syncer.Stop() + return nil + }, + }) + return syncer, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/client.go b/vendor/github.com/filecoin-project/lotus/node/modules/client.go new file mode 100644 index 0000000000..b4618015a6 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/client.go @@ -0,0 +1,136 @@ +package modules + +import ( + "context" + "path/filepath" + + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/ipfs/go-merkledag" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/routing" + "go.uber.org/fx" + + graphsyncimpl "github.com/filecoin-project/go-data-transfer/impl/graphsync" + "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-fil-markets/retrievalmarket/discovery" + retrievalimpl "github.com/filecoin-project/go-fil-markets/retrievalmarket/impl" + rmnet "github.com/filecoin-project/go-fil-markets/retrievalmarket/network" + "github.com/filecoin-project/go-fil-markets/storagemarket" + storageimpl "github.com/filecoin-project/go-fil-markets/storagemarket/impl" + "github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation" + smnet "github.com/filecoin-project/go-fil-markets/storagemarket/network" + "github.com/filecoin-project/go-statestore" + "github.com/filecoin-project/go-storedcounter" + "github.com/ipfs/go-bitswap" + "github.com/ipfs/go-bitswap/network" + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + "github.com/ipfs/go-filestore" + + "github.com/filecoin-project/lotus/markets/retrievaladapter" + "github.com/filecoin-project/lotus/node/impl/full" + payapi "github.com/filecoin-project/lotus/node/impl/paych" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/paychmgr" +) + +func ClientFstore(r repo.LockedRepo) (dtypes.ClientFilestore, error) { + clientds, err := r.Datastore("/client") + if err != nil { + return nil, err + } + blocks := namespace.Wrap(clientds, datastore.NewKey("blocks")) + + absPath, err := filepath.Abs(r.Path()) + if err != nil { + return nil, err + } + + fm := filestore.NewFileManager(clientds, filepath.Dir(absPath)) + fm.AllowFiles = true + // TODO: fm.AllowUrls (needs more code in client import) + + bs := blockstore.NewBlockstore(blocks) + return filestore.NewFilestore(bs, fm), nil +} + +func ClientBlockstore(fstore dtypes.ClientFilestore) dtypes.ClientBlockstore { + return blockstore.NewIdStore((*filestore.Filestore)(fstore)) +} + +// RegisterClientValidator is an initialization hook that registers the client +// request validator with the data transfer module as the validator for +// StorageDataTransferVoucher types +func RegisterClientValidator(crv dtypes.ClientRequestValidator, dtm dtypes.ClientDataTransfer) { + if err := dtm.RegisterVoucherType(&requestvalidation.StorageDataTransferVoucher{}, (*requestvalidation.UnifiedRequestValidator)(crv)); err != nil { + panic(err) + } +} + +// NewClientGraphsyncDataTransfer returns a data transfer manager that just +// uses the clients's Client DAG service for transfers +func NewClientGraphsyncDataTransfer(h host.Host, gs dtypes.Graphsync, ds dtypes.MetadataDS) dtypes.ClientDataTransfer { + sc := storedcounter.New(ds, datastore.NewKey("/datatransfer/client/counter")) + return graphsyncimpl.NewGraphSyncDataTransfer(h, gs, sc) +} + +// NewClientDealStore creates a statestore for the client to store its deals +func NewClientDealStore(ds dtypes.ClientDatastore) dtypes.ClientDealStore { + return statestore.New(ds) +} + +// NewClientDatastore creates a datastore for the client to store its deals +func NewClientDatastore(ds dtypes.MetadataDS) dtypes.ClientDatastore { + return namespace.Wrap(ds, datastore.NewKey("/deals/client")) +} + +// ClientDAG is a DAGService for the ClientBlockstore +func ClientDAG(mctx helpers.MetricsCtx, lc fx.Lifecycle, ibs dtypes.ClientBlockstore, rt routing.Routing, h host.Host) dtypes.ClientDAG { + bitswapNetwork := network.NewFromIpfsHost(h, rt) + bitswapOptions := []bitswap.Option{bitswap.ProvideEnabled(false)} + exch := bitswap.New(helpers.LifecycleCtx(mctx, lc), bitswapNetwork, ibs, bitswapOptions...) + + bsvc := blockservice.New(ibs, exch) + dag := merkledag.NewDAGService(bsvc) + + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return bsvc.Close() + }, + }) + + return dag +} + +func NewClientRequestValidator(deals dtypes.ClientDealStore) dtypes.ClientRequestValidator { + return requestvalidation.NewUnifiedRequestValidator(nil, deals) +} + +func StorageClient(lc fx.Lifecycle, h host.Host, ibs dtypes.ClientBlockstore, r repo.LockedRepo, dataTransfer dtypes.ClientDataTransfer, discovery *discovery.Local, deals dtypes.ClientDatastore, scn storagemarket.StorageClientNode) (storagemarket.StorageClient, error) { + net := smnet.NewFromLibp2pHost(h) + c, err := storageimpl.NewClient(net, ibs, dataTransfer, discovery, deals, scn) + if err != nil { + return nil, err + } + lc.Append(fx.Hook{ + OnStart: func(ctx context.Context) error { + return c.Start(ctx) + }, + OnStop: func(context.Context) error { + c.Stop() + return nil + }, + }) + return c, nil +} + +// RetrievalClient creates a new retrieval client attached to the client blockstore +func RetrievalClient(h host.Host, bs dtypes.ClientBlockstore, pmgr *paychmgr.Manager, payapi payapi.PaychAPI, resolver retrievalmarket.PeerResolver, ds dtypes.MetadataDS, chainapi full.ChainAPI) (retrievalmarket.RetrievalClient, error) { + adapter := retrievaladapter.NewRetrievalClientNode(pmgr, payapi, chainapi) + network := rmnet.NewFromLibp2pHost(h) + sc := storedcounter.New(ds, datastore.NewKey("/retr")) + return retrievalimpl.NewClient(network, bs, adapter, resolver, namespace.Wrap(ds, datastore.NewKey("/retrievals/client")), sc) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/core.go b/vendor/github.com/filecoin-project/lotus/node/modules/core.go new file mode 100644 index 0000000000..ca9872d90c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/core.go @@ -0,0 +1,95 @@ +package modules + +import ( + "context" + "crypto/rand" + "errors" + "io" + "io/ioutil" + + "github.com/gbrlsnchs/jwt/v3" + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/peerstore" + record "github.com/libp2p/go-libp2p-record" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc/auth" + + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/addrutil" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/repo" +) + +var log = logging.Logger("modules") + +type Genesis func() (*types.BlockHeader, error) + +// RecordValidator provides namesys compatible routing record validator +func RecordValidator(ps peerstore.Peerstore) record.Validator { + return record.NamespacedValidator{ + "pk": record.PublicKeyValidator{}, + } +} + +const JWTSecretName = "auth-jwt-private" //nolint:gosec + +type jwtPayload struct { + Allow []auth.Permission +} + +func APISecret(keystore types.KeyStore, lr repo.LockedRepo) (*dtypes.APIAlg, error) { + key, err := keystore.Get(JWTSecretName) + + if errors.Is(err, types.ErrKeyInfoNotFound) { + log.Warn("Generating new API secret") + + sk, err := ioutil.ReadAll(io.LimitReader(rand.Reader, 32)) + if err != nil { + return nil, err + } + + key = types.KeyInfo{ + Type: "jwt-hmac-secret", + PrivateKey: sk, + } + + if err := keystore.Put(JWTSecretName, key); err != nil { + return nil, xerrors.Errorf("writing API secret: %w", err) + } + + // TODO: make this configurable + p := jwtPayload{ + Allow: apistruct.AllPermissions, + } + + cliToken, err := jwt.Sign(&p, jwt.NewHS256(key.PrivateKey)) + if err != nil { + return nil, err + } + + if err := lr.SetAPIToken(cliToken); err != nil { + return nil, err + } + } else if err != nil { + return nil, xerrors.Errorf("could not get JWT Token: %w", err) + } + + return (*dtypes.APIAlg)(jwt.NewHS256(key.PrivateKey)), nil +} + +func ConfigBootstrap(peers []string) func() (dtypes.BootstrapPeers, error) { + return func() (dtypes.BootstrapPeers, error) { + return addrutil.ParseAddresses(context.TODO(), peers) + } +} + +func BuiltinBootstrap() (dtypes.BootstrapPeers, error) { + return build.BuiltinBootstrap() +} + +func DrandBootstrap() (dtypes.DrandBootstrap, error) { + return build.DrandBootstrap() +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/api.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/api.go new file mode 100644 index 0000000000..d57b05cfac --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/api.go @@ -0,0 +1,10 @@ +package dtypes + +import ( + "github.com/gbrlsnchs/jwt/v3" + "github.com/multiformats/go-multiaddr" +) + +type APIAlg jwt.HMACSHA + +type APIEndpoint multiaddr.Multiaddr diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/beacon.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/beacon.go new file mode 100644 index 0000000000..f3ebc4facd --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/beacon.go @@ -0,0 +1,6 @@ +package dtypes + +type DrandConfig struct { + Servers []string + ChainInfoJSON string +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/bootstrap.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/bootstrap.go new file mode 100644 index 0000000000..96cd2f673e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/bootstrap.go @@ -0,0 +1,8 @@ +package dtypes + +import "github.com/libp2p/go-libp2p-core/peer" + +type BootstrapPeers []peer.AddrInfo +type DrandBootstrap []peer.AddrInfo + +type Bootstrapper bool diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/chain.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/chain.go new file mode 100644 index 0000000000..0c924c12ab --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/chain.go @@ -0,0 +1,4 @@ +package dtypes + +type NetworkName string +type AfterGenesisSet struct{} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/miner.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/miner.go new file mode 100644 index 0000000000..33c6e4b046 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/miner.go @@ -0,0 +1,52 @@ +package dtypes + +import ( + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" +) + +type MinerAddress address.Address +type MinerID abi.ActorID + +// ConsiderOnlineStorageDealsConfigFunc is a function which reads from miner +// config to determine if the user has disabled storage deals (or not). +type ConsiderOnlineStorageDealsConfigFunc func() (bool, error) + +// SetConsiderOnlineStorageDealsConfigFunc is a function which is used to +// disable or enable storage deal acceptance. +type SetConsiderOnlineStorageDealsConfigFunc func(bool) error + +// ConsiderOnlineRetrievalDealsConfigFunc is a function which reads from miner +// config to determine if the user has disabled retrieval acceptance (or not). +type ConsiderOnlineRetrievalDealsConfigFunc func() (bool, error) + +// SetConsiderOnlineRetrievalDealsConfigFunc is a function which is used to +// disable or enable retrieval deal acceptance. +type SetConsiderOnlineRetrievalDealsConfigFunc func(bool) error + +// StorageDealPieceCidBlocklistConfigFunc is a function which reads from miner +// config to obtain a list of CIDs for which the storage miner will not accept +// storage proposals. +type StorageDealPieceCidBlocklistConfigFunc func() ([]cid.Cid, error) + +// SetStorageDealPieceCidBlocklistConfigFunc is a function which is used to set a +// list of CIDs for which the storage miner will reject deal proposals. +type SetStorageDealPieceCidBlocklistConfigFunc func([]cid.Cid) error + +// ConsiderOfflineStorageDealsConfigFunc is a function which reads from miner +// config to determine if the user has disabled storage deals (or not). +type ConsiderOfflineStorageDealsConfigFunc func() (bool, error) + +// SetConsiderOfflineStorageDealsConfigFunc is a function which is used to +// disable or enable storage deal acceptance. +type SetConsiderOfflineStorageDealsConfigFunc func(bool) error + +// ConsiderOfflineRetrievalDealsConfigFunc is a function which reads from miner +// config to determine if the user has disabled retrieval acceptance (or not). +type ConsiderOfflineRetrievalDealsConfigFunc func() (bool, error) + +// SetConsiderOfflineRetrievalDealsConfigFunc is a function which is used to +// disable or enable retrieval deal acceptance. +type SetConsiderOfflineRetrievalDealsConfigFunc func(bool) error diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/scorekeeper.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/scorekeeper.go new file mode 100644 index 0000000000..74bcb3f462 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/scorekeeper.go @@ -0,0 +1,24 @@ +package dtypes + +import ( + "sync" + + peer "github.com/libp2p/go-libp2p-core/peer" +) + +type ScoreKeeper struct { + lk sync.Mutex + scores map[peer.ID]float64 +} + +func (sk *ScoreKeeper) Update(scores map[peer.ID]float64) { + sk.lk.Lock() + sk.scores = scores + sk.lk.Unlock() +} + +func (sk *ScoreKeeper) Get() map[peer.ID]float64 { + sk.lk.Lock() + defer sk.lk.Unlock() + return sk.scores +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/shutdown.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/shutdown.go new file mode 100644 index 0000000000..6497b09380 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/shutdown.go @@ -0,0 +1,5 @@ +package dtypes + +// ShutdownChan is a channel to which you send a value if you intend to shut +// down the daemon (or storage miner), including the node and RPC server. +type ShutdownChan chan struct{} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/storage.go b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/storage.go new file mode 100644 index 0000000000..3eba07e4e5 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/dtypes/storage.go @@ -0,0 +1,50 @@ +package dtypes + +import ( + "github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation" + bserv "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-filestore" + "github.com/ipfs/go-graphsync" + blockstore "github.com/ipfs/go-ipfs-blockstore" + exchange "github.com/ipfs/go-ipfs-exchange-interface" + format "github.com/ipfs/go-ipld-format" + + datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-fil-markets/piecestore" + "github.com/filecoin-project/go-statestore" +) + +// MetadataDS stores metadata +// dy default it's namespaced under /metadata in main repo datastore +type MetadataDS datastore.Batching + +type ChainBlockstore blockstore.Blockstore + +type ChainGCLocker blockstore.GCLocker +type ChainGCBlockstore blockstore.GCBlockstore +type ChainExchange exchange.Interface +type ChainBlockService bserv.BlockService + +type ClientFilestore *filestore.Filestore +type ClientBlockstore blockstore.Blockstore +type ClientDAG format.DAGService +type ClientDealStore *statestore.StateStore +type ClientRequestValidator *requestvalidation.UnifiedRequestValidator +type ClientDatastore datastore.Batching + +type Graphsync graphsync.GraphExchange + +// ClientDataTransfer is a data transfer manager for the client +type ClientDataTransfer datatransfer.Manager + +type ProviderDealStore *statestore.StateStore +type ProviderPieceStore piecestore.PieceStore +type ProviderRequestValidator *requestvalidation.UnifiedRequestValidator + +// ProviderDataTransfer is a data transfer manager for the provider +type ProviderDataTransfer datatransfer.Manager + +type StagingDAG format.DAGService +type StagingBlockstore blockstore.Blockstore +type StagingGraphsync graphsync.GraphExchange diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/graphsync.go b/vendor/github.com/filecoin-project/lotus/node/modules/graphsync.go new file mode 100644 index 0000000000..601ad88405 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/graphsync.go @@ -0,0 +1,43 @@ +package modules + +import ( + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/ipfs/go-graphsync" + graphsyncimpl "github.com/ipfs/go-graphsync/impl" + gsnet "github.com/ipfs/go-graphsync/network" + "github.com/ipfs/go-graphsync/storeutil" + "github.com/libp2p/go-libp2p-core/host" + peer "github.com/libp2p/go-libp2p-peer" + "go.uber.org/fx" +) + +// Graphsync creates a graphsync instance from the given loader and storer +func Graphsync(mctx helpers.MetricsCtx, lc fx.Lifecycle, clientBs dtypes.ClientBlockstore, chainBs dtypes.ChainBlockstore, h host.Host) (dtypes.Graphsync, error) { + graphsyncNetwork := gsnet.NewFromLibp2pHost(h) + loader := storeutil.LoaderForBlockstore(clientBs) + storer := storeutil.StorerForBlockstore(clientBs) + gs := graphsyncimpl.New(helpers.LifecycleCtx(mctx, lc), graphsyncNetwork, loader, storer, graphsyncimpl.RejectAllRequestsByDefault()) + chainLoader := storeutil.LoaderForBlockstore(chainBs) + chainStorer := storeutil.StorerForBlockstore(chainBs) + err := gs.RegisterPersistenceOption("chainstore", chainLoader, chainStorer) + if err != nil { + return nil, err + } + gs.RegisterIncomingRequestHook(func(p peer.ID, requestData graphsync.RequestData, hookActions graphsync.IncomingRequestHookActions) { + _, has := requestData.Extension("chainsync") + if has { + // TODO: we should confirm the selector is a reasonable one before we validate + // TODO: this code will get more complicated and should probably not live here eventually + hookActions.ValidateRequest() + hookActions.UsePersistenceOption("chainstore") + } + }) + gs.RegisterOutgoingRequestHook(func(p peer.ID, requestData graphsync.RequestData, hookActions graphsync.OutgoingRequestHookActions) { + _, has := requestData.Extension("chainsync") + if has { + hookActions.UsePersistenceOption("chainstore") + } + }) + return gs, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/helpers/helpers.go b/vendor/github.com/filecoin-project/lotus/node/modules/helpers/helpers.go new file mode 100644 index 0000000000..f63b7eedd3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/helpers/helpers.go @@ -0,0 +1,25 @@ +package helpers + +import ( + "context" + + "go.uber.org/fx" +) + +// MetricsCtx is a context wrapper with metrics +type MetricsCtx context.Context + +// LifecycleCtx creates a context which will be cancelled when lifecycle stops +// +// This is a hack which we need because most of our services use contexts in a +// wrong way +func LifecycleCtx(mctx MetricsCtx, lc fx.Lifecycle) context.Context { + ctx, cancel := context.WithCancel(mctx) + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + cancel() + return nil + }, + }) + return ctx +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/ipfsclient.go b/vendor/github.com/filecoin-project/lotus/node/modules/ipfsclient.go new file mode 100644 index 0000000000..f405cb4c67 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/ipfsclient.go @@ -0,0 +1,45 @@ +package modules + +import ( + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/ipfs/go-filestore" + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/multiformats/go-multiaddr" + + "github.com/filecoin-project/lotus/lib/bufbstore" + "github.com/filecoin-project/lotus/lib/ipfsbstore" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +// IpfsClientBlockstore returns a ClientBlockstore implementation backed by an IPFS node. +// If ipfsMaddr is empty, a local IPFS node is assumed considering IPFS_PATH configuration. +// If ipfsMaddr is not empty, it will connect to the remote IPFS node with the provided multiaddress. +// The flag useForRetrieval indicates if the IPFS node will also be used for storing retrieving deals. +func IpfsClientBlockstore(ipfsMaddr string, useForRetrieval bool) func(helpers.MetricsCtx, fx.Lifecycle, dtypes.ClientFilestore) (dtypes.ClientBlockstore, error) { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, fstore dtypes.ClientFilestore) (dtypes.ClientBlockstore, error) { + var err error + var ipfsbs *ipfsbstore.IpfsBstore + if ipfsMaddr != "" { + var ma multiaddr.Multiaddr + ma, err = multiaddr.NewMultiaddr(ipfsMaddr) + if err != nil { + return nil, xerrors.Errorf("parsing ipfs multiaddr: %w", err) + } + ipfsbs, err = ipfsbstore.NewRemoteIpfsBstore(helpers.LifecycleCtx(mctx, lc), ma) + } else { + ipfsbs, err = ipfsbstore.NewIpfsBstore(helpers.LifecycleCtx(mctx, lc)) + } + if err != nil { + return nil, xerrors.Errorf("constructing ipfs blockstore: %w", err) + } + var ws blockstore.Blockstore + ws = ipfsbs + if !useForRetrieval { + ws = blockstore.NewIdStore((*filestore.Filestore)(fstore)) + } + return bufbstore.NewTieredBstore(ipfsbs, ws), nil + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/addrs.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/addrs.go new file mode 100644 index 0000000000..afb8ce910f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/addrs.go @@ -0,0 +1,117 @@ +package lp2p + +import ( + "fmt" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-core/host" + p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic" + mafilter "github.com/libp2p/go-maddr-filter" + ma "github.com/multiformats/go-multiaddr" + mamask "github.com/whyrusleeping/multiaddr-filter" +) + +func AddrFilters(filters []string) func() (opts Libp2pOpts, err error) { + return func() (opts Libp2pOpts, err error) { + for _, s := range filters { + f, err := mamask.NewMask(s) + if err != nil { + return opts, fmt.Errorf("incorrectly formatted address filter in config: %s", s) + } + opts.Opts = append(opts.Opts, libp2p.FilterAddresses(f)) //nolint:staticcheck + } + return opts, nil + } +} + +func makeAddrsFactory(announce []string, noAnnounce []string) (p2pbhost.AddrsFactory, error) { + var annAddrs []ma.Multiaddr + for _, addr := range announce { + maddr, err := ma.NewMultiaddr(addr) + if err != nil { + return nil, err + } + annAddrs = append(annAddrs, maddr) + } + + filters := mafilter.NewFilters() + noAnnAddrs := map[string]bool{} + for _, addr := range noAnnounce { + f, err := mamask.NewMask(addr) + if err == nil { + filters.AddFilter(*f, mafilter.ActionDeny) + continue + } + maddr, err := ma.NewMultiaddr(addr) + if err != nil { + return nil, err + } + noAnnAddrs[string(maddr.Bytes())] = true + } + + return func(allAddrs []ma.Multiaddr) []ma.Multiaddr { + var addrs []ma.Multiaddr + if len(annAddrs) > 0 { + addrs = annAddrs + } else { + addrs = allAddrs + } + + var out []ma.Multiaddr + for _, maddr := range addrs { + // check for exact matches + ok := noAnnAddrs[string(maddr.Bytes())] + // check for /ipcidr matches + if !ok && !filters.AddrBlocked(maddr) { + out = append(out, maddr) + } + } + return out + }, nil +} + +func AddrsFactory(announce []string, noAnnounce []string) func() (opts Libp2pOpts, err error) { + return func() (opts Libp2pOpts, err error) { + addrsFactory, err := makeAddrsFactory(announce, noAnnounce) + if err != nil { + return opts, err + } + opts.Opts = append(opts.Opts, libp2p.AddrsFactory(addrsFactory)) + return + } +} + +func listenAddresses(addresses []string) ([]ma.Multiaddr, error) { + var listen []ma.Multiaddr + for _, addr := range addresses { + maddr, err := ma.NewMultiaddr(addr) + if err != nil { + return nil, fmt.Errorf("failure to parse config.Addresses.Swarm: %s", addresses) + } + listen = append(listen, maddr) + } + + return listen, nil +} + +func StartListening(addresses []string) func(host host.Host) error { + return func(host host.Host) error { + listenAddrs, err := listenAddresses(addresses) + if err != nil { + return err + } + + // Actually start listening: + if err := host.Network().Listen(listenAddrs...); err != nil { + return err + } + + // list out our addresses + addrs, err := host.Network().InterfaceListenAddresses() + if err != nil { + return err + } + log.Infof("Swarm listening at: %s", addrs) + return nil + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/discovery.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/discovery.go new file mode 100644 index 0000000000..f281c66c77 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/discovery.go @@ -0,0 +1,35 @@ +package lp2p + +import ( + "context" + "time" + + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "go.uber.org/fx" + + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +const discoveryConnTimeout = time.Second * 30 + +type discoveryHandler struct { + ctx context.Context + host host.Host +} + +func (dh *discoveryHandler) HandlePeerFound(p peer.AddrInfo) { + log.Warnw("discovred peer", "peer", p) + ctx, cancel := context.WithTimeout(dh.ctx, discoveryConnTimeout) + defer cancel() + if err := dh.host.Connect(ctx, p); err != nil { + log.Warnw("failed to connect to peer found by discovery", "error", err) + } +} + +func DiscoveryHandler(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) *discoveryHandler { + return &discoveryHandler{ + ctx: helpers.LifecycleCtx(mctx, lc), + host: host, + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/host.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/host.go new file mode 100644 index 0000000000..b0436e9c93 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/host.go @@ -0,0 +1,113 @@ +package lp2p + +import ( + "context" + "fmt" + + nilrouting "github.com/ipfs/go-ipfs-routing/none" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + dht "github.com/libp2p/go-libp2p-kad-dht" + record "github.com/libp2p/go-libp2p-record" + routedhost "github.com/libp2p/go-libp2p/p2p/host/routed" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "go.uber.org/fx" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +type P2PHostIn struct { + fx.In + + ID peer.ID + Peerstore peerstore.Peerstore + + Opts [][]libp2p.Option `group:"libp2p"` +} + +// //////////////////////// + +type RawHost host.Host + +func Host(mctx helpers.MetricsCtx, lc fx.Lifecycle, params P2PHostIn) (RawHost, error) { + ctx := helpers.LifecycleCtx(mctx, lc) + + pkey := params.Peerstore.PrivKey(params.ID) + if pkey == nil { + return nil, fmt.Errorf("missing private key for node ID: %s", params.ID.Pretty()) + } + + opts := []libp2p.Option{ + libp2p.Identity(pkey), + libp2p.Peerstore(params.Peerstore), + libp2p.NoListenAddrs, + libp2p.Ping(true), + libp2p.UserAgent("lotus-" + build.UserVersion()), + } + for _, o := range params.Opts { + opts = append(opts, o...) + } + + h, err := libp2p.New(ctx, opts...) + if err != nil { + return nil, err + } + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return h.Close() + }, + }) + + return h, nil +} + +func MockHost(mn mocknet.Mocknet, id peer.ID, ps peerstore.Peerstore) (RawHost, error) { + return mn.AddPeerWithPeerstore(id, ps) +} + +func DHTRouting(mode dht.ModeOpt) interface{} { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host RawHost, dstore dtypes.MetadataDS, validator record.Validator, nn dtypes.NetworkName, bs dtypes.Bootstrapper) (BaseIpfsRouting, error) { + ctx := helpers.LifecycleCtx(mctx, lc) + + if bs { + mode = dht.ModeServer + } + + opts := []dht.Option{dht.Mode(mode), + dht.Datastore(dstore), + dht.Validator(validator), + dht.ProtocolPrefix(build.DhtProtocolName(nn)), + dht.QueryFilter(dht.PublicQueryFilter), + dht.RoutingTableFilter(dht.PublicRoutingTableFilter), + dht.DisableProviders(), + dht.DisableValues()} + d, err := dht.New( + ctx, host, opts..., + ) + + if err != nil { + return nil, err + } + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return d.Close() + }, + }) + + return d, nil + } +} + +func NilRouting(mctx helpers.MetricsCtx) (BaseIpfsRouting, error) { + return nilrouting.ConstructNilRouting(mctx, nil, nil, nil) +} + +func RoutedHost(rh RawHost, r BaseIpfsRouting) host.Host { + return routedhost.Wrap(rh, r) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/libp2p.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/libp2p.go new file mode 100644 index 0000000000..5a1666cb6d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/libp2p.go @@ -0,0 +1,110 @@ +package lp2p + +import ( + "crypto/rand" + "time" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "golang.org/x/xerrors" + + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p" + connmgr "github.com/libp2p/go-libp2p-connmgr" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peerstore" + "go.uber.org/fx" +) + +var log = logging.Logger("p2pnode") + +const ( + KLibp2pHost = "libp2p-host" + KTLibp2pHost = KLibp2pHost +) + +type Libp2pOpts struct { + fx.Out + + Opts []libp2p.Option `group:"libp2p"` +} + +func PrivKey(ks types.KeyStore) (crypto.PrivKey, error) { + k, err := ks.Get(KLibp2pHost) + if err == nil { + return crypto.UnmarshalPrivateKey(k.PrivateKey) + } + if !xerrors.Is(err, types.ErrKeyInfoNotFound) { + return nil, err + } + pk, err := genLibp2pKey() + if err != nil { + return nil, err + } + kbytes, err := pk.Bytes() + if err != nil { + return nil, err + } + + if err := ks.Put(KLibp2pHost, types.KeyInfo{ + Type: KTLibp2pHost, + PrivateKey: kbytes, + }); err != nil { + return nil, err + } + + return pk, nil +} + +func genLibp2pKey() (crypto.PrivKey, error) { + pk, _, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + return nil, err + } + return pk, nil +} + +// Misc options + +func ConnectionManager(low, high uint, grace time.Duration, protected []string) func() (opts Libp2pOpts, err error) { + return func() (Libp2pOpts, error) { + cm := connmgr.NewConnManager(int(low), int(high), grace) + for _, p := range protected { + pid, err := peer.IDFromString(p) + if err != nil { + return Libp2pOpts{}, xerrors.Errorf("failed to parse peer ID in protected peers array: %w", err) + } + + cm.Protect(pid, "config-prot") + } + + infos, err := build.BuiltinBootstrap() + if err != nil { + return Libp2pOpts{}, xerrors.Errorf("failed to get bootstrap peers: %w", err) + } + + for _, inf := range infos { + cm.Protect(inf.ID, "bootstrap") + } + + return Libp2pOpts{ + Opts: []libp2p.Option{libp2p.ConnectionManager(cm)}, + }, nil + } +} + +func PstoreAddSelfKeys(id peer.ID, sk crypto.PrivKey, ps peerstore.Peerstore) error { + if err := ps.AddPubKey(id, sk.GetPublic()); err != nil { + return err + } + + return ps.AddPrivKey(id, sk) +} + +func simpleOpt(opt libp2p.Option) func() (opts Libp2pOpts, err error) { + return func() (opts Libp2pOpts, err error) { + opts.Opts = append(opts.Opts, opt) + return + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/nat.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/nat.go new file mode 100644 index 0000000000..f6c541ef77 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/nat.go @@ -0,0 +1,40 @@ +package lp2p + +import ( + "github.com/libp2p/go-libp2p" +) + +/*import ( + "github.com/libp2p/go-libp2p" + autonat "github.com/libp2p/go-libp2p-autonat-svc" + host "github.com/libp2p/go-libp2p-core/host" + libp2pquic "github.com/libp2p/go-libp2p-quic-transport" + "go.uber.org/fx" + + "github.com/ipfs/go-ipfs/repo" + + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +func AutoNATService(quic bool) func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error { + return func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error { + // collect private net option in case swarm.key is presented + opts, _, err := PNet(repo) + if err != nil { + // swarm key exists but was failed to decode + return err + } + + if quic { + opts.Opts = append(opts.Opts, libp2p.DefaultTransports, libp2p.Transport(libp2pquic.NewTransport)) + } + + _, err = autonat.NewAutoNATService(helpers.LifecycleCtx(mctx, lc), host, opts.Opts...) + return err + } +} +*/ + +var AutoNATService = simpleOpt(libp2p.EnableNATService()) + +var NatPortMap = simpleOpt(libp2p.NATPortMap()) diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/pubsub.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/pubsub.go new file mode 100644 index 0000000000..ac23f56a89 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/pubsub.go @@ -0,0 +1,348 @@ +package lp2p + +import ( + "context" + "encoding/json" + "time" + + host "github.com/libp2p/go-libp2p-core/host" + peer "github.com/libp2p/go-libp2p-core/peer" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb" + blake2b "github.com/minio/blake2b-simd" + ma "github.com/multiformats/go-multiaddr" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +func init() { + // configure larger overlay parameters + pubsub.GossipSubD = 8 + pubsub.GossipSubDscore = 6 + pubsub.GossipSubDout = 3 + pubsub.GossipSubDlo = 6 + pubsub.GossipSubDhi = 12 + pubsub.GossipSubDlazy = 12 + pubsub.GossipSubDirectConnectInitialDelay = 30 * time.Second +} +func ScoreKeeper() *dtypes.ScoreKeeper { + return new(dtypes.ScoreKeeper) +} + +type GossipIn struct { + fx.In + Mctx helpers.MetricsCtx + Lc fx.Lifecycle + Host host.Host + Nn dtypes.NetworkName + Bp dtypes.BootstrapPeers + Db dtypes.DrandBootstrap + Cfg *config.Pubsub + Sk *dtypes.ScoreKeeper + Dr dtypes.DrandConfig +} + +func getDrandTopic(chainInfoJSON string) (string, error) { + var drandInfo = struct { + Hash string `json:"hash"` + }{} + err := json.Unmarshal([]byte(chainInfoJSON), &drandInfo) + if err != nil { + return "", xerrors.Errorf("could not unmarshal drand chain info: %w", err) + } + return "/drand/pubsub/v0.0.0/" + drandInfo.Hash, nil +} + +func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { + bootstrappers := make(map[peer.ID]struct{}) + for _, pi := range in.Bp { + bootstrappers[pi.ID] = struct{}{} + } + drandBootstrappers := make(map[peer.ID]struct{}) + for _, pi := range in.Db { + drandBootstrappers[pi.ID] = struct{}{} + } + + isBootstrapNode := in.Cfg.Bootstrapper + drandTopic, err := getDrandTopic(in.Dr.ChainInfoJSON) + if err != nil { + return nil, err + } + + options := []pubsub.Option{ + // Gossipsubv1.1 configuration + pubsub.WithFloodPublish(true), + pubsub.WithMessageIdFn(HashMsgId), + pubsub.WithPeerScore( + &pubsub.PeerScoreParams{ + AppSpecificScore: func(p peer.ID) float64 { + // return a heavy positive score for bootstrappers so that we don't unilaterally prune + // them and accept PX from them. + // we don't do that in the bootstrappers themselves to avoid creating a closed mesh + // between them (however we might want to consider doing just that) + _, ok := bootstrappers[p] + if ok && !isBootstrapNode { + return 2500 + } + + _, ok = drandBootstrappers[p] + if ok && !isBootstrapNode { + return 1500 + } + + // TODO: we want to plug the application specific score to the node itself in order + // to provide feedback to the pubsub system based on observed behaviour + return 0 + }, + AppSpecificWeight: 1, + + // This sets the IP colocation threshold to 1 peer per + IPColocationFactorThreshold: 1, + IPColocationFactorWeight: -100, + // TODO we want to whitelist IPv6 /64s that belong to datacenters etc + // IPColocationFactorWhitelist: map[string]struct{}{}, + + // P7: behavioural penalties, decay after 1hr + BehaviourPenaltyWeight: -10, + BehaviourPenaltyDecay: pubsub.ScoreParameterDecay(time.Hour), + + DecayInterval: pubsub.DefaultDecayInterval, + DecayToZero: pubsub.DefaultDecayToZero, + + // this retains non-positive scores for 6 hours + RetainScore: 6 * time.Hour, + + // topic parameters + Topics: map[string]*pubsub.TopicScoreParams{ + drandTopic: { + // expected 2 beaconsn/min + TopicWeight: 0.5, // 5x block topic + + // 1 tick per second, maxes at 1 after 1 hour + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 1 hour, cap at 100 blocks + FirstMessageDeliveriesWeight: 5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 100, // 100 blocks in an hour + + // Mesh Delivery Failure is currently turned off for blocks + // This is on purpose as + // - the traffic is very low for meaningful distribution of incoming edges. + // - the reaction time needs to be very slow -- in the order of 10 min at least + // so we might as well let opportunistic grafting repair the mesh on its own + // pace. + // - the network is too small, so large asymmetries can be expected between mesh + // edges. + // We should revisit this once the network grows. + // + // // tracks deliveries in the last minute + // // penalty activates at 1 minute and expects ~0.4 blocks + // MeshMessageDeliveriesWeight: -576, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 10, // 10 blocks in a minute + // MeshMessageDeliveriesThreshold: 0.41666, // 10/12/2 blocks/min + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + // + // // decays after 15 min + // MeshFailurePenaltyWeight: -576, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(15 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + build.BlocksTopic(in.Nn): { + // expected 10 blocks/min + TopicWeight: 0.1, // max is 50, max mesh penalty is -10, single invalid message is -100 + + // 1 tick per second, maxes at 1 after 1 hour + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 1 hour, cap at 100 blocks + FirstMessageDeliveriesWeight: 5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 100, // 100 blocks in an hour + + // Mesh Delivery Failure is currently turned off for blocks + // This is on purpose as + // - the traffic is very low for meaningful distribution of incoming edges. + // - the reaction time needs to be very slow -- in the order of 10 min at least + // so we might as well let opportunistic grafting repair the mesh on its own + // pace. + // - the network is too small, so large asymmetries can be expected between mesh + // edges. + // We should revisit this once the network grows. + // + // // tracks deliveries in the last minute + // // penalty activates at 1 minute and expects ~0.4 blocks + // MeshMessageDeliveriesWeight: -576, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 10, // 10 blocks in a minute + // MeshMessageDeliveriesThreshold: 0.41666, // 10/12/2 blocks/min + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + // + // // decays after 15 min + // MeshFailurePenaltyWeight: -576, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(15 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + build.MessagesTopic(in.Nn): { + // expected > 1 tx/second + TopicWeight: 0.05, // max is 25, max mesh penalty is -5, single invalid message is -100 + + // 1 tick per second, maxes at 1 hour + TimeInMeshWeight: 0.0002778, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 10min, cap at 1000 tx + FirstMessageDeliveriesWeight: 0.5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), + //FirstMessageDeliveriesCap: 1000, + FirstMessageDeliveriesCap: 1, // we can't yet properly validate them so only confer a tiny boost from delivery + + // Mesh Delivery Failure is currently turned off for messages + // This is on purpose as the network is still too small, which results in + // asymmetries and potential unmeshing from negative scores. + // // tracks deliveries in the last minute + // // penalty activates at 1 min and expects 2.5 txs + // MeshMessageDeliveriesWeight: -16, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 100, // 100 txs in a minute + // MeshMessageDeliveriesThreshold: 2.5, // 60/12/2 txs/minute + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + + // // decays after 5min + // MeshFailurePenaltyWeight: -16, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(5 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -2000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + }, + }, + &pubsub.PeerScoreThresholds{ + GossipThreshold: -500, + PublishThreshold: -1000, + GraylistThreshold: -2500, + AcceptPXThreshold: 1000, + OpportunisticGraftThreshold: 5, + }, + ), + pubsub.WithPeerScoreInspect(in.Sk.Update, 10*time.Second), + } + + // enable Peer eXchange on bootstrappers + if isBootstrapNode { + // turn off the mesh in bootstrappers -- only do gossip and PX + pubsub.GossipSubD = 0 + pubsub.GossipSubDscore = 0 + pubsub.GossipSubDlo = 0 + pubsub.GossipSubDhi = 0 + pubsub.GossipSubDout = 0 + pubsub.GossipSubDlazy = 1024 + pubsub.GossipSubGossipFactor = 0.5 + // turn on PX + options = append(options, pubsub.WithPeerExchange(true)) + } + + // direct peers + if in.Cfg.DirectPeers != nil { + var directPeerInfo []peer.AddrInfo + + for _, addr := range in.Cfg.DirectPeers { + a, err := ma.NewMultiaddr(addr) + if err != nil { + return nil, err + } + + pi, err := peer.AddrInfoFromP2pAddr(a) + if err != nil { + return nil, err + } + + directPeerInfo = append(directPeerInfo, *pi) + } + + options = append(options, pubsub.WithDirectPeers(directPeerInfo)) + } + + // tracer + if in.Cfg.RemoteTracer != "" { + a, err := ma.NewMultiaddr(in.Cfg.RemoteTracer) + if err != nil { + return nil, err + } + + pi, err := peer.AddrInfoFromP2pAddr(a) + if err != nil { + return nil, err + } + + tr, err := pubsub.NewRemoteTracer(context.TODO(), in.Host, *pi) + if err != nil { + return nil, err + } + + trw := newTracerWrapper(tr) + options = append(options, pubsub.WithEventTracer(trw)) + } + + // TODO: we want to hook the peer score inspector so that we can gain visibility + // in peer scores for debugging purposes -- this might be trigged by metrics collection + // options = append(options, pubsub.WithPeerScoreInspect(XXX, time.Second)) + + return pubsub.NewGossipSub(helpers.LifecycleCtx(in.Mctx, in.Lc), in.Host, options...) +} + +func HashMsgId(m *pubsub_pb.Message) string { + hash := blake2b.Sum256(m.Data) + return string(hash[:]) +} + +func newTracerWrapper(tr pubsub.EventTracer) pubsub.EventTracer { + return &tracerWrapper{tr: tr} +} + +type tracerWrapper struct { + tr pubsub.EventTracer +} + +func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) { + // this filters the trace events reported to the remote tracer to include only + // JOIN/LEAVE/GRAFT/PRUNE/PUBLISH/DELIVER. This significantly reduces bandwidth usage and still + // collects enough data to recover the state of the mesh and compute message delivery latency + // distributions. + // TODO: hook all events into local metrics for inspection through the dashboard + switch evt.GetType() { + case pubsub_pb.TraceEvent_PUBLISH_MESSAGE: + trw.tr.Trace(evt) + case pubsub_pb.TraceEvent_DELIVER_MESSAGE: + trw.tr.Trace(evt) + case pubsub_pb.TraceEvent_JOIN: + trw.tr.Trace(evt) + case pubsub_pb.TraceEvent_LEAVE: + trw.tr.Trace(evt) + case pubsub_pb.TraceEvent_GRAFT: + trw.tr.Trace(evt) + case pubsub_pb.TraceEvent_PRUNE: + trw.tr.Trace(evt) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/relay.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/relay.go new file mode 100644 index 0000000000..a6bedb12b3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/relay.go @@ -0,0 +1,28 @@ +package lp2p + +import ( + "fmt" + + "github.com/libp2p/go-libp2p" + coredisc "github.com/libp2p/go-libp2p-core/discovery" + routing "github.com/libp2p/go-libp2p-core/routing" + discovery "github.com/libp2p/go-libp2p-discovery" +) + +func NoRelay() func() (opts Libp2pOpts, err error) { + return func() (opts Libp2pOpts, err error) { + // always disabled, it's an eclipse attack vector + opts.Opts = append(opts.Opts, libp2p.DisableRelay()) + return + } +} + +// TODO: should be use baseRouting or can we use higher level router here? +func Discovery(router BaseIpfsRouting) (coredisc.Discovery, error) { + crouter, ok := router.(routing.ContentRouting) + if !ok { + return nil, fmt.Errorf("no suitable routing for discovery") + } + + return discovery.NewRoutingDiscovery(crouter), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/routing.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/routing.go new file mode 100644 index 0000000000..fe7f9d3f37 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/routing.go @@ -0,0 +1,70 @@ +package lp2p + +import ( + "context" + "sort" + + routing "github.com/libp2p/go-libp2p-core/routing" + dht "github.com/libp2p/go-libp2p-kad-dht" + record "github.com/libp2p/go-libp2p-record" + routinghelpers "github.com/libp2p/go-libp2p-routing-helpers" + "go.uber.org/fx" +) + +type BaseIpfsRouting routing.Routing + +type Router struct { + routing.Routing + + Priority int // less = more important +} + +type p2pRouterOut struct { + fx.Out + + Router Router `group:"routers"` +} + +func BaseRouting(lc fx.Lifecycle, in BaseIpfsRouting) (out p2pRouterOut, dr *dht.IpfsDHT) { + if dht, ok := in.(*dht.IpfsDHT); ok { + dr = dht + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return dr.Close() + }, + }) + } + + return p2pRouterOut{ + Router: Router{ + Priority: 1000, + Routing: in, + }, + }, dr +} + +type p2pOnlineRoutingIn struct { + fx.In + + Routers []Router `group:"routers"` + Validator record.Validator +} + +func Routing(in p2pOnlineRoutingIn) routing.Routing { + routers := in.Routers + + sort.SliceStable(routers, func(i, j int) bool { + return routers[i].Priority < routers[j].Priority + }) + + irouters := make([]routing.Routing, len(routers)) + for i, v := range routers { + irouters[i] = v.Routing + } + + return routinghelpers.Tiered{ + Routers: irouters, + Validator: in.Validator, + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/smux.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/smux.go new file mode 100644 index 0000000000..f5c74e18bb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/smux.go @@ -0,0 +1,54 @@ +package lp2p + +import ( + "os" + "strings" + + "github.com/libp2p/go-libp2p" + smux "github.com/libp2p/go-libp2p-core/mux" + mplex "github.com/libp2p/go-libp2p-mplex" + yamux "github.com/libp2p/go-libp2p-yamux" +) + +func makeSmuxTransportOption(mplexExp bool) libp2p.Option { + const yamuxID = "/yamux/1.0.0" + const mplexID = "/mplex/6.7.0" + + ymxtpt := *yamux.DefaultTransport + ymxtpt.AcceptBacklog = 512 + + if os.Getenv("YAMUX_DEBUG") != "" { + ymxtpt.LogOutput = os.Stderr + } + + muxers := map[string]smux.Multiplexer{yamuxID: &ymxtpt} + if mplexExp { + muxers[mplexID] = mplex.DefaultTransport + } + + // Allow muxer preference order overriding + order := []string{yamuxID, mplexID} + if prefs := os.Getenv("LIBP2P_MUX_PREFS"); prefs != "" { + order = strings.Fields(prefs) + } + + opts := make([]libp2p.Option, 0, len(order)) + for _, id := range order { + tpt, ok := muxers[id] + if !ok { + log.Warnf("unknown or duplicate muxer in LIBP2P_MUX_PREFS: %s", id) + continue + } + delete(muxers, id) + opts = append(opts, libp2p.Muxer(id, tpt)) + } + + return libp2p.ChainOptions(opts...) +} + +func SmuxTransport(mplex bool) func() (opts Libp2pOpts, err error) { + return func() (opts Libp2pOpts, err error) { + opts.Opts = append(opts.Opts, makeSmuxTransportOption(mplex)) + return + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/transport.go b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/transport.go new file mode 100644 index 0000000000..9dfa7843a2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/lp2p/transport.go @@ -0,0 +1,38 @@ +package lp2p + +import ( + "github.com/libp2p/go-libp2p" + metrics "github.com/libp2p/go-libp2p-core/metrics" + libp2pquic "github.com/libp2p/go-libp2p-quic-transport" + secio "github.com/libp2p/go-libp2p-secio" + tls "github.com/libp2p/go-libp2p-tls" +) + +var DefaultTransports = simpleOpt(libp2p.DefaultTransports) +var QUIC = simpleOpt(libp2p.Transport(libp2pquic.NewTransport)) + +func Security(enabled, preferTLS bool) interface{} { + if !enabled { + return func() (opts Libp2pOpts) { + // TODO: shouldn't this be Errorf to guarantee visibility? + log.Warnf(`Your lotus node has been configured to run WITHOUT ENCRYPTED CONNECTIONS. + You will not be able to connect to any nodes configured to use encrypted connections`) + opts.Opts = append(opts.Opts, libp2p.NoSecurity) + return opts + } + } + return func() (opts Libp2pOpts) { + if preferTLS { + opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(tls.ID, tls.New), libp2p.Security(secio.ID, secio.New))) + } else { + opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(secio.ID, secio.New), libp2p.Security(tls.ID, tls.New))) + } + return opts + } +} + +func BandwidthCounter() (opts Libp2pOpts, reporter metrics.Reporter) { + reporter = metrics.NewBandwidthCounter() + opts.Opts = append(opts.Opts, libp2p.BandwidthReporter(reporter)) + return opts, reporter +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/services.go b/vendor/github.com/filecoin-project/lotus/node/modules/services.go new file mode 100644 index 0000000000..d439843c48 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/services.go @@ -0,0 +1,128 @@ +package modules + +import ( + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + eventbus "github.com/libp2p/go-eventbus" + event "github.com/libp2p/go-libp2p-core/event" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "go.uber.org/fx" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-fil-markets/retrievalmarket/discovery" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/beacon" + "github.com/filecoin-project/lotus/chain/beacon/drand" + "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/sub" + "github.com/filecoin-project/lotus/lib/peermgr" + "github.com/filecoin-project/lotus/node/hello" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" +) + +func RunHello(mctx helpers.MetricsCtx, lc fx.Lifecycle, h host.Host, svc *hello.Service) error { + h.SetStreamHandler(hello.ProtocolID, svc.HandleStream) + + sub, err := h.EventBus().Subscribe(new(event.EvtPeerIdentificationCompleted), eventbus.BufSize(1024)) + if err != nil { + return xerrors.Errorf("failed to subscribe to event bus: %w", err) + } + + go func() { + for evt := range sub.Out() { + pic := evt.(event.EvtPeerIdentificationCompleted) + go func() { + if err := svc.SayHello(helpers.LifecycleCtx(mctx, lc), pic.Peer); err != nil { + log.Warnw("failed to say hello", "error", err, "peer", pic.Peer) + return + } + }() + } + }() + return nil +} + +func RunPeerMgr(mctx helpers.MetricsCtx, lc fx.Lifecycle, pmgr *peermgr.PeerMgr) { + go pmgr.Run(helpers.LifecycleCtx(mctx, lc)) +} + +func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { + h.SetStreamHandler(blocksync.BlockSyncProtocolID, svc.HandleStream) +} + +func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { + ctx := helpers.LifecycleCtx(mctx, lc) + + blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) + if err != nil { + panic(err) + } + + v := sub.NewBlockValidator( + chain, stmgr, + func(p peer.ID) { + ps.BlacklistPeer(p) + h.ConnManager().TagPeer(p, "badblock", -1000) + }) + + if err := ps.RegisterTopicValidator(build.BlocksTopic(nn), v.Validate); err != nil { + panic(err) + } + + go sub.HandleIncomingBlocks(ctx, blocksub, s, h.ConnManager()) +} + +func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, mpool *messagepool.MessagePool, nn dtypes.NetworkName) { + ctx := helpers.LifecycleCtx(mctx, lc) + + msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) + if err != nil { + panic(err) + } + + v := sub.NewMessageValidator(mpool) + + if err := ps.RegisterTopicValidator(build.MessagesTopic(nn), v.Validate); err != nil { + panic(err) + } + + go sub.HandleIncomingMessages(ctx, mpool, msgsub) +} + +func NewLocalDiscovery(ds dtypes.MetadataDS) *discovery.Local { + return discovery.NewLocal(namespace.Wrap(ds, datastore.NewKey("/deals/local"))) +} + +func RetrievalResolver(l *discovery.Local) retrievalmarket.PeerResolver { + return discovery.Multi(l) +} + +type RandomBeaconParams struct { + fx.In + + PubSub *pubsub.PubSub `optional:"true"` + Cs *store.ChainStore + DrandConfig dtypes.DrandConfig +} + +func BuiltinDrandConfig() dtypes.DrandConfig { + return build.DrandConfig +} + +func RandomBeacon(p RandomBeaconParams, _ dtypes.AfterGenesisSet) (beacon.RandomBeacon, error) { + gen, err := p.Cs.GetGenesis() + if err != nil { + return nil, err + } + + //return beacon.NewMockBeacon(build.BlockDelaySecs * time.Second) + return drand.NewDrandBeacon(gen.Timestamp, build.BlockDelaySecs, p.PubSub, p.DrandConfig) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/storage.go b/vendor/github.com/filecoin-project/lotus/node/modules/storage.go new file mode 100644 index 0000000000..1bdce1d2f4 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/storage.go @@ -0,0 +1,31 @@ +package modules + +import ( + "context" + + "go.uber.org/fx" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/repo" +) + +func LockedRepo(lr repo.LockedRepo) func(lc fx.Lifecycle) repo.LockedRepo { + return func(lc fx.Lifecycle) repo.LockedRepo { + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return lr.Close() + }, + }) + + return lr + } +} + +func KeyStore(lr repo.LockedRepo) (types.KeyStore, error) { + return lr.KeyStore() +} + +func Datastore(r repo.LockedRepo) (dtypes.MetadataDS, error) { + return r.Datastore("/metadata") +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/storageminer.go b/vendor/github.com/filecoin-project/lotus/node/modules/storageminer.go new file mode 100644 index 0000000000..99d95f77a2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/storageminer.go @@ -0,0 +1,558 @@ +package modules + +import ( + "context" + "errors" + "fmt" + "net/http" + + "github.com/ipfs/go-bitswap" + "github.com/ipfs/go-bitswap/network" + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + graphsync "github.com/ipfs/go-graphsync/impl" + gsnet "github.com/ipfs/go-graphsync/network" + "github.com/ipfs/go-graphsync/storeutil" + blockstore "github.com/ipfs/go-ipfs-blockstore" + "github.com/ipfs/go-merkledag" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/routing" + "go.uber.org/fx" + "go.uber.org/multierr" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + dtgraphsync "github.com/filecoin-project/go-data-transfer/impl/graphsync" + piecefilestore "github.com/filecoin-project/go-fil-markets/filestore" + "github.com/filecoin-project/go-fil-markets/piecestore" + "github.com/filecoin-project/go-fil-markets/retrievalmarket" + retrievalimpl "github.com/filecoin-project/go-fil-markets/retrievalmarket/impl" + rmnet "github.com/filecoin-project/go-fil-markets/retrievalmarket/network" + "github.com/filecoin-project/go-fil-markets/storagemarket" + storageimpl "github.com/filecoin-project/go-fil-markets/storagemarket/impl" + "github.com/filecoin-project/go-fil-markets/storagemarket/impl/requestvalidation" + "github.com/filecoin-project/go-fil-markets/storagemarket/impl/storedask" + smnet "github.com/filecoin-project/go-fil-markets/storagemarket/network" + "github.com/filecoin-project/go-jsonrpc/auth" + paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/go-statestore" + "github.com/filecoin-project/go-storedcounter" + "github.com/filecoin-project/lotus/node/config" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/sector-storage/stores" + "github.com/filecoin-project/specs-actors/actors/abi" + sealing "github.com/filecoin-project/storage-fsm" + + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/markets/retrievaladapter" + "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/modules/helpers" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/storage" +) + +var StorageCounterDSPrefix = "/storage/nextid" + +func minerAddrFromDS(ds dtypes.MetadataDS) (address.Address, error) { + maddrb, err := ds.Get(datastore.NewKey("miner-address")) + if err != nil { + return address.Undef, err + } + + return address.NewFromBytes(maddrb) +} + +func GetParams(sbc *ffiwrapper.Config) error { + ssize, err := sbc.SealProofType.SectorSize() + if err != nil { + return err + } + + // If built-in assets are disabled, we expect the user to have placed the right + // parameters in the right location on the filesystem (/var/tmp/filecoin-proof-parameters). + if build.DisableBuiltinAssets { + return nil + } + + if err := paramfetch.GetParams(context.TODO(), build.ParametersJSON(), uint64(ssize)); err != nil { + return xerrors.Errorf("fetching proof parameters: %w", err) + } + + return nil +} + +func MinerAddress(ds dtypes.MetadataDS) (dtypes.MinerAddress, error) { + ma, err := minerAddrFromDS(ds) + return dtypes.MinerAddress(ma), err +} + +func MinerID(ma dtypes.MinerAddress) (dtypes.MinerID, error) { + id, err := address.IDFromAddress(address.Address(ma)) + return dtypes.MinerID(id), err +} + +func StorageNetworkName(ctx helpers.MetricsCtx, a lapi.FullNode) (dtypes.NetworkName, error) { + return a.StateNetworkName(ctx) +} + +func ProofsConfig(maddr dtypes.MinerAddress, fnapi lapi.FullNode) (*ffiwrapper.Config, error) { + mi, err := fnapi.StateMinerInfo(context.TODO(), address.Address(maddr), types.EmptyTSK) + if err != nil { + return nil, err + } + + spt, err := ffiwrapper.SealProofTypeFromSectorSize(mi.SectorSize) + if err != nil { + return nil, xerrors.Errorf("bad sector size: %w", err) + } + + sb := &ffiwrapper.Config{ + SealProofType: spt, + } + + return sb, nil +} + +type sidsc struct { + sc *storedcounter.StoredCounter +} + +func (s *sidsc) Next() (abi.SectorNumber, error) { + i, err := s.sc.Next() + return abi.SectorNumber(i), err +} + +func SectorIDCounter(ds dtypes.MetadataDS) sealing.SectorIDCounter { + sc := storedcounter.New(ds, datastore.NewKey(StorageCounterDSPrefix)) + return &sidsc{sc} +} + +func StorageMiner(mctx helpers.MetricsCtx, lc fx.Lifecycle, api lapi.FullNode, h host.Host, ds dtypes.MetadataDS, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier) (*storage.Miner, error) { + maddr, err := minerAddrFromDS(ds) + if err != nil { + return nil, err + } + + ctx := helpers.LifecycleCtx(mctx, lc) + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return nil, err + } + + worker, err := api.StateAccountKey(ctx, mi.Worker, types.EmptyTSK) + if err != nil { + return nil, err + } + + fps, err := storage.NewWindowedPoStScheduler(api, sealer, sealer, maddr, worker) + if err != nil { + return nil, err + } + + sm, err := storage.NewMiner(api, maddr, worker, h, ds, sealer, sc, verif) + if err != nil { + return nil, err + } + + lc.Append(fx.Hook{ + OnStart: func(context.Context) error { + go fps.Run(ctx) + return sm.Run(ctx) + }, + OnStop: sm.Stop, + }) + + return sm, nil +} + +func HandleRetrieval(host host.Host, lc fx.Lifecycle, m retrievalmarket.RetrievalProvider) { + lc.Append(fx.Hook{ + OnStart: func(context.Context) error { + return m.Start() + }, + OnStop: func(context.Context) error { + return m.Stop() + }, + }) +} + +func HandleDeals(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, h storagemarket.StorageProvider) { + ctx := helpers.LifecycleCtx(mctx, lc) + + lc.Append(fx.Hook{ + OnStart: func(context.Context) error { + return h.Start(ctx) + }, + OnStop: func(context.Context) error { + return h.Stop() + }, + }) +} + +// RegisterProviderValidator is an initialization hook that registers the provider +// request validator with the data transfer module as the validator for +// StorageDataTransferVoucher types +func RegisterProviderValidator(mrv dtypes.ProviderRequestValidator, dtm dtypes.ProviderDataTransfer) { + if err := dtm.RegisterVoucherType(&requestvalidation.StorageDataTransferVoucher{}, (*requestvalidation.UnifiedRequestValidator)(mrv)); err != nil { + panic(err) + } +} + +// NewProviderDAGServiceDataTransfer returns a data transfer manager that just +// uses the provider's Staging DAG service for transfers +func NewProviderDAGServiceDataTransfer(h host.Host, gs dtypes.StagingGraphsync, ds dtypes.MetadataDS) dtypes.ProviderDataTransfer { + sc := storedcounter.New(ds, datastore.NewKey("/datatransfer/provider/counter")) + return dtgraphsync.NewGraphSyncDataTransfer(h, gs, sc) +} + +// NewProviderDealStore creates a statestore for the client to store its deals +func NewProviderDealStore(ds dtypes.MetadataDS) dtypes.ProviderDealStore { + return statestore.New(namespace.Wrap(ds, datastore.NewKey("/deals/provider"))) +} + +// NewProviderPieceStore creates a statestore for storing metadata about pieces +// shared by the storage and retrieval providers +func NewProviderPieceStore(ds dtypes.MetadataDS) dtypes.ProviderPieceStore { + return piecestore.NewPieceStore(namespace.Wrap(ds, datastore.NewKey("/storagemarket"))) +} + +// StagingBlockstore creates a blockstore for staging blocks for a miner +// in a storage deal, prior to sealing +func StagingBlockstore(r repo.LockedRepo) (dtypes.StagingBlockstore, error) { + stagingds, err := r.Datastore("/staging") + if err != nil { + return nil, err + } + + bs := blockstore.NewBlockstore(stagingds) + ibs := blockstore.NewIdStore(bs) + + return ibs, nil +} + +// StagingDAG is a DAGService for the StagingBlockstore +func StagingDAG(mctx helpers.MetricsCtx, lc fx.Lifecycle, ibs dtypes.StagingBlockstore, rt routing.Routing, h host.Host) (dtypes.StagingDAG, error) { + + bitswapNetwork := network.NewFromIpfsHost(h, rt) + bitswapOptions := []bitswap.Option{bitswap.ProvideEnabled(false)} + exch := bitswap.New(helpers.LifecycleCtx(mctx, lc), bitswapNetwork, ibs, bitswapOptions...) + + bsvc := blockservice.New(ibs, exch) + dag := merkledag.NewDAGService(bsvc) + + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return bsvc.Close() + }, + }) + + return dag, nil +} + +// StagingGraphsync creates a graphsync instance which reads and writes blocks +// to the StagingBlockstore +func StagingGraphsync(mctx helpers.MetricsCtx, lc fx.Lifecycle, ibs dtypes.StagingBlockstore, h host.Host) dtypes.StagingGraphsync { + graphsyncNetwork := gsnet.NewFromLibp2pHost(h) + loader := storeutil.LoaderForBlockstore(ibs) + storer := storeutil.StorerForBlockstore(ibs) + gs := graphsync.New(helpers.LifecycleCtx(mctx, lc), graphsyncNetwork, loader, storer, graphsync.RejectAllRequestsByDefault()) + + return gs +} + +func SetupBlockProducer(lc fx.Lifecycle, ds dtypes.MetadataDS, api lapi.FullNode, epp gen.WinningPoStProver) (*miner.Miner, error) { + minerAddr, err := minerAddrFromDS(ds) + if err != nil { + return nil, err + } + + m := miner.NewMiner(api, epp, minerAddr) + + lc.Append(fx.Hook{ + OnStart: func(ctx context.Context) error { + if err := m.Start(ctx); err != nil { + return err + } + return nil + }, + OnStop: func(ctx context.Context) error { + return m.Stop(ctx) + }, + }) + + return m, nil +} + +func NewProviderRequestValidator(deals dtypes.ProviderDealStore) dtypes.ProviderRequestValidator { + return requestvalidation.NewUnifiedRequestValidator(deals, nil) +} + +func NewStorageAsk(ctx helpers.MetricsCtx, fapi lapi.FullNode, ds dtypes.MetadataDS, minerAddress dtypes.MinerAddress, spn storagemarket.StorageProviderNode) (*storedask.StoredAsk, error) { + + mi, err := fapi.StateMinerInfo(ctx, address.Address(minerAddress), types.EmptyTSK) + if err != nil { + return nil, err + } + + storedAsk, err := storedask.NewStoredAsk(namespace.Wrap(ds, datastore.NewKey("/deals/provider")), datastore.NewKey("latest-ask"), spn, address.Address(minerAddress)) + if err != nil { + return nil, err + } + // Hacky way to set max piece size to the sector size + a := storedAsk.GetAsk().Ask + err = storedAsk.SetAsk(a.Price, a.Expiry-a.Timestamp, storagemarket.MaxPieceSize(abi.PaddedPieceSize(mi.SectorSize))) + if err != nil { + return storedAsk, err + } + return storedAsk, nil +} + +func StorageProvider(minerAddress dtypes.MinerAddress, ffiConfig *ffiwrapper.Config, storedAsk *storedask.StoredAsk, h host.Host, ds dtypes.MetadataDS, ibs dtypes.StagingBlockstore, r repo.LockedRepo, pieceStore dtypes.ProviderPieceStore, dataTransfer dtypes.ProviderDataTransfer, spn storagemarket.StorageProviderNode, onlineOk dtypes.ConsiderOnlineStorageDealsConfigFunc, offlineOk dtypes.ConsiderOfflineStorageDealsConfigFunc, blocklistFunc dtypes.StorageDealPieceCidBlocklistConfigFunc) (storagemarket.StorageProvider, error) { + net := smnet.NewFromLibp2pHost(h) + store, err := piecefilestore.NewLocalFileStore(piecefilestore.OsPath(r.Path())) + if err != nil { + return nil, err + } + + opt := storageimpl.CustomDealDecisionLogic(func(ctx context.Context, deal storagemarket.MinerDeal) (bool, string, error) { + b, err := onlineOk() + if err != nil { + return false, "miner error", err + } + + if deal.Ref != nil && deal.Ref.TransferType != storagemarket.TTManual && !b { + log.Warnf("online storage deal consideration disabled; rejecting storage deal proposal from client: %s", deal.Client.String()) + return false, "miner is not considering online storage deals", nil + } + + b, err = offlineOk() + if err != nil { + return false, "miner error", err + } + + if deal.Ref != nil && deal.Ref.TransferType == storagemarket.TTManual && !b { + log.Warnf("offline storage deal consideration disabled; rejecting storage deal proposal from client: %s", deal.Client.String()) + return false, "miner is not accepting offline storage deals", nil + } + + blocklist, err := blocklistFunc() + if err != nil { + return false, "miner error", err + } + + for idx := range blocklist { + if deal.Proposal.PieceCID.Equals(blocklist[idx]) { + log.Warnf("piece CID in proposal %s is blocklisted; rejecting storage deal proposal from client: %s", deal.Proposal.PieceCID, deal.Client.String()) + return false, fmt.Sprintf("miner has blocklisted piece CID %s", deal.Proposal.PieceCID), nil + } + } + + return true, "", nil + }) + + p, err := storageimpl.NewProvider(net, namespace.Wrap(ds, datastore.NewKey("/deals/provider")), ibs, store, pieceStore, dataTransfer, spn, address.Address(minerAddress), ffiConfig.SealProofType, storedAsk, opt) + if err != nil { + return p, err + } + + return p, nil +} + +// RetrievalProvider creates a new retrieval provider attached to the provider blockstore +func RetrievalProvider(h host.Host, miner *storage.Miner, sealer sectorstorage.SectorManager, full lapi.FullNode, ds dtypes.MetadataDS, pieceStore dtypes.ProviderPieceStore, ibs dtypes.StagingBlockstore, onlineOk dtypes.ConsiderOnlineRetrievalDealsConfigFunc, offlineOk dtypes.ConsiderOfflineRetrievalDealsConfigFunc) (retrievalmarket.RetrievalProvider, error) { + adapter := retrievaladapter.NewRetrievalProviderNode(miner, sealer, full) + + maddr, err := minerAddrFromDS(ds) + if err != nil { + return nil, err + } + + netwk := rmnet.NewFromLibp2pHost(h) + + opt := retrievalimpl.DealDeciderOpt(func(ctx context.Context, state retrievalmarket.ProviderDealState) (bool, string, error) { + b, err := onlineOk() + if err != nil { + return false, "miner error", err + } + + if !b { + log.Warn("online retrieval deal consideration disabled; rejecting retrieval deal proposal from client") + return false, "miner is not accepting online retrieval deals", nil + } + + b, err = offlineOk() + if err != nil { + return false, "miner error", err + } + + if !b { + log.Info("offline retrieval has not been implemented yet") + } + + return true, "", nil + }) + + return retrievalimpl.NewProvider(maddr, adapter, netwk, pieceStore, ibs, namespace.Wrap(ds, datastore.NewKey("/retrievals/provider")), opt) +} + +func SectorStorage(mctx helpers.MetricsCtx, lc fx.Lifecycle, ls stores.LocalStorage, si stores.SectorIndex, cfg *ffiwrapper.Config, sc sectorstorage.SealerConfig, urls sectorstorage.URLs, sa sectorstorage.StorageAuth) (*sectorstorage.Manager, error) { + ctx := helpers.LifecycleCtx(mctx, lc) + + sst, err := sectorstorage.New(ctx, ls, si, cfg, sc, urls, sa) + if err != nil { + return nil, err + } + + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + if err := sst.Close(); err != nil { + log.Errorf("%+v", err) + } + + return nil + }, + }) + + return sst, nil +} + +func StorageAuth(ctx helpers.MetricsCtx, ca lapi.Common) (sectorstorage.StorageAuth, error) { + token, err := ca.AuthNew(ctx, []auth.Permission{"admin"}) + if err != nil { + return nil, xerrors.Errorf("creating storage auth header: %w", err) + } + + headers := http.Header{} + headers.Add("Authorization", "Bearer "+string(token)) + return sectorstorage.StorageAuth(headers), nil +} + +func NewConsiderOnlineStorageDealsConfigFunc(r repo.LockedRepo) (dtypes.ConsiderOnlineStorageDealsConfigFunc, error) { + return func() (out bool, err error) { + err = readCfg(r, func(cfg *config.StorageMiner) { + out = cfg.Dealmaking.ConsiderOnlineStorageDeals + }) + return + }, nil +} + +func NewSetConsideringOnlineStorageDealsFunc(r repo.LockedRepo) (dtypes.SetConsiderOnlineStorageDealsConfigFunc, error) { + return func(b bool) (err error) { + err = mutateCfg(r, func(cfg *config.StorageMiner) { + cfg.Dealmaking.ConsiderOnlineStorageDeals = b + }) + return + }, nil +} + +func NewConsiderOnlineRetrievalDealsConfigFunc(r repo.LockedRepo) (dtypes.ConsiderOnlineRetrievalDealsConfigFunc, error) { + return func() (out bool, err error) { + err = readCfg(r, func(cfg *config.StorageMiner) { + out = cfg.Dealmaking.ConsiderOnlineRetrievalDeals + }) + return + }, nil +} + +func NewSetConsiderOnlineRetrievalDealsConfigFunc(r repo.LockedRepo) (dtypes.SetConsiderOnlineRetrievalDealsConfigFunc, error) { + return func(b bool) (err error) { + err = mutateCfg(r, func(cfg *config.StorageMiner) { + cfg.Dealmaking.ConsiderOnlineRetrievalDeals = b + }) + return + }, nil +} + +func NewStorageDealPieceCidBlocklistConfigFunc(r repo.LockedRepo) (dtypes.StorageDealPieceCidBlocklistConfigFunc, error) { + return func() (out []cid.Cid, err error) { + err = readCfg(r, func(cfg *config.StorageMiner) { + out = cfg.Dealmaking.PieceCidBlocklist + }) + return + }, nil +} + +func NewSetStorageDealPieceCidBlocklistConfigFunc(r repo.LockedRepo) (dtypes.SetStorageDealPieceCidBlocklistConfigFunc, error) { + return func(blocklist []cid.Cid) (err error) { + err = mutateCfg(r, func(cfg *config.StorageMiner) { + cfg.Dealmaking.PieceCidBlocklist = blocklist + }) + return + }, nil +} + +func NewConsiderOfflineStorageDealsConfigFunc(r repo.LockedRepo) (dtypes.ConsiderOfflineStorageDealsConfigFunc, error) { + return func() (out bool, err error) { + err = readCfg(r, func(cfg *config.StorageMiner) { + out = cfg.Dealmaking.ConsiderOfflineStorageDeals + }) + return + }, nil +} + +func NewSetConsideringOfflineStorageDealsFunc(r repo.LockedRepo) (dtypes.SetConsiderOfflineStorageDealsConfigFunc, error) { + return func(b bool) (err error) { + err = mutateCfg(r, func(cfg *config.StorageMiner) { + cfg.Dealmaking.ConsiderOfflineStorageDeals = b + }) + return + }, nil +} + +func NewConsiderOfflineRetrievalDealsConfigFunc(r repo.LockedRepo) (dtypes.ConsiderOfflineRetrievalDealsConfigFunc, error) { + return func() (out bool, err error) { + err = readCfg(r, func(cfg *config.StorageMiner) { + out = cfg.Dealmaking.ConsiderOfflineRetrievalDeals + }) + return + }, nil +} + +func NewSetConsiderOfflineRetrievalDealsConfigFunc(r repo.LockedRepo) (dtypes.SetConsiderOfflineRetrievalDealsConfigFunc, error) { + return func(b bool) (err error) { + err = mutateCfg(r, func(cfg *config.StorageMiner) { + cfg.Dealmaking.ConsiderOfflineRetrievalDeals = b + }) + return + }, nil +} + +func readCfg(r repo.LockedRepo, accessor func(*config.StorageMiner)) error { + raw, err := r.Config() + if err != nil { + return err + } + + cfg, ok := raw.(*config.StorageMiner) + if !ok { + return xerrors.New("expected address of config.StorageMiner") + } + + accessor(cfg) + + return nil +} + +func mutateCfg(r repo.LockedRepo, mutator func(*config.StorageMiner)) error { + var typeErr error + + setConfigErr := r.SetConfig(func(raw interface{}) { + cfg, ok := raw.(*config.StorageMiner) + if !ok { + typeErr = errors.New("expected storage miner config") + return + } + + mutator(cfg) + }) + + return multierr.Combine(typeErr, setConfigErr) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/testing/beacon.go b/vendor/github.com/filecoin-project/lotus/node/modules/testing/beacon.go new file mode 100644 index 0000000000..a4ef822fca --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/testing/beacon.go @@ -0,0 +1,12 @@ +package testing + +import ( + "time" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/beacon" +) + +func RandomBeacon() (beacon.RandomBeacon, error) { + return beacon.NewMockBeacon(time.Duration(build.BlockDelaySecs) * time.Second), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/testing/genesis.go b/vendor/github.com/filecoin-project/lotus/node/modules/testing/genesis.go new file mode 100644 index 0000000000..930c11fc8e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/testing/genesis.go @@ -0,0 +1,106 @@ +package testing + +import ( + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "time" + + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-cid" + offline "github.com/ipfs/go-ipfs-exchange-offline" + logging "github.com/ipfs/go-log/v2" + "github.com/ipfs/go-merkledag" + "github.com/ipld/go-car" + "github.com/mitchellh/go-homedir" + "golang.org/x/xerrors" + + "github.com/filecoin-project/specs-actors/actors/runtime" + + "github.com/filecoin-project/lotus/chain/gen" + 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/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +var glog = logging.Logger("genesis") + +func MakeGenesisMem(out io.Writer, template genesis.Template) func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { + return func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { + return func() (*types.BlockHeader, error) { + glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network") + b, err := genesis2.MakeGenesisBlock(context.TODO(), bs, syscalls, template) + if err != nil { + return nil, xerrors.Errorf("make genesis block failed: %w", err) + } + offl := offline.Exchange(bs) + blkserv := blockservice.New(bs, offl) + dserv := merkledag.NewDAGService(blkserv) + + if err := car.WriteCarWithWalker(context.TODO(), dserv, []cid.Cid{b.Genesis.Cid()}, out, gen.CarWalkFunc); err != nil { + return nil, xerrors.Errorf("failed to write car file: %w", err) + } + + return b.Genesis, nil + } + } +} + +func MakeGenesis(outFile, genesisTemplate string) func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { + return func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { + return func() (*types.BlockHeader, error) { + glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network") + genesisTemplate, err := homedir.Expand(genesisTemplate) + if err != nil { + return nil, err + } + + fdata, err := ioutil.ReadFile(genesisTemplate) + if err != nil { + return nil, xerrors.Errorf("reading preseals json: %w", err) + } + + var template genesis.Template + if err := json.Unmarshal(fdata, &template); err != nil { + return nil, err + } + + if template.Timestamp == 0 { + template.Timestamp = uint64(time.Now().Unix()) + } + + b, err := genesis2.MakeGenesisBlock(context.TODO(), bs, syscalls, template) + if err != nil { + return nil, xerrors.Errorf("make genesis block: %w", err) + } + + fmt.Printf("GENESIS MINER ADDRESS: t0%d\n", genesis2.MinerStart) + + f, err := os.OpenFile(outFile, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nil, err + } + + offl := offline.Exchange(bs) + blkserv := blockservice.New(bs, offl) + dserv := merkledag.NewDAGService(blkserv) + + if err := car.WriteCarWithWalker(context.TODO(), dserv, []cid.Cid{b.Genesis.Cid()}, f, gen.CarWalkFunc); err != nil { + return nil, err + } + + glog.Warnf("WRITING GENESIS FILE AT %s", f.Name()) + + if err := f.Close(); err != nil { + return nil, err + } + + return b.Genesis, nil + } + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/modules/testing/storage.go b/vendor/github.com/filecoin-project/lotus/node/modules/testing/storage.go new file mode 100644 index 0000000000..525d86b069 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/modules/testing/storage.go @@ -0,0 +1,39 @@ +package testing + +import ( + "context" + + "github.com/ipfs/go-blockservice" + "github.com/ipfs/go-datastore" + dsync "github.com/ipfs/go-datastore/sync" + blockstore "github.com/ipfs/go-ipfs-blockstore" + offline "github.com/ipfs/go-ipfs-exchange-offline" + ipld "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-merkledag" + "go.uber.org/fx" +) + +func MapBlockstore() blockstore.Blockstore { + // TODO: proper datastore + bds := dsync.MutexWrap(datastore.NewMapDatastore()) + bs := blockstore.NewBlockstore(bds) + return blockstore.NewIdStore(bs) +} + +func MapDatastore() datastore.Batching { + return dsync.MutexWrap(datastore.NewMapDatastore()) +} + +func MemoryClientDag(lc fx.Lifecycle) ipld.DAGService { + ibs := blockstore.NewBlockstore(datastore.NewMapDatastore()) + bsvc := blockservice.New(ibs, offline.Exchange(ibs)) + dag := merkledag.NewDAGService(bsvc) + + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return bsvc.Close() + }, + }) + + return dag +} diff --git a/vendor/github.com/filecoin-project/lotus/node/node_test.go b/vendor/github.com/filecoin-project/lotus/node/node_test.go new file mode 100644 index 0000000000..dea886989e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/node_test.go @@ -0,0 +1,532 @@ +package node_test + +import ( + "bytes" + "context" + "crypto/rand" + "io/ioutil" + "net/http/httptest" + "os" + "testing" + "time" + + "github.com/filecoin-project/lotus/lib/lotuslog" + "github.com/filecoin-project/lotus/storage/mockstorage" + "github.com/filecoin-project/sector-storage/ffiwrapper" + + "github.com/filecoin-project/go-storedcounter" + "github.com/ipfs/go-datastore" + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/api/test" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" + genesis "github.com/filecoin-project/lotus/genesis" + "github.com/filecoin-project/lotus/miner" + "github.com/filecoin-project/lotus/node" + "github.com/filecoin-project/lotus/node/modules" + modtest "github.com/filecoin-project/lotus/node/modules/testing" + "github.com/filecoin-project/lotus/node/repo" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/sector-storage/mock" +) + +func init() { + _ = logging.SetLogLevel("*", "INFO") + + power.ConsensusMinerMinPower = big.NewInt(2048) + saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ + abi.RegisteredSealProof_StackedDrg2KiBV1: {}, + } + verifreg.MinVerifiedDealSize = big.NewInt(256) +} + +func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, act address.Address, pk crypto.PrivKey, tnd test.TestNode, mn mocknet.Mocknet, opts node.Option) test.TestStorageNode { + r := repo.NewMemory(nil) + + lr, err := r.Lock(repo.StorageMiner) + require.NoError(t, err) + + ks, err := lr.KeyStore() + require.NoError(t, err) + + kbytes, err := pk.Bytes() + require.NoError(t, err) + + err = ks.Put("libp2p-host", types.KeyInfo{ + Type: "libp2p-host", + PrivateKey: kbytes, + }) + require.NoError(t, err) + + ds, err := lr.Datastore("/metadata") + require.NoError(t, err) + err = ds.Put(datastore.NewKey("miner-address"), act.Bytes()) + require.NoError(t, err) + + nic := storedcounter.New(ds, datastore.NewKey(modules.StorageCounterDSPrefix)) + for i := 0; i < test.GenesisPreseals; i++ { + _, err := nic.Next() + require.NoError(t, err) + } + _, err = nic.Next() + require.NoError(t, err) + + err = lr.Close() + require.NoError(t, err) + + peerid, err := peer.IDFromPrivateKey(pk) + require.NoError(t, err) + + enc, err := actors.SerializeParams(&saminer.ChangePeerIDParams{NewID: abi.PeerID(peerid)}) + require.NoError(t, err) + + msg := &types.Message{ + To: act, + From: waddr, + Method: builtin.MethodsMiner.ChangePeerID, + Params: enc, + Value: types.NewInt(0), + GasPrice: types.NewInt(0), + GasLimit: 1000000, + } + + _, err = tnd.MpoolPushMessage(ctx, msg) + require.NoError(t, err) + + // start node + var minerapi api.StorageMiner + + mineBlock := make(chan func(bool, error)) + // TODO: use stop + _, err = node.New(ctx, + node.StorageMiner(&minerapi), + node.Online(), + node.Repo(r), + node.Test(), + + node.MockHost(mn), + + node.Override(new(api.FullNode), tnd), + node.Override(new(*miner.Miner), miner.NewTestMiner(mineBlock, act)), + + opts, + ) + if err != nil { + t.Fatalf("failed to construct node: %v", err) + } + + /*// Bootstrap with full node + remoteAddrs, err := tnd.NetAddrsListen(ctx) + require.NoError(t, err) + + err = minerapi.NetConnect(ctx, remoteAddrs) + require.NoError(t, err)*/ + mineOne := func(ctx context.Context, cb func(bool, error)) error { + select { + case mineBlock <- cb: + return nil + case <-ctx.Done(): + return ctx.Err() + } + } + + return test.TestStorageNode{StorageMiner: minerapi, MineOne: mineOne} +} + +func builder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { + ctx := context.Background() + mn := mocknet.New(ctx) + + fulls := make([]test.TestNode, nFull) + storers := make([]test.TestStorageNode, len(storage)) + + pk, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + minerPid, err := peer.IDFromPrivateKey(pk) + require.NoError(t, err) + + var genbuf bytes.Buffer + + if len(storage) > 1 { + panic("need more peer IDs") + } + // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE + // TODO: would be great if there was a better way to fake the preseals + + var genms []genesis.Miner + var maddrs []address.Address + var genaccs []genesis.Actor + var keys []*wallet.Key + + var presealDirs []string + for i := 0; i < len(storage); i++ { + maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i)) + if err != nil { + t.Fatal(err) + } + tdir, err := ioutil.TempDir("", "preseal-memgen") + if err != nil { + t.Fatal(err) + } + genm, k, err := seed.PreSeal(maddr, abi.RegisteredSealProof_StackedDrg2KiBV1, 0, test.GenesisPreseals, tdir, []byte("make genesis mem random"), nil, true) + if err != nil { + t.Fatal(err) + } + genm.PeerId = minerPid + + wk, err := wallet.NewKey(*k) + if err != nil { + return nil, nil + } + + genaccs = append(genaccs, genesis.Actor{ + Type: genesis.TAccount, + Balance: big.Mul(big.NewInt(50000), types.NewInt(build.FilecoinPrecision)), + Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(), + }) + + keys = append(keys, wk) + presealDirs = append(presealDirs, tdir) + maddrs = append(maddrs, maddr) + genms = append(genms, *genm) + } + + templ := &genesis.Template{ + Accounts: genaccs, + Miners: genms, + Timestamp: uint64(time.Now().Unix() - 10000), // some time sufficiently far in the past + } + + // END PRESEAL SECTION + + for i := 0; i < nFull; i++ { + var genesis node.Option + if i == 0 { + genesis = node.Override(new(modules.Genesis), modtest.MakeGenesisMem(&genbuf, *templ)) + } else { + genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genbuf.Bytes())) + } + + var err error + // TODO: Don't ignore stop + _, err = node.New(ctx, + node.FullAPI(&fulls[i].FullNode), + node.Online(), + node.Repo(repo.NewMemory(nil)), + node.MockHost(mn), + node.Test(), + + genesis, + ) + if err != nil { + t.Fatal(err) + } + + } + + for i, def := range storage { + // TODO: support non-bootstrap miners + if i != 0 { + t.Fatal("only one storage node supported") + } + if def.Full != 0 { + t.Fatal("storage nodes only supported on the first full node") + } + + f := fulls[def.Full] + if _, err := f.FullNode.WalletImport(ctx, &keys[i].KeyInfo); err != nil { + t.Fatal(err) + } + if err := f.FullNode.WalletSetDefault(ctx, keys[i].Address); err != nil { + t.Fatal(err) + } + + genMiner := maddrs[i] + wa := genms[i].Worker + + storers[i] = testStorageNode(ctx, t, wa, genMiner, pk, f, mn, node.Options()) + if err := storers[i].StorageAddLocal(ctx, presealDirs[i]); err != nil { + t.Fatalf("%+v", err) + } + /* + sma := storers[i].StorageMiner.(*impl.StorageMinerAPI) + + psd := presealDirs[i] + */ + } + + if err := mn.LinkAll(); err != nil { + t.Fatal(err) + } + + return fulls, storers +} + +func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { + ctx := context.Background() + mn := mocknet.New(ctx) + + fulls := make([]test.TestNode, nFull) + storers := make([]test.TestStorageNode, len(storage)) + + var genbuf bytes.Buffer + + // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE + // TODO: would be great if there was a better way to fake the preseals + + var genms []genesis.Miner + var genaccs []genesis.Actor + var maddrs []address.Address + var presealDirs []string + var keys []*wallet.Key + var pidKeys []crypto.PrivKey + for i := 0; i < len(storage); i++ { + maddr, err := address.NewIDAddress(genesis2.MinerStart + uint64(i)) + if err != nil { + t.Fatal(err) + } + tdir, err := ioutil.TempDir("", "preseal-memgen") + if err != nil { + t.Fatal(err) + } + + preseals := storage[i].Preseal + if preseals == test.PresealGenesis { + preseals = test.GenesisPreseals + } + + genm, k, err := mockstorage.PreSeal(2048, maddr, preseals) + if err != nil { + t.Fatal(err) + } + + pk, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + minerPid, err := peer.IDFromPrivateKey(pk) + require.NoError(t, err) + + genm.PeerId = minerPid + + wk, err := wallet.NewKey(*k) + if err != nil { + return nil, nil + } + + genaccs = append(genaccs, genesis.Actor{ + Type: genesis.TAccount, + Balance: big.Mul(big.NewInt(50000), types.NewInt(build.FilecoinPrecision)), + Meta: (&genesis.AccountMeta{Owner: wk.Address}).ActorMeta(), + }) + + keys = append(keys, wk) + pidKeys = append(pidKeys, pk) + presealDirs = append(presealDirs, tdir) + maddrs = append(maddrs, maddr) + genms = append(genms, *genm) + } + templ := &genesis.Template{ + Accounts: genaccs, + Miners: genms, + Timestamp: uint64(time.Now().Unix()) - (build.BlockDelaySecs * 20000), + } + + // END PRESEAL SECTION + + for i := 0; i < nFull; i++ { + var genesis node.Option + if i == 0 { + genesis = node.Override(new(modules.Genesis), modtest.MakeGenesisMem(&genbuf, *templ)) + } else { + genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genbuf.Bytes())) + } + + var err error + // TODO: Don't ignore stop + _, err = node.New(ctx, + node.FullAPI(&fulls[i].FullNode), + node.Online(), + node.Repo(repo.NewMemory(nil)), + node.MockHost(mn), + node.Test(), + + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + + genesis, + ) + if err != nil { + t.Fatalf("%+v", err) + } + } + + for i, def := range storage { + // TODO: support non-bootstrap miners + if def.Full != 0 { + t.Fatal("storage nodes only supported on the first full node") + } + + f := fulls[def.Full] + if _, err := f.FullNode.WalletImport(ctx, &keys[i].KeyInfo); err != nil { + return nil, nil + } + if err := f.FullNode.WalletSetDefault(ctx, keys[i].Address); err != nil { + return nil, nil + } + + storers[i] = testStorageNode(ctx, t, genms[i].Worker, maddrs[i], pidKeys[i], f, mn, node.Options( + node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { + return mock.NewMockSectorMgr(build.DefaultSectorSize()), nil + }), + node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Unset(new(*sectorstorage.Manager)), + )) + } + + if err := mn.LinkAll(); err != nil { + t.Fatal(err) + } + + return fulls, storers +} + +func TestAPI(t *testing.T) { + test.TestApis(t, builder) +} + +func rpcBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) { + fullApis, storaApis := builder(t, nFull, storage) + fulls := make([]test.TestNode, nFull) + storers := make([]test.TestStorageNode, len(storage)) + + for i, a := range fullApis { + rpcServer := jsonrpc.NewServer() + rpcServer.Register("Filecoin", a) + testServ := httptest.NewServer(rpcServer) // todo: close + + var err error + fulls[i].FullNode, _, err = client.NewFullNodeRPC("ws://"+testServ.Listener.Addr().String(), nil) + if err != nil { + t.Fatal(err) + } + } + + for i, a := range storaApis { + rpcServer := jsonrpc.NewServer() + rpcServer.Register("Filecoin", a) + testServ := httptest.NewServer(rpcServer) // todo: close + + var err error + storers[i].StorageMiner, _, err = client.NewStorageMinerRPC("ws://"+testServ.Listener.Addr().String(), nil) + if err != nil { + t.Fatal(err) + } + storers[i].MineOne = a.MineOne + } + + return fulls, storers +} + +func TestAPIRPC(t *testing.T) { + test.TestApis(t, rpcBuilder) +} + +func TestAPIDealFlow(t *testing.T) { + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + t.Run("TestDealFlow", func(t *testing.T) { + test.TestDealFlow(t, mockSbBuilder, 10*time.Millisecond, false) + }) + t.Run("WithExportedCAR", func(t *testing.T) { + test.TestDealFlow(t, mockSbBuilder, 10*time.Millisecond, true) + }) + t.Run("TestDoubleDealFlow", func(t *testing.T) { + test.TestDoubleDealFlow(t, mockSbBuilder, 10*time.Millisecond) + }) +} + +func TestAPIDealFlowReal(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode") + } + lotuslog.SetupLogLevels() + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + test.TestDealFlow(t, builder, time.Second, false) +} + +func TestDealMining(t *testing.T) { + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + test.TestDealMining(t, mockSbBuilder, 50*time.Millisecond, false) +} + +func TestPledgeSectors(t *testing.T) { + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + t.Run("1", func(t *testing.T) { + test.TestPledgeSector(t, mockSbBuilder, 50*time.Millisecond, 1) + }) + + t.Run("100", func(t *testing.T) { + test.TestPledgeSector(t, mockSbBuilder, 50*time.Millisecond, 100) + }) + + t.Run("1000", func(t *testing.T) { + if testing.Short() { // takes ~16s + t.Skip("skipping test in short mode") + } + + test.TestPledgeSector(t, mockSbBuilder, 50*time.Millisecond, 1000) + }) +} + +func TestWindowedPost(t *testing.T) { + if os.Getenv("LOTUS_TEST_WINDOW_POST") != "1" { + t.Skip("this takes a few minutes, set LOTUS_TEST_WINDOW_POST=1 to run") + } + + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + test.TestWindowPost(t, mockSbBuilder, 5*time.Millisecond, 10) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/options.go b/vendor/github.com/filecoin-project/lotus/node/options.go new file mode 100644 index 0000000000..c92e209be8 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/options.go @@ -0,0 +1,156 @@ +package node + +import ( + "reflect" + + "go.uber.org/fx" +) + +// Option is a functional option which can be used with the New function to +// change how the node is constructed +// +// Options are applied in sequence +type Option func(*Settings) error + +// Options groups multiple options into one +func Options(opts ...Option) Option { + return func(s *Settings) error { + for _, opt := range opts { + if err := opt(s); err != nil { + return err + } + } + return nil + } +} + +// Error is a special option which returns an error when applied +func Error(err error) Option { + return func(_ *Settings) error { + return err + } +} + +func ApplyIf(check func(s *Settings) bool, opts ...Option) Option { + return func(s *Settings) error { + if check(s) { + return Options(opts...)(s) + } + return nil + } +} + +func If(b bool, opts ...Option) Option { + return ApplyIf(func(s *Settings) bool { + return b + }, opts...) +} + +// Override option changes constructor for a given type +func Override(typ, constructor interface{}) Option { + return func(s *Settings) error { + if i, ok := typ.(invoke); ok { + s.invokes[i] = fx.Invoke(constructor) + return nil + } + + if c, ok := typ.(special); ok { + s.modules[c] = fx.Provide(constructor) + return nil + } + ctor := as(constructor, typ) + rt := reflect.TypeOf(typ).Elem() + + s.modules[rt] = fx.Provide(ctor) + return nil + } +} + +func Unset(typ interface{}) Option { + return func(s *Settings) error { + if i, ok := typ.(invoke); ok { + s.invokes[i] = nil + return nil + } + + if c, ok := typ.(special); ok { + delete(s.modules, c) + return nil + } + rt := reflect.TypeOf(typ).Elem() + + delete(s.modules, rt) + return nil + } +} + +// From(*T) -> func(t T) T {return t} +func From(typ interface{}) interface{} { + rt := []reflect.Type{reflect.TypeOf(typ).Elem()} + ft := reflect.FuncOf(rt, rt, false) + return reflect.MakeFunc(ft, func(args []reflect.Value) (results []reflect.Value) { + return args + }).Interface() +} + +// from go-ipfs +// as casts input constructor to a given interface (if a value is given, it +// wraps it into a constructor). +// +// Note: this method may look like a hack, and in fact it is one. +// This is here only because https://github.com/uber-go/fx/issues/673 wasn't +// released yet +// +// Note 2: when making changes here, make sure this method stays at +// 100% coverage. This makes it less likely it will be terribly broken +func as(in interface{}, as interface{}) interface{} { + outType := reflect.TypeOf(as) + + if outType.Kind() != reflect.Ptr { + panic("outType is not a pointer") + } + + if reflect.TypeOf(in).Kind() != reflect.Func { + ctype := reflect.FuncOf(nil, []reflect.Type{outType.Elem()}, false) + + return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) { + out := reflect.New(outType.Elem()) + out.Elem().Set(reflect.ValueOf(in)) + + return []reflect.Value{out.Elem()} + }).Interface() + } + + inType := reflect.TypeOf(in) + + ins := make([]reflect.Type, inType.NumIn()) + outs := make([]reflect.Type, inType.NumOut()) + + for i := range ins { + ins[i] = inType.In(i) + } + outs[0] = outType.Elem() + for i := range outs[1:] { + outs[i+1] = inType.Out(i + 1) + } + + ctype := reflect.FuncOf(ins, outs, false) + + return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) { + outs := reflect.ValueOf(in).Call(args) + + out := reflect.New(outType.Elem()) + if outs[0].Type().AssignableTo(outType.Elem()) { + // Out: Iface = In: *Struct; Out: Iface = In: OtherIface + out.Elem().Set(outs[0]) + } else { + // Out: Iface = &(In: Struct) + t := reflect.New(outs[0].Type()) + t.Elem().Set(outs[0]) + out.Elem().Set(t) + } + outs[0] = out.Elem() + + return outs + }).Interface() +} diff --git a/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo.go b/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo.go new file mode 100644 index 0000000000..b223731d9f --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo.go @@ -0,0 +1,488 @@ +package repo + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/BurntSushi/toml" + "github.com/ipfs/go-datastore" + fslock "github.com/ipfs/go-fs-lock" + logging "github.com/ipfs/go-log/v2" + "github.com/mitchellh/go-homedir" + "github.com/multiformats/go-base32" + "github.com/multiformats/go-multiaddr" + "golang.org/x/xerrors" + + "github.com/filecoin-project/sector-storage/stores" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/config" +) + +const ( + fsAPI = "api" + fsAPIToken = "token" + fsConfig = "config.toml" + fsStorageConfig = "storage.json" + fsDatastore = "datastore" + fsLock = "repo.lock" + fsKeystore = "keystore" +) + +type RepoType int + +const ( + _ = iota // Default is invalid + FullNode RepoType = iota + StorageMiner + Worker +) + +func defConfForType(t RepoType) interface{} { + switch t { + case FullNode: + return config.DefaultFullNode() + case StorageMiner: + return config.DefaultStorageMiner() + case Worker: + return &struct{}{} + default: + panic(fmt.Sprintf("unknown RepoType(%d)", int(t))) + } +} + +var log = logging.Logger("repo") + +var ErrRepoExists = xerrors.New("repo exists") + +// FsRepo is struct for repo, use NewFS to create +type FsRepo struct { + path string +} + +var _ Repo = &FsRepo{} + +// NewFS creates a repo instance based on a path on file system +func NewFS(path string) (*FsRepo, error) { + path, err := homedir.Expand(path) + if err != nil { + return nil, err + } + + return &FsRepo{ + path: path, + }, nil +} + +func (fsr *FsRepo) Exists() (bool, error) { + _, err := os.Stat(filepath.Join(fsr.path, fsDatastore)) + notexist := os.IsNotExist(err) + if notexist { + err = nil + } + return !notexist, err +} + +func (fsr *FsRepo) Init(t RepoType) error { + exist, err := fsr.Exists() + if err != nil { + return err + } + if exist { + return nil + } + + log.Infof("Initializing repo at '%s'", fsr.path) + err = os.Mkdir(fsr.path, 0755) //nolint: gosec + if err != nil && !os.IsExist(err) { + return err + } + + if err := fsr.initConfig(t); err != nil { + return xerrors.Errorf("init config: %w", err) + } + + return fsr.initKeystore() + +} + +func (fsr *FsRepo) initConfig(t RepoType) error { + cfgP := filepath.Join(fsr.path, fsConfig) + + _, err := os.Stat(cfgP) + if err == nil { + // exists + return nil + } else if !os.IsNotExist(err) { + return err + } + + c, err := os.Create(cfgP) + if err != nil { + return err + } + + comm, err := config.ConfigComment(defConfForType(t)) + if err != nil { + return xerrors.Errorf("comment: %w", err) + } + _, err = c.Write(comm) + if err != nil { + return xerrors.Errorf("write config: %w", err) + } + + if err := c.Close(); err != nil { + return xerrors.Errorf("close config: %w", err) + } + return nil +} + +func (fsr *FsRepo) initKeystore() error { + kstorePath := filepath.Join(fsr.path, fsKeystore) + if _, err := os.Stat(kstorePath); err == nil { + return ErrRepoExists + } else if !os.IsNotExist(err) { + return err + } + return os.Mkdir(kstorePath, 0700) +} + +// APIEndpoint returns endpoint of API in this repo +func (fsr *FsRepo) APIEndpoint() (multiaddr.Multiaddr, error) { + p := filepath.Join(fsr.path, fsAPI) + + f, err := os.Open(p) + if os.IsNotExist(err) { + return nil, ErrNoAPIEndpoint + } else if err != nil { + return nil, err + } + defer f.Close() //nolint: errcheck // Read only op + + data, err := ioutil.ReadAll(f) + if err != nil { + return nil, xerrors.Errorf("failed to read %q: %w", p, err) + } + strma := string(data) + strma = strings.TrimSpace(strma) + + apima, err := multiaddr.NewMultiaddr(strma) + if err != nil { + return nil, err + } + return apima, nil +} + +func (fsr *FsRepo) APIToken() ([]byte, error) { + p := filepath.Join(fsr.path, fsAPIToken) + f, err := os.Open(p) + + if os.IsNotExist(err) { + return nil, ErrNoAPIEndpoint + } else if err != nil { + return nil, err + } + defer f.Close() //nolint: errcheck // Read only op + + tb, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + + return bytes.TrimSpace(tb), nil +} + +// Lock acquires exclusive lock on this repo +func (fsr *FsRepo) Lock(repoType RepoType) (LockedRepo, error) { + locked, err := fslock.Locked(fsr.path, fsLock) + if err != nil { + return nil, xerrors.Errorf("could not check lock status: %w", err) + } + if locked { + return nil, ErrRepoAlreadyLocked + } + + closer, err := fslock.Lock(fsr.path, fsLock) + if err != nil { + return nil, xerrors.Errorf("could not lock the repo: %w", err) + } + return &fsLockedRepo{ + path: fsr.path, + repoType: repoType, + closer: closer, + }, nil +} + +type fsLockedRepo struct { + path string + repoType RepoType + closer io.Closer + + ds datastore.Batching + dsErr error + dsOnce sync.Once + + storageLk sync.Mutex + configLk sync.Mutex +} + +func (fsr *fsLockedRepo) Path() string { + return fsr.path +} + +func (fsr *fsLockedRepo) Close() error { + err := os.Remove(fsr.join(fsAPI)) + + if err != nil && !os.IsNotExist(err) { + return xerrors.Errorf("could not remove API file: %w", err) + } + if fsr.ds != nil { + if err := fsr.ds.Close(); err != nil { + return xerrors.Errorf("could not close datastore: %w", err) + } + } + + err = fsr.closer.Close() + fsr.closer = nil + return err +} + +// join joins path elements with fsr.path +func (fsr *fsLockedRepo) join(paths ...string) string { + return filepath.Join(append([]string{fsr.path}, paths...)...) +} + +func (fsr *fsLockedRepo) stillValid() error { + if fsr.closer == nil { + return ErrClosedRepo + } + return nil +} + +func (fsr *fsLockedRepo) Config() (interface{}, error) { + fsr.configLk.Lock() + defer fsr.configLk.Unlock() + + return fsr.loadConfigFromDisk() +} + +func (fsr *fsLockedRepo) loadConfigFromDisk() (interface{}, error) { + return config.FromFile(fsr.join(fsConfig), defConfForType(fsr.repoType)) +} + +func (fsr *fsLockedRepo) SetConfig(c func(interface{})) error { + if err := fsr.stillValid(); err != nil { + return err + } + + fsr.configLk.Lock() + defer fsr.configLk.Unlock() + + cfg, err := fsr.loadConfigFromDisk() + if err != nil { + return err + } + + // mutate in-memory representation of config + c(cfg) + + // buffer into which we write TOML bytes + buf := new(bytes.Buffer) + + // encode now-mutated config as TOML and write to buffer + err = toml.NewEncoder(buf).Encode(cfg) + if err != nil { + return err + } + + // write buffer of TOML bytes to config file + err = ioutil.WriteFile(fsr.join(fsConfig), buf.Bytes(), 0644) + if err != nil { + return err + } + + return nil +} + +func (fsr *fsLockedRepo) GetStorage() (stores.StorageConfig, error) { + fsr.storageLk.Lock() + defer fsr.storageLk.Unlock() + + return fsr.getStorage(nil) +} + +func (fsr *fsLockedRepo) getStorage(def *stores.StorageConfig) (stores.StorageConfig, error) { + c, err := config.StorageFromFile(fsr.join(fsStorageConfig), def) + if err != nil { + return stores.StorageConfig{}, err + } + return *c, nil +} + +func (fsr *fsLockedRepo) SetStorage(c func(*stores.StorageConfig)) error { + fsr.storageLk.Lock() + defer fsr.storageLk.Unlock() + + sc, err := fsr.getStorage(&stores.StorageConfig{}) + if err != nil { + return xerrors.Errorf("get storage: %w", err) + } + + c(&sc) + + return config.WriteStorageFile(fsr.join(fsStorageConfig), sc) +} + +func (fsr *fsLockedRepo) Stat(path string) (stores.FsStat, error) { + return stores.Stat(path) +} + +func (fsr *fsLockedRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error { + if err := fsr.stillValid(); err != nil { + return err + } + return ioutil.WriteFile(fsr.join(fsAPI), []byte(ma.String()), 0644) +} + +func (fsr *fsLockedRepo) SetAPIToken(token []byte) error { + if err := fsr.stillValid(); err != nil { + return err + } + return ioutil.WriteFile(fsr.join(fsAPIToken), token, 0600) +} + +func (fsr *fsLockedRepo) KeyStore() (types.KeyStore, error) { + if err := fsr.stillValid(); err != nil { + return nil, err + } + return fsr, nil +} + +var kstrPermissionMsg = "permissions of key: '%s' are too relaxed, " + + "required: 0600, got: %#o" + +// List lists all the keys stored in the KeyStore +func (fsr *fsLockedRepo) List() ([]string, error) { + if err := fsr.stillValid(); err != nil { + return nil, err + } + + kstorePath := fsr.join(fsKeystore) + dir, err := os.Open(kstorePath) + if err != nil { + return nil, xerrors.Errorf("opening dir to list keystore: %w", err) + } + files, err := dir.Readdir(-1) + if err != nil { + return nil, xerrors.Errorf("reading keystore dir: %w", err) + } + keys := make([]string, 0, len(files)) + for _, f := range files { + if f.Mode()&0077 != 0 { + return nil, xerrors.Errorf(kstrPermissionMsg, f.Name(), f.Mode()) + } + name, err := base32.RawStdEncoding.DecodeString(f.Name()) + if err != nil { + return nil, xerrors.Errorf("decoding key: '%s': %w", f.Name(), err) + } + keys = append(keys, string(name)) + } + return keys, nil +} + +// Get gets a key out of keystore and returns types.KeyInfo coresponding to named key +func (fsr *fsLockedRepo) Get(name string) (types.KeyInfo, error) { + if err := fsr.stillValid(); err != nil { + return types.KeyInfo{}, err + } + + encName := base32.RawStdEncoding.EncodeToString([]byte(name)) + keyPath := fsr.join(fsKeystore, encName) + + fstat, err := os.Stat(keyPath) + if os.IsNotExist(err) { + return types.KeyInfo{}, xerrors.Errorf("opening key '%s': %w", name, types.ErrKeyInfoNotFound) + } else if err != nil { + return types.KeyInfo{}, xerrors.Errorf("opening key '%s': %w", name, err) + } + + if fstat.Mode()&0077 != 0 { + return types.KeyInfo{}, xerrors.Errorf(kstrPermissionMsg, name, fstat.Mode()) + } + + file, err := os.Open(keyPath) + if err != nil { + return types.KeyInfo{}, xerrors.Errorf("opening key '%s': %w", name, err) + } + defer file.Close() //nolint: errcheck // read only op + + data, err := ioutil.ReadAll(file) + if err != nil { + return types.KeyInfo{}, xerrors.Errorf("reading key '%s': %w", name, err) + } + + var res types.KeyInfo + err = json.Unmarshal(data, &res) + if err != nil { + return types.KeyInfo{}, xerrors.Errorf("decoding key '%s': %w", name, err) + } + + return res, nil +} + +// Put saves key info under given name +func (fsr *fsLockedRepo) Put(name string, info types.KeyInfo) error { + if err := fsr.stillValid(); err != nil { + return err + } + + encName := base32.RawStdEncoding.EncodeToString([]byte(name)) + keyPath := fsr.join(fsKeystore, encName) + + _, err := os.Stat(keyPath) + if err == nil { + return xerrors.Errorf("checking key before put '%s': %w", name, types.ErrKeyExists) + } else if !os.IsNotExist(err) { + return xerrors.Errorf("checking key before put '%s': %w", name, err) + } + + keyData, err := json.Marshal(info) + if err != nil { + return xerrors.Errorf("encoding key '%s': %w", name, err) + } + + err = ioutil.WriteFile(keyPath, keyData, 0600) + if err != nil { + return xerrors.Errorf("writing key '%s': %w", name, err) + } + return nil +} + +func (fsr *fsLockedRepo) Delete(name string) error { + if err := fsr.stillValid(); err != nil { + return err + } + + encName := base32.RawStdEncoding.EncodeToString([]byte(name)) + keyPath := fsr.join(fsKeystore, encName) + + _, err := os.Stat(keyPath) + if os.IsNotExist(err) { + return xerrors.Errorf("checking key before delete '%s': %w", name, types.ErrKeyInfoNotFound) + } else if err != nil { + return xerrors.Errorf("checking key before delete '%s': %w", name, err) + } + + err = os.Remove(keyPath) + if err != nil { + return xerrors.Errorf("deleting key '%s': %w", name, err) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_ds.go b/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_ds.go new file mode 100644 index 0000000000..034635c4fc --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_ds.go @@ -0,0 +1,74 @@ +package repo + +import ( + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/mount" + "github.com/ipfs/go-datastore/namespace" + "golang.org/x/xerrors" + "os" + "path/filepath" + + badger "github.com/ipfs/go-ds-badger2" + levelds "github.com/ipfs/go-ds-leveldb" + "github.com/ipfs/go-ds-measure" + ldbopts "github.com/syndtr/goleveldb/leveldb/opt" +) + +var fsDatastores = map[string]func(path string) (datastore.Batching, error){ + "chain": badgerDs, + "metadata": levelDs, + + // Those need to be fast for large writes... but also need a really good GC :c + "staging": badgerDs, // miner specific + "client": badgerDs, // client specific +} + +func badgerDs(path string) (datastore.Batching, error) { + opts := badger.DefaultOptions + opts.Truncate = true + + return badger.NewDatastore(path, &opts) +} + +func levelDs(path string) (datastore.Batching, error) { + return levelds.NewDatastore(path, &levelds.Options{ + Compression: ldbopts.NoCompression, + }) +} + +func (fsr *fsLockedRepo) openDatastore() (datastore.Batching, error) { + if err := os.MkdirAll(fsr.join(fsDatastore), 0755); err != nil { + return nil, xerrors.Errorf("mkdir %s: %w", fsr.join(fsDatastore), err) + } + + var mounts []mount.Mount + + for p, ctor := range fsDatastores { + prefix := datastore.NewKey(p) + + // TODO: optimization: don't init datastores we don't need + ds, err := ctor(fsr.join(filepath.Join(fsDatastore, p))) + if err != nil { + return nil, xerrors.Errorf("opening datastore %s: %w", prefix, err) + } + + ds = measure.New("fsrepo."+p, ds) + + mounts = append(mounts, mount.Mount{ + Prefix: prefix, + Datastore: ds, + }) + } + + return mount.New(mounts), nil +} + +func (fsr *fsLockedRepo) Datastore(ns string) (datastore.Batching, error) { + fsr.dsOnce.Do(func() { + fsr.ds, fsr.dsErr = fsr.openDatastore() + }) + if fsr.dsErr != nil { + return nil, fsr.dsErr + } + return namespace.Wrap(fsr.ds, datastore.NewKey(ns)), nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_test.go b/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_test.go new file mode 100644 index 0000000000..bd03cc084e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/repo/fsrepo_test.go @@ -0,0 +1,33 @@ +package repo + +import ( + "io/ioutil" + "os" + "testing" +) + +func genFsRepo(t *testing.T) (*FsRepo, func()) { + path, err := ioutil.TempDir("", "lotus-repo-") + if err != nil { + t.Fatal(err) + } + + repo, err := NewFS(path) + if err != nil { + t.Fatal(err) + } + + err = repo.Init(FullNode) + if err != ErrRepoExists && err != nil { + t.Fatal(err) + } + return repo, func() { + _ = os.RemoveAll(path) + } +} + +func TestFsBasic(t *testing.T) { + repo, closer := genFsRepo(t) + defer closer() + basicTest(t, repo) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/repo/interface.go b/vendor/github.com/filecoin-project/lotus/node/repo/interface.go new file mode 100644 index 0000000000..5950f813fb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/repo/interface.go @@ -0,0 +1,59 @@ +package repo + +import ( + "errors" + + "github.com/filecoin-project/sector-storage/stores" + + "github.com/ipfs/go-datastore" + "github.com/multiformats/go-multiaddr" + + "github.com/filecoin-project/lotus/chain/types" +) + +var ( + ErrNoAPIEndpoint = errors.New("API not running (no endpoint)") + ErrNoAPIToken = errors.New("API token not set") + ErrRepoAlreadyLocked = errors.New("repo is already locked (lotus daemon already running)") + ErrClosedRepo = errors.New("repo is no longer open") +) + +type Repo interface { + // APIEndpoint returns multiaddress for communication with Lotus API + APIEndpoint() (multiaddr.Multiaddr, error) + + // APIToken returns JWT API Token for use in operations that require auth + APIToken() ([]byte, error) + + // Lock locks the repo for exclusive use. + Lock(RepoType) (LockedRepo, error) +} + +type LockedRepo interface { + // Close closes repo and removes lock. + Close() error + + // Returns datastore defined in this repo. + Datastore(namespace string) (datastore.Batching, error) + + // Returns config in this repo + Config() (interface{}, error) + SetConfig(func(interface{})) error + + GetStorage() (stores.StorageConfig, error) + SetStorage(func(*stores.StorageConfig)) error + Stat(path string) (stores.FsStat, error) + + // SetAPIEndpoint sets the endpoint of the current API + // so it can be read by API clients + SetAPIEndpoint(multiaddr.Multiaddr) error + + // SetAPIToken sets JWT API Token for CLI + SetAPIToken([]byte) error + + // KeyStore returns store of private keys for Filecoin transactions + KeyStore() (types.KeyStore, error) + + // Path returns absolute path of the repo + Path() string +} diff --git a/vendor/github.com/filecoin-project/lotus/node/repo/memrepo.go b/vendor/github.com/filecoin-project/lotus/node/repo/memrepo.go new file mode 100644 index 0000000000..399b239c19 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/repo/memrepo.go @@ -0,0 +1,357 @@ +package repo + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "github.com/google/uuid" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + dssync "github.com/ipfs/go-datastore/sync" + "github.com/multiformats/go-multiaddr" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/sector-storage/stores" +) + +type MemRepo struct { + api struct { + sync.Mutex + ma multiaddr.Multiaddr + token []byte + } + + repoLock chan struct{} + token *byte + + datastore datastore.Datastore + keystore map[string]types.KeyInfo + + // given a repo type, produce the default config + configF func(t RepoType) interface{} + + // holds the current config value + config struct { + sync.Mutex + val interface{} + } +} + +type lockedMemRepo struct { + mem *MemRepo + t RepoType + sync.RWMutex + + tempDir string + token *byte + sc *stores.StorageConfig +} + +func (lmem *lockedMemRepo) GetStorage() (stores.StorageConfig, error) { + if err := lmem.checkToken(); err != nil { + return stores.StorageConfig{}, err + } + + if lmem.sc == nil { + lmem.sc = &stores.StorageConfig{StoragePaths: []stores.LocalPath{ + {Path: lmem.Path()}, + }} + } + + return *lmem.sc, nil +} + +func (lmem *lockedMemRepo) SetStorage(c func(*stores.StorageConfig)) error { + if err := lmem.checkToken(); err != nil { + return err + } + + _, _ = lmem.GetStorage() + + c(lmem.sc) + return nil +} + +func (lmem *lockedMemRepo) Stat(path string) (stores.FsStat, error) { + return stores.Stat(path) +} + +func (lmem *lockedMemRepo) Path() string { + lmem.Lock() + defer lmem.Unlock() + + if lmem.tempDir != "" { + return lmem.tempDir + } + + t, err := ioutil.TempDir(os.TempDir(), "lotus-memrepo-temp-") + if err != nil { + panic(err) // only used in tests, probably fine + } + + if lmem.t == StorageMiner { + if err := config.WriteStorageFile(filepath.Join(t, fsStorageConfig), stores.StorageConfig{ + StoragePaths: []stores.LocalPath{ + {Path: t}, + }}); err != nil { + panic(err) + } + + b, err := json.MarshalIndent(&stores.LocalStorageMeta{ + ID: stores.ID(uuid.New().String()), + Weight: 10, + CanSeal: true, + CanStore: true, + }, "", " ") + if err != nil { + panic(err) + } + + if err := ioutil.WriteFile(filepath.Join(t, "sectorstore.json"), b, 0644); err != nil { + panic(err) + } + } + + lmem.tempDir = t + return t +} + +var _ Repo = &MemRepo{} + +// MemRepoOptions contains options for memory repo +type MemRepoOptions struct { + Ds datastore.Datastore + ConfigF func(RepoType) interface{} + KeyStore map[string]types.KeyInfo +} + +// NewMemory creates new memory based repo with provided options. +// opts can be nil, it will be replaced with defaults. +// Any field in opts can be nil, they will be replaced by defaults. +func NewMemory(opts *MemRepoOptions) *MemRepo { + if opts == nil { + opts = &MemRepoOptions{} + } + if opts.ConfigF == nil { + opts.ConfigF = defConfForType + } + if opts.Ds == nil { + opts.Ds = dssync.MutexWrap(datastore.NewMapDatastore()) + } + if opts.KeyStore == nil { + opts.KeyStore = make(map[string]types.KeyInfo) + } + + return &MemRepo{ + repoLock: make(chan struct{}, 1), + + datastore: opts.Ds, + configF: opts.ConfigF, + keystore: opts.KeyStore, + } +} + +func (mem *MemRepo) APIEndpoint() (multiaddr.Multiaddr, error) { + mem.api.Lock() + defer mem.api.Unlock() + if mem.api.ma == nil { + return nil, ErrNoAPIEndpoint + } + return mem.api.ma, nil +} + +func (mem *MemRepo) APIToken() ([]byte, error) { + mem.api.Lock() + defer mem.api.Unlock() + if mem.api.ma == nil { + return nil, ErrNoAPIToken + } + return mem.api.token, nil +} + +func (mem *MemRepo) Lock(t RepoType) (LockedRepo, error) { + select { + case mem.repoLock <- struct{}{}: + default: + return nil, ErrRepoAlreadyLocked + } + mem.token = new(byte) + + return &lockedMemRepo{ + mem: mem, + t: t, + token: mem.token, + }, nil +} + +func (lmem *lockedMemRepo) checkToken() error { + lmem.RLock() + defer lmem.RUnlock() + if lmem.mem.token != lmem.token { + return ErrClosedRepo + } + return nil +} + +func (lmem *lockedMemRepo) Close() error { + if err := lmem.checkToken(); err != nil { + return err + } + lmem.Lock() + defer lmem.Unlock() + + if lmem.mem.token != lmem.token { + return ErrClosedRepo + } + + if lmem.tempDir != "" { + if err := os.RemoveAll(lmem.tempDir); err != nil { + return err + } + lmem.tempDir = "" + } + + lmem.mem.token = nil + lmem.mem.api.Lock() + lmem.mem.api.ma = nil + lmem.mem.api.Unlock() + <-lmem.mem.repoLock // unlock + return nil + +} + +func (lmem *lockedMemRepo) Datastore(ns string) (datastore.Batching, error) { + if err := lmem.checkToken(); err != nil { + return nil, err + } + + return namespace.Wrap(lmem.mem.datastore, datastore.NewKey(ns)), nil +} + +func (lmem *lockedMemRepo) Config() (interface{}, error) { + if err := lmem.checkToken(); err != nil { + return nil, err + } + + lmem.mem.config.Lock() + defer lmem.mem.config.Unlock() + + if lmem.mem.config.val == nil { + lmem.mem.config.val = lmem.mem.configF(lmem.t) + } + + return lmem.mem.config.val, nil +} + +func (lmem *lockedMemRepo) SetConfig(c func(interface{})) error { + if err := lmem.checkToken(); err != nil { + return err + } + + lmem.mem.config.Lock() + defer lmem.mem.config.Unlock() + + if lmem.mem.config.val == nil { + lmem.mem.config.val = lmem.mem.configF(lmem.t) + } + + c(lmem.mem.config.val) + + return nil +} + +func (lmem *lockedMemRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error { + if err := lmem.checkToken(); err != nil { + return err + } + lmem.mem.api.Lock() + lmem.mem.api.ma = ma + lmem.mem.api.Unlock() + return nil +} + +func (lmem *lockedMemRepo) SetAPIToken(token []byte) error { + if err := lmem.checkToken(); err != nil { + return err + } + lmem.mem.api.Lock() + lmem.mem.api.token = token + lmem.mem.api.Unlock() + return nil +} + +func (lmem *lockedMemRepo) KeyStore() (types.KeyStore, error) { + if err := lmem.checkToken(); err != nil { + return nil, err + } + return lmem, nil +} + +// Implement KeyStore on the same instance + +// List lists all the keys stored in the KeyStore +func (lmem *lockedMemRepo) List() ([]string, error) { + if err := lmem.checkToken(); err != nil { + return nil, err + } + lmem.RLock() + defer lmem.RUnlock() + + res := make([]string, 0, len(lmem.mem.keystore)) + for k := range lmem.mem.keystore { + res = append(res, k) + } + return res, nil +} + +// Get gets a key out of keystore and returns types.KeyInfo coresponding to named key +func (lmem *lockedMemRepo) Get(name string) (types.KeyInfo, error) { + if err := lmem.checkToken(); err != nil { + return types.KeyInfo{}, err + } + lmem.RLock() + defer lmem.RUnlock() + + key, ok := lmem.mem.keystore[name] + if !ok { + return types.KeyInfo{}, xerrors.Errorf("getting key '%s': %w", name, types.ErrKeyInfoNotFound) + } + return key, nil +} + +// Put saves key info under given name +func (lmem *lockedMemRepo) Put(name string, key types.KeyInfo) error { + if err := lmem.checkToken(); err != nil { + return err + } + lmem.Lock() + defer lmem.Unlock() + + _, isThere := lmem.mem.keystore[name] + if isThere { + return xerrors.Errorf("putting key '%s': %w", name, types.ErrKeyExists) + } + + lmem.mem.keystore[name] = key + return nil +} + +func (lmem *lockedMemRepo) Delete(name string) error { + if err := lmem.checkToken(); err != nil { + return err + } + lmem.Lock() + defer lmem.Unlock() + + _, isThere := lmem.mem.keystore[name] + if !isThere { + return xerrors.Errorf("deleting key '%s': %w", name, types.ErrKeyInfoNotFound) + } + delete(lmem.mem.keystore, name) + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/node/repo/memrepo_test.go b/vendor/github.com/filecoin-project/lotus/node/repo/memrepo_test.go new file mode 100644 index 0000000000..965bc02c19 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/repo/memrepo_test.go @@ -0,0 +1,10 @@ +package repo + +import ( + "testing" +) + +func TestMemBasic(t *testing.T) { + repo := NewMemory(nil) + basicTest(t, repo) +} diff --git a/vendor/github.com/filecoin-project/lotus/node/repo/repo_test.go b/vendor/github.com/filecoin-project/lotus/node/repo/repo_test.go new file mode 100644 index 0000000000..444fab267a --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/repo/repo_test.go @@ -0,0 +1,130 @@ +package repo + +import ( + "testing" + + "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/assert" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/config" + + "github.com/stretchr/testify/require" +) + +func basicTest(t *testing.T, repo Repo) { + apima, err := repo.APIEndpoint() + if assert.Error(t, err) { + assert.Equal(t, ErrNoAPIEndpoint, err) + } + assert.Nil(t, apima, "with no api endpoint, return should be nil") + + lrepo, err := repo.Lock(FullNode) + assert.NoError(t, err, "should be able to lock once") + assert.NotNil(t, lrepo, "locked repo shouldn't be nil") + + { + lrepo2, err := repo.Lock(FullNode) + if assert.Error(t, err) { + assert.Equal(t, ErrRepoAlreadyLocked, err) + } + assert.Nil(t, lrepo2, "with locked repo errors, nil should be returned") + } + + err = lrepo.Close() + assert.NoError(t, err, "should be able to unlock") + + lrepo, err = repo.Lock(FullNode) + assert.NoError(t, err, "should be able to relock") + assert.NotNil(t, lrepo, "locked repo shouldn't be nil") + + ma, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/43244") + assert.NoError(t, err, "creating multiaddr shouldn't error") + + err = lrepo.SetAPIEndpoint(ma) + assert.NoError(t, err, "setting multiaddr shouldn't error") + + apima, err = repo.APIEndpoint() + assert.NoError(t, err, "setting multiaddr shouldn't error") + assert.Equal(t, ma, apima, "returned API multiaddr should be the same") + + c1, err := lrepo.Config() + assert.Equal(t, config.DefaultFullNode(), c1, "there should be a default config") + assert.NoError(t, err, "config should not error") + + // mutate config and persist back to repo + err = lrepo.SetConfig(func(c interface{}) { + cfg := c.(*config.FullNode) + cfg.Client.IpfsMAddr = "duvall" + }) + assert.NoError(t, err) + + // load config and verify changes + c2, err := lrepo.Config() + require.NoError(t, err) + cfg2 := c2.(*config.FullNode) + require.Equal(t, cfg2.Client.IpfsMAddr, "duvall") + + err = lrepo.Close() + assert.NoError(t, err, "should be able to close") + + apima, err = repo.APIEndpoint() + + if assert.Error(t, err) { + assert.Equal(t, ErrNoAPIEndpoint, err, "after closing repo, api should be nil") + } + assert.Nil(t, apima, "with closed repo, apima should be set back to nil") + + k1 := types.KeyInfo{Type: "foo"} + k2 := types.KeyInfo{Type: "bar"} + + lrepo, err = repo.Lock(FullNode) + assert.NoError(t, err, "should be able to relock") + assert.NotNil(t, lrepo, "locked repo shouldn't be nil") + + kstr, err := lrepo.KeyStore() + assert.NoError(t, err, "should be able to get keystore") + assert.NotNil(t, lrepo, "keystore shouldn't be nil") + + list, err := kstr.List() + assert.NoError(t, err, "should be able to list key") + assert.Empty(t, list, "there should be no keys") + + err = kstr.Put("k1", k1) + assert.NoError(t, err, "should be able to put k1") + + err = kstr.Put("k1", k1) + if assert.Error(t, err, "putting key under the same name should error") { + assert.True(t, xerrors.Is(err, types.ErrKeyExists), "returned error is ErrKeyExists") + } + + k1prim, err := kstr.Get("k1") + assert.NoError(t, err, "should be able to get k1") + assert.Equal(t, k1, k1prim, "returned key should be the same") + + k2prim, err := kstr.Get("k2") + if assert.Error(t, err, "should not be able to get k2") { + assert.True(t, xerrors.Is(err, types.ErrKeyInfoNotFound), "returned error is ErrKeyNotFound") + } + assert.Empty(t, k2prim, "there should be no output for k2") + + err = kstr.Put("k2", k2) + assert.NoError(t, err, "should be able to put k2") + + list, err = kstr.List() + assert.NoError(t, err, "should be able to list keys") + assert.ElementsMatch(t, []string{"k1", "k2"}, list, "returned elements match") + + err = kstr.Delete("k2") + assert.NoError(t, err, "should be able to delete key") + + list, err = kstr.List() + assert.NoError(t, err, "should be able to list keys") + assert.ElementsMatch(t, []string{"k1"}, list, "returned elements match") + + err = kstr.Delete("k2") + if assert.Error(t, err) { + assert.True(t, xerrors.Is(err, types.ErrKeyInfoNotFound), "returned errror is ErrKeyNotFound") + } +} diff --git a/vendor/github.com/filecoin-project/lotus/node/testopts.go b/vendor/github.com/filecoin-project/lotus/node/testopts.go new file mode 100644 index 0000000000..f348fc5551 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/node/testopts.go @@ -0,0 +1,20 @@ +package node + +import ( + "errors" + + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" + + "github.com/filecoin-project/lotus/node/modules/lp2p" +) + +func MockHost(mn mocknet.Mocknet) Option { + return Options( + ApplyIf(func(s *Settings) bool { return !s.Online }, + Error(errors.New("MockHost must be specified after Online")), + ), + + Override(new(lp2p.RawHost), lp2p.MockHost), + Override(new(mocknet.Mocknet), mn), + ) +} diff --git a/vendor/github.com/filecoin-project/lotus/paychmgr/cbor_gen.go b/vendor/github.com/filecoin-project/lotus/paychmgr/cbor_gen.go new file mode 100644 index 0000000000..6277bf4659 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/paychmgr/cbor_gen.go @@ -0,0 +1,395 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package paychmgr + +import ( + "fmt" + "io" + + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *VoucherInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{162}); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Voucher (paych.SignedVoucher) (struct) + if len("Voucher") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Voucher\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Voucher"))); err != nil { + return err + } + if _, err := io.WriteString(w, "Voucher"); err != nil { + return err + } + + if err := t.Voucher.MarshalCBOR(w); err != nil { + return err + } + + // t.Proof ([]uint8) (slice) + if len("Proof") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Proof\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Proof"))); err != nil { + return err + } + if _, err := io.WriteString(w, "Proof"); err != nil { + return err + } + + if len(t.Proof) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Proof was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Proof))); err != nil { + return err + } + + if _, err := w.Write(t.Proof); err != nil { + return err + } + return nil +} + +func (t *VoucherInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("VoucherInfo: map struct too large (%d)", extra) + } + + var name string + n := extra + + for i := uint64(0); i < n; i++ { + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + name = string(sval) + } + + switch name { + // t.Voucher (paych.SignedVoucher) (struct) + case "Voucher": + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Voucher = new(paych.SignedVoucher) + if err := t.Voucher.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Voucher pointer: %w", err) + } + } + + } + // t.Proof ([]uint8) (slice) + case "Proof": + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Proof: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Proof = make([]byte, extra) + if _, err := io.ReadFull(br, t.Proof); err != nil { + return err + } + + default: + return fmt.Errorf("unknown struct field %d: '%s'", i, name) + } + } + + return nil +} +func (t *ChannelInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{166}); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Channel (address.Address) (struct) + if len("Channel") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Channel\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Channel"))); err != nil { + return err + } + if _, err := io.WriteString(w, "Channel"); err != nil { + return err + } + + if err := t.Channel.MarshalCBOR(w); err != nil { + return err + } + + // t.Control (address.Address) (struct) + if len("Control") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Control\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Control"))); err != nil { + return err + } + if _, err := io.WriteString(w, "Control"); err != nil { + return err + } + + if err := t.Control.MarshalCBOR(w); err != nil { + return err + } + + // t.Target (address.Address) (struct) + if len("Target") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Target\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Target"))); err != nil { + return err + } + if _, err := io.WriteString(w, "Target"); err != nil { + return err + } + + if err := t.Target.MarshalCBOR(w); err != nil { + return err + } + + // t.Direction (uint64) (uint64) + if len("Direction") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Direction\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Direction"))); err != nil { + return err + } + if _, err := io.WriteString(w, "Direction"); err != nil { + return err + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Direction)); err != nil { + return err + } + + // t.Vouchers ([]*paychmgr.VoucherInfo) (slice) + if len("Vouchers") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Vouchers\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("Vouchers"))); err != nil { + return err + } + if _, err := io.WriteString(w, "Vouchers"); err != nil { + return err + } + + if len(t.Vouchers) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Vouchers was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Vouchers))); err != nil { + return err + } + for _, v := range t.Vouchers { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.NextLane (uint64) (uint64) + if len("NextLane") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"NextLane\" was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("NextLane"))); err != nil { + return err + } + if _, err := io.WriteString(w, "NextLane"); err != nil { + return err + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.NextLane)); err != nil { + return err + } + + return nil +} + +func (t *ChannelInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("ChannelInfo: map struct too large (%d)", extra) + } + + var name string + n := extra + + for i := uint64(0); i < n; i++ { + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + name = string(sval) + } + + switch name { + // t.Channel (address.Address) (struct) + case "Channel": + + { + + if err := t.Channel.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Channel: %w", err) + } + + } + // t.Control (address.Address) (struct) + case "Control": + + { + + if err := t.Control.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Control: %w", err) + } + + } + // t.Target (address.Address) (struct) + case "Target": + + { + + if err := t.Target.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Target: %w", err) + } + + } + // t.Direction (uint64) (uint64) + case "Direction": + + { + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Direction = uint64(extra) + + } + // t.Vouchers ([]*paychmgr.VoucherInfo) (slice) + case "Vouchers": + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Vouchers: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Vouchers = make([]*VoucherInfo, extra) + } + + for i := 0; i < int(extra); i++ { + + var v VoucherInfo + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Vouchers[i] = &v + } + + // t.NextLane (uint64) (uint64) + case "NextLane": + + { + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.NextLane = uint64(extra) + + } + + default: + return fmt.Errorf("unknown struct field %d: '%s'", i, name) + } + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/paychmgr/paych.go b/vendor/github.com/filecoin-project/lotus/paychmgr/paych.go new file mode 100644 index 0000000000..763c448f99 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/paychmgr/paych.go @@ -0,0 +1,373 @@ +package paychmgr + +import ( + "bytes" + "context" + "fmt" + "math" + + cborutil "github.com/filecoin-project/go-cbor-util" + "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/paych" + "golang.org/x/xerrors" + + logging "github.com/ipfs/go-log/v2" + "go.uber.org/fx" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" + "github.com/filecoin-project/lotus/node/impl/full" +) + +var log = logging.Logger("paych") + +type ManagerApi struct { + fx.In + + full.MpoolAPI + full.WalletAPI + full.StateAPI +} + +type Manager struct { + store *Store + sm *stmgr.StateManager + + mpool full.MpoolAPI + wallet full.WalletAPI + state full.StateAPI +} + +func NewManager(sm *stmgr.StateManager, pchstore *Store, api ManagerApi) *Manager { + return &Manager{ + store: pchstore, + sm: sm, + + mpool: api.MpoolAPI, + wallet: api.WalletAPI, + state: api.StateAPI, + } +} + +func maxLaneFromState(st *paych.State) (uint64, error) { + maxLane := uint64(math.MaxInt64) + for _, state := range st.LaneStates { + if (state.ID)+1 > maxLane+1 { + maxLane = state.ID + } + } + return maxLane, nil +} + +func (pm *Manager) TrackInboundChannel(ctx context.Context, ch address.Address) error { + _, st, err := pm.loadPaychState(ctx, ch) + if err != nil { + return err + } + + var account account.State + _, err = pm.sm.LoadActorState(ctx, st.From, &account, nil) + if err != nil { + return err + } + from := account.Address + _, err = pm.sm.LoadActorState(ctx, st.To, &account, nil) + if err != nil { + return err + } + to := account.Address + + maxLane, err := maxLaneFromState(st) + if err != nil { + return err + } + + return pm.store.TrackChannel(&ChannelInfo{ + Channel: ch, + Control: to, + Target: from, + + Direction: DirInbound, + NextLane: maxLane + 1, + }) +} + +func (pm *Manager) loadOutboundChannelInfo(ctx context.Context, ch address.Address) (*ChannelInfo, error) { + _, st, err := pm.loadPaychState(ctx, ch) + if err != nil { + return nil, err + } + + maxLane, err := maxLaneFromState(st) + if err != nil { + return nil, err + } + + var account account.State + _, err = pm.sm.LoadActorState(ctx, st.From, &account, nil) + if err != nil { + return nil, err + } + from := account.Address + _, err = pm.sm.LoadActorState(ctx, st.To, &account, nil) + if err != nil { + return nil, err + } + to := account.Address + + return &ChannelInfo{ + Channel: ch, + Control: from, + Target: to, + + Direction: DirOutbound, + NextLane: maxLane + 1, + }, nil +} + +func (pm *Manager) TrackOutboundChannel(ctx context.Context, ch address.Address) error { + ci, err := pm.loadOutboundChannelInfo(ctx, ch) + if err != nil { + return err + } + + return pm.store.TrackChannel(ci) +} + +func (pm *Manager) ListChannels() ([]address.Address, error) { + return pm.store.ListChannels() +} + +func (pm *Manager) GetChannelInfo(addr address.Address) (*ChannelInfo, error) { + return pm.store.getChannelInfo(addr) +} + +// checks if the given voucher is valid (is or could become spendable at some point) +func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) error { + act, pca, err := pm.loadPaychState(ctx, ch) + if err != nil { + return err + } + + var account account.State + _, err = pm.sm.LoadActorState(ctx, pca.From, &account, nil) + if err != nil { + return err + } + from := account.Address + + // verify signature + vb, err := sv.SigningBytes() + if err != nil { + return err + } + + // TODO: technically, either party may create and sign a voucher. + // However, for now, we only accept them from the channel creator. + // More complex handling logic can be added later + if err := sigs.Verify(sv.Signature, from, vb); err != nil { + return err + } + + sendAmount := sv.Amount + + // now check the lane state + // TODO: should check against vouchers in our local store too + // there might be something conflicting + ls := findLane(pca.LaneStates, uint64(sv.Lane)) + if ls == nil { + } else { + if (ls.Nonce) >= sv.Nonce { + return fmt.Errorf("nonce too low") + } + + sendAmount = types.BigSub(sv.Amount, ls.Redeemed) + } + + // TODO: also account for vouchers on other lanes we've received + newTotal := types.BigAdd(sendAmount, pca.ToSend) + if act.Balance.LessThan(newTotal) { + return fmt.Errorf("not enough funds in channel to cover voucher") + } + + if len(sv.Merges) != 0 { + return fmt.Errorf("dont currently support paych lane merges") + } + + return nil +} + +// checks if the given voucher is currently spendable +func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { + owner, err := pm.getPaychOwner(ctx, ch) + if err != nil { + return false, err + } + + if sv.Extra != nil && proof == nil { + known, err := pm.ListVouchers(ctx, ch) + if err != nil { + return false, err + } + + for _, v := range known { + eq, err := cborutil.Equals(v.Voucher, sv) + if err != nil { + return false, err + } + if v.Proof != nil && eq { + log.Info("CheckVoucherSpendable: using stored proof") + proof = v.Proof + break + } + } + if proof == nil { + log.Warn("CheckVoucherSpendable: nil proof for voucher with validation") + } + } + + enc, err := actors.SerializeParams(&paych.UpdateChannelStateParams{ + Sv: *sv, + Secret: secret, + Proof: proof, + }) + if err != nil { + return false, err + } + + ret, err := pm.sm.Call(ctx, &types.Message{ + From: owner, + To: ch, + Method: builtin.MethodsPaych.UpdateChannelState, + Params: enc, + }, nil) + if err != nil { + return false, err + } + + if ret.MsgRct.ExitCode != 0 { + return false, nil + } + + return true, nil +} + +func (pm *Manager) getPaychOwner(ctx context.Context, ch address.Address) (address.Address, error) { + var state paych.State + if _, err := pm.sm.LoadActorState(ctx, ch, &state, nil); err != nil { + return address.Address{}, err + } + + return state.From, nil +} + +func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { + if err := pm.CheckVoucherValid(ctx, ch, sv); err != nil { + return types.NewInt(0), err + } + + pm.store.lk.Lock() + defer pm.store.lk.Unlock() + + ci, err := pm.store.getChannelInfo(ch) + if err != nil { + return types.NewInt(0), err + } + + laneState, err := pm.laneState(ctx, ch, uint64(sv.Lane)) + if err != nil { + return types.NewInt(0), err + } + + if minDelta.GreaterThan(types.NewInt(0)) && laneState.Nonce > sv.Nonce { + return types.NewInt(0), xerrors.Errorf("already storing voucher with higher nonce; %d > %d", laneState.Nonce, sv.Nonce) + } + + // look for duplicates + for i, v := range ci.Vouchers { + eq, err := cborutil.Equals(sv, v.Voucher) + if err != nil { + return types.BigInt{}, err + } + if !eq { + continue + } + if v.Proof != nil { + if !bytes.Equal(v.Proof, proof) { + log.Warnf("AddVoucher: multiple proofs for single voucher, storing both") + break + } + log.Warnf("AddVoucher: voucher re-added with matching proof") + return types.NewInt(0), nil + } + + log.Warnf("AddVoucher: adding proof to stored voucher") + ci.Vouchers[i] = &VoucherInfo{ + Voucher: v.Voucher, + Proof: proof, + } + + return types.NewInt(0), pm.store.putChannelInfo(ci) + } + + delta := types.BigSub(sv.Amount, laneState.Redeemed) + if minDelta.GreaterThan(delta) { + return delta, xerrors.Errorf("addVoucher: supplied token amount too low; minD=%s, D=%s; laneAmt=%s; v.Amt=%s", minDelta, delta, laneState.Redeemed, sv.Amount) + } + + ci.Vouchers = append(ci.Vouchers, &VoucherInfo{ + Voucher: sv, + Proof: proof, + }) + + if ci.NextLane <= (sv.Lane) { + ci.NextLane = sv.Lane + 1 + } + + return delta, pm.store.putChannelInfo(ci) +} + +func (pm *Manager) AllocateLane(ch address.Address) (uint64, error) { + return pm.store.AllocateLane(ch) +} + +func (pm *Manager) ListVouchers(ctx context.Context, ch address.Address) ([]*VoucherInfo, error) { + // TODO: just having a passthrough method like this feels odd. Seems like + // there should be some filtering we're doing here + return pm.store.VouchersForPaych(ch) +} + +func (pm *Manager) OutboundChanTo(from, to address.Address) (address.Address, error) { + pm.store.lk.Lock() + defer pm.store.lk.Unlock() + + return pm.store.findChan(func(ci *ChannelInfo) bool { + if ci.Direction != DirOutbound { + return false + } + return ci.Control == from && ci.Target == to + }) +} + +func (pm *Manager) NextNonceForLane(ctx context.Context, ch address.Address, lane uint64) (uint64, error) { + vouchers, err := pm.store.VouchersForPaych(ch) + if err != nil { + return 0, err + } + + var maxnonce uint64 + for _, v := range vouchers { + if uint64(v.Voucher.Lane) == lane { + if uint64(v.Voucher.Nonce) > maxnonce { + maxnonce = uint64(v.Voucher.Nonce) + } + } + } + + return maxnonce + 1, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/paychmgr/simple.go b/vendor/github.com/filecoin-project/lotus/paychmgr/simple.go new file mode 100644 index 0000000000..d0dee5e191 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/paychmgr/simple.go @@ -0,0 +1,146 @@ +package paychmgr + +import ( + "bytes" + "context" + + "github.com/filecoin-project/specs-actors/actors/builtin" + init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" +) + +func (pm *Manager) createPaych(ctx context.Context, from, to address.Address, amt types.BigInt) (cid.Cid, error) { + params, aerr := actors.SerializeParams(&paych.ConstructorParams{From: from, To: to}) + if aerr != nil { + return cid.Undef, aerr + } + + enc, aerr := actors.SerializeParams(&init_.ExecParams{ + CodeCID: builtin.PaymentChannelActorCodeID, + ConstructorParams: params, + }) + if aerr != nil { + return cid.Undef, aerr + } + + msg := &types.Message{ + To: builtin.InitActorAddr, + From: from, + Value: amt, + Method: builtin.MethodsInit.Exec, + Params: enc, + GasLimit: 1000000, + GasPrice: types.NewInt(0), + } + + smsg, err := pm.mpool.MpoolPushMessage(ctx, msg) + if err != nil { + return cid.Undef, xerrors.Errorf("initializing paych actor: %w", err) + } + mcid := smsg.Cid() + go pm.waitForPaychCreateMsg(ctx, mcid) + return mcid, nil +} + +// WaitForPaychCreateMsg waits for mcid to appear on chain and returns the robust address of the +// created payment channel +// TODO: wait outside the store lock! +// (tricky because we need to setup channel tracking before we know its address) +func (pm *Manager) waitForPaychCreateMsg(ctx context.Context, mcid cid.Cid) { + defer pm.store.lk.Unlock() + mwait, err := pm.state.StateWaitMsg(ctx, mcid, build.MessageConfidence) + if err != nil { + log.Errorf("wait msg: %w", err) + return + } + + if mwait.Receipt.ExitCode != 0 { + log.Errorf("payment channel creation failed (exit code %d)", mwait.Receipt.ExitCode) + return + } + + var decodedReturn init_.ExecReturn + err = decodedReturn.UnmarshalCBOR(bytes.NewReader(mwait.Receipt.Return)) + if err != nil { + log.Error(err) + return + } + paychaddr := decodedReturn.RobustAddress + + ci, err := pm.loadOutboundChannelInfo(ctx, paychaddr) + if err != nil { + log.Errorf("loading channel info: %w", err) + return + } + + if err := pm.store.trackChannel(ci); err != nil { + log.Errorf("tracking channel: %w", err) + } +} + +func (pm *Manager) addFunds(ctx context.Context, ch address.Address, from address.Address, amt types.BigInt) (cid.Cid, error) { + msg := &types.Message{ + To: ch, + From: from, + Value: amt, + Method: 0, + GasLimit: 1000000, + GasPrice: types.NewInt(0), + } + + smsg, err := pm.mpool.MpoolPushMessage(ctx, msg) + if err != nil { + return cid.Undef, err + } + mcid := smsg.Cid() + go pm.waitForAddFundsMsg(ctx, mcid) + return mcid, nil +} + +// WaitForAddFundsMsg waits for mcid to appear on chain and returns error, if any +// TODO: wait outside the store lock! +// (tricky because we need to setup channel tracking before we know it's address) +func (pm *Manager) waitForAddFundsMsg(ctx context.Context, mcid cid.Cid) { + defer pm.store.lk.Unlock() + mwait, err := pm.state.StateWaitMsg(ctx, mcid, build.MessageConfidence) + if err != nil { + log.Error(err) + } + + if mwait.Receipt.ExitCode != 0 { + log.Errorf("voucher channel creation failed: adding funds (exit code %d)", mwait.Receipt.ExitCode) + } +} + +func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, ensureFree types.BigInt) (address.Address, cid.Cid, error) { + pm.store.lk.Lock() // unlock only on err; wait funcs will defer unlock + var mcid cid.Cid + ch, err := pm.store.findChan(func(ci *ChannelInfo) bool { + if ci.Direction != DirOutbound { + return false + } + return ci.Control == from && ci.Target == to + }) + if err != nil { + pm.store.lk.Unlock() + return address.Undef, cid.Undef, xerrors.Errorf("findChan: %w", err) + } + if ch != address.Undef { + // TODO: Track available funds + mcid, err = pm.addFunds(ctx, ch, from, ensureFree) + } else { + mcid, err = pm.createPaych(ctx, from, to, ensureFree) + } + if err != nil { + pm.store.lk.Unlock() + } + return ch, mcid, err +} diff --git a/vendor/github.com/filecoin-project/lotus/paychmgr/state.go b/vendor/github.com/filecoin-project/lotus/paychmgr/state.go new file mode 100644 index 0000000000..6aff6bd9ed --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/paychmgr/state.go @@ -0,0 +1,80 @@ +package paychmgr + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + xerrors "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types" +) + +func (pm *Manager) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *paych.State, error) { + var pcast paych.State + act, err := pm.sm.LoadActorState(ctx, ch, &pcast, nil) + if err != nil { + return nil, nil, err + } + + return act, &pcast, nil +} + +func findLane(states []*paych.LaneState, lane uint64) *paych.LaneState { + var ls *paych.LaneState + for _, laneState := range states { + if uint64(laneState.ID) == lane { + ls = laneState + break + } + } + return ls +} + +func (pm *Manager) laneState(ctx context.Context, ch address.Address, lane uint64) (paych.LaneState, error) { + _, state, err := pm.loadPaychState(ctx, ch) + if err != nil { + return paych.LaneState{}, err + } + + // TODO: we probably want to call UpdateChannelState with all vouchers to be fully correct + // (but technically dont't need to) + // TODO: make sure this is correct + + ls := findLane(state.LaneStates, lane) + if ls == nil { + ls = &paych.LaneState{ + ID: lane, + Redeemed: types.NewInt(0), + Nonce: 0, + } + } + + vouchers, err := pm.store.VouchersForPaych(ch) + if err != nil { + if err == ErrChannelNotTracked { + return *ls, nil + } + return paych.LaneState{}, err + } + + for _, v := range vouchers { + for range v.Voucher.Merges { + return paych.LaneState{}, xerrors.Errorf("paych merges not handled yet") + } + + if v.Voucher.Lane != lane { + continue + } + + if v.Voucher.Nonce < ls.Nonce { + log.Warnf("Found outdated voucher: ch=%s, lane=%d, v.nonce=%d lane.nonce=%d", ch, lane, v.Voucher.Nonce, ls.Nonce) + continue + } + + ls.Nonce = v.Voucher.Nonce + ls.Redeemed = v.Voucher.Amount + } + + return *ls, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/paychmgr/store.go b/vendor/github.com/filecoin-project/lotus/paychmgr/store.go new file mode 100644 index 0000000000..66a514feb2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/paychmgr/store.go @@ -0,0 +1,202 @@ +package paychmgr + +import ( + "bytes" + "errors" + "fmt" + "strings" + "sync" + + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + dsq "github.com/ipfs/go-datastore/query" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + cborrpc "github.com/filecoin-project/go-cbor-util" + + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +var ErrChannelNotTracked = errors.New("channel not tracked") + +type Store struct { + lk sync.Mutex // TODO: this can be split per paych + + ds datastore.Batching +} + +func NewStore(ds dtypes.MetadataDS) *Store { + ds = namespace.Wrap(ds, datastore.NewKey("/paych/")) + return &Store{ + ds: ds, + } +} + +const ( + DirInbound = 1 + DirOutbound = 2 +) + +type VoucherInfo struct { + Voucher *paych.SignedVoucher + Proof []byte +} + +type ChannelInfo struct { + Channel address.Address + Control address.Address + Target address.Address + + Direction uint64 + Vouchers []*VoucherInfo + NextLane uint64 +} + +func dskeyForChannel(addr address.Address) datastore.Key { + return datastore.NewKey(addr.String()) +} + +func (ps *Store) putChannelInfo(ci *ChannelInfo) error { + k := dskeyForChannel(ci.Channel) + + b, err := cborrpc.Dump(ci) + if err != nil { + return err + } + + return ps.ds.Put(k, b) +} + +func (ps *Store) getChannelInfo(addr address.Address) (*ChannelInfo, error) { + k := dskeyForChannel(addr) + + b, err := ps.ds.Get(k) + if err == datastore.ErrNotFound { + return nil, ErrChannelNotTracked + } + if err != nil { + return nil, err + } + + var ci ChannelInfo + if err := ci.UnmarshalCBOR(bytes.NewReader(b)); err != nil { + return nil, err + } + + return &ci, nil +} + +func (ps *Store) TrackChannel(ch *ChannelInfo) error { + ps.lk.Lock() + defer ps.lk.Unlock() + + return ps.trackChannel(ch) +} + +func (ps *Store) trackChannel(ch *ChannelInfo) error { + _, err := ps.getChannelInfo(ch.Channel) + switch err { + default: + return err + case nil: + return fmt.Errorf("already tracking channel: %s", ch.Channel) + case ErrChannelNotTracked: + return ps.putChannelInfo(ch) + } +} + +func (ps *Store) ListChannels() ([]address.Address, error) { + ps.lk.Lock() + defer ps.lk.Unlock() + + res, err := ps.ds.Query(dsq.Query{KeysOnly: true}) + if err != nil { + return nil, err + } + defer res.Close() //nolint:errcheck + + var out []address.Address + for { + res, ok := res.NextSync() + if !ok { + break + } + + if res.Error != nil { + return nil, err + } + + addr, err := address.NewFromString(strings.TrimPrefix(res.Key, "/")) + if err != nil { + return nil, xerrors.Errorf("failed reading paych key (%q) from datastore: %w", res.Key, err) + } + + out = append(out, addr) + } + + return out, nil +} + +func (ps *Store) findChan(filter func(*ChannelInfo) bool) (address.Address, error) { + res, err := ps.ds.Query(dsq.Query{}) + if err != nil { + return address.Undef, err + } + defer res.Close() //nolint:errcheck + + var ci ChannelInfo + + for { + res, ok := res.NextSync() + if !ok { + break + } + + if res.Error != nil { + return address.Undef, err + } + + if err := ci.UnmarshalCBOR(bytes.NewReader(res.Value)); err != nil { + return address.Undef, err + } + + if !filter(&ci) { + continue + } + + addr, err := address.NewFromString(strings.TrimPrefix(res.Key, "/")) + if err != nil { + return address.Undef, xerrors.Errorf("failed reading paych key (%q) from datastore: %w", res.Key, err) + } + + return addr, nil + } + + return address.Undef, nil +} + +func (ps *Store) AllocateLane(ch address.Address) (uint64, error) { + ps.lk.Lock() + defer ps.lk.Unlock() + + ci, err := ps.getChannelInfo(ch) + if err != nil { + return 0, err + } + + out := ci.NextLane + ci.NextLane++ + + return out, ps.putChannelInfo(ci) +} + +func (ps *Store) VouchersForPaych(ch address.Address) ([]*VoucherInfo, error) { + ci, err := ps.getChannelInfo(ch) + if err != nil { + return nil, err + } + + return ci.Vouchers, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/scripts/archive-branches.sh b/vendor/github.com/filecoin-project/lotus/scripts/archive-branches.sh new file mode 100755 index 0000000000..98fdfaeb8e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/archive-branches.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' + +org=filecoin-project +repo=lotus +arch_repo="$org/lotus-archived" +api_repo="repos/$org/$repo" + +exclusions=( + 'master' +) + +gh_api_next() { + links=$(grep '^Link:' | sed -e 's/Link: //' -e 's/, /\n/g') + echo "$links" | grep '; rel="next"' >/dev/null || return + link=$(echo "$links" | grep '; rel="next"' | sed -e 's/^.*//') + + curl -n -f -sD >(gh_api_next) "$link" +} + +gh_api() { + curl -n -f -sD >(gh_api_next) "https://api.github.com/$1" | jq -s '[.[] | .[]]' +} + +pr_branches() { + gh_api "$api_repo/pulls" | jq -r '.[].head.label | select(test("^'"$org"':"))' \ + | sed 's/^'"$org"'://' +} + +origin_refs() { + format=${1-'%(refname:short)'} + + git for-each-ref --format "$format" refs/remotes/origin | sed 's|^origin/||' +} + +active_branches() { + origin_refs '%(refname:short) %(committerdate:unix)' |awk \ +' BEGIN { monthAgo = systime() - 31*24*60*60 } + { if ($2 > monthAgo) print $1 } +' +} + +git remote add archived "git@github.com:$arch_repo.git" || true + +branches_to_move="$(cat <(active_branches) <(pr_branches) <((IFS=$'\n'; echo "${exclusions[*]}")) | sort -u | comm - <(origin_refs | sort) -13)" + +echo "================" +printf "%s\n" "$branches_to_move" +echo "================" + +echo "Please confirm move of above branches [y/N]:" + +read -r line +case "$line" in + [Yy]|[Yy][Ee][Ss]) ;; + *) exit 1 ;; +esac + + +printf "%s\n" "$branches_to_move" | \ +while read -r ref; do + git push archived "origin/$ref:refs/heads/$ref/$(date --rfc-3339=date)" + git push origin --delete "$ref" + done + diff --git a/vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus b/vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus new file mode 100644 index 0000000000..20c312b6ce --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +_cli_bash_autocomplete() { + local cur opts base; + COMPREPLY=(); + cur="${COMP_WORDS[COMP_CWORD]}"; + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-completion ); + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ); + return 0; +}; +complete -F _cli_bash_autocomplete lotus \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus-storage-miner b/vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus-storage-miner new file mode 100644 index 0000000000..10ee5b77fc --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/bash-completion/lotus-storage-miner @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +_cli_bash_autocomplete() { + local cur opts base; + COMPREPLY=(); + cur="${COMP_WORDS[COMP_CWORD]}"; + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-completion ); + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ); + return 0; +}; +complete -F _cli_bash_autocomplete lotus-storage-miner \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/scripts/bootstrap.toml b/vendor/github.com/filecoin-project/lotus/scripts/bootstrap.toml new file mode 100644 index 0000000000..81cd60ccdf --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/bootstrap.toml @@ -0,0 +1,2 @@ +[Libp2p] +ListenAddresses = ["/ip4/0.0.0.0/tcp/1347"] diff --git a/vendor/github.com/filecoin-project/lotus/scripts/build-bundle.sh b/vendor/github.com/filecoin-project/lotus/scripts/build-bundle.sh new file mode 100755 index 0000000000..16cab49d1b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/build-bundle.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -ex + +ARCHS=( + "darwin" + "linux" +) + +REQUIRED=( + "ipfs" + "sha512sum" +) +for REQUIRE in "${REQUIRED[@]}" +do + command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed" +done + +mkdir bundle +pushd bundle + +BINARIES=( + "lotus" + "lotus-storage-miner" + "lotus-seal-worker" +) + +export IPFS_PATH=`mktemp -d` +ipfs init +ipfs daemon & +PID="$!" +trap "kill -9 ${PID}" EXIT +sleep 30 + +for ARCH in "${ARCHS[@]}" +do + mkdir -p "${ARCH}/lotus" + pushd "${ARCH}" + for BINARY in "${BINARIES[@]}" + do + cp "../../${ARCH}/${BINARY}" "lotus/" + chmod +x "lotus/${BINARY}" + done + + tar -zcvf "../lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" lotus + popd + rm -rf "${ARCH}" + + sha512sum "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" | cut -d" " -f1 > "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz.sha512" + + ipfs add "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" | cut -d" " -f2 > "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz.cid" +done +popd diff --git a/vendor/github.com/filecoin-project/lotus/scripts/chainwatch.service b/vendor/github.com/filecoin-project/lotus/scripts/chainwatch.service new file mode 100644 index 0000000000..74afee0e97 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/chainwatch.service @@ -0,0 +1,15 @@ +[Unit] +Description=Chainwatch +After=lotus-daemon.service +Requires=lotus-daemon.service + +[Service] +Environment=GOLOG_FILE="/var/log/lotus/chainwatch.log" +Environment=GOLOG_LOG_FMT="json" +Environment=LOTUS_DB="" +Environment=LOTUS_PATH="%h/.lotus" +EnvironmentFile=-/etc/lotus/chainwatch.env +ExecStart=/usr/local/bin/chainwatch run + +[Install] +WantedBy=multi-user.target diff --git a/vendor/github.com/filecoin-project/lotus/scripts/deploy-bootstrapper.sh b/vendor/github.com/filecoin-project/lotus/scripts/deploy-bootstrapper.sh new file mode 100755 index 0000000000..98e2cd7985 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/deploy-bootstrapper.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +log() { + echo -e "\e[33m$1\e[39m" +} + +host=$1 + +log "> Deploying bootstrap node $host" +log "Stopping lotus daemon" + +ssh "$host" 'systemctl stop lotus-daemon' & +ssh "$host" 'systemctl stop lotus-storage-miner' & + +wait + +ssh "$host" 'rm -rf .lotus' & +ssh "$host" 'rm -rf .lotusstorage' & + +scp -C lotus "${host}":/usr/local/bin/lotus & +scp -C lotus-storage-miner "${host}":/usr/local/bin/lotus-storage-miner & + +wait + +log 'Initializing repo' + +ssh "$host" 'systemctl start lotus-daemon' +scp scripts/bootstrap.toml "${host}:.lotus/config.toml" +ssh "$host" "echo -e '[Metrics]\nNickname=\"Boot-$host\"' >> .lotus/config.toml" +ssh "$host" 'systemctl restart lotus-daemon' + +log 'Extracting addr info' + +ssh "$host" 'lotus net listen' | grep -v '/10' | grep -v '/127' >> build/bootstrap/bootstrappers.pi diff --git a/vendor/github.com/filecoin-project/lotus/scripts/deploy-miner.sh b/vendor/github.com/filecoin-project/lotus/scripts/deploy-miner.sh new file mode 100755 index 0000000000..b1603aca66 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/deploy-miner.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +HOST=$1 + +ssh "$HOST" '[ -e ~/.lotusstorage/token ]' && exit 0 + +ssh "$HOST" 'lotus wallet new bls > addr' +ssh "$HOST" 'curl http://147.75.80.29:777/sendcoll?address=$(cat addr)' & +ssh "$HOST" 'curl http://147.75.80.29:777/sendcoll?address=$(cat addr)' & +ssh "$HOST" 'curl http://147.75.80.29:777/send?address=$(cat addr)' & +wait + +echo "SYNC WAIT" +sleep 30 + +ssh "$HOST" 'lotus sync wait' +ssh "$HOST" 'lotus-storage-miner init --owner=$(cat addr)' +ssh "$HOST" 'systemctl start lotus-storage-miner' & diff --git a/vendor/github.com/filecoin-project/lotus/scripts/deploy-node.sh b/vendor/github.com/filecoin-project/lotus/scripts/deploy-node.sh new file mode 100755 index 0000000000..57856f945b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/deploy-node.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +set -euo pipefail +IFS=$'\n\t' + + +HOST=$1 + +# upload binaries +# TODO: destroy + +FILES_TO_SEND=( + ./lotus + ./lotus-storage-miner + scripts/lotus-daemon.service + scripts/louts-miner.service +) + +rsync -P "${FILES_TO_SEND[@]}" "$HOST:~/lotus-stage/" + +ssh "$HOST" 'bash -s' << 'EOF' +set -euo pipefail + +systemctl stop lotus-storage-miner +systemctl stop lotus-daemon +mkdir -p .lotus .lotusstorage + +cd "$HOME/lotus-stage/" +cp -f lotus lotus-storage-miner /usr/local/bin +cp -f lotus-daemon.service /etc/systemd/system/lotus-daemon.service +cp -f lotus-miner.service /etc/systemd/system/lotus-storage-miner.service + +systemctl daemon-reload +systemctl start lotus-daemon +EOF + + +# setup miner actor diff --git a/vendor/github.com/filecoin-project/lotus/scripts/dev/drop-local-repos b/vendor/github.com/filecoin-project/lotus/scripts/dev/drop-local-repos new file mode 100755 index 0000000000..939030bad9 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/dev/drop-local-repos @@ -0,0 +1,5 @@ +#!/usr/bin/env sh + +set -o xtrace + +rm -rf ~/.lotus ~/.lotusstorage/ ~/.genesis-sectors ~/.lotusworker diff --git a/vendor/github.com/filecoin-project/lotus/scripts/dev/gen-daemon b/vendor/github.com/filecoin-project/lotus/scripts/dev/gen-daemon new file mode 100755 index 0000000000..af25123d32 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/dev/gen-daemon @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +set -o xtrace + +export TRUST_PARAMS=1 +tag=${TAG:-debug} + +go run -tags=$tag ./cmd/lotus-seed pre-seal --sector-size 2KiB --num-sectors 2 +go run -tags=$tag ./cmd/lotus-seed genesis new localnet.json +go run -tags=$tag ./cmd/lotus-seed genesis add-miner localnet.json ~/.genesis-sectors/pre-seal-t01000.json +go run -tags=$tag ./cmd/lotus daemon --lotus-make-genesis=devel.gen --genesis-template=localnet.json --bootstrap=false diff --git a/vendor/github.com/filecoin-project/lotus/scripts/dev/sminer-init b/vendor/github.com/filecoin-project/lotus/scripts/dev/sminer-init new file mode 100755 index 0000000000..2f4a3f7afa --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/dev/sminer-init @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +set -o xtrace + +export TRUST_PARAMS=1 + +tag=${TAG:-debug} + +go run -tags=$tag ./cmd/lotus wallet import ~/.genesis-sectors/pre-seal-t01000.key +go run -tags=$tag ./cmd/lotus-storage-miner init --actor=t01000 --genesis-miner --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json diff --git a/vendor/github.com/filecoin-project/lotus/scripts/devnet.bash b/vendor/github.com/filecoin-project/lotus/scripts/devnet.bash new file mode 100755 index 0000000000..4fe81eea49 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/devnet.bash @@ -0,0 +1,196 @@ +#!/usr/bin/env bash + +session="lotus-interop" +wdaemon="daemon" +wminer="miner" +wsetup="setup" +wpledging="pledging" +wcli="cli" +wshell="cli" +faucet="http://t01000.miner.interopnet.kittyhawk.wtf" + + +PLEDGE_COUNT="${1:-20}" + +if [ -z "$BRANCH" ]; then + BRANCH="interopnet" +fi + +if [ -z "$BUILD" ]; then + BUILD="no" +fi + +if [ -z "$DEVNET" ]; then + DEVNET="yes" +fi + +BASEDIR=$(mktemp -d -t "lotus-interopnet.XXXX") + +if [ "$BUILD" == "yes" ]; then + git clone --branch "$BRANCH" https://github.com/filecoin-project/lotus.git "${BASEDIR}/build" +fi + + +mkdir -p "${BASEDIR}/scripts" +mkdir -p "${BASEDIR}/bin" + +cat > "${BASEDIR}/scripts/build.bash" </dev/null 2>&1 && pwd )" +pushd \$SCRIPTDIR/../build + +pwd +env RUSTFLAGS="-C target-cpu=native -g" FFI_BUILD_FROM_SOURCE=1 make clean deps lotus lotus-storage-miner lotus-shed +cp lotus lotus-storage-miner lotus-shed ../bin/ + +popd +EOF + +cat > "${BASEDIR}/scripts/env.fish" < "${BASEDIR}/scripts/env.bash" < "${BASEDIR}/scripts/create_miner.bash" < "${BASEDIR}/scripts/pledge_sectors.bash" < ${PLEDGE_COUNT} )); then + break + fi + + while true; do + state=\$(lotus-storage-miner sectors list | tail -n1 | awk '{print \$2}') + + if [ -z "\$state" ]; then + break + fi + + case \$state in + PreCommit1 | PreCommit2 | Packing | Unsealed | PreCommitting | Committing | CommitWait | FinalizeSector ) sleep 30 ;; + WaitSeed | Proving ) break ;; + * ) echo "Unknown Sector State: \$state" + lotus-storage-miner sectors status --log \$current + break ;; + esac + done + + lotus-storage-miner sectors pledge + + while [ "\$current" == "\$sector" ]; do + sector=\$(lotus-storage-miner sectors list | tail -n1 | awk '{print \$1}' | tr -d ':') + sleep 5 + done + + current="\$sector" +done +EOF + +cat > "${BASEDIR}/scripts/monitor.bash" <&1 | tee -a ${BASEDIR}/daemon.log" C-m + +export LOTUS_PATH="${BASEDIR}/.lotus" +${BASEDIR}/bin/lotus wait-api + +tmux send-keys -t $session:$wminer "${BASEDIR}/scripts/create_miner.bash" C-m +tmux send-keys -t $session:$wminer "lotus-storage-miner run --api 48020 --nosync 2>&1 | tee -a ${BASEDIR}/miner.log" C-m +tmux send-keys -t $session:$wcli "${BASEDIR}/scripts/monitor.bash" C-m +tmux send-keys -t $session:$wpleding "${BASEDIR}/scripts/pledge_sectors.bash" C-m + +tmux select-window -t $session:$wcli + +tmux attach-session -t $session + diff --git a/vendor/github.com/filecoin-project/lotus/scripts/filebeat.yml b/vendor/github.com/filecoin-project/lotus/scripts/filebeat.yml new file mode 100644 index 0000000000..38c9adbc74 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/filebeat.yml @@ -0,0 +1,76 @@ +############################# Filebeat ##################################### + +filebeat.inputs: + +- type: log + paths: + - /root/.lotusstorage/logs + fields: + logzio_codec: json + token: + type: lotus-miner + fields_under_root: true + json.keys_under_root: false + json.message_key: msg + + encoding: utf-8 + ignore_older: 3h +- type: log + paths: + - /root/.lotus/logs + fields: + logzio_codec: json + token: + type: lotus-daemon + fields_under_root: true + json.keys_under_root: false + json.message_key: msg + encoding: utf-8 + ignore_older: 3h + +#For version 6.x and lower +#filebeat.registry_file: /var/lib/filebeat/registry + +#For version 7 and higher +filebeat.registry.path: /var/lib/filebeat + +#The following processors are to ensure compatibility with version 7 +processors: +- rename: + fields: + - from: "agent" + to: "beat_agent" + ignore_missing: true +- rename: + fields: + - from: "log.file.path" + to: "source" + ignore_missing: true + +- if: + has_fields: ['json.ts'] + then: + - timestamp: + field: 'json.ts' + layouts: + - '2006-01-02T15:04:05.000Z0700' + test: + - '2019-10-10T22:37:48.297+0200' + - drop_fields: + fields: ['json.ts'] +- if: + has_fields: ['json.msg'] + then: + - rename: + fields: + - from: 'json.msg' + to: 'message' + + +############################# Output ########################################## + +output: + logstash: + hosts: ["listener.logz.io:5015"] + ssl: + certificate_authorities: ['/etc/pki/tls/certs/COMODORSADomainValidationSecureServerCA.crt'] diff --git a/vendor/github.com/filecoin-project/lotus/scripts/init-network.sh b/vendor/github.com/filecoin-project/lotus/scripts/init-network.sh new file mode 100755 index 0000000000..3ca243c15b --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/init-network.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash + +set -xeo + +NUM_SECTORS=2 +SECTOR_SIZE=2KiB + + +sdt0111=$(mktemp -d) +sdt0222=$(mktemp -d) +sdt0333=$(mktemp -d) + +staging=$(mktemp -d) + +make debug + +./lotus-seed --sector-dir="${sdt0111}" pre-seal --miner-addr=t0111 --sector-offset=0 --sector-size=${SECTOR_SIZE} --num-sectors=${NUM_SECTORS} & +./lotus-seed --sector-dir="${sdt0222}" pre-seal --miner-addr=t0222 --sector-offset=0 --sector-size=${SECTOR_SIZE} --num-sectors=${NUM_SECTORS} & +./lotus-seed --sector-dir="${sdt0333}" pre-seal --miner-addr=t0333 --sector-offset=0 --sector-size=${SECTOR_SIZE} --num-sectors=${NUM_SECTORS} & + +wait + +./lotus-seed aggregate-manifests "${sdt0111}/pre-seal-t0111.json" "${sdt0222}/pre-seal-t0222.json" "${sdt0333}/pre-seal-t0333.json" > "${staging}/genesis.json" + +lotus_path=$(mktemp -d) + +./lotus --repo="${lotus_path}" daemon --lotus-make-random-genesis="${staging}/devnet.car" --genesis-presealed-sectors="${staging}/genesis.json" --bootstrap=false & +lpid=$! + +sleep 3 + +kill "$lpid" + +wait + +cp "${staging}/devnet.car" build/genesis/devnet.car + +make debug + +ldt0111=$(mktemp -d) +ldt0222=$(mktemp -d) +ldt0333=$(mktemp -d) + +sdlist=( "$sdt0111" "$sdt0222" "$sdt0333" ) +ldlist=( "$ldt0111" "$ldt0222" "$ldt0333" ) + +for (( i=0; i<${#sdlist[@]}; i++ )); do + preseal=${sdlist[$i]} + fullpath=$(find ${preseal} -type f -iname 'pre-seal-*.json') + filefull=$(basename ${fullpath}) + filename=${filefull%%.*} + mineraddr=$(echo $filename | sed 's/pre-seal-//g') + + wallet_raw=$(jq -rc ".${mineraddr}.Key" < ${preseal}/${filefull}) + wallet_b16=$(./lotus-shed base16 "${wallet_raw}") + wallet_adr=$(./lotus-shed keyinfo --format="{{.Address}}" "${wallet_b16}") + wallet_adr_enc=$(./lotus-shed base32 "wallet-${wallet_adr}") + + mkdir -p "${ldlist[$i]}/keystore" + cat > "${ldlist[$i]}/keystore/${wallet_adr_enc}" < "scripts/bash-completion/$1" +echo '#!/usr/bin/env zsh' > "scripts/zsh-completion/$1" + +$1 --init-completion=bash >> "scripts/bash-completion/$1" +$1 --init-completion=zsh >> "scripts/zsh-completion/$1" diff --git a/vendor/github.com/filecoin-project/lotus/scripts/miner-mon.sh b/vendor/github.com/filecoin-project/lotus/scripts/miner-mon.sh new file mode 100755 index 0000000000..cf78660a77 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/miner-mon.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +SESSION=$(cat /proc/sys/kernel/random/uuid) + +tmux -2 new-session -d -s $SESSION + +tmux new-window -t $SESSION:1 -n 'Storage Miner' + +tmux split-window -h + +tmux select-pane -t 0 +tmux send-keys "watch -n1 './lotus-storage-miner info'" C-m + +tmux split-window -v + +tmux select-pane -t 1 +tmux send-keys "watch -n1 './lotus-storage-miner workers list'" C-m + +tmux select-pane -t 2 +tmux send-keys "watch -n1 './lotus-storage-miner storage list'" C-m + + +tmux -2 attach-session -t $SESSION diff --git a/vendor/github.com/filecoin-project/lotus/scripts/publish-release.sh b/vendor/github.com/filecoin-project/lotus/scripts/publish-release.sh new file mode 100755 index 0000000000..103de1f0f0 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/publish-release.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +set -e + +pushd bundle + +# make sure we have a token set, api requests won't work otherwise +if [ -z "${GITHUB_TOKEN}" ]; then + echo "\${GITHUB_TOKEN} not set, publish failed" + exit 1 +fi + +REQUIRED=( + "jq" + "curl" +) +for REQUIRE in "${REQUIRED[@]}" +do + command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed" +done + +#see if the release already exists by tag +RELEASE_RESPONSE=` + curl \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/releases/tags/${CIRCLE_TAG}" +` +RELEASE_ID=`echo "${RELEASE_RESPONSE}" | jq '.id'` + +if [ "${RELEASE_ID}" = "null" ]; then + echo "creating release" + + RELEASE_DATA="{ + \"tag_name\": \"${CIRCLE_TAG}\", + \"target_commitish\": \"${CIRCLE_SHA1}\", + \"name\": \"${CIRCLE_TAG}\", + \"body\": \"\", + \"prerelease\": false + }" + + # create it if it doesn't exist yet + RELEASE_RESPONSE=` + curl \ + --request POST \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + --header "Content-Type: application/json" \ + --data "${RELEASE_DATA}" \ + "https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/${CIRCLE_PROJECT_REPONAME}/releases" + ` +else + echo "release already exists" +fi + +RELEASE_UPLOAD_URL=`echo "${RELEASE_RESPONSE}" | jq -r '.upload_url' | cut -d'{' -f1` + +bundles=( + "lotus_${CIRCLE_TAG}_linux-amd64.tar.gz" + "lotus_${CIRCLE_TAG}_linux-amd64.tar.gz.cid" + "lotus_${CIRCLE_TAG}_linux-amd64.tar.gz.sha512" + "lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz" + "lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz.cid" + "lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz.sha512" +) +for RELEASE_FILE in "${bundles[@]}" +do + echo "Uploading release bundle: ${RELEASE_FILE}" + curl \ + --request POST \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + --header "Content-Type: application/octet-stream" \ + --data-binary "@${RELEASE_FILE}" \ + "$RELEASE_UPLOAD_URL?name=$(basename "${RELEASE_FILE}")" + + echo "Release bundle uploaded: ${RELEASE_FILE}" +done + +popd + +miscellaneous=( + "README.md" + "LICENSE-MIT" + "LICENSE-APACHE" +) +for MISC in "${miscellaneous[@]}" +do + echo "Uploading release bundle: ${MISC}" + curl \ + --request POST \ + --header "Authorization: token ${GITHUB_TOKEN}" \ + --header "Content-Type: application/octet-stream" \ + --data-binary "@${MISC}" \ + "$RELEASE_UPLOAD_URL?name=$(basename "${MISC}")" + + echo "Release bundle uploaded: ${MISC}" +done diff --git a/vendor/github.com/filecoin-project/lotus/scripts/quick-network-join.bash b/vendor/github.com/filecoin-project/lotus/scripts/quick-network-join.bash new file mode 100755 index 0000000000..33e0069b2c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/quick-network-join.bash @@ -0,0 +1,180 @@ +#!/usr/bin/env bash + +session="lotus-interop" +wdaemon="daemon" +wminer="miner" +wsetup="setup" +wpledging="pledging" +wcli="cli" +faucet="https://t01000.miner.interopnet.kittyhawk.wtf" + +PLEDGE_COUNT="${1:-20}" +BRANCH="interopnet" +BASEDIR=$(mktemp -d -t "lotus-interopnet.XXXX") + +git clone --branch "$BRANCH" https://github.com/filecoin-project/lotus.git "${BASEDIR}/build" + +mkdir -p "${BASEDIR}/scripts" +mkdir -p "${BASEDIR}/bin" + +cat > "${BASEDIR}/scripts/build.bash" </dev/null 2>&1 && pwd )" +pushd \$SCRIPTDIR/../build + +pwd +env RUSTFLAGS="-C target-cpu=native -g" FFI_BUILD_FROM_SOURCE=1 make clean deps lotus lotus-storage-miner lotus-shed +cp lotus lotus-storage-miner lotus-shed ../bin/ + +popd +EOF + +cat > "${BASEDIR}/scripts/env.fish" < "${BASEDIR}/scripts/env.bash" < "${BASEDIR}/scripts/create_miner.bash" < "${BASEDIR}/scripts/pledge_sectors.bash" < ${PLEDGE_COUNT} )); then + break + fi + + while true; do + state=\$(lotus-storage-miner sectors list | tail -n1 | awk '{print \$2}') + + if [ -z "\$state" ]; then + break + fi + + case \$state in + PreCommit1 | PreCommit2 | Packing | Unsealed | PreCommitting | Committing | CommitWait | FinalizeSector ) sleep 30 ;; + WaitSeed | Proving ) break ;; + * ) echo "Unknown Sector State: \$state" + lotus-storage-miner sectors status --log \$current + break ;; + esac + done + + lotus-storage-miner sectors pledge + + while [ "\$current" == "\$sector" ]; do + sector=\$(lotus-storage-miner sectors list | tail -n1 | awk '{print \$1}' | tr -d ':') + sleep 5 + done + + current="\$sector" +done +EOF + +cat > "${BASEDIR}/scripts/monitor.bash" <&1 | tee -a ${BASEDIR}/daemon.log" C-m + +sleep 30 + +tmux send-keys -t $session:$wminer "${BASEDIR}/scripts/create_miner.bash" C-m +tmux send-keys -t $session:$wminer "lotus-storage-miner run --api 48020 2>&1 | tee -a ${BASEDIR}/miner.log" C-m +tmux send-keys -t $session:$wcli "${BASEDIR}/scripts/monitor.bash" C-m +tmux send-keys -t $session:$wpleding "${BASEDIR}/scripts/pledge_sectors.bash" C-m + +tmux select-window -t $session:$wcli + +tmux attach-session -t $session + diff --git a/vendor/github.com/filecoin-project/lotus/scripts/setup-host.sh b/vendor/github.com/filecoin-project/lotus/scripts/setup-host.sh new file mode 100755 index 0000000000..bda0a2c981 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/setup-host.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +HOST=$1 + +scp scripts/lotus-daemon.service "${HOST}:/etc/systemd/system/lotus-daemon.service" +scp scripts/lotus-miner.service "${HOST}:/etc/systemd/system/lotus-storage-miner.service" diff --git a/vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus b/vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus new file mode 100644 index 0000000000..bbd886ae4d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus @@ -0,0 +1,12 @@ +#!/usr/bin/env zsh +autoload -U compinit && compinit; +autoload -U bashcompinit && bashcompinit; +_cli_bash_autocomplete() { + local cur opts base; + COMPREPLY=(); + cur="${COMP_WORDS[COMP_CWORD]}"; + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-completion ); + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ); + return 0; +}; +complete -F _cli_bash_autocomplete lotus \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus-storage-miner b/vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus-storage-miner new file mode 100644 index 0000000000..1ff14be3a1 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/scripts/zsh-completion/lotus-storage-miner @@ -0,0 +1,12 @@ +#!/usr/bin/env zsh +autoload -U compinit && compinit; +autoload -U bashcompinit && bashcompinit; +_cli_bash_autocomplete() { + local cur opts base; + COMPREPLY=(); + cur="${COMP_WORDS[COMP_CWORD]}"; + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-completion ); + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ); + return 0; +}; +complete -F _cli_bash_autocomplete lotus-storage-miner \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/storage/adapter_events.go b/vendor/github.com/filecoin-project/lotus/storage/adapter_events.go new file mode 100644 index 0000000000..db37f4c0c3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/adapter_events.go @@ -0,0 +1,29 @@ +package storage + +import ( + "context" + + "github.com/filecoin-project/specs-actors/actors/abi" + + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/types" + sealing "github.com/filecoin-project/storage-fsm" +) + +var _ sealing.Events = new(EventsAdapter) + +type EventsAdapter struct { + delegate *events.Events +} + +func NewEventsAdapter(api *events.Events) EventsAdapter { + return EventsAdapter{delegate: api} +} + +func (e EventsAdapter) ChainAt(hnd sealing.HeightHandler, rev sealing.RevertHandler, confidence int, h abi.ChainEpoch) error { + return e.delegate.ChainAt(func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error { + return hnd(ctx, ts.Key().Bytes(), curH) + }, func(ctx context.Context, ts *types.TipSet) error { + return rev(ctx, ts.Key().Bytes()) + }, confidence, h) +} diff --git a/vendor/github.com/filecoin-project/lotus/storage/adapter_storage_miner.go b/vendor/github.com/filecoin-project/lotus/storage/adapter_storage_miner.go new file mode 100644 index 0000000000..5fc8119978 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/adapter_storage_miner.go @@ -0,0 +1,240 @@ +package storage + +import ( + "bytes" + "context" + + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "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/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/util/adt" + + "github.com/filecoin-project/lotus/api/apibstore" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + sealing "github.com/filecoin-project/storage-fsm" +) + +var _ sealing.SealingAPI = new(SealingAPIAdapter) + +type SealingAPIAdapter struct { + delegate storageMinerApi +} + +func NewSealingAPIAdapter(api storageMinerApi) SealingAPIAdapter { + return SealingAPIAdapter{delegate: api} +} + +func (s SealingAPIAdapter) StateMinerSectorSize(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) (abi.SectorSize, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return 0, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + // TODO: update storage-fsm to just StateMinerInfo + mi, err := s.delegate.StateMinerInfo(ctx, maddr, tsk) + if err != nil { + return 0, err + } + return mi.SectorSize, nil +} + +func (s SealingAPIAdapter) StateMinerInitialPledgeCollateral(ctx context.Context, a address.Address, n abi.SectorNumber, tok sealing.TipSetToken) (big.Int, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return big.Zero(), xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + return s.delegate.StateMinerInitialPledgeCollateral(ctx, a, n, tsk) +} + +func (s SealingAPIAdapter) StateMinerWorkerAddress(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) (address.Address, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return address.Undef, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + // TODO: update storage-fsm to just StateMinerInfo + mi, err := s.delegate.StateMinerInfo(ctx, maddr, tsk) + if err != nil { + return address.Undef, err + } + return mi.Worker, nil +} + +func (s SealingAPIAdapter) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok sealing.TipSetToken) (*miner.Deadlines, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + return s.delegate.StateMinerDeadlines(ctx, maddr, tsk) +} + +func (s SealingAPIAdapter) StateWaitMsg(ctx context.Context, mcid cid.Cid) (sealing.MsgLookup, error) { + wmsg, err := s.delegate.StateWaitMsg(ctx, mcid, build.MessageConfidence) + if err != nil { + return sealing.MsgLookup{}, err + } + + return sealing.MsgLookup{ + Receipt: sealing.MessageReceipt{ + ExitCode: wmsg.Receipt.ExitCode, + Return: wmsg.Receipt.Return, + GasUsed: wmsg.Receipt.GasUsed, + }, + TipSetTok: wmsg.TipSet.Key().Bytes(), + Height: wmsg.TipSet.Height(), + }, nil +} + +func (s SealingAPIAdapter) StateComputeDataCommitment(ctx context.Context, maddr address.Address, sectorType abi.RegisteredSealProof, deals []abi.DealID, tok sealing.TipSetToken) (cid.Cid, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + ccparams, err := actors.SerializeParams(&market.ComputeDataCommitmentParams{ + DealIDs: deals, + SectorType: sectorType, + }) + if err != nil { + return cid.Undef, xerrors.Errorf("computing params for ComputeDataCommitment: %w", err) + } + + ccmt := &types.Message{ + To: builtin.StorageMarketActorAddr, + From: maddr, + Value: types.NewInt(0), + GasPrice: types.NewInt(0), + GasLimit: 9999999999, + Method: builtin.MethodsMarket.ComputeDataCommitment, + Params: ccparams, + } + r, err := s.delegate.StateCall(ctx, ccmt, tsk) + if err != nil { + return cid.Undef, xerrors.Errorf("calling ComputeDataCommitment: %w", err) + } + if r.MsgRct.ExitCode != 0 { + return cid.Undef, xerrors.Errorf("receipt for ComputeDataCommitment had exit code %d", r.MsgRct.ExitCode) + } + + var c cbg.CborCid + if err := c.UnmarshalCBOR(bytes.NewReader(r.MsgRct.Return)); err != nil { + return cid.Undef, xerrors.Errorf("failed to unmarshal CBOR to CborCid: %w", err) + } + + return cid.Cid(c), nil +} + +func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok sealing.TipSetToken) (*miner.SectorPreCommitOnChainInfo, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + act, err := s.delegate.StateGetActor(ctx, maddr, tsk) + if err != nil { + return nil, xerrors.Errorf("handleSealFailed(%d): temp error: %+v", sectorNumber, err) + } + + st, err := s.delegate.ChainReadObj(ctx, act.Head) + if err != nil { + return nil, xerrors.Errorf("handleSealFailed(%d): temp error: %+v", sectorNumber, err) + } + + var state miner.State + if err := state.UnmarshalCBOR(bytes.NewReader(st)); err != nil { + return nil, xerrors.Errorf("handleSealFailed(%d): temp error: unmarshaling miner state: %+v", sectorNumber, err) + } + + precommits, err := adt.AsMap(store.ActorStore(ctx, apibstore.NewAPIBlockstore(s.delegate)), state.PreCommittedSectors) + if err != nil { + return nil, err + } + + var pci miner.SectorPreCommitOnChainInfo + ok, err := precommits.Get(adt.UIntKey(uint64(sectorNumber)), &pci) + if err != nil { + return nil, err + } + if !ok { + return nil, nil + } + + return &pci, nil +} + +func (s SealingAPIAdapter) StateSectorGetInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok sealing.TipSetToken) (*miner.SectorOnChainInfo, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return nil, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err) + } + + return s.delegate.StateSectorGetInfo(ctx, maddr, sectorNumber, tsk) +} + +func (s SealingAPIAdapter) StateMarketStorageDeal(ctx context.Context, dealID abi.DealID, tok sealing.TipSetToken) (market.DealProposal, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return market.DealProposal{}, err + } + + deal, err := s.delegate.StateMarketStorageDeal(ctx, dealID, tsk) + if err != nil { + return market.DealProposal{}, err + } + + return deal.Proposal, nil +} + +func (s SealingAPIAdapter) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, gasPrice big.Int, gasLimit int64, params []byte) (cid.Cid, error) { + msg := types.Message{ + To: to, + From: from, + Value: value, + GasPrice: gasPrice, + GasLimit: gasLimit, + Method: method, + Params: params, + } + + smsg, err := s.delegate.MpoolPushMessage(ctx, &msg) + if err != nil { + return cid.Undef, err + } + + return smsg.Cid(), nil +} + +func (s SealingAPIAdapter) ChainHead(ctx context.Context) (sealing.TipSetToken, abi.ChainEpoch, error) { + head, err := s.delegate.ChainHead(ctx) + if err != nil { + return nil, 0, err + } + + return head.Key().Bytes(), head.Height(), nil +} + +func (s SealingAPIAdapter) ChainGetRandomness(ctx context.Context, tok sealing.TipSetToken, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) { + tsk, err := types.TipSetKeyFromBytes(tok) + if err != nil { + return nil, err + } + + return s.delegate.ChainGetRandomness(ctx, tsk, personalization, randEpoch, entropy) +} + +func (s SealingAPIAdapter) ChainReadObj(ctx context.Context, ocid cid.Cid) ([]byte, error) { + return s.delegate.ChainReadObj(ctx, ocid) +} diff --git a/vendor/github.com/filecoin-project/lotus/storage/miner.go b/vendor/github.com/filecoin-project/lotus/storage/miner.go new file mode 100644 index 0000000000..514af527ad --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/miner.go @@ -0,0 +1,193 @@ +package storage + +import ( + "context" + "errors" + "time" + + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/host" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-storage/storage" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules/dtypes" + sealing "github.com/filecoin-project/storage-fsm" +) + +var log = logging.Logger("storageminer") + +type Miner struct { + api storageMinerApi + h host.Host + sealer sectorstorage.SectorManager + ds datastore.Batching + sc sealing.SectorIDCounter + verif ffiwrapper.Verifier + + maddr address.Address + worker address.Address + + sealing *sealing.Sealing +} + +type storageMinerApi interface { + // Call a read only method on actors (no interaction with the chain required) + StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) + StateMinerDeadlines(ctx context.Context, maddr address.Address, tok types.TipSetKey) (*miner.Deadlines, error) + StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) + StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) + StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) + StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) + StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) + StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error) + StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) // TODO: removeme eventually + StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) + StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) + StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error) + StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) + StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) + + MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) + + ChainHead(context.Context) (*types.TipSet, error) + ChainNotify(context.Context) (<-chan []*api.HeadChange, error) + ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) + ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) + ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) + ChainReadObj(context.Context, cid.Cid) ([]byte, error) + ChainHasObj(context.Context, cid.Cid) (bool, error) + ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) + + WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error) + WalletBalance(context.Context, address.Address) (types.BigInt, error) + WalletHas(context.Context, address.Address) (bool, error) +} + +func NewMiner(api storageMinerApi, maddr, worker address.Address, h host.Host, ds datastore.Batching, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier) (*Miner, error) { + m := &Miner{ + api: api, + h: h, + sealer: sealer, + ds: ds, + sc: sc, + verif: verif, + + maddr: maddr, + worker: worker, + } + + return m, nil +} + +func (m *Miner) Run(ctx context.Context) error { + if err := m.runPreflightChecks(ctx); err != nil { + return xerrors.Errorf("miner preflight checks failed: %w", err) + } + + md, err := m.api.StateMinerProvingDeadline(ctx, m.maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + evts := events.NewEvents(ctx, m.api) + adaptedAPI := NewSealingAPIAdapter(m.api) + pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, 10000000, md.PeriodStart%miner.WPoStProvingPeriod) + m.sealing = sealing.New(adaptedAPI, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp) + + go m.sealing.Run(ctx) //nolint:errcheck // logged intside the function + + return nil +} + +func (m *Miner) Stop(ctx context.Context) error { + return m.sealing.Stop(ctx) +} + +func (m *Miner) runPreflightChecks(ctx context.Context) error { + has, err := m.api.WalletHas(ctx, m.worker) + if err != nil { + return xerrors.Errorf("failed to check wallet for worker key: %w", err) + } + + if !has { + return errors.New("key for worker not found in local wallet") + } + + log.Infof("starting up miner %s, worker addr %s", m.maddr, m.worker) + return nil +} + +type StorageWpp struct { + prover storage.Prover + verifier ffiwrapper.Verifier + miner abi.ActorID + winnRpt abi.RegisteredPoStProof +} + +func NewWinningPoStProver(api api.FullNode, prover storage.Prover, verifier ffiwrapper.Verifier, miner dtypes.MinerID) (*StorageWpp, error) { + ma, err := address.NewIDAddress(uint64(miner)) + if err != nil { + return nil, err + } + + mi, err := api.StateMinerInfo(context.TODO(), ma, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("getting sector size: %w", err) + } + + spt, err := ffiwrapper.SealProofTypeFromSectorSize(mi.SectorSize) + if err != nil { + return nil, err + } + + wpt, err := spt.RegisteredWinningPoStProof() + if err != nil { + return nil, err + } + + return &StorageWpp{prover, verifier, abi.ActorID(miner), wpt}, nil +} + +var _ gen.WinningPoStProver = (*StorageWpp)(nil) + +func (wpp *StorageWpp) GenerateCandidates(ctx context.Context, randomness abi.PoStRandomness, eligibleSectorCount uint64) ([]uint64, error) { + start := time.Now() + + cds, err := wpp.verifier.GenerateWinningPoStSectorChallenge(ctx, wpp.winnRpt, wpp.miner, randomness, eligibleSectorCount) + if err != nil { + return nil, xerrors.Errorf("failed to generate candidates: %w", err) + } + log.Infof("Generate candidates took %s (C: %+v)", time.Since(start), cds) + return cds, nil +} + +func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []abi.SectorInfo, rand abi.PoStRandomness) ([]abi.PoStProof, error) { + if build.InsecurePoStValidation { + log.Warn("Generating fake EPost proof! You should only see this while running tests!") + return []abi.PoStProof{{ProofBytes: []byte("valid proof")}}, nil + } + + log.Infof("Computing WinningPoSt ;%+v; %v", ssi, rand) + + start := time.Now() + proof, err := wpp.prover.GenerateWinningPoSt(ctx, wpp.miner, ssi, rand) + if err != nil { + return nil, err + } + log.Infof("GenerateWinningPoSt took %s", time.Since(start)) + return proof, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/storage/mockstorage/preseal.go b/vendor/github.com/filecoin-project/lotus/storage/mockstorage/preseal.go new file mode 100644 index 0000000000..740deb6c9d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/mockstorage/preseal.go @@ -0,0 +1,64 @@ +package mockstorage + +import ( + "github.com/filecoin-project/go-address" + commcid "github.com/filecoin-project/go-fil-commcid" + "github.com/filecoin-project/sector-storage/mock" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/crypto" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/lotus/genesis" + "github.com/filecoin-project/sector-storage/ffiwrapper" + "github.com/filecoin-project/sector-storage/zerocomm" +) + +func PreSeal(ssize abi.SectorSize, maddr address.Address, sectors int) (*genesis.Miner, *types.KeyInfo, error) { + k, err := wallet.GenerateKey(crypto.SigTypeBLS) + if err != nil { + return nil, nil, err + } + + genm := &genesis.Miner{ + Owner: k.Address, + Worker: k.Address, + MarketBalance: big.NewInt(0), + PowerBalance: big.NewInt(0), + SectorSize: ssize, + Sectors: make([]*genesis.PreSeal, sectors), + } + + st, err := ffiwrapper.SealProofTypeFromSectorSize(ssize) + if err != nil { + return nil, nil, err + } + + for i := range genm.Sectors { + preseal := &genesis.PreSeal{} + + preseal.ProofType = st + preseal.CommD = zerocomm.ZeroPieceCommitment(abi.PaddedPieceSize(ssize).Unpadded()) + d, _ := commcid.CIDToPieceCommitmentV1(preseal.CommD) + r := mock.CommDR(d) + preseal.CommR = commcid.ReplicaCommitmentV1ToCID(r[:]) + preseal.SectorID = abi.SectorNumber(i + 1) + preseal.Deal = market.DealProposal{ + PieceCID: preseal.CommD, + PieceSize: abi.PaddedPieceSize(ssize), + Client: maddr, + Provider: maddr, + StartEpoch: 1, + EndEpoch: 10000, + StoragePricePerEpoch: big.Zero(), + ProviderCollateral: big.Zero(), + ClientCollateral: big.Zero(), + } + + genm.Sectors[i] = preseal + } + + return genm, &k.KeyInfo, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/storage/sealing.go b/vendor/github.com/filecoin-project/lotus/storage/sealing.go new file mode 100644 index 0000000000..f5716e85d9 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/sealing.go @@ -0,0 +1,45 @@ +package storage + +import ( + "context" + "io" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + + sealing "github.com/filecoin-project/storage-fsm" +) + +// TODO: refactor this to be direct somehow + +func (m *Miner) Address() address.Address { + return m.sealing.Address() +} + +func (m *Miner) AllocatePiece(size abi.UnpaddedPieceSize) (sectorID abi.SectorNumber, offset uint64, err error) { + return m.sealing.AllocatePiece(size) +} + +func (m *Miner) SealPiece(ctx context.Context, size abi.UnpaddedPieceSize, r io.Reader, sectorID abi.SectorNumber, d sealing.DealInfo) error { + return m.sealing.SealPiece(ctx, size, r, sectorID, d) +} + +func (m *Miner) ListSectors() ([]sealing.SectorInfo, error) { + return m.sealing.ListSectors() +} + +func (m *Miner) GetSectorInfo(sid abi.SectorNumber) (sealing.SectorInfo, error) { + return m.sealing.GetSectorInfo(sid) +} + +func (m *Miner) PledgeSector() error { + return m.sealing.PledgeSector() +} + +func (m *Miner) ForceSectorState(ctx context.Context, id abi.SectorNumber, state sealing.SectorState) error { + return m.sealing.ForceSectorState(ctx, id, state) +} + +func (m *Miner) RemoveSector(ctx context.Context, id abi.SectorNumber) error { + return m.sealing.Remove(ctx, id) +} diff --git a/vendor/github.com/filecoin-project/lotus/storage/sectorblocks/blocks.go b/vendor/github.com/filecoin-project/lotus/storage/sectorblocks/blocks.go new file mode 100644 index 0000000000..5b4b3e3c43 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/sectorblocks/blocks.go @@ -0,0 +1,172 @@ +package sectorblocks + +import ( + "bytes" + "context" + "encoding/binary" + "errors" + "io" + "sync" + + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + "github.com/ipfs/go-datastore/query" + dshelp "github.com/ipfs/go-ipfs-ds-help" + "golang.org/x/xerrors" + + cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/go-padreader" + "github.com/filecoin-project/specs-actors/actors/abi" + sealing "github.com/filecoin-project/storage-fsm" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/storage" +) + +type SealSerialization uint8 + +const ( + SerializationUnixfs0 SealSerialization = 'u' +) + +var dsPrefix = datastore.NewKey("/sealedblocks") + +var ErrNotFound = errors.New("not found") + +func DealIDToDsKey(dealID abi.DealID) datastore.Key { + buf := make([]byte, binary.MaxVarintLen64) + size := binary.PutUvarint(buf, uint64(dealID)) + return dshelp.NewKeyFromBinary(buf[:size]) +} + +func DsKeyToDealID(key datastore.Key) (uint64, error) { + buf, err := dshelp.BinaryFromDsKey(key) + if err != nil { + return 0, err + } + dealID, _ := binary.Uvarint(buf) + return dealID, nil +} + +type SectorBlocks struct { + *storage.Miner + + keys datastore.Batching + keyLk sync.Mutex +} + +func NewSectorBlocks(miner *storage.Miner, ds dtypes.MetadataDS) *SectorBlocks { + sbc := &SectorBlocks{ + Miner: miner, + keys: namespace.Wrap(ds, dsPrefix), + } + + return sbc +} + +func (st *SectorBlocks) writeRef(dealID abi.DealID, sectorID abi.SectorNumber, offset uint64, size abi.UnpaddedPieceSize) error { + st.keyLk.Lock() // TODO: make this multithreaded + defer st.keyLk.Unlock() + + v, err := st.keys.Get(DealIDToDsKey(dealID)) + if err == datastore.ErrNotFound { + err = nil + } + if err != nil { + return xerrors.Errorf("getting existing refs: %w", err) + } + + var refs api.SealedRefs + if len(v) > 0 { + if err := cborutil.ReadCborRPC(bytes.NewReader(v), &refs); err != nil { + return xerrors.Errorf("decoding existing refs: %w", err) + } + } + + refs.Refs = append(refs.Refs, api.SealedRef{ + SectorID: sectorID, + Offset: offset, + Size: size, + }) + + newRef, err := cborutil.Dump(&refs) + if err != nil { + return xerrors.Errorf("serializing refs: %w", err) + } + return st.keys.Put(DealIDToDsKey(dealID), newRef) // TODO: batch somehow +} + +func (st *SectorBlocks) AddPiece(ctx context.Context, size abi.UnpaddedPieceSize, r io.Reader, d sealing.DealInfo) (sectorID abi.SectorNumber, err error) { + sectorID, pieceOffset, err := st.Miner.AllocatePiece(padreader.PaddedSize(uint64(size))) + if err != nil { + return 0, err + } + + err = st.writeRef(d.DealID, sectorID, pieceOffset, size) + if err != nil { + return 0, err + } + + return sectorID, st.Miner.SealPiece(ctx, size, r, sectorID, d) +} + +func (st *SectorBlocks) List() (map[uint64][]api.SealedRef, error) { + res, err := st.keys.Query(query.Query{}) + if err != nil { + return nil, err + } + + ents, err := res.Rest() + if err != nil { + return nil, err + } + + out := map[uint64][]api.SealedRef{} + for _, ent := range ents { + dealID, err := DsKeyToDealID(datastore.RawKey(ent.Key)) + if err != nil { + return nil, err + } + + var refs api.SealedRefs + if err := cborutil.ReadCborRPC(bytes.NewReader(ent.Value), &refs); err != nil { + return nil, err + } + + out[dealID] = refs.Refs + } + + return out, nil +} + +func (st *SectorBlocks) GetRefs(dealID abi.DealID) ([]api.SealedRef, error) { // TODO: track local sectors + ent, err := st.keys.Get(DealIDToDsKey(dealID)) + if err == datastore.ErrNotFound { + err = ErrNotFound + } + if err != nil { + return nil, err + } + + var refs api.SealedRefs + if err := cborutil.ReadCborRPC(bytes.NewReader(ent), &refs); err != nil { + return nil, err + } + + return refs.Refs, nil +} + +func (st *SectorBlocks) GetSize(dealID abi.DealID) (uint64, error) { + refs, err := st.GetRefs(dealID) + if err != nil { + return 0, err + } + + return uint64(refs[0].Size), nil +} + +func (st *SectorBlocks) Has(dealID abi.DealID) (bool, error) { + // TODO: ensure sector is still there + return st.keys.Has(DealIDToDsKey(dealID)) +} diff --git a/vendor/github.com/filecoin-project/lotus/storage/wdpost_run.go b/vendor/github.com/filecoin-project/lotus/storage/wdpost_run.go new file mode 100644 index 0000000000..0034e4b5e3 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/wdpost_run.go @@ -0,0 +1,528 @@ +package storage + +import ( + "bytes" + "context" + "errors" + "time" + + "github.com/filecoin-project/go-bitfield" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/crypto" + "go.opencensus.io/trace" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" +) + +var errNoPartitions = errors.New("no partitions") + +func (s *WindowPoStScheduler) failPost(deadline *miner.DeadlineInfo) { + log.Errorf("TODO") + /*s.failLk.Lock() + if eps > s.failed { + s.failed = eps + } + s.failLk.Unlock()*/ +} + +func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *miner.DeadlineInfo, ts *types.TipSet) { + ctx, abort := context.WithCancel(ctx) + + s.abort = abort + s.activeDeadline = deadline + + go func() { + defer abort() + + ctx, span := trace.StartSpan(ctx, "WindowPoStScheduler.doPost") + defer span.End() + + proof, err := s.runPost(ctx, *deadline, ts) + switch err { + case errNoPartitions: + return + case nil: + if err := s.submitPost(ctx, proof); err != nil { + log.Errorf("submitPost failed: %+v", err) + s.failPost(deadline) + return + } + default: + log.Errorf("runPost failed: %+v", err) + s.failPost(deadline) + return + } + }() +} + +func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check *abi.BitField) (*abi.BitField, error) { + spt, err := s.proofType.RegisteredSealProof() + if err != nil { + return nil, xerrors.Errorf("getting seal proof type: %w", err) + } + + mid, err := address.IDFromAddress(s.actor) + if err != nil { + return nil, err + } + + sectors := make(map[abi.SectorID]struct{}) + var tocheck []abi.SectorID + err = check.ForEach(func(snum uint64) error { + s := abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(snum), + } + + tocheck = append(tocheck, s) + sectors[s] = struct{}{} + return nil + }) + if err != nil { + return nil, xerrors.Errorf("iterating over bitfield: %w", err) + } + + bad, err := s.faultTracker.CheckProvable(ctx, spt, tocheck) + if err != nil { + return nil, xerrors.Errorf("checking provable sectors: %w", err) + } + for _, id := range bad { + delete(sectors, id) + } + + log.Warnw("Checked sectors", "checked", len(tocheck), "good", len(sectors)) + + sbf := bitfield.New() + for s := range sectors { + (&sbf).Set(uint64(s.Number)) + } + + return &sbf, nil +} + +func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, deadline uint64, deadlineSectors *abi.BitField, ts *types.TipSet) error { + faults, err := s.api.StateMinerFaults(ctx, s.actor, ts.Key()) + if err != nil { + return xerrors.Errorf("getting on-chain faults: %w", err) + } + + fc, err := faults.Count() + if err != nil { + return xerrors.Errorf("counting faulty sectors: %w", err) + } + + if fc == 0 { + return nil + } + + recov, err := s.api.StateMinerRecoveries(ctx, s.actor, ts.Key()) + if err != nil { + return xerrors.Errorf("getting on-chain recoveries: %w", err) + } + + unrecovered, err := bitfield.SubtractBitField(faults, recov) + if err != nil { + return xerrors.Errorf("subtracting recovered set from fault set: %w", err) + } + + unrecovered, err = bitfield.IntersectBitField(unrecovered, deadlineSectors) + if err != nil { + return xerrors.Errorf("intersect unrecovered set with deadlineSectors: %w", err) + } + + uc, err := unrecovered.Count() + if err != nil { + return xerrors.Errorf("counting unrecovered sectors: %w", err) + } + + if uc == 0 { + return nil + } + + sbf, err := s.checkSectors(ctx, unrecovered) + if err != nil { + return xerrors.Errorf("checking unrecovered sectors: %w", err) + } + + // if all sectors failed to recover, don't declare recoveries + sbfCount, err := sbf.Count() + if err != nil { + return xerrors.Errorf("counting recovered sectors: %w", err) + } + + if sbfCount == 0 { + log.Warnw("No recoveries to declare", "deadline", deadline, "faulty", uc) + return nil + } + + params := &miner.DeclareFaultsRecoveredParams{ + Recoveries: []miner.RecoveryDeclaration{{Deadline: deadline, Sectors: sbf}}, + } + + enc, aerr := actors.SerializeParams(params) + if aerr != nil { + return xerrors.Errorf("could not serialize declare recoveries parameters: %w", aerr) + } + + msg := &types.Message{ + To: s.actor, + From: s.worker, + Method: builtin.MethodsMiner.DeclareFaultsRecovered, + Params: enc, + Value: types.NewInt(0), + GasLimit: 10000000, // i dont know help + GasPrice: types.NewInt(2), + } + + sm, err := s.api.MpoolPushMessage(ctx, msg) + if err != nil { + return xerrors.Errorf("pushing message to mpool: %w", err) + } + + log.Warnw("declare faults recovered Message CID", "cid", sm.Cid()) + + rec, err := s.api.StateWaitMsg(context.TODO(), sm.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("declare faults recovered wait error: %w", err) + } + + if rec.Receipt.ExitCode != 0 { + return xerrors.Errorf("declare faults recovered wait non-0 exit code: %d", rec.Receipt.ExitCode) + } + + return nil +} + +func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, deadline uint64, deadlineSectors *abi.BitField, ts *types.TipSet) error { + dc, err := deadlineSectors.Count() + if err != nil { + return xerrors.Errorf("counting deadline sectors: %w", err) + } + if dc == 0 { + // nothing can become faulty + return nil + } + + toCheck, err := s.getSectorsToProve(ctx, deadlineSectors, true, ts) + if err != nil { + return xerrors.Errorf("getting next sectors to prove: %w", err) + } + + good, err := s.checkSectors(ctx, deadlineSectors) + if err != nil { + return xerrors.Errorf("checking sectors: %w", err) + } + + faulty, err := bitfield.SubtractBitField(toCheck, good) + if err != nil { + return xerrors.Errorf("calculating faulty sector set: %w", err) + } + + c, err := faulty.Count() + if err != nil { + return xerrors.Errorf("counting faulty sectors: %w", err) + } + + if c == 0 { + return nil + } + + log.Errorw("DETECTED FAULTY SECTORS, declaring faults", "count", c) + + params := &miner.DeclareFaultsParams{ + Faults: []miner.FaultDeclaration{ + { + Deadline: deadline, + Sectors: faulty, + }, + }, + } + + enc, aerr := actors.SerializeParams(params) + if aerr != nil { + return xerrors.Errorf("could not serialize declare faults parameters: %w", aerr) + } + + msg := &types.Message{ + To: s.actor, + From: s.worker, + Method: builtin.MethodsMiner.DeclareFaults, + Params: enc, + Value: types.NewInt(0), // TODO: Is there a fee? + GasLimit: 10000000, // i dont know help + GasPrice: types.NewInt(2), + } + + sm, err := s.api.MpoolPushMessage(ctx, msg) + if err != nil { + return xerrors.Errorf("pushing message to mpool: %w", err) + } + + log.Warnw("declare faults Message CID", "cid", sm.Cid()) + + rec, err := s.api.StateWaitMsg(context.TODO(), sm.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("declare faults wait error: %w", err) + } + + if rec.Receipt.ExitCode != 0 { + return xerrors.Errorf("declare faults wait non-0 exit code: %d", rec.Receipt.ExitCode) + } + + return nil +} + +// the input sectors must match with the miner actor +func (s *WindowPoStScheduler) getSectorsToProve(ctx context.Context, deadlineSectors *abi.BitField, ignoreRecoveries bool, ts *types.TipSet) (*abi.BitField, error) { + stateFaults, err := s.api.StateMinerFaults(ctx, s.actor, ts.Key()) + if err != nil { + return nil, xerrors.Errorf("getting on-chain faults: %w", err) + } + + faults, err := bitfield.IntersectBitField(deadlineSectors, stateFaults) + if err != nil { + return nil, xerrors.Errorf("failed to intersect proof sectors with faults: %w", err) + } + + recoveries, err := s.api.StateMinerRecoveries(ctx, s.actor, ts.Key()) + if err != nil { + return nil, xerrors.Errorf("getting on-chain recoveries: %w", err) + } + + if !ignoreRecoveries { + expectedRecoveries, err := bitfield.IntersectBitField(faults, recoveries) + if err != nil { + return nil, xerrors.Errorf("failed to intersect recoveries with faults: %w", err) + } + + faults, err = bitfield.SubtractBitField(faults, expectedRecoveries) + if err != nil { + return nil, xerrors.Errorf("failed to subtract recoveries from faults: %w", err) + } + } + + nonFaults, err := bitfield.SubtractBitField(deadlineSectors, faults) + if err != nil { + return nil, xerrors.Errorf("failed to diff bitfields: %w", err) + } + + empty, err := nonFaults.IsEmpty() + if err != nil { + return nil, xerrors.Errorf("failed to check if bitfield was empty: %w", err) + } + if empty { + return nil, xerrors.Errorf("no non-faulty sectors in partitions: %w", err) + } + + return nonFaults, nil +} + +func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo, ts *types.TipSet) (*miner.SubmitWindowedPoStParams, error) { + ctx, span := trace.StartSpan(ctx, "storage.runPost") + defer span.End() + + deadlines, err := s.api.StateMinerDeadlines(ctx, s.actor, ts.Key()) + if err != nil { + return nil, xerrors.Errorf("getting miner deadlines: %w", err) + } + + { + // check faults / recoveries for the *next* deadline. It's already too + // late to declare them for this deadline + declDeadline := (di.Index + 1) % miner.WPoStPeriodDeadlines + + if err := s.checkNextRecoveries(ctx, declDeadline, deadlines.Due[declDeadline], ts); err != nil { + // TODO: This is potentially quite bad, but not even trying to post when this fails is objectively worse + log.Errorf("checking sector recoveries: %v", err) + } + + if err := s.checkNextFaults(ctx, declDeadline, deadlines.Due[declDeadline], ts); err != nil { + // TODO: This is also potentially really bad, but we try to post anyways + log.Errorf("checking sector faults: %v", err) + } + + } + + buf := new(bytes.Buffer) + if err := s.actor.MarshalCBOR(buf); err != nil { + return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) + } + rand, err := s.api.ChainGetRandomness(ctx, ts.Key(), crypto.DomainSeparationTag_WindowedPoStChallengeSeed, di.Challenge, buf.Bytes()) + if err != nil { + return nil, xerrors.Errorf("failed to get chain randomness for windowPost (ts=%d; deadline=%d): %w", ts.Height(), di, err) + } + + firstPartition, _, err := miner.PartitionsForDeadline(deadlines, s.partitionSectors, di.Index) + if err != nil { + return nil, xerrors.Errorf("getting partitions for deadline: %w", err) + } + + partitionCount, _, err := miner.DeadlineCount(deadlines, s.partitionSectors, di.Index) + if err != nil { + return nil, xerrors.Errorf("getting deadline partition count: %w", err) + } + + dc, err := deadlines.Due[di.Index].Count() + if err != nil { + return nil, xerrors.Errorf("get deadline count: %w", err) + } + + log.Infof("di: %+v", di) + log.Infof("dc: %+v", dc) + log.Infof("fp: %+v", firstPartition) + log.Infof("pc: %+v", partitionCount) + log.Infof("ts: %+v (%d)", ts.Key(), ts.Height()) + + if partitionCount == 0 { + return nil, errNoPartitions + } + + partitions := make([]uint64, partitionCount) + for i := range partitions { + partitions[i] = firstPartition + uint64(i) + } + + nps, err := s.getSectorsToProve(ctx, deadlines.Due[di.Index], false, ts) + if err != nil { + return nil, xerrors.Errorf("get need prove sectors: %w", err) + } + + good, err := s.checkSectors(ctx, nps) + if err != nil { + return nil, xerrors.Errorf("checking sectors to skip: %w", err) + } + + skipped, err := bitfield.SubtractBitField(nps, good) + if err != nil { + return nil, xerrors.Errorf("nps - good: %w", err) + } + + skipCount, err := skipped.Count() + if err != nil { + return nil, xerrors.Errorf("getting skipped sector count: %w", err) + } + + ssi, err := s.sortedSectorInfo(ctx, good, ts) + if err != nil { + return nil, xerrors.Errorf("getting sorted sector info: %w", err) + } + + if len(ssi) == 0 { + log.Warn("attempted to run windowPost without any sectors...") + return nil, xerrors.Errorf("no sectors to run windowPost on") + } + + log.Infow("running windowPost", + "chain-random", rand, + "deadline", di, + "height", ts.Height(), + "skipped", skipCount) + + var snums []abi.SectorNumber + for _, si := range ssi { + snums = append(snums, si.SectorNumber) + } + + tsStart := time.Now() + + log.Infow("generating windowPost", + "sectors", len(ssi)) + + mid, err := address.IDFromAddress(s.actor) + if err != nil { + return nil, err + } + + postOut, postSkipped, err := s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), ssi, abi.PoStRandomness(rand)) + if err != nil { + return nil, xerrors.Errorf("running post failed: %w", err) + } + + if len(postOut) == 0 { + return nil, xerrors.Errorf("received proofs back from generate window post") + } + + for _, sector := range postSkipped { + skipped.Set(uint64(sector.Number)) + } + + elapsed := time.Since(tsStart) + log.Infow("submitting window PoSt", "elapsed", elapsed) + + return &miner.SubmitWindowedPoStParams{ + Deadline: di.Index, + Partitions: partitions, + Proofs: postOut, + Skipped: *skipped, + }, nil +} + +func (s *WindowPoStScheduler) sortedSectorInfo(ctx context.Context, deadlineSectors *abi.BitField, ts *types.TipSet) ([]abi.SectorInfo, error) { + sset, err := s.api.StateMinerSectors(ctx, s.actor, deadlineSectors, false, ts.Key()) + if err != nil { + return nil, err + } + + sbsi := make([]abi.SectorInfo, len(sset)) + for k, sector := range sset { + sbsi[k] = abi.SectorInfo{ + SectorNumber: sector.ID, + SealedCID: sector.Info.Info.SealedCID, + SealProof: sector.Info.Info.SealProof, + } + } + + return sbsi, nil +} + +func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.SubmitWindowedPoStParams) error { + ctx, span := trace.StartSpan(ctx, "storage.commitPost") + defer span.End() + + enc, aerr := actors.SerializeParams(proof) + if aerr != nil { + return xerrors.Errorf("could not serialize submit post parameters: %w", aerr) + } + + msg := &types.Message{ + To: s.actor, + From: s.worker, + Method: builtin.MethodsMiner.SubmitWindowedPoSt, + Params: enc, + Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late + // TODO: Gaslimit needs to be calculated accurately. Before that, use the largest Gaslimit + GasLimit: build.BlockGasLimit, + GasPrice: types.NewInt(1), + } + + // TODO: consider maybe caring about the output + sm, err := s.api.MpoolPushMessage(ctx, msg) + if err != nil { + return xerrors.Errorf("pushing message to mpool: %w", err) + } + + log.Infof("Submitted window post: %s", sm.Cid()) + + go func() { + rec, err := s.api.StateWaitMsg(context.TODO(), sm.Cid(), build.MessageConfidence) + if err != nil { + log.Error(err) + return + } + + if rec.Receipt.ExitCode == 0 { + return + } + + log.Errorf("Submitting window post %s failed: exit %d", sm.Cid(), rec.Receipt.ExitCode) + }() + + return nil +} diff --git a/vendor/github.com/filecoin-project/lotus/storage/wdpost_sched.go b/vendor/github.com/filecoin-project/lotus/storage/wdpost_sched.go new file mode 100644 index 0000000000..077209a4eb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/storage/wdpost_sched.go @@ -0,0 +1,220 @@ +package storage + +import ( + "context" + "time" + + "go.opencensus.io/trace" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + sectorstorage "github.com/filecoin-project/sector-storage" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-storage/storage" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +const StartConfidence = 4 // TODO: config + +type WindowPoStScheduler struct { + api storageMinerApi + prover storage.Prover + faultTracker sectorstorage.FaultTracker + proofType abi.RegisteredPoStProof + partitionSectors uint64 + + actor address.Address + worker address.Address + + cur *types.TipSet + + // if a post is in progress, this indicates for which ElectionPeriodStart + activeDeadline *miner.DeadlineInfo + abort context.CancelFunc + + //failed abi.ChainEpoch // eps + //failLk sync.Mutex +} + +func NewWindowedPoStScheduler(api storageMinerApi, sb storage.Prover, ft sectorstorage.FaultTracker, actor address.Address, worker address.Address) (*WindowPoStScheduler, error) { + mi, err := api.StateMinerInfo(context.TODO(), actor, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("getting sector size: %w", err) + } + + rt, err := mi.SealProofType.RegisteredWindowPoStProof() + if err != nil { + return nil, err + } + + return &WindowPoStScheduler{ + api: api, + prover: sb, + faultTracker: ft, + proofType: rt, + partitionSectors: mi.WindowPoStPartitionSectors, + + actor: actor, + worker: worker, + }, nil +} + +func deadlineEquals(a, b *miner.DeadlineInfo) bool { + if a == nil || b == nil { + return b == a + } + + return a.PeriodStart == b.PeriodStart && a.Index == b.Index && a.Challenge == b.Challenge +} + +func (s *WindowPoStScheduler) Run(ctx context.Context) { + defer s.abortActivePoSt() + + var notifs <-chan []*api.HeadChange + var err error + var gotCur bool + + // not fine to panic after this point + for { + if notifs == nil { + notifs, err = s.api.ChainNotify(ctx) + if err != nil { + log.Errorf("ChainNotify error: %+v") + + time.Sleep(10 * time.Second) + continue + } + + gotCur = false + } + + select { + case changes, ok := <-notifs: + if !ok { + log.Warn("WindowPoStScheduler notifs channel closed") + notifs = nil + continue + } + + if !gotCur { + if len(changes) != 1 { + log.Errorf("expected first notif to have len = 1") + continue + } + if changes[0].Type != store.HCCurrent { + log.Errorf("expected first notif to tell current ts") + continue + } + + if err := s.update(ctx, changes[0].Val); err != nil { + log.Errorf("%+v", err) + } + + gotCur = true + continue + } + + ctx, span := trace.StartSpan(ctx, "WindowPoStScheduler.headChange") + + var lowest, highest *types.TipSet = s.cur, nil + + for _, change := range changes { + if change.Val == nil { + log.Errorf("change.Val was nil") + } + switch change.Type { + case store.HCRevert: + lowest = change.Val + case store.HCApply: + highest = change.Val + } + } + + if err := s.revert(ctx, lowest); err != nil { + log.Error("handling head reverts in windowPost sched: %+v", err) + } + if err := s.update(ctx, highest); err != nil { + log.Error("handling head updates in windowPost sched: %+v", err) + } + + span.End() + case <-ctx.Done(): + return + } + } +} + +func (s *WindowPoStScheduler) revert(ctx context.Context, newLowest *types.TipSet) error { + if s.cur == newLowest { + return nil + } + s.cur = newLowest + + newDeadline, err := s.api.StateMinerProvingDeadline(ctx, s.actor, newLowest.Key()) + if err != nil { + return err + } + + if !deadlineEquals(s.activeDeadline, newDeadline) { + s.abortActivePoSt() + } + + return nil +} + +func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) error { + if new == nil { + return xerrors.Errorf("no new tipset in WindowPoStScheduler.update") + } + + di, err := s.api.StateMinerProvingDeadline(ctx, s.actor, new.Key()) + if err != nil { + return err + } + + if deadlineEquals(s.activeDeadline, di) { + return nil // already working on this deadline + } + + if !di.PeriodStarted() { + return nil // not proving anything yet + } + + s.abortActivePoSt() + + if di.Challenge+StartConfidence >= new.Height() { + log.Info("not starting windowPost yet, waiting for startconfidence", di.Challenge, di.Challenge+StartConfidence, new.Height()) + return nil + } + + /*s.failLk.Lock() + if s.failed > 0 { + s.failed = 0 + s.activeEPS = 0 + } + s.failLk.Unlock()*/ + log.Infof("at %d, doPost for P %d, dd %d", new.Height(), di.PeriodStart, di.Index) + + s.doPost(ctx, di, new) + + return nil +} + +func (s *WindowPoStScheduler) abortActivePoSt() { + if s.activeDeadline == nil { + return // noop + } + + if s.abort != nil { + s.abort() + } + + log.Warnf("Aborting Window PoSt (Deadline: %+v)", s.activeDeadline) + + s.activeDeadline = nil + s.abort = nil +} diff --git a/vendor/github.com/filecoin-project/lotus/tools/dockers/README.md b/vendor/github.com/filecoin-project/lotus/tools/dockers/README.md new file mode 100644 index 0000000000..66bfdc2e35 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/dockers/README.md @@ -0,0 +1,3 @@ +## About + +In [docker-examples/](docker-examples/) are community-contributed Docker and Docker Compose examples. diff --git a/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/README.md b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/README.md new file mode 100644 index 0000000000..24a6c3d2f2 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/README.md @@ -0,0 +1,34 @@ +## About + +In this `docker-examples/` directory are community-contributed Docker and Docker Compose examples. + +#### Example Use Cases + +- **For a miner** + - basic storage miner (`miner-basic-`) + - distributed storage miner +- **For API endpoints for building apps** + - local node for a developer (`api-local-`) + - hosted endpoint for apps / multiple developers (`api-hosted-`) +- **For a local devnet or shared devnet** + - basic local devnet (also see [lotus docs on setting up a local devnet](https://lotu.sh/en+setup-local-dev-net)) + - shared devnet + + +## Contributions + +- `miner-basic-busybox` - from @ldoublewood ([lotus PR 745](https://github.com/filecoin-project/lotus/pull/745)) +- `api-local-arch` - from @mateodelnorte +- `api-hosted-debian-nginx` - from @RTradeLtd + +#### More examples: +- [Issue 1143](https://github.com/filecoin-project/lotus/issues/1143) +- [PR 1047](https://github.com/filecoin-project/lotus/pull/1047/files) + +## Contributing + +:whale: Have a new type of Docker to share? + +Make a PR with a new folder for it, describe its purpose and link to the repo or provide the Docker files. Add it to *Contributions* above. + +:beetle: See a bug? File an Issue so we can keep these up-to-date. diff --git a/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-hosted-debian-nginx/README.md b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-hosted-debian-nginx/README.md new file mode 100644 index 0000000000..b41e399d45 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-hosted-debian-nginx/README.md @@ -0,0 +1,10 @@ +## Description + +- **For API endpoints for building apps** + - hosted endpoint for multiple developers + +Another container spins up a simple block explorer. + +## Repo + +https://github.com/RTradeLtd/lotus-infra \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-local-arch/README.md b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-local-arch/README.md new file mode 100644 index 0000000000..a31403f680 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/api-local-arch/README.md @@ -0,0 +1,8 @@ +## Description + +- **For API endpoints for building apps** + - local node for a developer + +## Repo + +https://github.com/mateodelnorte/filecoin-lotus-docker \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/Dockerfile b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/Dockerfile new file mode 100644 index 0000000000..5464a81bfb --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/Dockerfile @@ -0,0 +1,95 @@ +FROM golang:1.14.1-buster +MAINTAINER ldoublewood + +ENV SRC_DIR /lotus + +RUN apt-get update && apt-get install -y ca-certificates llvm clang mesa-opencl-icd ocl-icd-opencl-dev jq + +RUN curl -sSf https://sh.rustup.rs | sh -s -- -y + + +# Get su-exec, a very minimal tool for dropping privileges, +# and tini, a very minimal init daemon for containers +ENV SUEXEC_VERSION v0.2 +ENV TINI_VERSION v0.18.0 +RUN set -x \ + && cd /tmp \ + && git clone https://github.com/ncopa/su-exec.git \ + && cd su-exec \ + && git checkout -q $SUEXEC_VERSION \ + && make \ + && cd /tmp \ + && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \ + && chmod +x tini + +# Download packages first so they can be cached. +COPY go.mod go.sum $SRC_DIR/ +COPY extern/ $SRC_DIR/extern/ +RUN cd $SRC_DIR \ + && go mod download + +COPY Makefile $SRC_DIR + +# Because extern/filecoin-ffi building script need to get version number from git +COPY .git/ $SRC_DIR/.git/ +COPY .gitmodules $SRC_DIR/ + +# Download dependence first +RUN cd $SRC_DIR \ + && mkdir $SRC_DIR/build \ + && . $HOME/.cargo/env \ + && make clean \ + && make deps + + +COPY . $SRC_DIR + +ARG MAKE_TARGET=all + +# Build the thing. +RUN cd $SRC_DIR \ + && . $HOME/.cargo/env \ + && make $MAKE_TARGET + +# Now comes the actual target image, which aims to be as small as possible. +FROM busybox:1-glibc +MAINTAINER ldoublewood + +# Get the executable binary and TLS CAs from the build container. +ENV SRC_DIR /lotus +COPY --from=0 $SRC_DIR/lotus /usr/local/bin/lotus +COPY --from=0 $SRC_DIR/lotus-* /usr/local/bin/ +COPY --from=0 /tmp/su-exec/su-exec /sbin/su-exec +COPY --from=0 /tmp/tini /sbin/tini +COPY --from=0 /etc/ssl/certs /etc/ssl/certs + + +# This shared lib (part of glibc) doesn't seem to be included with busybox. +COPY --from=0 /lib/x86_64-linux-gnu/libdl-2.28.so /lib/libdl.so.2 +COPY --from=0 /lib/x86_64-linux-gnu/libutil-2.28.so /lib/libutil.so.1 +COPY --from=0 /usr/lib/x86_64-linux-gnu/libOpenCL.so.1.0.0 /lib/libOpenCL.so.1 +COPY --from=0 /lib/x86_64-linux-gnu/librt-2.28.so /lib/librt.so.1 +COPY --from=0 /lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/libgcc_s.so.1 + +# WS port +EXPOSE 1234 +# P2P port +EXPOSE 5678 + + +# Create the home directory and switch to a non-privileged user. +ENV HOME_PATH /data +ENV PARAMCACHE_PATH /var/tmp/filecoin-proof-parameters + +RUN mkdir -p $HOME_PATH $PARAMCACHE_PATH \ + && adduser -D -h $HOME_PATH -u 1000 -G users lotus \ + && chown lotus:users $HOME_PATH $PARAMCACHE_PATH + + +VOLUME $HOME_PATH +VOLUME $PARAMCACHE_PATH + +USER lotus + +# Execute the daemon subcommand by default +CMD ["/sbin/tini", "--", "lotus", "daemon"] diff --git a/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/README.md b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/README.md new file mode 100644 index 0000000000..067f87d10d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/dockers/docker-examples/basic-miner-busybox/README.md @@ -0,0 +1,4 @@ +## Description + +- **For a miner** + - basic storage miner diff --git a/vendor/github.com/filecoin-project/lotus/tools/stats/.gitignore b/vendor/github.com/filecoin-project/lotus/tools/stats/.gitignore new file mode 100644 index 0000000000..07a22a1a0e --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/stats/.gitignore @@ -0,0 +1 @@ +env.stats diff --git a/vendor/github.com/filecoin-project/lotus/tools/stats/collect.go b/vendor/github.com/filecoin-project/lotus/tools/stats/collect.go new file mode 100644 index 0000000000..3d031a4156 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/stats/collect.go @@ -0,0 +1,63 @@ +package stats + +import ( + "context" + "time" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/specs-actors/actors/abi" + client "github.com/influxdata/influxdb1-client/v2" +) + +func Collect(ctx context.Context, api api.FullNode, influx client.Client, database string, height int64, headlag int) { + tipsetsCh, err := GetTips(ctx, api, abi.ChainEpoch(height), headlag) + if err != nil { + log.Fatal(err) + } + + wq := NewInfluxWriteQueue(ctx, influx) + defer wq.Close() + + for tipset := range tipsetsCh { + log.Infow("Collect stats", "height", tipset.Height()) + pl := NewPointList() + height := tipset.Height() + + if err := RecordTipsetPoints(ctx, api, pl, tipset); err != nil { + log.Warnw("Failed to record tipset", "height", height, "error", err) + continue + } + + if err := RecordTipsetMessagesPoints(ctx, api, pl, tipset); err != nil { + log.Warnw("Failed to record messages", "height", height, "error", err) + continue + } + + if err := RecordTipsetStatePoints(ctx, api, pl, tipset); err != nil { + log.Warnw("Failed to record state", "height", height, "error", err) + continue + } + + // Instead of having to pass around a bunch of generic stuff we want for each point + // we will just add them at the end. + + tsTimestamp := time.Unix(int64(tipset.MinTimestamp()), int64(0)) + + nb, err := InfluxNewBatch() + if err != nil { + log.Fatal(err) + } + + for _, pt := range pl.Points() { + pt.SetTime(tsTimestamp) + + nb.AddPoint(NewPointFrom(pt)) + } + + nb.SetDatabase(database) + + log.Infow("Adding points", "count", len(nb.Points()), "height", tipset.Height()) + + wq.AddBatch(nb) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer.go b/vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer.go new file mode 100644 index 0000000000..1c3bf9777c --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer.go @@ -0,0 +1,47 @@ +package stats + +import ( + "container/list" + + "github.com/filecoin-project/lotus/api" +) + +type headBuffer struct { + buffer *list.List + size int +} + +func NewHeadBuffer(size int) *headBuffer { + buffer := list.New() + buffer.Init() + + return &headBuffer{ + buffer: buffer, + size: size, + } +} + +func (h *headBuffer) Push(hc *api.HeadChange) (rethc *api.HeadChange) { + if h.buffer.Len() == h.size { + var ok bool + + el := h.buffer.Front() + rethc, ok = el.Value.(*api.HeadChange) + if !ok { + panic("Value from list is not the correct type") + } + + h.buffer.Remove(el) + } + + h.buffer.PushBack(hc) + + return +} + +func (h *headBuffer) Pop() { + el := h.buffer.Back() + if el != nil { + h.buffer.Remove(el) + } +} diff --git a/vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer_test.go b/vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer_test.go new file mode 100644 index 0000000000..098c90a96d --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/stats/head_buffer_test.go @@ -0,0 +1,43 @@ +package stats + +import ( + "testing" + + "github.com/filecoin-project/lotus/api" + "github.com/stretchr/testify/require" +) + +func TestHeadBuffer(t *testing.T) { + + t.Run("Straight push through", func(t *testing.T) { + hb := NewHeadBuffer(5) + require.Nil(t, hb.Push(&api.HeadChange{Type: "1"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "2"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "3"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "4"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "5"})) + + hc := hb.Push(&api.HeadChange{Type: "6"}) + require.Equal(t, hc.Type, "1") + }) + + t.Run("Reverts", func(t *testing.T) { + hb := NewHeadBuffer(5) + require.Nil(t, hb.Push(&api.HeadChange{Type: "1"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "2"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "3"})) + hb.Pop() + require.Nil(t, hb.Push(&api.HeadChange{Type: "3a"})) + hb.Pop() + require.Nil(t, hb.Push(&api.HeadChange{Type: "3b"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "4"})) + require.Nil(t, hb.Push(&api.HeadChange{Type: "5"})) + + hc := hb.Push(&api.HeadChange{Type: "6"}) + require.Equal(t, hc.Type, "1") + hc = hb.Push(&api.HeadChange{Type: "7"}) + require.Equal(t, hc.Type, "2") + hc = hb.Push(&api.HeadChange{Type: "8"}) + require.Equal(t, hc.Type, "3b") + }) +} diff --git a/vendor/github.com/filecoin-project/lotus/tools/stats/metrics.go b/vendor/github.com/filecoin-project/lotus/tools/stats/metrics.go new file mode 100644 index 0000000000..6263637314 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/stats/metrics.go @@ -0,0 +1,364 @@ +package stats + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "math/big" + "strings" + "time" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/util/adt" + + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" + + cbg "github.com/whyrusleeping/cbor-gen" + + _ "github.com/influxdata/influxdb1-client" + models "github.com/influxdata/influxdb1-client/models" + client "github.com/influxdata/influxdb1-client/v2" + + logging "github.com/ipfs/go-log/v2" +) + +var log = logging.Logger("stats") + +type PointList struct { + points []models.Point +} + +func NewPointList() *PointList { + return &PointList{} +} + +func (pl *PointList) AddPoint(p models.Point) { + pl.points = append(pl.points, p) +} + +func (pl *PointList) Points() []models.Point { + return pl.points +} + +type InfluxWriteQueue struct { + ch chan client.BatchPoints +} + +func NewInfluxWriteQueue(ctx context.Context, influx client.Client) *InfluxWriteQueue { + ch := make(chan client.BatchPoints, 128) + + maxRetries := 10 + + go func() { + main: + for { + select { + case <-ctx.Done(): + return + case batch := <-ch: + for i := 0; i < maxRetries; i++ { + if err := influx.Write(batch); err != nil { + log.Warnw("Failed to write batch", "error", err) + time.Sleep(time.Second * 15) + continue + } + + continue main + } + + log.Error("Dropping batch due to failure to write") + } + } + }() + + return &InfluxWriteQueue{ + ch: ch, + } +} + +func (i *InfluxWriteQueue) AddBatch(bp client.BatchPoints) { + i.ch <- bp +} + +func (i *InfluxWriteQueue) Close() { + close(i.ch) +} + +func InfluxClient(addr, user, pass string) (client.Client, error) { + return client.NewHTTPClient(client.HTTPConfig{ + Addr: addr, + Username: user, + Password: pass, + }) +} + +func InfluxNewBatch() (client.BatchPoints, error) { + return client.NewBatchPoints(client.BatchPointsConfig{}) +} + +func NewPoint(name string, value interface{}) models.Point { + pt, _ := models.NewPoint(name, models.Tags{}, map[string]interface{}{"value": value}, time.Now()) + return pt +} + +func NewPointFrom(p models.Point) *client.Point { + return client.NewPointFrom(p) +} + +func RecordTipsetPoints(ctx context.Context, api api.FullNode, pl *PointList, tipset *types.TipSet) error { + cids := []string{} + for _, cid := range tipset.Cids() { + cids = append(cids, cid.String()) + } + + p := NewPoint("chain.height", int64(tipset.Height())) + p.AddTag("tipset", strings.Join(cids, " ")) + pl.AddPoint(p) + + p = NewPoint("chain.block_count", len(cids)) + pl.AddPoint(p) + + tsTime := time.Unix(int64(tipset.MinTimestamp()), int64(0)) + p = NewPoint("chain.blocktime", tsTime.Unix()) + pl.AddPoint(p) + + for _, blockheader := range tipset.Blocks() { + bs, err := blockheader.Serialize() + if err != nil { + return err + } + p := NewPoint("chain.election", 1) + p.AddTag("miner", blockheader.Miner.String()) + pl.AddPoint(p) + + p = NewPoint("chain.blockheader_size", len(bs)) + pl.AddPoint(p) + } + + return nil +} + +type apiIpldStore struct { + ctx context.Context + api api.FullNode +} + +func (ht *apiIpldStore) Context() context.Context { + return ht.ctx +} + +func (ht *apiIpldStore) Get(ctx context.Context, c cid.Cid, out interface{}) error { + raw, err := ht.api.ChainReadObj(ctx, c) + if err != nil { + return err + } + + cu, ok := out.(cbg.CBORUnmarshaler) + if ok { + if err := cu.UnmarshalCBOR(bytes.NewReader(raw)); err != nil { + return err + } + return nil + } + + return fmt.Errorf("Object does not implement CBORUnmarshaler") +} + +func (ht *apiIpldStore) Put(ctx context.Context, v interface{}) (cid.Cid, error) { + return cid.Undef, fmt.Errorf("Put is not implemented on apiIpldStore") +} + +func RecordTipsetStatePoints(ctx context.Context, api api.FullNode, pl *PointList, tipset *types.TipSet) error { + pc, err := api.StatePledgeCollateral(ctx, tipset.Key()) + if err != nil { + return err + } + + attoFil := types.NewInt(build.FilecoinPrecision).Int + + pcFil := new(big.Rat).SetFrac(pc.Int, attoFil) + pcFilFloat, _ := pcFil.Float64() + p := NewPoint("chain.pledge_collateral", pcFilFloat) + pl.AddPoint(p) + + netBal, err := api.WalletBalance(ctx, builtin.RewardActorAddr) + if err != nil { + return err + } + + netBalFil := new(big.Rat).SetFrac(netBal.Int, attoFil) + netBalFilFloat, _ := netBalFil.Float64() + p = NewPoint("network.balance", netBalFilFloat) + pl.AddPoint(p) + + totalPower, err := api.StateMinerPower(ctx, address.Address{}, tipset.Key()) + if err != nil { + return err + } + + p = NewPoint("chain.power", totalPower.TotalPower.QualityAdjPower.Int64()) + pl.AddPoint(p) + + powerActor, err := api.StateGetActor(ctx, builtin.StoragePowerActorAddr, tipset.Key()) + if err != nil { + return err + } + + powerRaw, err := api.ChainReadObj(ctx, powerActor.Head) + if err != nil { + return err + } + + var powerActorState power.State + + if err := powerActorState.UnmarshalCBOR(bytes.NewReader(powerRaw)); err != nil { + return fmt.Errorf("failed to unmarshal power actor state: %w", err) + } + + s := &apiIpldStore{ctx, api} + mp, err := adt.AsMap(s, powerActorState.Claims) + if err != nil { + return err + } + + err = mp.ForEach(nil, func(key string) error { + addr, err := address.NewFromBytes([]byte(key)) + if err != nil { + return err + } + + var claim power.Claim + keyerAddr := adt.AddrKey(addr) + mp.Get(keyerAddr, &claim) + + if claim.QualityAdjPower.Int64() == 0 { + return nil + } + + p = NewPoint("chain.miner_power", claim.QualityAdjPower.Int64()) + p.AddTag("miner", addr.String()) + pl.AddPoint(p) + + return nil + }) + if err != nil { + return err + } + + return nil +} + +type msgTag struct { + actor string + method uint64 + exitcode uint8 +} + +func RecordTipsetMessagesPoints(ctx context.Context, api api.FullNode, pl *PointList, tipset *types.TipSet) error { + cids := tipset.Cids() + if len(cids) == 0 { + return fmt.Errorf("no cids in tipset") + } + + msgs, err := api.ChainGetParentMessages(ctx, cids[0]) + if err != nil { + return err + } + + recp, err := api.ChainGetParentReceipts(ctx, cids[0]) + if err != nil { + return err + } + + msgn := make(map[msgTag][]cid.Cid) + + for i, msg := range msgs { + p := NewPoint("chain.message_gasprice", msg.Message.GasPrice.Int64()) + pl.AddPoint(p) + + bs, err := msg.Message.Serialize() + if err != nil { + return err + } + + p = NewPoint("chain.message_size", len(bs)) + pl.AddPoint(p) + + actor, err := api.StateGetActor(ctx, msg.Message.To, tipset.Key()) + if err != nil { + return err + } + + dm, err := multihash.Decode(actor.Code.Hash()) + if err != nil { + continue + } + tag := msgTag{ + actor: string(dm.Digest), + method: uint64(msg.Message.Method), + exitcode: uint8(recp[i].ExitCode), + } + + found := false + for _, c := range msgn[tag] { + if c.Equals(msg.Cid) { + found = true + break + } + } + if !found { + msgn[tag] = append(msgn[tag], msg.Cid) + } + } + + for t, m := range msgn { + p := NewPoint("chain.message_count", len(m)) + p.AddTag("actor", t.actor) + p.AddTag("method", fmt.Sprintf("%d", t.method)) + p.AddTag("exitcode", fmt.Sprintf("%d", t.exitcode)) + pl.AddPoint(p) + + } + + return nil +} + +func ResetDatabase(influx client.Client, database string) error { + log.Info("Resetting database") + q := client.NewQuery(fmt.Sprintf(`DROP DATABASE "%s"; CREATE DATABASE "%s";`, database, database), "", "") + _, err := influx.Query(q) + return err +} + +func GetLastRecordedHeight(influx client.Client, database string) (int64, error) { + log.Info("Retrieving last record height") + q := client.NewQuery(`SELECT "value" FROM "chain.height" ORDER BY time DESC LIMIT 1`, database, "") + res, err := influx.Query(q) + if err != nil { + return 0, err + } + + if len(res.Results) == 0 { + return 0, fmt.Errorf("No results found for last recorded height") + } + + if len(res.Results[0].Series) == 0 { + return 0, fmt.Errorf("No results found for last recorded height") + } + + height, err := (res.Results[0].Series[0].Values[0][1].(json.Number)).Int64() + if err != nil { + return 0, err + } + + log.Infow("Last record height", "height", height) + + return height, nil +} diff --git a/vendor/github.com/filecoin-project/lotus/tools/stats/rpc.go b/vendor/github.com/filecoin-project/lotus/tools/stats/rpc.go new file mode 100644 index 0000000000..d053ff5614 --- /dev/null +++ b/vendor/github.com/filecoin-project/lotus/tools/stats/rpc.go @@ -0,0 +1,224 @@ +package stats + +import ( + "context" + "net/http" + "time" + + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/specs-actors/actors/abi" + manet "github.com/multiformats/go-multiaddr-net" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/repo" +) + +func getAPI(path string) (string, http.Header, error) { + r, err := repo.NewFS(path) + if err != nil { + return "", nil, err + } + + ma, err := r.APIEndpoint() + if err != nil { + return "", nil, xerrors.Errorf("failed to get api endpoint: %w", err) + } + _, addr, err := manet.DialArgs(ma) + if err != nil { + return "", nil, err + } + var headers http.Header + token, err := r.APIToken() + if err != nil { + log.Warnw("Couldn't load CLI token, capabilities may be limited", "error", err) + } else { + headers = http.Header{} + headers.Add("Authorization", "Bearer "+string(token)) + } + + return "ws://" + addr + "/rpc/v0", headers, nil +} + +func WaitForSyncComplete(ctx context.Context, napi api.FullNode) error { +sync_complete: + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(5 * time.Second): + state, err := napi.SyncState(ctx) + if err != nil { + return err + } + + for i, w := range state.ActiveSyncs { + if w.Target == nil { + continue + } + + if w.Stage == api.StageSyncErrored { + log.Errorw( + "Syncing", + "worker", i, + "base", w.Base.Key(), + "target", w.Target.Key(), + "target_height", w.Target.Height(), + "height", w.Height, + "error", w.Message, + "stage", chain.SyncStageString(w.Stage), + ) + } else { + log.Infow( + "Syncing", + "worker", i, + "base", w.Base.Key(), + "target", w.Target.Key(), + "target_height", w.Target.Height(), + "height", w.Height, + "stage", chain.SyncStageString(w.Stage), + ) + } + + if w.Stage == api.StageSyncComplete { + break sync_complete + } + } + } + } + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(5 * time.Second): + head, err := napi.ChainHead(ctx) + if err != nil { + return err + } + + timestampDelta := time.Now().Unix() - int64(head.MinTimestamp()) + + log.Infow( + "Waiting for reasonable head height", + "height", head.Height(), + "timestamp_delta", timestampDelta, + ) + + // If we get within 20 blocks of the current exected block height we + // consider sync complete. Block propagation is not always great but we still + // want to be recording stats as soon as we can + if timestampDelta < int64(build.BlockDelaySecs)*20 { + return nil + } + } + } +} + +func GetTips(ctx context.Context, api api.FullNode, lastHeight abi.ChainEpoch, headlag int) (<-chan *types.TipSet, error) { + chmain := make(chan *types.TipSet) + + hb := NewHeadBuffer(headlag) + + notif, err := api.ChainNotify(ctx) + if err != nil { + return nil, err + } + + go func() { + defer close(chmain) + + ping := time.Tick(30 * time.Second) + + for { + select { + case changes := <-notif: + for _, change := range changes { + log.Infow("Head event", "height", change.Val.Height(), "type", change.Type) + + switch change.Type { + case store.HCCurrent: + tipsets, err := loadTipsets(ctx, api, change.Val, lastHeight) + if err != nil { + log.Info(err) + return + } + + for _, tipset := range tipsets { + chmain <- tipset + } + case store.HCApply: + if out := hb.Push(change); out != nil { + chmain <- out.Val + } + case store.HCRevert: + hb.Pop() + } + } + case <-ping: + log.Info("Running health check") + + cctx, cancel := context.WithTimeout(ctx, 5*time.Second) + + if _, err := api.ID(cctx); err != nil { + log.Error("Health check failed") + cancel() + return + } + + cancel() + + log.Info("Node online") + case <-ctx.Done(): + return + } + } + }() + + return chmain, nil +} + +func loadTipsets(ctx context.Context, api api.FullNode, curr *types.TipSet, lowestHeight abi.ChainEpoch) ([]*types.TipSet, error) { + tipsets := []*types.TipSet{} + for { + if curr.Height() == 0 { + break + } + + if curr.Height() <= lowestHeight { + break + } + + log.Infow("Walking back", "height", curr.Height()) + tipsets = append(tipsets, curr) + + tsk := curr.Parents() + prev, err := api.ChainGetTipSet(ctx, tsk) + if err != nil { + return tipsets, err + } + + curr = prev + } + + for i, j := 0, len(tipsets)-1; i < j; i, j = i+1, j-1 { + tipsets[i], tipsets[j] = tipsets[j], tipsets[i] + } + + return tipsets, nil +} + +func GetFullNodeAPI(repo string) (api.FullNode, jsonrpc.ClientCloser, error) { + addr, headers, err := getAPI(repo) + if err != nil { + return nil, nil, err + } + + return client.NewFullNodeRPC(addr, headers) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/.circleci/config.yml b/vendor/github.com/filecoin-project/specs-actors/.circleci/config.yml new file mode 100644 index 0000000000..01488bc5fd --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/.circleci/config.yml @@ -0,0 +1,124 @@ +version: 2.1 +orbs: + go: gotest/tools@0.0.9 + codecov: codecov/codecov@1.0.2 + +executors: + golang: + docker: + - image: circleci/golang:1.13 + resource_class: small + +commands: + install-deps: + steps: + - go/install-ssh + - go/install: {package: git} + prepare: + parameters: + linux: + default: true + description: is a linux build environment? + type: boolean + steps: + - checkout + - when: + condition: << parameters.linux >> + steps: + - run: sudo apt-get update + build-all: + + +jobs: + mod-tidy-check: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - go/mod-tidy-check + + build-all: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - run: sudo apt-get update + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - run: + command: make build + - store_artifacts: + path: specs-actors + - store_artifacts: + path: specs-actors + + test-all: + executor: golang + steps: + - install-deps + - prepare + - go/mod-download + - run: sudo apt-get update + - restore_cache: + name: restore go mod cache + key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }} + - run: + command: | + make test-coverage + mkdir -p /tmp/artifacts + mv coverage.out /tmp/artifacts/coverage.out + - codecov/upload: + file: /tmp/artifacts/coverage.out + - store_artifacts: + path: specs-actors + + lint: &lint + description: | + Run golangci-lint. + parameters: + executor: + type: executor + default: golang + golangci-lint-version: + type: string + default: 1.23.1 + concurrency: + type: string + default: '2' + description: | + Concurrency used to run linters. Defaults to 2 because NumCPU is not + aware of container CPU limits. + args: + type: string + default: '' + description: | + Arguments to pass to golangci-lint + executor: << parameters.executor >> + steps: + - install-deps + - prepare + - run: + command: make build + - go/install-golangci-lint: + gobin: $HOME/.local/bin + version: << parameters.golangci-lint-version >> + - run: + name: Lint + command: | + $HOME/.local/bin/golangci-lint run -v --skip-dirs-use-default=false\ + --concurrency << parameters.concurrency >> << parameters.args >> + + lint-all: + <<: *lint + +workflows: + version: 2.1 + ci: + jobs: + - lint-all + - mod-tidy-check + - build-all + - test-all diff --git a/vendor/github.com/filecoin-project/specs-actors/.codecov.yml b/vendor/github.com/filecoin-project/specs-actors/.codecov.yml new file mode 100644 index 0000000000..91b44cc3d8 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/.codecov.yml @@ -0,0 +1,31 @@ +# Documentation: +# https://docs.codecov.io/docs/codecovyml-reference +# https://docs.codecov.io/docs/pull-request-comments +# https://gist.github.com/stevepeak/53bee7b2c326b24a9b4a + +coverage: + range: 50..90 + round: down + precision: 1 + status: + patch: off + +ignore: + - "**/*/cbor_gen.go" + - "support/**/*" + - "gen/**/*" + +comment: + layout: "diff" # "diff, flags, files" + behavior: default + require_changes: false # if true: only post the comment if coverage changes + require_base: true # [yes :: must have a base report to post] + require_head: true # [yes :: must have a head report to post] + branches: [] # branch names that can post comment + +codecov: + notify: + # yes: will delay sending notifications until all ci is finished + # no: will send notifications without checking ci status and wait till "after_n_builds" are uploaded + require_ci_to_pass: false + diff --git a/vendor/github.com/filecoin-project/specs-actors/CONTRIBUTING.md b/vendor/github.com/filecoin-project/specs-actors/CONTRIBUTING.md new file mode 100644 index 0000000000..a3b191235e --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/CONTRIBUTING.md @@ -0,0 +1,3 @@ +## Contributing + +Please [read the spec process](https://filecoin-project.github.io/specs/#intro__process). Please file PRs on github with fixes. diff --git a/vendor/github.com/filecoin-project/specs-actors/COPYRIGHT b/vendor/github.com/filecoin-project/specs-actors/COPYRIGHT new file mode 100644 index 0000000000..6aa4b36128 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/COPYRIGHT @@ -0,0 +1,3 @@ +Copyright 2020. Protocol Labs, Inc. + +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/vendor/github.com/filecoin-project/specs-actors/LICENSE-APACHE b/vendor/github.com/filecoin-project/specs-actors/LICENSE-APACHE new file mode 100644 index 0000000000..22608cf836 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/LICENSE-APACHE @@ -0,0 +1,13 @@ +Copyright 2020. Protocol Labs, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/filecoin-project/specs-actors/LICENSE-MIT b/vendor/github.com/filecoin-project/specs-actors/LICENSE-MIT new file mode 100644 index 0000000000..c6134ad88a --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright 2020. Protocol Labs, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/filecoin-project/specs-actors/Makefile b/vendor/github.com/filecoin-project/specs-actors/Makefile new file mode 100644 index 0000000000..0b36f0a980 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/Makefile @@ -0,0 +1,29 @@ +GO_BIN ?= go +GOLINT ?= golangci-lint + +all: build lint test tidy +.PHONY: all + +build: + $(GO_BIN) build ./... +.PHONY: build + +test: + $(GO_BIN) test ./... +.PHONY: test + +test-coverage: + $(GO_BIN) test -coverprofile=coverage.out ./... +.PHONY: test-coverage + +tidy: + $(GO_BIN) mod tidy +.PHONY: tidy + +lint: + $(GOLINT) run --skip-dirs-use-default=false ./... +.PHONY: lint + +gen: + $(GO_BIN) run ./gen/gen.go +.PHONY: gen diff --git a/vendor/github.com/filecoin-project/specs-actors/README.md b/vendor/github.com/filecoin-project/specs-actors/README.md new file mode 100644 index 0000000000..c86fd0c3ad --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/README.md @@ -0,0 +1,31 @@ +# Filecoin actors +[![CircleCI](https://circleci.com/gh/filecoin-project/specs-actors.svg?style=svg)](https://circleci.com/gh/filecoin-project/specs-actors) +[![codecov](https://codecov.io/gh/filecoin-project/specs-actors/branch/master/graph/badge.svg)](https://codecov.io/gh/filecoin-project/specs-actors) + +This repo is the specification of the Filecoin builtin actors, in the form of executable code. + +This is a companion to the rest of the [Filecoin Specification](https://github.com/filecoin-project/specs), +but also directly usable by Go implementations of Filecoin. + +## Versioning + +Releases of this repo follow semantic versioning rules, with consideration of distributed state machines. +- The major version will remain `0` or `1` for the forseeable future. + We do not bump the major version every time there's a backwards-incompatible change in state machine evaluation, + or actor interfaces, because this interacts very poorly with Go's module resolution, + requiring a change of all import paths. + After `1.0` we may consider using the major version number to version the `Runtime` interface, which is the link between + the actors and the system in which they are embedded. +- A minor version change indicates a backwards-incompatible change in the state machine evaluation, including + actor exported methods or constant values, while retaining compatibility of the `Runtime` interface. + This means that the same sequence of messages might produce different states at two different versions. + In a blockchain, this would usually require a coordinated network upgrade or "hard fork". + After `1.0`, a minor version change may alter behaviour but not exported code or actor interfaces. +- A patch version change may alter state evaluation (but not exported code or actor interfaces). + After `1.0`, a patch version change indicates a backward compatible fix or improvement that doesn't change + state evaluation semantics or exported interfaces. + +## License +This repository is dual-licensed under Apache 2.0 and MIT terms. + +Copyright 2019-2020. Protocol Labs, Inc. diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int.go new file mode 100644 index 0000000000..05fbf05115 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int.go @@ -0,0 +1,305 @@ +package big + +import ( + "encoding/json" + "fmt" + "io" + "math/big" + + cbg "github.com/whyrusleeping/cbor-gen" +) + +// BigIntMaxSerializedLen is the max length of a byte slice representing a CBOR serialized big. +const BigIntMaxSerializedLen = 128 + +type Int struct { + *big.Int +} + +func NewInt(i int64) Int { + return Int{big.NewInt(0).SetInt64(i)} +} + +func NewIntUnsigned(i uint64) Int { + return Int{big.NewInt(0).SetUint64(i)} +} + +func Zero() Int { + return NewInt(0) +} + +// PositiveFromUnsignedBytes interprets b as the bytes of a big-endian unsigned +// integer and returns a positive Int with this absolute value. +func PositiveFromUnsignedBytes(b []byte) Int { + i := big.NewInt(0).SetBytes(b) + return Int{i} +} + +func FromString(s string) (Int, error) { + v, ok := big.NewInt(0).SetString(s, 10) + if !ok { + return Int{}, fmt.Errorf("failed to parse string as a big int") + } + + return Int{v}, nil +} + +func (bi Int) Copy() Int { + cpy := Int{} + cpy.Int.Set(bi.Int) + return cpy +} + +func Mul(a, b Int) Int { + return Int{big.NewInt(0).Mul(a.Int, b.Int)} +} + +func Div(a, b Int) Int { + return Int{big.NewInt(0).Div(a.Int, b.Int)} +} + +func Mod(a, b Int) Int { + return Int{big.NewInt(0).Mod(a.Int, b.Int)} +} + +func Add(a, b Int) Int { + return Int{big.NewInt(0).Add(a.Int, b.Int)} +} + +func Sum(num1 Int, ints ...Int) Int { + sum := num1 + for _, i := range ints { + sum = Add(sum, i) + } + return sum +} + +func Sub(a, b Int) Int { + return Int{big.NewInt(0).Sub(a.Int, b.Int)} +} + +// Returns a**e unless e <= 0 (in which case returns 1). +func Exp(a Int, e Int) Int { + return Int{big.NewInt(0).Exp(a.Int, e.Int, nil)} +} + +// Returns x << n +func Lsh(a Int, n uint) Int { + return Int{big.NewInt(0).Lsh(a.Int, n)} +} + +// Returns x >> n +func Rsh(a Int, n uint) Int { + return Int{big.NewInt(0).Rsh(a.Int, n)} +} + +func BitLen(a Int) uint { + return uint(a.Int.BitLen()) +} + +func Max(x, y Int) Int { + // taken from max.Max() + if x.Equals(Zero()) && x.Equals(y) { + if x.Sign() != 0 { + return y + } + return x + } + if x.GreaterThan(y) { + return x + } + return y +} + +func Min(x, y Int) Int { + // taken from max.Min() + if x.Equals(Zero()) && x.Equals(y) { + if x.Sign() != 0 { + return x + } + return y + } + if x.LessThan(y) { + return x + } + return y +} + +func Cmp(a, b Int) int { + return a.Int.Cmp(b.Int) +} + +// LessThan returns true if bi < o +func (bi Int) LessThan(o Int) bool { + return Cmp(bi, o) < 0 +} + +// LessThanEqual returns true if bi <= o +func (bi Int) LessThanEqual(o Int) bool { + return bi.LessThan(o) || bi.Equals(o) +} + +// GreaterThan returns true if bi > o +func (bi Int) GreaterThan(o Int) bool { + return Cmp(bi, o) > 0 +} + +// GreaterThanEqual returns true if bi >= o +func (bi Int) GreaterThanEqual(o Int) bool { + return bi.GreaterThan(o) || bi.Equals(o) +} + +// Neg returns the negative of bi. +func (bi Int) Neg() Int { + return Int{big.NewInt(0).Neg(bi.Int)} +} + +// Equals returns true if bi == o +func (bi Int) Equals(o Int) bool { + return Cmp(bi, o) == 0 +} + +func (bi *Int) MarshalJSON() ([]byte, error) { + if bi.Int == nil { + zero := Zero() + return json.Marshal(zero) + } + return json.Marshal(bi.String()) +} + +func (bi *Int) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + i, ok := big.NewInt(0).SetString(s, 10) + if !ok { + return fmt.Errorf("failed to parse big string: '%s'", string(b)) + } + + bi.Int = i + return nil +} + +func (bi *Int) Bytes() ([]byte, error) { + if bi.Int == nil { + return []byte{}, fmt.Errorf("failed to convert to bytes, big is nil") + } + + switch { + case bi.Sign() > 0: + return append([]byte{0}, bi.Int.Bytes()...), nil + case bi.Sign() < 0: + return append([]byte{1}, bi.Int.Bytes()...), nil + default: // bi.Sign() == 0: + return []byte{}, nil + } +} + +func FromBytes(buf []byte) (Int, error) { + if len(buf) == 0 { + return NewInt(0), nil + } + + var negative bool + switch buf[0] { + case 0: + negative = false + case 1: + negative = true + default: + return Zero(), fmt.Errorf("big int prefix should be either 0 or 1, got %d", buf[0]) + } + + i := big.NewInt(0).SetBytes(buf[1:]) + if negative { + i.Neg(i) + } + + return Int{i}, nil +} + +func (bi *Int) MarshalBinary() ([]byte, error) { + if bi.Int == nil { + zero := Zero() + return zero.Bytes() + } + return bi.Bytes() +} + +func (bi *Int) UnmarshalBinary(buf []byte) error { + i, err := FromBytes(buf) + if err != nil { + return err + } + + *bi = i + + return nil +} + +func (bi *Int) MarshalCBOR(w io.Writer) error { + if bi.Int == nil { + zero := Zero() + return zero.MarshalCBOR(w) + } + + enc, err := bi.Bytes() + if err != nil { + return err + } + + header := cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(enc))) + if _, err := w.Write(header); err != nil { + return err + } + + if _, err := w.Write(enc); err != nil { + return err + } + + return nil +} + +func (bi *Int) UnmarshalCBOR(br io.Reader) error { + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + + if maj != cbg.MajByteString { + return fmt.Errorf("cbor input for fil big int was not a byte string (%x)", maj) + } + + if extra == 0 { + bi.Int = big.NewInt(0) + return nil + } + + if extra > BigIntMaxSerializedLen { + return fmt.Errorf("big integer byte array too long") + } + + buf := make([]byte, extra) + if _, err := io.ReadFull(br, buf); err != nil { + return err + } + + i, err := FromBytes(buf) + if err != nil { + return err + } + + *bi = i + + return nil +} + +func (bi *Int) IsZero() bool { + return bi.Int.Sign() == 0 +} + +func (bi *Int) Nil() bool { + return bi.Int == nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int_test.go new file mode 100644 index 0000000000..53e3e0077f --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/big/int_test.go @@ -0,0 +1,157 @@ +package big + +import ( + "bytes" + "fmt" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestBigIntSerializationRoundTrip(t *testing.T) { + testValues := []string{ + "0", "1", "10", "-10", "9999", "12345678901234567891234567890123456789012345678901234567890", + } + + for _, v := range testValues { + bi, err := FromString(v) + if err != nil { + t.Fatal(err) + } + + buf := new(bytes.Buffer) + if err := bi.MarshalCBOR(buf); err != nil { + t.Fatal(err) + } + + var out Int + if err := out.UnmarshalCBOR(buf); err != nil { + t.Fatal(err) + } + + if Cmp(out, bi) != 0 { + t.Fatal("failed to round trip Int through cbor") + } + + } + + // nil check + bi := Int{} + var buf bytes.Buffer + err := bi.MarshalCBOR(&buf) + require.NoError(t, err) + + assert.Equal(t, "@", buf.String()) + +} + +func TestNewInt(t *testing.T) { + a := int64(999) + ta := NewInt(a) + b := big.NewInt(999) + tb := Int{Int: b} + assert.True(t, ta.Equals(tb)) + assert.Equal(t, "999", ta.String()) +} + +func TestInt_MarshalUnmarshalJSON(t *testing.T) { + ta := NewInt(54321) + tb := NewInt(0) + + res, err := ta.MarshalJSON() + require.NoError(t, err) + assert.Equal(t, "\"54321\"", string(res[:])) + + require.NoError(t, tb.UnmarshalJSON(res)) + assert.Equal(t, ta, tb) + + assert.EqualError(t, tb.UnmarshalJSON([]byte("123garbage"[:])), "invalid character 'g' after top-level value") + + tnil := Int{} + s, err := tnil.MarshalJSON() + require.NoError(t, err) + assert.Equal(t, "\"0\"", string(s)) +} + +func TestOperations(t *testing.T) { + testCases := []struct { + name string + f func(Int, Int) Int + expected Int + }{ + {name: "Sum", f: Add, expected: NewInt(7000)}, + {name: "Sub", f: Sub, expected: NewInt(3000)}, + {name: "Mul", f: Mul, expected: NewInt(10000000)}, + {name: "Div", f: Div, expected: NewInt(2)}, + {name: "Mod", f: Mod, expected: NewInt(1000)}, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + ta := Int{Int: big.NewInt(5000)} + tb := Int{Int: big.NewInt(2000)} + assert.Equal(t, testCase.expected, testCase.f(ta, tb)) + }) + } + + ta := NewInt(5000) + tb := NewInt(2000) + tc := NewInt(2000) + assert.Equal(t, Cmp(ta, tb), 1) + assert.Equal(t, Cmp(tb, ta), -1) + assert.Equal(t, Cmp(tb, tc), 0) + assert.True(t, ta.GreaterThan(tb)) + assert.False(t, ta.LessThan(tb)) + assert.True(t, tb.Equals(tc)) + + ta = Int{} + assert.True(t, ta.Nil()) +} + +func TestSum(t *testing.T) { + b1 := NewInt(1) + b2 := NewInt(2) + b3 := NewInt(3) + b4 := NewInt(4) + + require.EqualValues(t, NewInt(10), Sum(b1, b2, b3, b4)) + + require.EqualValues(t, NewInt(20), Sum(NewInt(20))) +} + +func TestInt_Format(t *testing.T) { + ta := NewInt(33333000000) + + s := fmt.Sprintf("%s", ta) // nolint: gosimple + assert.Equal(t, "33333000000", s) + + s1 := fmt.Sprintf("%v", ta) // nolint: gosimple + assert.Equal(t, "33333000000", s1) + + s2 := fmt.Sprintf("%-15d", ta) // nolint: gosimple + assert.Equal(t, "33333000000 ", s2) +} + +func TestPositveFromUnsignedBytes(t *testing.T) { + res := PositiveFromUnsignedBytes([]byte("garbage"[:])) + // garbage in, garbage out + expected := Int{Int: big.NewInt(29099066505914213)} + assert.Equal(t, expected, res) + + expected2 := Int{Int: big.NewInt(12345)} + expectedRes := expected2.Int.Bytes() + res = PositiveFromUnsignedBytes(expectedRes) + assert.Equal(t, expected2, res) + assert.Equal(t, 1, res.Sign()) // positive +} + +func TestFromString(t *testing.T) { + _, err := FromString("garbage") + assert.EqualError(t, err, "failed to parse string as a big int") + + res, err := FromString("12345") + require.NoError(t, err) + expected := Int{Int: big.NewInt(12345)} + assert.Equal(t, expected, res) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield.go new file mode 100644 index 0000000000..25eb825e92 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield.go @@ -0,0 +1,79 @@ +package abi + +import ( + "fmt" + + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-bitfield/rle" +) + +type BitField = bitfield.BitField + +func NewBitField() *BitField { + bf, err := bitfield.NewFromBytes([]byte{}) + if err != nil { + panic(fmt.Sprintf("creating empty rle: %+v", err)) + } + return &bf +} + +func isEmpty(iter rlepluslazy.RunIterator) (bool, error) { + // Look for the first non-zero bit. + for iter.HasNext() { + r, err := iter.NextRun() + if err != nil { + return false, err + } + if r.Val { + return false, nil + } + } + return true, nil +} + +// Checks whether bitfield `a` contains any bit that is set in bitfield `b`. +func BitFieldContainsAny(a, b *BitField) (bool, error) { + aruns, err := a.RunIterator() + if err != nil { + return false, err + } + + bruns, err := b.RunIterator() + if err != nil { + return false, err + } + + // Take the intersection of the two bitfields. + combined, err := rlepluslazy.And(aruns, bruns) + if err != nil { + return false, err + } + + // Look for the first non-zero bit. + empty, err := isEmpty(combined) + if err != nil { + return false, err + } + return !empty, nil +} + +// Checks whether bitfield `a` contains all bits set in bitfield `b`. +func BitFieldContainsAll(a, b *BitField) (bool, error) { + aruns, err := a.RunIterator() + if err != nil { + return false, err + } + + bruns, err := b.RunIterator() + if err != nil { + return false, err + } + + // Remove any elements in a from b. If b contains bits not in a, some + // bits will remain. + combined, err := rlepluslazy.Subtract(bruns, aruns) + if err != nil { + return false, err + } + return isEmpty(combined) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield_test.go new file mode 100644 index 0000000000..1faea73a01 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/bitfield_test.go @@ -0,0 +1,95 @@ +package abi_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/specs-actors/actors/abi" +) + +func TestBitFieldUnset(t *testing.T) { + bf := abi.NewBitField() + bf.Set(1) + bf.Set(2) + bf.Set(3) + bf.Set(4) + bf.Set(5) + + bf.Unset(3) + + m, err := bf.AllMap(100) + assert.NoError(t, err) + _, found := m[3] + assert.False(t, found) + + cnt, err := bf.Count() + assert.NoError(t, err) + assert.Equal(t, uint64(4), cnt) + + bf2 := roundtripMarshal(t, bf) + + cnt, err = bf2.Count() + assert.NoError(t, err) + assert.Equal(t, uint64(4), cnt) + + m, err = bf.AllMap(100) + assert.NoError(t, err) + _, found = m[3] + assert.False(t, found) +} + +func roundtripMarshal(t *testing.T, in *abi.BitField) *abi.BitField { + buf := new(bytes.Buffer) + err := in.MarshalCBOR(buf) + assert.NoError(t, err) + + bf2 := abi.NewBitField() + err = bf2.UnmarshalCBOR(buf) + assert.NoError(t, err) + return bf2 +} + +func TestBitFieldContains(t *testing.T) { + a := abi.NewBitField() + a.Set(2) + a.Set(4) + a.Set(5) + + b := abi.NewBitField() + b.Set(3) + b.Set(4) + + c := abi.NewBitField() + c.Set(2) + c.Set(5) + + assertContainsAny := func(a, b *abi.BitField, expected bool) { + t.Helper() + actual, err := abi.BitFieldContainsAny(a, b) + assert.NoError(t, err) + assert.Equal(t, expected, actual) + } + + assertContainsAll := func(a, b *abi.BitField, expected bool) { + t.Helper() + actual, err := abi.BitFieldContainsAll(a, b) + assert.NoError(t, err) + assert.Equal(t, expected, actual) + } + + assertContainsAny(a, b, true) + assertContainsAny(b, a, true) + assertContainsAny(a, c, true) + assertContainsAny(c, a, true) + assertContainsAny(b, c, false) + assertContainsAny(c, b, false) + + assertContainsAll(a, b, false) + assertContainsAll(b, a, false) + assertContainsAll(a, c, true) + assertContainsAll(c, a, false) + assertContainsAll(b, c, false) + assertContainsAll(c, b, false) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/cbor_gen.go new file mode 100644 index 0000000000..24d86e0dd6 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/cbor_gen.go @@ -0,0 +1,929 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package abi + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *PieceInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Size (abi.PaddedPieceSize) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Size))); err != nil { + return err + } + + // t.PieceCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.PieceCID); err != nil { + return xerrors.Errorf("failed to write cid field t.PieceCID: %w", err) + } + + return nil +} + +func (t *PieceInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Size (abi.PaddedPieceSize) (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.Size = PaddedPieceSize(extra) + + } + // t.PieceCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.PieceCID: %w", err) + } + + t.PieceCID = c + + } + return nil +} + +func (t *SectorID) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Miner (abi.ActorID) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Miner))); err != nil { + return err + } + + // t.Number (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Number))); err != nil { + return err + } + + return nil +} + +func (t *SectorID) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Miner (abi.ActorID) (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.Miner = ActorID(extra) + + } + // t.Number (abi.SectorNumber) (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.Number = SectorNumber(extra) + + } + return nil +} + +func (t *SectorInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.SealProof (abi.RegisteredSealProof) (int64) + if t.SealProof >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealProof))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealProof)-1)); err != nil { + return err + } + } + + // t.SectorNumber (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorNumber))); err != nil { + return err + } + + // t.SealedCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.SealedCID); err != nil { + return xerrors.Errorf("failed to write cid field t.SealedCID: %w", err) + } + + return nil +} + +func (t *SectorInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SealProof (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProof = RegisteredSealProof(extraI) + } + // t.SectorNumber (abi.SectorNumber) (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.SectorNumber = SectorNumber(extra) + + } + // t.SealedCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.SealedCID: %w", err) + } + + t.SealedCID = c + + } + return nil +} + +func (t *SealVerifyInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{136}); err != nil { + return err + } + + // t.SealProof (abi.RegisteredSealProof) (int64) + if t.SealProof >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealProof))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealProof)-1)); err != nil { + return err + } + } + + // t.SectorID (abi.SectorID) (struct) + if err := t.SectorID.MarshalCBOR(w); err != nil { + return err + } + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.Randomness (abi.SealRandomness) (slice) + if len(t.Randomness) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Randomness was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Randomness)))); err != nil { + return err + } + if _, err := w.Write(t.Randomness); err != nil { + return err + } + + // t.InteractiveRandomness (abi.InteractiveSealRandomness) (slice) + if len(t.InteractiveRandomness) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.InteractiveRandomness was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.InteractiveRandomness)))); err != nil { + return err + } + if _, err := w.Write(t.InteractiveRandomness); err != nil { + return err + } + + // t.Proof ([]uint8) (slice) + if len(t.Proof) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Proof was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Proof)))); err != nil { + return err + } + if _, err := w.Write(t.Proof); err != nil { + return err + } + + // t.SealedCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.SealedCID); err != nil { + return xerrors.Errorf("failed to write cid field t.SealedCID: %w", err) + } + + // t.UnsealedCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.UnsealedCID); err != nil { + return xerrors.Errorf("failed to write cid field t.UnsealedCID: %w", err) + } + + return nil +} + +func (t *SealVerifyInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 8 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SealProof (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProof = RegisteredSealProof(extraI) + } + // t.SectorID (abi.SectorID) (struct) + + { + + if err := t.SectorID.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.SectorID: %w", err) + } + + } + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = DealID(val) + } + + // t.Randomness (abi.SealRandomness) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Randomness: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Randomness = make([]byte, extra) + if _, err := io.ReadFull(br, t.Randomness); err != nil { + return err + } + // t.InteractiveRandomness (abi.InteractiveSealRandomness) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.InteractiveRandomness: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.InteractiveRandomness = make([]byte, extra) + if _, err := io.ReadFull(br, t.InteractiveRandomness); err != nil { + return err + } + // t.Proof ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Proof: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Proof = make([]byte, extra) + if _, err := io.ReadFull(br, t.Proof); err != nil { + return err + } + // t.SealedCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.SealedCID: %w", err) + } + + t.SealedCID = c + + } + // t.UnsealedCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.UnsealedCID: %w", err) + } + + t.UnsealedCID = c + + } + return nil +} + +func (t *PoStProof) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.PoStProof (abi.RegisteredPoStProof) (int64) + if t.PoStProof >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.PoStProof))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.PoStProof)-1)); err != nil { + return err + } + } + + // t.ProofBytes ([]uint8) (slice) + if len(t.ProofBytes) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.ProofBytes was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.ProofBytes)))); err != nil { + return err + } + if _, err := w.Write(t.ProofBytes); err != nil { + return err + } + return nil +} + +func (t *PoStProof) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.PoStProof (abi.RegisteredPoStProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.PoStProof = RegisteredPoStProof(extraI) + } + // t.ProofBytes ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.ProofBytes: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.ProofBytes = make([]byte, extra) + if _, err := io.ReadFull(br, t.ProofBytes); err != nil { + return err + } + return nil +} + +func (t *WindowPoStVerifyInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.Randomness (abi.PoStRandomness) (slice) + if len(t.Randomness) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Randomness was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Randomness)))); err != nil { + return err + } + if _, err := w.Write(t.Randomness); err != nil { + return err + } + + // t.Proofs ([]abi.PoStProof) (slice) + if len(t.Proofs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Proofs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Proofs)))); err != nil { + return err + } + for _, v := range t.Proofs { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.ChallengedSectors ([]abi.SectorInfo) (slice) + if len(t.ChallengedSectors) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.ChallengedSectors was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.ChallengedSectors)))); err != nil { + return err + } + for _, v := range t.ChallengedSectors { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.Prover (abi.ActorID) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Prover))); err != nil { + return err + } + + return nil +} + +func (t *WindowPoStVerifyInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Randomness (abi.PoStRandomness) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Randomness: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Randomness = make([]byte, extra) + if _, err := io.ReadFull(br, t.Randomness); err != nil { + return err + } + // t.Proofs ([]abi.PoStProof) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Proofs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Proofs = make([]PoStProof, extra) + } + + for i := 0; i < int(extra); i++ { + + var v PoStProof + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Proofs[i] = v + } + + // t.ChallengedSectors ([]abi.SectorInfo) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.ChallengedSectors: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.ChallengedSectors = make([]SectorInfo, extra) + } + + for i := 0; i < int(extra); i++ { + + var v SectorInfo + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.ChallengedSectors[i] = v + } + + // t.Prover (abi.ActorID) (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.Prover = ActorID(extra) + + } + return nil +} + +func (t *WinningPoStVerifyInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.Randomness (abi.PoStRandomness) (slice) + if len(t.Randomness) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Randomness was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Randomness)))); err != nil { + return err + } + if _, err := w.Write(t.Randomness); err != nil { + return err + } + + // t.Proofs ([]abi.PoStProof) (slice) + if len(t.Proofs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Proofs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Proofs)))); err != nil { + return err + } + for _, v := range t.Proofs { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.ChallengedSectors ([]abi.SectorInfo) (slice) + if len(t.ChallengedSectors) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.ChallengedSectors was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.ChallengedSectors)))); err != nil { + return err + } + for _, v := range t.ChallengedSectors { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.Prover (abi.ActorID) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Prover))); err != nil { + return err + } + + return nil +} + +func (t *WinningPoStVerifyInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Randomness (abi.PoStRandomness) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Randomness: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Randomness = make([]byte, extra) + if _, err := io.ReadFull(br, t.Randomness); err != nil { + return err + } + // t.Proofs ([]abi.PoStProof) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Proofs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Proofs = make([]PoStProof, extra) + } + + for i := 0; i < int(extra); i++ { + + var v PoStProof + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Proofs[i] = v + } + + // t.ChallengedSectors ([]abi.SectorInfo) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.ChallengedSectors: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.ChallengedSectors = make([]SectorInfo, extra) + } + + for i := 0; i < int(extra); i++ { + + var v SectorInfo + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.ChallengedSectors[i] = v + } + + // t.Prover (abi.ActorID) (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.Prover = ActorID(extra) + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/constants.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/constants.go new file mode 100644 index 0000000000..cf885e702c --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/constants.go @@ -0,0 +1,11 @@ +package abi + +import "github.com/filecoin-project/specs-actors/actors/abi/big" + +// Number of token units in an abstract "FIL" token. +// The network works purely in the indivisible token amounts. This constant converts to a fixed decimal with more +// human-friendly scale. +var TokenPrecision = big.NewIntUnsigned(1_000_000_000_000_000_000) + +// The maximum supply of Filecoin that will ever exist (in token units) +var TotalFilecoin = big.Mul(big.NewIntUnsigned(2_000_000_000), TokenPrecision) diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/deal.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/deal.go new file mode 100644 index 0000000000..9e791c4637 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/deal.go @@ -0,0 +1,9 @@ +package abi + +import big "github.com/filecoin-project/specs-actors/actors/abi/big" + +type DealID uint64 + +// BigInt types are aliases rather than new types because the latter introduce incredible amounts of noise converting to +// and from types in order to manipulate values. We give up some type safety for ergonomics. +type DealWeight = big.Int // units: byte-epochs diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/invokee.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/invokee.go new file mode 100644 index 0000000000..c4aca44e3e --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/invokee.go @@ -0,0 +1,5 @@ +package abi + +type Invokee interface { + Exports() []interface{} +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/piece.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/piece.go new file mode 100644 index 0000000000..f54ce568e6 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/piece.go @@ -0,0 +1,50 @@ +package abi + +import ( + "math/bits" + + cid "github.com/ipfs/go-cid" + "github.com/pkg/errors" +) + +// UnpaddedPieceSize is the size of a piece, in bytes +type UnpaddedPieceSize uint64 +type PaddedPieceSize uint64 + +func (s UnpaddedPieceSize) Padded() PaddedPieceSize { + return PaddedPieceSize(s + (s / 127)) +} + +func (s UnpaddedPieceSize) Validate() error { + if s < 127 { + return errors.New("minimum piece size is 127 bytes") + } + + // is 127 * 2^n + if uint64(s)>>bits.TrailingZeros64(uint64(s)) != 127 { + return errors.New("unpadded piece size must be a power of 2 multiple of 127") + } + + return nil +} + +func (s PaddedPieceSize) Unpadded() UnpaddedPieceSize { + return UnpaddedPieceSize(s - (s / 128)) +} + +func (s PaddedPieceSize) Validate() error { + if s < 128 { + return errors.New("minimum padded piece size is 128 bytes") + } + + if bits.OnesCount64(uint64(s)) != 1 { + return errors.New("padded piece size must be a power of 2") + } + + return nil +} + +type PieceInfo struct { + Size PaddedPieceSize // Size in nodes. For BLS12-381 (capacity 254 bits), must be >= 16. (16 * 8 = 128) + PieceCID cid.Cid +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/piece_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/piece_test.go new file mode 100644 index 0000000000..3952bb6be2 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/piece_test.go @@ -0,0 +1,57 @@ +package abi + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPieceSize(t *testing.T) { + // happy + require.NoError(t, UnpaddedPieceSize(127).Validate()) + require.NoError(t, UnpaddedPieceSize(1016).Validate()) + require.NoError(t, UnpaddedPieceSize(34091302912).Validate()) + + require.NoError(t, PaddedPieceSize(128).Validate()) + require.NoError(t, PaddedPieceSize(1024).Validate()) + require.NoError(t, PaddedPieceSize(34359738368).Validate()) + + // convert + require.Equal(t, PaddedPieceSize(128), UnpaddedPieceSize(127).Padded()) + require.Equal(t, PaddedPieceSize(1024), UnpaddedPieceSize(1016).Padded()) + require.Equal(t, PaddedPieceSize(34359738368), UnpaddedPieceSize(34091302912).Padded()) + + require.Equal(t, UnpaddedPieceSize(127), PaddedPieceSize(128).Unpadded()) + require.Equal(t, UnpaddedPieceSize(1016), PaddedPieceSize(1024).Unpadded()) + require.Equal(t, UnpaddedPieceSize(34091302912), PaddedPieceSize(34359738368).Unpadded()) + + // swap + require.NoError(t, UnpaddedPieceSize(127).Padded().Validate()) + require.NoError(t, UnpaddedPieceSize(1016).Padded().Validate()) + require.NoError(t, UnpaddedPieceSize(34091302912).Padded().Validate()) + + require.NoError(t, PaddedPieceSize(128).Unpadded().Validate()) + require.NoError(t, PaddedPieceSize(1024).Unpadded().Validate()) + require.NoError(t, PaddedPieceSize(34359738368).Unpadded().Validate()) + + // roundtrip + require.NoError(t, UnpaddedPieceSize(127).Padded().Unpadded().Validate()) + require.NoError(t, UnpaddedPieceSize(1016).Padded().Unpadded().Validate()) + require.NoError(t, UnpaddedPieceSize(34091302912).Padded().Unpadded().Validate()) + + require.NoError(t, PaddedPieceSize(128).Unpadded().Padded().Validate()) + require.NoError(t, PaddedPieceSize(1024).Unpadded().Padded().Validate()) + require.NoError(t, PaddedPieceSize(34359738368).Unpadded().Padded().Validate()) + + // unhappy + require.Error(t, UnpaddedPieceSize(9).Validate()) + require.Error(t, UnpaddedPieceSize(128).Validate()) + require.Error(t, UnpaddedPieceSize(99453687).Validate()) + require.Error(t, UnpaddedPieceSize(1016+0x1000000).Validate()) + + require.Error(t, PaddedPieceSize(8).Validate()) + require.Error(t, PaddedPieceSize(127).Validate()) + require.Error(t, PaddedPieceSize(99453687).Validate()) + require.Error(t, PaddedPieceSize(0xc00).Validate()) + require.Error(t, PaddedPieceSize(1025).Validate()) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/primitives.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/primitives.go new file mode 100644 index 0000000000..8b892bcd73 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/primitives.go @@ -0,0 +1,68 @@ +package abi + +import ( + "strconv" + + "github.com/filecoin-project/specs-actors/actors/abi/big" +) + +// The abi package contains definitions of all types that cross the VM boundary and are used +// within actor code. +// +// Primitive types include numerics and opaque array types. + +// Epoch number of the chain state, which acts as a proxy for time within the VM. +type ChainEpoch int64 + +func (e ChainEpoch) String() string { + return strconv.FormatInt(int64(e), 10) +} + +// A sequential number assigned to an actor when created by the InitActor. +// This ID is embedded in ID-type addresses. +type ActorID uint64 + +func (e ActorID) String() string { + return strconv.FormatInt(int64(e), 10) +} + +// MethodNum is an integer that represents a particular method +// in an actor's function table. These numbers are used to compress +// invocation of actor code, and to decouple human language concerns +// about method names from the ability to uniquely refer to a particular +// method. +// +// Consider MethodNum numbers to be similar in concerns as for +// offsets in function tables (in programming languages), and for +// tags in ProtocolBuffer fields. Tags in ProtocolBuffers recommend +// assigning a unique tag to a field and never reusing that tag. +// If a field is no longer used, the field name may change but should +// still remain defined in the code to ensure the tag number is not +// reused accidentally. The same should apply to the MethodNum +// associated with methods in Filecoin VM Actors. +type MethodNum uint64 + +func (e MethodNum) String() string { + return strconv.FormatInt(int64(e), 10) +} + +// TokenAmount is an amount of Filecoin tokens. This type is used within +// the VM in message execution, to account movement of tokens, payment +// of VM gas, and more. +// +// BigInt types are aliases rather than new types because the latter introduce incredible amounts of noise converting to +// and from types in order to manipulate values. We give up some type safety for ergonomics. +type TokenAmount = big.Int + +func NewTokenAmount(t int64) TokenAmount { + return big.NewInt(t) +} + +// Randomness is a string of random bytes +type Randomness []byte + +// Multiaddrs is a byte array representing a Libp2p MultiAddress +type Multiaddrs = []byte + +// PeerID is a byte array representing a Libp2p PeerID +type PeerID = []byte diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/sector.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/sector.go new file mode 100644 index 0000000000..b8c77d097f --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/sector.go @@ -0,0 +1,265 @@ +package abi + +import ( + "fmt" + "strconv" + + cid "github.com/ipfs/go-cid" + "github.com/pkg/errors" + + big "github.com/filecoin-project/specs-actors/actors/abi/big" +) + +// SectorNumber is a numeric identifier for a sector. It is usually relative to a miner. +type SectorNumber uint64 + +func (s SectorNumber) String() string { + return strconv.FormatUint(uint64(s), 10) +} + +// SectorSize indicates one of a set of possible sizes in the network. +// Ideally, SectorSize would be an enum +// type SectorSize enum { +// 1KiB = 1024 +// 1MiB = 1048576 +// 1GiB = 1073741824 +// 1TiB = 1099511627776 +// 1PiB = 1125899906842624 +// 1EiB = 1152921504606846976 +// max = 18446744073709551615 +// } +type SectorSize uint64 + +// Formats the size as a decimal string. +func (s SectorSize) String() string { + return strconv.FormatUint(uint64(s), 10) +} + +// Abbreviates the size as a human-scale number. +// This approximates (truncates) the size unless it is a power of 1024. +func (s SectorSize) ShortString() string { + var biUnits = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"} + unit := 0 + for s >= 1024 && unit < len(biUnits)-1 { + s /= 1024 + unit++ + } + return fmt.Sprintf("%d%s", s, biUnits[unit]) +} + +type SectorID struct { + Miner ActorID + Number SectorNumber +} + +// The unit of storage power (measured in bytes) +type StoragePower = big.Int + +type SectorQuality = big.Int + +func NewStoragePower(n int64) StoragePower { + return big.NewInt(n) +} + +type RegisteredProof = int64 + +// This ordering, defines mappings to UInt in a way which MUST never change. +type RegisteredSealProof RegisteredProof + +const ( + RegisteredSealProof_StackedDrg2KiBV1 = RegisteredSealProof(0) + RegisteredSealProof_StackedDrg8MiBV1 = RegisteredSealProof(1) + RegisteredSealProof_StackedDrg512MiBV1 = RegisteredSealProof(2) + RegisteredSealProof_StackedDrg32GiBV1 = RegisteredSealProof(3) + RegisteredSealProof_StackedDrg64GiBV1 = RegisteredSealProof(4) +) + +type RegisteredPoStProof RegisteredProof + +const ( + RegisteredPoStProof_StackedDrgWinning2KiBV1 = RegisteredPoStProof(0) + RegisteredPoStProof_StackedDrgWinning8MiBV1 = RegisteredPoStProof(1) + RegisteredPoStProof_StackedDrgWinning512MiBV1 = RegisteredPoStProof(2) + RegisteredPoStProof_StackedDrgWinning32GiBV1 = RegisteredPoStProof(3) + RegisteredPoStProof_StackedDrgWinning64GiBV1 = RegisteredPoStProof(4) + RegisteredPoStProof_StackedDrgWindow2KiBV1 = RegisteredPoStProof(5) + RegisteredPoStProof_StackedDrgWindow8MiBV1 = RegisteredPoStProof(6) + RegisteredPoStProof_StackedDrgWindow512MiBV1 = RegisteredPoStProof(7) + RegisteredPoStProof_StackedDrgWindow32GiBV1 = RegisteredPoStProof(8) + RegisteredPoStProof_StackedDrgWindow64GiBV1 = RegisteredPoStProof(9) +) + +func (p RegisteredPoStProof) RegisteredSealProof() (RegisteredSealProof, error) { + switch p { + case RegisteredPoStProof_StackedDrgWinning2KiBV1, RegisteredPoStProof_StackedDrgWindow2KiBV1: + return RegisteredSealProof_StackedDrg2KiBV1, nil + case RegisteredPoStProof_StackedDrgWinning8MiBV1, RegisteredPoStProof_StackedDrgWindow8MiBV1: + return RegisteredSealProof_StackedDrg8MiBV1, nil + case RegisteredPoStProof_StackedDrgWinning512MiBV1, RegisteredPoStProof_StackedDrgWindow512MiBV1: + return RegisteredSealProof_StackedDrg512MiBV1, nil + case RegisteredPoStProof_StackedDrgWinning32GiBV1, RegisteredPoStProof_StackedDrgWindow32GiBV1: + return RegisteredSealProof_StackedDrg32GiBV1, nil + case RegisteredPoStProof_StackedDrgWinning64GiBV1, RegisteredPoStProof_StackedDrgWindow64GiBV1: + return RegisteredSealProof_StackedDrg64GiBV1, nil + default: + return 0, errors.Errorf("unsupported PoSt proof type: %v", p) + } +} + +func (p RegisteredSealProof) SectorSize() (SectorSize, error) { + switch p { + case RegisteredSealProof_StackedDrg2KiBV1: + return 2 << 10, nil + case RegisteredSealProof_StackedDrg8MiBV1: + return 8 << 20, nil + case RegisteredSealProof_StackedDrg512MiBV1: + return 512 << 20, nil + case RegisteredSealProof_StackedDrg32GiBV1: + return 32 << 30, nil + case RegisteredSealProof_StackedDrg64GiBV1: + return 2 * (32 << 30), nil + default: + return 0, errors.Errorf("unsupported proof type: %v", p) + } +} + +func (p RegisteredPoStProof) SectorSize() (SectorSize, error) { + // Resolve to seal proof and then compute size from that. + sp, err := p.RegisteredSealProof() + if err != nil { + return 0, err + } + return sp.SectorSize() +} + +// Returns the partition size, in sectors, associated with a proof type. +// The partition size is the number of sectors proved in a single PoSt proof. +func (p RegisteredSealProof) WindowPoStPartitionSectors() (uint64, error) { + // These numbers must match those used by the proofs library. + // See https://github.com/filecoin-project/rust-fil-proofs/blob/master/filecoin-proofs/src/constants.rs#L85 + switch p { + case RegisteredSealProof_StackedDrg64GiBV1: + return 2300, nil + case RegisteredSealProof_StackedDrg32GiBV1: + return 2349, nil + case RegisteredSealProof_StackedDrg2KiBV1: + return 2, nil + case RegisteredSealProof_StackedDrg8MiBV1: + return 2, nil + case RegisteredSealProof_StackedDrg512MiBV1: + return 2, nil + default: + return 0, errors.Errorf("unsupported proof type: %v", p) + } +} + +// Returns the partition size, in sectors, associated with a proof type. +// The partition size is the number of sectors proved in a single PoSt proof. +func (p RegisteredPoStProof) WindowPoStPartitionSectors() (uint64, error) { + // Resolve to seal proof and then compute size from that. + sp, err := p.RegisteredSealProof() + if err != nil { + return 0, err + } + return sp.WindowPoStPartitionSectors() +} + +// RegisteredWinningPoStProof produces the PoSt-specific RegisteredProof corresponding +// to the receiving RegisteredProof. +func (p RegisteredSealProof) RegisteredWinningPoStProof() (RegisteredPoStProof, error) { + switch p { + case RegisteredSealProof_StackedDrg64GiBV1: + return RegisteredPoStProof_StackedDrgWinning64GiBV1, nil + case RegisteredSealProof_StackedDrg32GiBV1: + return RegisteredPoStProof_StackedDrgWinning32GiBV1, nil + case RegisteredSealProof_StackedDrg2KiBV1: + return RegisteredPoStProof_StackedDrgWinning2KiBV1, nil + case RegisteredSealProof_StackedDrg8MiBV1: + return RegisteredPoStProof_StackedDrgWinning8MiBV1, nil + case RegisteredSealProof_StackedDrg512MiBV1: + return RegisteredPoStProof_StackedDrgWinning512MiBV1, nil + default: + return 0, errors.Errorf("unsupported mapping from %+v to PoSt-specific RegisteredProof", p) + } +} + +// RegisteredWindowPoStProof produces the PoSt-specific RegisteredProof corresponding +// to the receiving RegisteredProof. +func (p RegisteredSealProof) RegisteredWindowPoStProof() (RegisteredPoStProof, error) { + switch p { + case RegisteredSealProof_StackedDrg64GiBV1: + return RegisteredPoStProof_StackedDrgWindow64GiBV1, nil + case RegisteredSealProof_StackedDrg32GiBV1: + return RegisteredPoStProof_StackedDrgWindow32GiBV1, nil + case RegisteredSealProof_StackedDrg2KiBV1: + return RegisteredPoStProof_StackedDrgWindow2KiBV1, nil + case RegisteredSealProof_StackedDrg8MiBV1: + return RegisteredPoStProof_StackedDrgWindow8MiBV1, nil + case RegisteredSealProof_StackedDrg512MiBV1: + return RegisteredPoStProof_StackedDrgWindow512MiBV1, nil + default: + return 0, errors.Errorf("unsupported mapping from %+v to PoSt-specific RegisteredProof", p) + } +} + +// SectorMaximumLifetime is the maximum duration a sector sealed with this proof may exist between activation and expiration +func (p RegisteredSealProof) SectorMaximumLifetime() ChainEpoch { + // For all Stacked DRG sectors, the max is 5 years + epochsPerYear := 1_262_277 + fiveYears := 5 * epochsPerYear + return ChainEpoch(fiveYears) +} + +/// +/// Sealing +/// + +type SealRandomness Randomness +type InteractiveSealRandomness Randomness + +// Information needed to verify a seal proof. +type SealVerifyInfo struct { + SealProof RegisteredSealProof + SectorID + DealIDs []DealID + Randomness SealRandomness + InteractiveRandomness InteractiveSealRandomness + Proof []byte + SealedCID cid.Cid // CommR + UnsealedCID cid.Cid // CommD +} + +/// +/// PoSting +/// + +type PoStRandomness Randomness + +// Information about a sector necessary for PoSt verification. +type SectorInfo struct { + SealProof RegisteredSealProof // RegisteredProof used when sealing - needs to be mapped to PoSt registered proof when used to verify a PoSt + SectorNumber SectorNumber + SealedCID cid.Cid // CommR +} + +type PoStProof struct { + PoStProof RegisteredPoStProof + ProofBytes []byte +} + +// Information needed to verify a Winning PoSt attached to a block header. +// Note: this is not used within the state machine, but by the consensus/election mechanisms. +type WinningPoStVerifyInfo struct { + Randomness PoStRandomness + Proofs []PoStProof + ChallengedSectors []SectorInfo + Prover ActorID // used to derive 32-byte prover ID +} + +// Information needed to verify a Window PoSt submitted directly to a miner actor. +type WindowPoStVerifyInfo struct { + Randomness PoStRandomness + Proofs []PoStProof + ChallengedSectors []SectorInfo + Prover ActorID // used to derive 32-byte prover ID +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/abi/sector_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/abi/sector_test.go new file mode 100644 index 0000000000..41576c97f2 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/abi/sector_test.go @@ -0,0 +1,38 @@ +package abi_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/specs-actors/actors/abi" +) + +func TestSectorSizeString(t *testing.T) { + assert.Equal(t, "0", abi.SectorSize(0).String()) + assert.Equal(t, "1", abi.SectorSize(1).String()) + assert.Equal(t, "1024", abi.SectorSize(1024).String()) + assert.Equal(t, "1234", abi.SectorSize(1234).String()) + assert.Equal(t, "1125899906842624", abi.SectorSize(1125899906842624).String()) +} + +func TestSectorSizeShortString(t *testing.T) { + kib := uint64(1024) + pib := uint64(1125899906842624) + + assert.Equal(t, "0B", abi.SectorSize(0).ShortString()) + assert.Equal(t, "1B", abi.SectorSize(1).ShortString()) + assert.Equal(t, "1023B", abi.SectorSize(1023).ShortString()) + assert.Equal(t, "1KiB", abi.SectorSize(kib).ShortString()) + assert.Equal(t, "1KiB", abi.SectorSize(kib+1).ShortString()) // truncated + assert.Equal(t, "1KiB", abi.SectorSize(kib*2-1).ShortString()) // truncated + assert.Equal(t, "2KiB", abi.SectorSize(kib*2).ShortString()) + assert.Equal(t, "2KiB", abi.SectorSize(kib*2+1).ShortString()) // truncated + assert.Equal(t, "1023KiB", abi.SectorSize(kib*1023).ShortString()) + assert.Equal(t, "1MiB", abi.SectorSize(1048576).ShortString()) + assert.Equal(t, "1GiB", abi.SectorSize(1073741824).ShortString()) + assert.Equal(t, "1TiB", abi.SectorSize(1099511627776).ShortString()) + assert.Equal(t, "1PiB", abi.SectorSize(pib).ShortString()) + assert.Equal(t, "1EiB", abi.SectorSize(pib*kib).ShortString()) + assert.Equal(t, "10EiB", abi.SectorSize(pib*kib*10).ShortString()) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_actor.go new file mode 100644 index 0000000000..ef335b5beb --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_actor.go @@ -0,0 +1,50 @@ +package account + +import ( + addr "github.com/filecoin-project/go-address" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + 1: a.Constructor, + 2: a.PubkeyAddress, + } +} + +var _ abi.Invokee = Actor{} + +type State struct { + Address addr.Address +} + +func (a Actor) Constructor(rt vmr.Runtime, address *addr.Address) *adt.EmptyValue { + // Account actors are created implicitly by sending a message to a pubkey-style address. + // This constructor is not invoked by the InitActor, but by the system. + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + switch address.Protocol() { + case addr.SECP256K1: + case addr.BLS: + break // ok + default: + rt.Abortf(exitcode.ErrIllegalArgument, "address must use BLS or SECP protocol, got %v", address.Protocol()) + } + st := State{Address: *address} + rt.State().Create(&st) + return nil +} + +// Fetches the pubkey-type address from this actor. +func (a Actor) PubkeyAddress(rt vmr.Runtime, _ *adt.EmptyValue) addr.Address { + rt.ValidateImmediateCallerAcceptAny() + var st State + rt.State().Readonly(&st) + return st.Address +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_test.go new file mode 100644 index 0000000000..678d3b5e84 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/account_test.go @@ -0,0 +1,78 @@ +package account_test + +import ( + "context" + "testing" + + "github.com/filecoin-project/go-address" + "github.com/stretchr/testify/assert" + + 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/runtime/exitcode" + mock "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +type constructorTestCase struct { + desc string + addr address.Address + exitCode exitcode.ExitCode +} + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, account.Actor{}) +} + +func TestAccountactor(t *testing.T) { + actor := account.Actor{} + + receiver := tutil.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver).WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + testCases := []constructorTestCase{ + { + desc: "happy path construct SECP256K1 address", + addr: tutil.NewSECP256K1Addr(t, "secpaddress"), + exitCode: exitcode.Ok, + }, + { + desc: "happy path construct BLS address", + addr: tutil.NewBLSAddr(t, 1), + exitCode: exitcode.Ok, + }, + { + desc: "fail to construct account actor using ID address", + addr: tutil.NewIDAddr(t, 1), + exitCode: exitcode.ErrIllegalArgument, + }, + { + desc: "fail to construct account actor using Actor address", + addr: tutil.NewActorAddr(t, "actoraddress"), + exitCode: exitcode.ErrIllegalArgument, + }, + } + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + rt := builder.Build(t) + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + + if tc.exitCode.IsSuccess() { + rt.Call(actor.Constructor, &tc.addr) + + var st account.State + rt.GetState(&st) + assert.Equal(t, tc.addr, st.Address) + + rt.ExpectValidateCallerAny() + pubkeyAddress := rt.Call(actor.PubkeyAddress, nil).(address.Address) + assert.Equal(t, tc.addr, pubkeyAddress) + } else { + rt.ExpectAbort(tc.exitCode, func() { + rt.Call(actor.Constructor, &tc.addr) + }) + } + rt.Verify() + }) + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/cbor_gen.go new file mode 100644 index 0000000000..b6df873b90 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/account/cbor_gen.go @@ -0,0 +1,56 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package account + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cbor_gen.go new file mode 100644 index 0000000000..b16cddcbe2 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cbor_gen.go @@ -0,0 +1,147 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package builtin + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *MinerAddrs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Owner (address.Address) (struct) + if err := t.Owner.MarshalCBOR(w); err != nil { + return err + } + + // t.Worker (address.Address) (struct) + if err := t.Worker.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *MinerAddrs) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Owner (address.Address) (struct) + + { + + if err := t.Owner.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Owner: %w", err) + } + + } + // t.Worker (address.Address) (struct) + + { + + if err := t.Worker.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Worker: %w", err) + } + + } + return nil +} + +func (t *ConfirmSectorProofsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Sectors ([]abi.SectorNumber) (slice) + if len(t.Sectors) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Sectors was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Sectors)))); err != nil { + return err + } + for _, v := range t.Sectors { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + return nil +} + +func (t *ConfirmSectorProofsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Sectors ([]abi.SectorNumber) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Sectors: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Sectors = make([]abi.SectorNumber, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.Sectors slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.Sectors was not a uint, instead got %d", maj) + } + + t.Sectors[i] = abi.SectorNumber(val) + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/codes.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/codes.go new file mode 100644 index 0000000000..2a64a264f3 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/codes.go @@ -0,0 +1,99 @@ +package builtin + +import ( + "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" +) + +// The built-in actor code IDs +var ( + SystemActorCodeID cid.Cid + InitActorCodeID cid.Cid + CronActorCodeID cid.Cid + AccountActorCodeID cid.Cid + StoragePowerActorCodeID cid.Cid + StorageMinerActorCodeID cid.Cid + StorageMarketActorCodeID cid.Cid + PaymentChannelActorCodeID cid.Cid + MultisigActorCodeID cid.Cid + RewardActorCodeID cid.Cid + VerifiedRegistryActorCodeID cid.Cid + CallerTypesSignable []cid.Cid +) + +func init() { + builder := cid.V1Builder{Codec: cid.Raw, MhType: mh.IDENTITY} + makeBuiltin := func(s string) cid.Cid { + c, err := builder.Sum([]byte(s)) + if err != nil { + panic(err) + } + return c + } + + SystemActorCodeID = makeBuiltin("fil/1/system") + InitActorCodeID = makeBuiltin("fil/1/init") + CronActorCodeID = makeBuiltin("fil/1/cron") + AccountActorCodeID = makeBuiltin("fil/1/account") + StoragePowerActorCodeID = makeBuiltin("fil/1/storagepower") + StorageMinerActorCodeID = makeBuiltin("fil/1/storageminer") + StorageMarketActorCodeID = makeBuiltin("fil/1/storagemarket") + PaymentChannelActorCodeID = makeBuiltin("fil/1/paymentchannel") + MultisigActorCodeID = makeBuiltin("fil/1/multisig") + RewardActorCodeID = makeBuiltin("fil/1/reward") + VerifiedRegistryActorCodeID = makeBuiltin("fil/1/verifiedregistry") + + // Set of actor code types that can represent external signing parties. + CallerTypesSignable = []cid.Cid{AccountActorCodeID, MultisigActorCodeID} +} + +// IsBuiltinActor returns true if the code belongs to an actor defined in this repo. +func IsBuiltinActor(code cid.Cid) bool { + return code.Equals(SystemActorCodeID) || + code.Equals(InitActorCodeID) || + code.Equals(CronActorCodeID) || + code.Equals(AccountActorCodeID) || + code.Equals(StoragePowerActorCodeID) || + code.Equals(StorageMinerActorCodeID) || + code.Equals(StorageMarketActorCodeID) || + code.Equals(PaymentChannelActorCodeID) || + code.Equals(MultisigActorCodeID) || + code.Equals(RewardActorCodeID) || + code.Equals(VerifiedRegistryActorCodeID) +} + +// ActorNameByCode returns the (string) name of the actor given a cid code. +func ActorNameByCode(code cid.Cid) string { + if !code.Defined() { + return "" + } + + names := map[cid.Cid]string{ + SystemActorCodeID: "fil/1/system", + InitActorCodeID: "fil/1/init", + CronActorCodeID: "fil/1/cron", + AccountActorCodeID: "fil/1/account", + StoragePowerActorCodeID: "fil/1/storagepower", + StorageMinerActorCodeID: "fil/1/storageminer", + StorageMarketActorCodeID: "fil/1/storagemarket", + PaymentChannelActorCodeID: "fil/1/paymentchannel", + MultisigActorCodeID: "fil/1/multisig", + RewardActorCodeID: "fil/1/reward", + } + name, ok := names[code] + if !ok { + return "" + } + return name +} + +// Tests whether a code CID represents an actor that can be an external principal: i.e. an account or multisig. +// We could do something more sophisticated here: https://github.com/filecoin-project/specs-actors/issues/178 +func IsPrincipal(code cid.Cid) bool { + for _, c := range CallerTypesSignable { + if c.Equals(code) { + return true + } + } + return false +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cbor_gen.go new file mode 100644 index 0000000000..67eb0da1f9 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cbor_gen.go @@ -0,0 +1,222 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package cron + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Entries ([]cron.Entry) (slice) + if len(t.Entries) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Entries was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Entries)))); err != nil { + return err + } + for _, v := range t.Entries { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Entries ([]cron.Entry) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Entries: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Entries = make([]Entry, extra) + } + + for i := 0; i < int(extra); i++ { + + var v Entry + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Entries[i] = v + } + + return nil +} + +func (t *Entry) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Receiver (address.Address) (struct) + if err := t.Receiver.MarshalCBOR(w); err != nil { + return err + } + + // t.MethodNum (abi.MethodNum) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.MethodNum))); err != nil { + return err + } + + return nil +} + +func (t *Entry) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Receiver (address.Address) (struct) + + { + + if err := t.Receiver.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Receiver: %w", err) + } + + } + // t.MethodNum (abi.MethodNum) (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.MethodNum = abi.MethodNum(extra) + + } + return nil +} + +func (t *ConstructorParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Entries ([]cron.Entry) (slice) + if len(t.Entries) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Entries was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Entries)))); err != nil { + return err + } + for _, v := range t.Entries { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *ConstructorParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Entries ([]cron.Entry) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Entries: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Entries = make([]Entry, extra) + } + + for i := 0; i < int(extra); i++ { + + var v Entry + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Entries[i] = v + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_actor.go new file mode 100644 index 0000000000..3cccafd2ae --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_actor.go @@ -0,0 +1,44 @@ +package cron + +import ( + abi "github.com/filecoin-project/specs-actors/actors/abi" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +// The cron actor is a built-in singleton that sends messages to other registered actors at the end of each epoch. +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.EpochTick, + } +} + +var _ abi.Invokee = Actor{} + +type ConstructorParams struct { + Entries []Entry +} + +func (a Actor) Constructor(rt vmr.Runtime, params *ConstructorParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + rt.State().Create(ConstructState(params.Entries)) + return nil +} + +// Invoked by the system after all other messages in the epoch have been processed. +func (a Actor) EpochTick(rt vmr.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + + var st State + rt.State().Readonly(&st) + for _, entry := range st.Entries { + _, _ = rt.Send(entry.Receiver, entry.MethodNum, nil, abi.NewTokenAmount(0)) + // Any error and return value are ignored. + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_state.go new file mode 100644 index 0000000000..b82c5758f4 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_state.go @@ -0,0 +1,35 @@ +package cron + +import ( + addr "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" +) + +type State struct { + Entries []Entry +} + +type Entry struct { + Receiver addr.Address // The actor to call (must be an ID-address) + MethodNum abi.MethodNum // The method number to call (must accept empty parameters) +} + +func ConstructState(entries []Entry) *State { + return &State{Entries: entries} +} + +// The default entries to install in the cron actor's state at genesis. +func BuiltInEntries() []Entry { + return []Entry{ + { + Receiver: builtin.StoragePowerActorAddr, + MethodNum: builtin.MethodsPower.OnEpochTickEnd, + }, + { + Receiver: builtin.StorageMarketActorAddr, + MethodNum: builtin.MethodsMarket.CronTick, + }, + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_test.go new file mode 100644 index 0000000000..675a33c3d7 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/cron/cron_test.go @@ -0,0 +1,107 @@ +package cron_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + cron "github.com/filecoin-project/specs-actors/actors/builtin/cron" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + mock "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, cron.Actor{}) +} + +func TestConstructor(t *testing.T) { + actor := cronHarness{cron.Actor{}, t} + + receiver := tutil.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver).WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + t.Run("construct with empty entries", func(t *testing.T) { + rt := builder.Build(t) + + var nilCronEntries = []cron.Entry(nil) + actor.constructAndVerify(rt, nilCronEntries...) + + var st cron.State + rt.GetState(&st) + assert.Equal(t, nilCronEntries, st.Entries) + }) + + t.Run("construct with non-empty entries", func(t *testing.T) { + rt := builder.Build(t) + + var cronEntries = []cron.Entry{ + {Receiver: tutil.NewIDAddr(t, 1001), MethodNum: abi.MethodNum(1001)}, + {Receiver: tutil.NewIDAddr(t, 1002), MethodNum: abi.MethodNum(1002)}, + {Receiver: tutil.NewIDAddr(t, 1003), MethodNum: abi.MethodNum(1003)}, + {Receiver: tutil.NewIDAddr(t, 1004), MethodNum: abi.MethodNum(1004)}, + } + actor.constructAndVerify(rt, cronEntries...) + + var st cron.State + rt.GetState(&st) + assert.Equal(t, cronEntries, st.Entries) + }) +} + +func TestEpochTick(t *testing.T) { + actor := cronHarness{cron.Actor{}, t} + + receiver := tutil.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver).WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + t.Run("epoch tick with empty entries", func(t *testing.T) { + rt := builder.Build(t) + + var nilCronEntries = []cron.Entry(nil) + actor.constructAndVerify(rt, nilCronEntries...) + actor.epochTickAndVerify(rt) + }) + + t.Run("epoch tick with non-empty entries", func(t *testing.T) { + rt := builder.Build(t) + + entry1 := cron.Entry{Receiver: tutil.NewIDAddr(t, 1001), MethodNum: abi.MethodNum(1001)} + entry2 := cron.Entry{Receiver: tutil.NewIDAddr(t, 1002), MethodNum: abi.MethodNum(1002)} + entry3 := cron.Entry{Receiver: tutil.NewIDAddr(t, 1003), MethodNum: abi.MethodNum(1003)} + entry4 := cron.Entry{Receiver: tutil.NewIDAddr(t, 1004), MethodNum: abi.MethodNum(1004)} + + actor.constructAndVerify(rt, entry1, entry2, entry3, entry4) + // exit code should not matter + rt.ExpectSend(entry1.Receiver, entry1.MethodNum, nil, big.Zero(), nil, exitcode.Ok) + rt.ExpectSend(entry2.Receiver, entry2.MethodNum, nil, big.Zero(), nil, exitcode.ErrIllegalArgument) + rt.ExpectSend(entry3.Receiver, entry3.MethodNum, nil, big.Zero(), nil, exitcode.ErrInsufficientFunds) + rt.ExpectSend(entry4.Receiver, entry4.MethodNum, nil, big.Zero(), nil, exitcode.ErrForbidden) + actor.epochTickAndVerify(rt) + }) + +} + +type cronHarness struct { + cron.Actor + t testing.TB +} + +func (h *cronHarness) constructAndVerify(rt *mock.Runtime, entries ...cron.Entry) { + params := cron.ConstructorParams{Entries: entries} + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + ret := rt.Call(h.Constructor, ¶ms) + assert.Nil(h.t, ret) + rt.Verify() +} + +func (h *cronHarness) epochTickAndVerify(rt *mock.Runtime) { + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + ret := rt.Call(h.EpochTick, nil) + assert.Nil(h.t, ret) + rt.Verify() +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/exported/actors.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/exported/actors.go new file mode 100644 index 0000000000..1bb7f3cc03 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/exported/actors.go @@ -0,0 +1,85 @@ +package exported + +import ( + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + cid "github.com/ipfs/go-cid" + + "github.com/filecoin-project/specs-actors/actors/builtin/account" + "github.com/filecoin-project/specs-actors/actors/builtin/cron" + init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/builtin/reward" + "github.com/filecoin-project/specs-actors/actors/builtin/system" + "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" +) + +var _ abi.Invokee = BuiltinActor{} + +type BuiltinActor struct { + actor abi.Invokee + code cid.Cid +} + +// Code is the CodeID (cid) of the actor. +func (b BuiltinActor) Code() cid.Cid { + return b.code +} + +// Exports returns a slice of callable Actor methods. +func (b BuiltinActor) Exports() []interface{} { + return b.actor.Exports() +} + +func BuiltinActors() []BuiltinActor { + return []BuiltinActor{ + { + actor: account.Actor{}, + code: builtin.AccountActorCodeID, + }, + { + actor: cron.Actor{}, + code: builtin.CronActorCodeID, + }, + { + actor: init_.Actor{}, + code: builtin.InitActorCodeID, + }, + { + actor: market.Actor{}, + code: builtin.StorageMarketActorCodeID, + }, + { + actor: miner.Actor{}, + code: builtin.StorageMinerActorCodeID, + }, + { + actor: multisig.Actor{}, + code: builtin.MultisigActorCodeID, + }, + { + actor: paych.Actor{}, + code: builtin.PaymentChannelActorCodeID, + }, + { + actor: power.Actor{}, + code: builtin.StoragePowerActorCodeID, + }, + { + actor: reward.Actor{}, + code: builtin.RewardActorCodeID, + }, + { + actor: system.Actor{}, + code: builtin.SystemActorCodeID, + }, + { + actor: verifreg.Actor{}, + code: builtin.VerifiedRegistryActorCodeID, + }, + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/cbor_gen.go new file mode 100644 index 0000000000..551fb31617 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/cbor_gen.go @@ -0,0 +1,287 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package init + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.AddressMap (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.AddressMap); err != nil { + return xerrors.Errorf("failed to write cid field t.AddressMap: %w", err) + } + + // t.NextID (abi.ActorID) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NextID))); err != nil { + return err + } + + // t.NetworkName (string) (string) + if len(t.NetworkName) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.NetworkName was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.NetworkName)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.NetworkName)); err != nil { + return err + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.AddressMap (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.AddressMap: %w", err) + } + + t.AddressMap = c + + } + // t.NextID (abi.ActorID) (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.NextID = abi.ActorID(extra) + + } + // t.NetworkName (string) (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.NetworkName = string(sval) + } + return nil +} + +func (t *ConstructorParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.NetworkName (string) (string) + if len(t.NetworkName) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.NetworkName was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.NetworkName)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.NetworkName)); err != nil { + return err + } + return nil +} + +func (t *ConstructorParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.NetworkName (string) (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.NetworkName = string(sval) + } + return nil +} + +func (t *ExecParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.CodeCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.CodeCID); err != nil { + return xerrors.Errorf("failed to write cid field t.CodeCID: %w", err) + } + + // t.ConstructorParams ([]uint8) (slice) + if len(t.ConstructorParams) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.ConstructorParams was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.ConstructorParams)))); err != nil { + return err + } + if _, err := w.Write(t.ConstructorParams); err != nil { + return err + } + return nil +} + +func (t *ExecParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.CodeCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.CodeCID: %w", err) + } + + t.CodeCID = c + + } + // t.ConstructorParams ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.ConstructorParams: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.ConstructorParams = make([]byte, extra) + if _, err := io.ReadFull(br, t.ConstructorParams); err != nil { + return err + } + return nil +} + +func (t *ExecReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.IDAddress (address.Address) (struct) + if err := t.IDAddress.MarshalCBOR(w); err != nil { + return err + } + + // t.RobustAddress (address.Address) (struct) + if err := t.RobustAddress.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *ExecReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.IDAddress (address.Address) (struct) + + { + + if err := t.IDAddress.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.IDAddress: %w", err) + } + + } + // t.RobustAddress (address.Address) (struct) + + { + + if err := t.RobustAddress.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RobustAddress: %w", err) + } + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor.go new file mode 100644 index 0000000000..a4111c57b2 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor.go @@ -0,0 +1,101 @@ +package init + +import ( + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + runtime "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + autil "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +// The init actor uniquely has the power to create new actors. +// It maintains a table resolving pubkey and temporary actor addresses to the canonical ID-addresses. +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.Exec, + } +} + +var _ abi.Invokee = Actor{} + +type ConstructorParams struct { + NetworkName string +} + +func (a Actor) Constructor(rt runtime.Runtime, params *ConstructorParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + emptyMap, err := adt.MakeEmptyMap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to construct state: %v", err) + } + + st := ConstructState(emptyMap, params.NetworkName) + rt.State().Create(st) + return nil +} + +type ExecParams struct { + CodeCID cid.Cid + ConstructorParams []byte +} + +type ExecReturn struct { + IDAddress addr.Address // The canonical ID-based address for the actor. + RobustAddress addr.Address // A more expensive but re-org-safe address for the newly created actor. +} + +func (a Actor) Exec(rt runtime.Runtime, params *ExecParams) *ExecReturn { + rt.ValidateImmediateCallerAcceptAny() + callerCodeCID, ok := rt.GetActorCodeCID(rt.Message().Caller()) + autil.AssertMsg(ok, "no code for actor at %s", rt.Message().Caller()) + if !canExec(callerCodeCID, params.CodeCID) { + rt.Abortf(exitcode.ErrForbidden, "caller type %v cannot exec actor type %v", callerCodeCID, params.CodeCID) + } + + // Compute a re-org-stable address. + // This address exists for use by messages coming from outside the system, in order to + // stably address the newly created actor even if a chain re-org causes it to end up with + // a different ID. + uniqueAddress := rt.NewActorAddress() + + // Allocate an ID for this actor. + // Store mapping of pubkey or actor address to actor ID + var st State + idAddr := rt.State().Transaction(&st, func() interface{} { + idAddr, err := st.MapAddressToNewID(adt.AsStore(rt), uniqueAddress) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "exec failed: %v", err) + } + return idAddr + }).(addr.Address) + + // Create an empty actor. + rt.CreateActor(params.CodeCID, idAddr) + + // Invoke constructor. + _, code := rt.Send(idAddr, builtin.MethodConstructor, runtime.CBORBytes(params.ConstructorParams), rt.Message().ValueReceived()) + builtin.RequireSuccess(rt, code, "constructor failed") + + return &ExecReturn{idAddr, uniqueAddress} +} + +func canExec(callerCodeID cid.Cid, execCodeID cid.Cid) bool { + switch execCodeID { + case builtin.StorageMinerActorCodeID: + if callerCodeID == builtin.StoragePowerActorCodeID { + return true + } + return false + case builtin.PaymentChannelActorCodeID, builtin.MultisigActorCodeID: + return true + default: + return false + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor_state.go new file mode 100644 index 0000000000..66b08c31a4 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_actor_state.go @@ -0,0 +1,91 @@ +package init + +import ( + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + errors "github.com/pkg/errors" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + autil "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +var ErrAddressNotFound = errors.New("address not found") + +type AddrKey = adt.AddrKey + +type State struct { + AddressMap cid.Cid // HAMT[addr.Address]abi.ActorID + NextID abi.ActorID + NetworkName string +} + +func ConstructState(addressMapRoot cid.Cid, networkName string) *State { + return &State{ + AddressMap: addressMapRoot, + NextID: abi.ActorID(builtin.FirstNonSingletonActorId), + NetworkName: networkName, + } +} + +// ResolveAddress resolves an address to an ID-address, if possible. +// If the provided address is an ID address, it is returned as-is. +// This means that ID-addresses (which should only appear as values, not keys) and singleton actor addresses +// pass through unchanged. +// +// Post-condition: all addresses succesfully returned by this method satisfy `addr.Protocol() == addr.ID`. +func (s *State) ResolveAddress(store adt.Store, address addr.Address) (addr.Address, error) { + // Short-circuit ID address resolution. + if address.Protocol() == addr.ID { + return address, nil + } + + // Lookup address. + m, err := adt.AsMap(store, s.AddressMap) + if err != nil { + return addr.Undef, xerrors.Errorf("failed to load address map: %w", err) + } + + var actorID cbg.CborInt + found, err := m.Get(AddrKey(address), &actorID) + if err != nil { + return addr.Undef, errors.Wrapf(err, "resolve address failed to look up map") + } + if found { + // Reconstruct address from the ActorID. + idAddr, err2 := addr.NewIDAddress(uint64(actorID)) + autil.Assert(err2 == nil) + return idAddr, nil + } + + // Not found. + return addr.Undef, ErrAddressNotFound +} + +// Allocates a new ID address and stores a mapping of the argument address to it. +// Returns the newly-allocated address. +func (s *State) MapAddressToNewID(store adt.Store, address addr.Address) (addr.Address, error) { + actorID := cbg.CborInt(s.NextID) + s.NextID++ + + m, err := adt.AsMap(store, s.AddressMap) + if err != nil { + return addr.Undef, xerrors.Errorf("failed to load address map: %w", err) + } + err = m.Put(AddrKey(address), &actorID) + if err != nil { + return addr.Undef, xerrors.Errorf("map address failed to store entry: %w", err) + } + amr, err := m.Root() + if err != nil { + return addr.Undef, xerrors.Errorf("failed to get address map root: %w", err) + } + s.AddressMap = amr + + idAddr, err := addr.NewIDAddress(uint64(actorID)) + autil.Assert(err == nil) + return idAddr, nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_test.go new file mode 100644 index 0000000000..9e530e5d76 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/init/init_test.go @@ -0,0 +1,232 @@ +package init_test + +import ( + "context" + "testing" + + cid "github.com/ipfs/go-cid" + assert "github.com/stretchr/testify/assert" + + addr "github.com/filecoin-project/go-address" + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" + runtime "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" + mock "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, init_.Actor{}) +} + +func TestConstructor(t *testing.T) { + actor := initHarness{init_.Actor{}, t} + + receiver := tutil.NewIDAddr(t, 1000) + builder := mock.NewBuilder(context.Background(), receiver).WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + rt := builder.Build(t) + actor.constructAndVerify(rt) +} + +func TestExec(t *testing.T) { + actor := initHarness{init_.Actor{}, t} + + receiver := tutil.NewIDAddr(t, 1000) + anne := tutil.NewIDAddr(t, 1001) + builder := mock.NewBuilder(context.Background(), receiver).WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + t.Run("abort actors that cannot call exec", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + actor.execAndVerify(rt, builtin.StoragePowerActorCodeID, []byte{}) + }) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + actor.execAndVerify(rt, cid.Undef, []byte{}) + }) + }) + + var fakeParams = runtime.CBORBytes([]byte{'D', 'E', 'A', 'D', 'B', 'E', 'E', 'F'}) + var balance = abi.NewTokenAmount(100) + + t.Run("happy path exec create 2 payment channels", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt) + // anne execs a payment channel actor with 100 FIL. + rt.SetCaller(anne, builtin.AccountActorCodeID) + + rt.SetBalance(balance) + rt.SetReceived(balance) + + // re-org-stable address of the payment channel actor + uniqueAddr1 := tutil.NewActorAddr(t, "paych") + rt.SetNewActorAddress(uniqueAddr1) + + // next id address + expectedIdAddr1 := tutil.NewIDAddr(t, 100) + rt.ExpectCreateActor(builtin.PaymentChannelActorCodeID, expectedIdAddr1) + + // expect anne creating a payment channel to trigger a send to the payment channels constructor + rt.ExpectSend(expectedIdAddr1, builtin.MethodConstructor, fakeParams, balance, nil, exitcode.Ok) + execRet1 := actor.execAndVerify(rt, builtin.PaymentChannelActorCodeID, fakeParams) + assert.Equal(t, uniqueAddr1, execRet1.RobustAddress) + assert.Equal(t, expectedIdAddr1, execRet1.IDAddress) + + var st init_.State + rt.GetState(&st) + actualIdAddr, err := st.ResolveAddress(adt.AsStore(rt), uniqueAddr1) + assert.NoError(t, err) + assert.Equal(t, expectedIdAddr1, actualIdAddr) + + // creating another actor should get a different address, the below logic is a repeat of the above to insure + // the next ID address created is incremented. 100 -> 101 + rt.SetBalance(balance) + rt.SetReceived(balance) + uniqueAddr2 := tutil.NewActorAddr(t, "paych2") + rt.SetNewActorAddress(uniqueAddr2) + // the incremented ID address. + expectedIdAddr2 := tutil.NewIDAddr(t, 101) + rt.ExpectCreateActor(builtin.PaymentChannelActorCodeID, expectedIdAddr2) + + // expect anne creating a payment channel to trigger a send to the payment channels constructor + rt.ExpectSend(expectedIdAddr2, builtin.MethodConstructor, fakeParams, balance, nil, exitcode.Ok) + execRet2 := actor.execAndVerify(rt, builtin.PaymentChannelActorCodeID, fakeParams) + assert.Equal(t, uniqueAddr2, execRet2.RobustAddress) + assert.Equal(t, expectedIdAddr2, execRet2.IDAddress) + + var st2 init_.State + rt.GetState(&st2) + actualIdAddr2, err := st2.ResolveAddress(adt.AsStore(rt), uniqueAddr2) + assert.NoError(t, err) + assert.Equal(t, expectedIdAddr2, actualIdAddr2) + }) + + t.Run("happy path exec create storage miner", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt) + + // only the storage power actor can create a miner + rt.SetCaller(builtin.StoragePowerActorAddr, builtin.StoragePowerActorCodeID) + + // re-org-stable address of the storage miner actor + uniqueAddr := tutil.NewActorAddr(t, "miner") + rt.SetNewActorAddress(uniqueAddr) + + // next id address + expectedIdAddr := tutil.NewIDAddr(t, 100) + rt.ExpectCreateActor(builtin.StorageMinerActorCodeID, expectedIdAddr) + + // expect storage power actor creating a storage miner actor to trigger a send to the storage miner actors constructor + rt.ExpectSend(expectedIdAddr, builtin.MethodConstructor, fakeParams, big.Zero(), nil, exitcode.Ok) + execRet := actor.execAndVerify(rt, builtin.StorageMinerActorCodeID, fakeParams) + assert.Equal(t, uniqueAddr, execRet.RobustAddress) + assert.Equal(t, expectedIdAddr, execRet.IDAddress) + + var st init_.State + rt.GetState(&st) + actualIdAddr, err := st.ResolveAddress(adt.AsStore(rt), uniqueAddr) + assert.NoError(t, err) + assert.Equal(t, expectedIdAddr, actualIdAddr) + + // returns error if not able to resolve + expUnknowAddr := tutil.NewActorAddr(t, "flurbo") + actualUnknownAddr, err := st.ResolveAddress(adt.AsStore(rt), expUnknowAddr) + assert.Error(t, err) + assert.Equal(t, addr.Undef, actualUnknownAddr) + }) + + t.Run("happy path create multisig actor", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt) + + // actor creating the multisig actor + someAccountActor := tutil.NewIDAddr(t, 1234) + rt.SetCaller(someAccountActor, builtin.AccountActorCodeID) + + uniqueAddr := tutil.NewActorAddr(t, "multisig") + rt.SetNewActorAddress(uniqueAddr) + + // next id address + expectedIdAddr := tutil.NewIDAddr(t, 100) + rt.ExpectCreateActor(builtin.MultisigActorCodeID, expectedIdAddr) + + // expect a send to the multisig actor constructor + rt.ExpectSend(expectedIdAddr, builtin.MethodConstructor, fakeParams, big.Zero(), nil, exitcode.Ok) + execRet := actor.execAndVerify(rt, builtin.MultisigActorCodeID, fakeParams) + assert.Equal(t, uniqueAddr, execRet.RobustAddress) + assert.Equal(t, expectedIdAddr, execRet.IDAddress) + }) + + t.Run("sending to constructor failure", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt) + + // only the storage power actor can create a miner + rt.SetCaller(builtin.StoragePowerActorAddr, builtin.StoragePowerActorCodeID) + + // re-org-stable address of the storage miner actor + uniqueAddr := tutil.NewActorAddr(t, "miner") + rt.SetNewActorAddress(uniqueAddr) + + // next id address + expectedIdAddr := tutil.NewIDAddr(t, 100) + rt.ExpectCreateActor(builtin.StorageMinerActorCodeID, expectedIdAddr) + + // expect storage power actor creating a storage miner actor to trigger a send to the storage miner actors constructor + rt.ExpectSend(expectedIdAddr, builtin.MethodConstructor, fakeParams, big.Zero(), nil, exitcode.ErrIllegalState) + var execRet *init_.ExecReturn + rt.ExpectAbort(exitcode.ErrIllegalState, func() { + execRet = actor.execAndVerify(rt, builtin.StorageMinerActorCodeID, fakeParams) + assert.Nil(t, execRet) + }) + + // since the send failed the uniqueAddr not resolve + var st init_.State + rt.GetState(&st) + noResoAddr, err := st.ResolveAddress(adt.AsStore(rt), uniqueAddr) + assert.Error(t, err) + assert.Equal(t, addr.Undef, noResoAddr) + + }) + +} + +type initHarness struct { + init_.Actor + t testing.TB +} + +func (h *initHarness) constructAndVerify(rt *mock.Runtime) { + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + ret := rt.Call(h.Constructor, &init_.ConstructorParams{NetworkName: "mock"}) + assert.Nil(h.t, ret) + rt.Verify() + + var st init_.State + rt.GetState(&st) + emptyMap, err := adt.AsMap(adt.AsStore(rt), st.AddressMap) + assert.NoError(h.t, err) + assert.Equal(h.t, tutil.MustRoot(h.t, emptyMap), st.AddressMap) + assert.Equal(h.t, abi.ActorID(builtin.FirstNonSingletonActorId), st.NextID) + assert.Equal(h.t, "mock", st.NetworkName) +} + +func (h *initHarness) execAndVerify(rt *mock.Runtime, codeID cid.Cid, constructorParams []byte) *init_.ExecReturn { + rt.ExpectValidateCallerAny() + ret := rt.Call(h.Exec, &init_.ExecParams{ + CodeCID: codeID, + ConstructorParams: constructorParams, + }).(*init_.ExecReturn) + rt.Verify() + return ret +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/cbor_gen.go new file mode 100644 index 0000000000..22cadd1ec6 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/cbor_gen.go @@ -0,0 +1,1406 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package market + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{139}); err != nil { + return err + } + + // t.Proposals (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.Proposals); err != nil { + return xerrors.Errorf("failed to write cid field t.Proposals: %w", err) + } + + // t.States (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.States); err != nil { + return xerrors.Errorf("failed to write cid field t.States: %w", err) + } + + // t.PendingProposals (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.PendingProposals); err != nil { + return xerrors.Errorf("failed to write cid field t.PendingProposals: %w", err) + } + + // t.EscrowTable (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.EscrowTable); err != nil { + return xerrors.Errorf("failed to write cid field t.EscrowTable: %w", err) + } + + // t.LockedTable (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.LockedTable); err != nil { + return xerrors.Errorf("failed to write cid field t.LockedTable: %w", err) + } + + // t.NextID (abi.DealID) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NextID))); err != nil { + return err + } + + // t.DealOpsByEpoch (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.DealOpsByEpoch); err != nil { + return xerrors.Errorf("failed to write cid field t.DealOpsByEpoch: %w", err) + } + + // t.LastCron (abi.ChainEpoch) (int64) + if t.LastCron >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.LastCron))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.LastCron)-1)); err != nil { + return err + } + } + + // t.TotalClientLockedCollateral (big.Int) (struct) + if err := t.TotalClientLockedCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalProviderLockedCollateral (big.Int) (struct) + if err := t.TotalProviderLockedCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalClientStorageFee (big.Int) (struct) + if err := t.TotalClientStorageFee.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 11 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Proposals (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Proposals: %w", err) + } + + t.Proposals = c + + } + // t.States (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.States: %w", err) + } + + t.States = c + + } + // t.PendingProposals (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.PendingProposals: %w", err) + } + + t.PendingProposals = c + + } + // t.EscrowTable (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.EscrowTable: %w", err) + } + + t.EscrowTable = c + + } + // t.LockedTable (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.LockedTable: %w", err) + } + + t.LockedTable = c + + } + // t.NextID (abi.DealID) (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.NextID = abi.DealID(extra) + + } + // t.DealOpsByEpoch (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.DealOpsByEpoch: %w", err) + } + + t.DealOpsByEpoch = c + + } + // t.LastCron (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.LastCron = abi.ChainEpoch(extraI) + } + // t.TotalClientLockedCollateral (big.Int) (struct) + + { + + if err := t.TotalClientLockedCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalClientLockedCollateral: %w", err) + } + + } + // t.TotalProviderLockedCollateral (big.Int) (struct) + + { + + if err := t.TotalProviderLockedCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalProviderLockedCollateral: %w", err) + } + + } + // t.TotalClientStorageFee (big.Int) (struct) + + { + + if err := t.TotalClientStorageFee.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalClientStorageFee: %w", err) + } + + } + return nil +} + +func (t *WithdrawBalanceParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.ProviderOrClientAddress (address.Address) (struct) + if err := t.ProviderOrClientAddress.MarshalCBOR(w); err != nil { + return err + } + + // t.Amount (big.Int) (struct) + if err := t.Amount.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *WithdrawBalanceParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.ProviderOrClientAddress (address.Address) (struct) + + { + + if err := t.ProviderOrClientAddress.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ProviderOrClientAddress: %w", err) + } + + } + // t.Amount (big.Int) (struct) + + { + + if err := t.Amount.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Amount: %w", err) + } + + } + return nil +} + +func (t *PublishStorageDealsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Deals ([]market.ClientDealProposal) (slice) + if len(t.Deals) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Deals was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Deals)))); err != nil { + return err + } + for _, v := range t.Deals { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *PublishStorageDealsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Deals ([]market.ClientDealProposal) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Deals: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Deals = make([]ClientDealProposal, extra) + } + + for i := 0; i < int(extra); i++ { + + var v ClientDealProposal + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Deals[i] = v + } + + return nil +} + +func (t *ActivateDealsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.SectorExpiry (abi.ChainEpoch) (int64) + if t.SectorExpiry >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorExpiry))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SectorExpiry)-1)); err != nil { + return err + } + } + return nil +} + +func (t *ActivateDealsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = abi.DealID(val) + } + + // t.SectorExpiry (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SectorExpiry = abi.ChainEpoch(extraI) + } + return nil +} + +func (t *VerifyDealsForActivationParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.SectorExpiry (abi.ChainEpoch) (int64) + if t.SectorExpiry >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorExpiry))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SectorExpiry)-1)); err != nil { + return err + } + } + + // t.SectorStart (abi.ChainEpoch) (int64) + if t.SectorStart >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorStart))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SectorStart)-1)); err != nil { + return err + } + } + return nil +} + +func (t *VerifyDealsForActivationParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = abi.DealID(val) + } + + // t.SectorExpiry (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SectorExpiry = abi.ChainEpoch(extraI) + } + // t.SectorStart (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SectorStart = abi.ChainEpoch(extraI) + } + return nil +} + +func (t *VerifyDealsForActivationReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.DealWeight (big.Int) (struct) + if err := t.DealWeight.MarshalCBOR(w); err != nil { + return err + } + + // t.VerifiedDealWeight (big.Int) (struct) + if err := t.VerifiedDealWeight.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *VerifyDealsForActivationReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.DealWeight (big.Int) (struct) + + { + + if err := t.DealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.DealWeight: %w", err) + } + + } + // t.VerifiedDealWeight (big.Int) (struct) + + { + + if err := t.VerifiedDealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.VerifiedDealWeight: %w", err) + } + + } + return nil +} + +func (t *ComputeDataCommitmentParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.SectorType (abi.RegisteredSealProof) (int64) + if t.SectorType >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorType))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SectorType)-1)); err != nil { + return err + } + } + return nil +} + +func (t *ComputeDataCommitmentParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = abi.DealID(val) + } + + // t.SectorType (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SectorType = abi.RegisteredSealProof(extraI) + } + return nil +} + +func (t *OnMinerSectorsTerminateParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + return nil +} + +func (t *OnMinerSectorsTerminateParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = abi.DealID(val) + } + + return nil +} + +func (t *PublishStorageDealsReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.IDs ([]abi.DealID) (slice) + if len(t.IDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.IDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.IDs)))); err != nil { + return err + } + for _, v := range t.IDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + return nil +} + +func (t *PublishStorageDealsReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.IDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.IDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.IDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.IDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.IDs was not a uint, instead got %d", maj) + } + + t.IDs[i] = abi.DealID(val) + } + + return nil +} + +func (t *DealProposal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{139}); err != nil { + return err + } + + // t.PieceCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.PieceCID); err != nil { + return xerrors.Errorf("failed to write cid field t.PieceCID: %w", err) + } + + // t.PieceSize (abi.PaddedPieceSize) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.PieceSize))); err != nil { + return err + } + + // t.VerifiedDeal (bool) (bool) + if err := cbg.WriteBool(w, t.VerifiedDeal); err != nil { + return err + } + + // t.Client (address.Address) (struct) + if err := t.Client.MarshalCBOR(w); err != nil { + return err + } + + // t.Provider (address.Address) (struct) + if err := t.Provider.MarshalCBOR(w); err != nil { + return err + } + + // t.Label (string) (string) + if len(t.Label) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Label was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Label)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.Label)); err != nil { + return err + } + + // t.StartEpoch (abi.ChainEpoch) (int64) + if t.StartEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.StartEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.StartEpoch)-1)); err != nil { + return err + } + } + + // t.EndEpoch (abi.ChainEpoch) (int64) + if t.EndEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.EndEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.EndEpoch)-1)); err != nil { + return err + } + } + + // t.StoragePricePerEpoch (big.Int) (struct) + if err := t.StoragePricePerEpoch.MarshalCBOR(w); err != nil { + return err + } + + // t.ProviderCollateral (big.Int) (struct) + if err := t.ProviderCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.ClientCollateral (big.Int) (struct) + if err := t.ClientCollateral.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *DealProposal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 11 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.PieceCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.PieceCID: %w", err) + } + + t.PieceCID = c + + } + // t.PieceSize (abi.PaddedPieceSize) (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.PieceSize = abi.PaddedPieceSize(extra) + + } + // t.VerifiedDeal (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.VerifiedDeal = false + case 21: + t.VerifiedDeal = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Client (address.Address) (struct) + + { + + if err := t.Client.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Client: %w", err) + } + + } + // t.Provider (address.Address) (struct) + + { + + if err := t.Provider.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Provider: %w", err) + } + + } + // t.Label (string) (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.Label = string(sval) + } + // t.StartEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.StartEpoch = abi.ChainEpoch(extraI) + } + // t.EndEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.EndEpoch = abi.ChainEpoch(extraI) + } + // t.StoragePricePerEpoch (big.Int) (struct) + + { + + if err := t.StoragePricePerEpoch.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.StoragePricePerEpoch: %w", err) + } + + } + // t.ProviderCollateral (big.Int) (struct) + + { + + if err := t.ProviderCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ProviderCollateral: %w", err) + } + + } + // t.ClientCollateral (big.Int) (struct) + + { + + if err := t.ClientCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ClientCollateral: %w", err) + } + + } + return nil +} + +func (t *ClientDealProposal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Proposal (market.DealProposal) (struct) + if err := t.Proposal.MarshalCBOR(w); err != nil { + return err + } + + // t.ClientSignature (crypto.Signature) (struct) + if err := t.ClientSignature.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *ClientDealProposal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Proposal (market.DealProposal) (struct) + + { + + if err := t.Proposal.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Proposal: %w", err) + } + + } + // t.ClientSignature (crypto.Signature) (struct) + + { + + if err := t.ClientSignature.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ClientSignature: %w", err) + } + + } + return nil +} + +func (t *DealState) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.SectorStartEpoch (abi.ChainEpoch) (int64) + if t.SectorStartEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorStartEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SectorStartEpoch)-1)); err != nil { + return err + } + } + + // t.LastUpdatedEpoch (abi.ChainEpoch) (int64) + if t.LastUpdatedEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.LastUpdatedEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.LastUpdatedEpoch)-1)); err != nil { + return err + } + } + + // t.SlashEpoch (abi.ChainEpoch) (int64) + if t.SlashEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SlashEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SlashEpoch)-1)); err != nil { + return err + } + } + return nil +} + +func (t *DealState) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SectorStartEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SectorStartEpoch = abi.ChainEpoch(extraI) + } + // t.LastUpdatedEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.LastUpdatedEpoch = abi.ChainEpoch(extraI) + } + // t.SlashEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SlashEpoch = abi.ChainEpoch(extraI) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/deal.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/deal.go new file mode 100644 index 0000000000..2d9680fbaf --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/deal.go @@ -0,0 +1,91 @@ +package market + +import ( + "bytes" + + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + acrypto "github.com/filecoin-project/specs-actors/actors/crypto" +) + +// Note: Deal Collateral is only released and returned to clients and miners +// when the storage deal stops counting towards power. In the current iteration, +// it will be released when the sector containing the storage deals expires, +// even though some storage deals can expire earlier than the sector does. +// Collaterals are denominated in PerEpoch to incur a cost for self dealing or +// minimal deals that last for a long time. +// Note: ClientCollateralPerEpoch may not be needed and removed pending future confirmation. +// There will be a Minimum value for both client and provider deal collateral. +type DealProposal struct { + PieceCID cid.Cid // CommP + PieceSize abi.PaddedPieceSize + VerifiedDeal bool + Client addr.Address + Provider addr.Address + + // Label is an arbitrary client chosen label to apply to the deal + Label string + + // Nominal start epoch. Deal payment is linear between StartEpoch and EndEpoch, + // with total amount StoragePricePerEpoch * (EndEpoch - StartEpoch). + // Storage deal must appear in a sealed (proven) sector no later than StartEpoch, + // otherwise it is invalid. + StartEpoch abi.ChainEpoch + EndEpoch abi.ChainEpoch + StoragePricePerEpoch abi.TokenAmount + + ProviderCollateral abi.TokenAmount + ClientCollateral abi.TokenAmount +} + +// ClientDealProposal is a DealProposal signed by a client +type ClientDealProposal struct { + Proposal DealProposal + ClientSignature acrypto.Signature +} + +func (p *DealProposal) Duration() abi.ChainEpoch { + return p.EndEpoch - p.StartEpoch +} + +func (p *DealProposal) TotalStorageFee() abi.TokenAmount { + return big.Mul(p.StoragePricePerEpoch, big.NewInt(int64(p.Duration()))) +} + +func (p *DealProposal) ClientBalanceRequirement() abi.TokenAmount { + return big.Add(p.ClientCollateral, p.TotalStorageFee()) +} + +func (p *DealProposal) ProviderBalanceRequirement() abi.TokenAmount { + return p.ProviderCollateral +} + +func (p *DealProposal) Cid() (cid.Cid, error) { + buf := new(bytes.Buffer) + if err := p.MarshalCBOR(buf); err != nil { + return cid.Undef, err + } + b := buf.Bytes() + + mhType := uint64(mh.BLAKE2B_MIN + 31) + mhLen := -1 + + hash, err := mh.Sum(b, mhType, mhLen) + if err != nil { + return cid.Undef, err + } + + c := cid.NewCidV1(cid.DagCBOR, hash) + + return c, nil +} + +type DealState struct { + SectorStartEpoch abi.ChainEpoch // -1 if not yet included in proven sector + LastUpdatedEpoch abi.ChainEpoch // -1 if deal state never updated + SlashEpoch abi.ChainEpoch // -1 if deal never slashed +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_actor.go new file mode 100644 index 0000000000..dc06f9311f --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_actor.go @@ -0,0 +1,750 @@ +package market + +import ( + "fmt" + + addr "github.com/filecoin-project/go-address" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + verifreg "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + . "github.com/filecoin-project/specs-actors/actors/util" + "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Actor struct{} + +type Runtime = vmr.Runtime + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.AddBalance, + 3: a.WithdrawBalance, + 4: a.PublishStorageDeals, + 5: a.VerifyDealsForActivation, + 6: a.ActivateDeals, + 7: a.OnMinerSectorsTerminate, + 8: a.ComputeDataCommitment, + 9: a.CronTick, + } +} + +var _ abi.Invokee = Actor{} + +//////////////////////////////////////////////////////////////////////////////// +// Actor methods +//////////////////////////////////////////////////////////////////////////////// + +func (a Actor) Constructor(rt Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + + emptyArray, err := adt.MakeEmptyArray(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to create storage market state: %v", err) + } + + emptyMap, err := adt.MakeEmptyMap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to create storage market state: %v", err) + } + + emptyMSet, err := MakeEmptySetMultimap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to create storage market state: %v", err) + } + + st := ConstructState(emptyArray, emptyMap, emptyMSet) + rt.State().Create(st) + return nil +} + +type WithdrawBalanceParams struct { + ProviderOrClientAddress addr.Address + Amount abi.TokenAmount +} + +// Attempt to withdraw the specified amount from the balance held in escrow. +// If less than the specified amount is available, yields the entire available balance. +func (a Actor) WithdrawBalance(rt Runtime, params *WithdrawBalanceParams) *adt.EmptyValue { + if params.Amount.LessThan(big.Zero()) { + rt.Abortf(exitcode.ErrIllegalArgument, "negative amount %v", params.Amount) + } + + nominal, recipient := escrowAddress(rt, params.ProviderOrClientAddress) + + amountSlashedTotal := abi.NewTokenAmount(0) + amountExtracted := abi.NewTokenAmount(0) + var st State + rt.State().Transaction(&st, func() interface{} { + // The withdrawable amount might be slightly less than nominal + // depending on whether or not all relevant entries have been processed + // by cron + + minBalance := st.GetLockedBalance(rt, nominal) + + et, err := adt.AsBalanceTable(adt.AsStore(rt), st.EscrowTable) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "load escrow table: %v", err) + } + ex, err := et.SubtractWithMinimum(nominal, params.Amount, minBalance) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "subtract form escrow table: %v", err) + } + + etc, err := et.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush escrow table: %w", err) + } + st.EscrowTable = etc + amountExtracted = ex + return nil + }) + + if amountSlashedTotal.GreaterThan(big.Zero()) { + _, code := rt.Send(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, amountSlashedTotal) + builtin.RequireSuccess(rt, code, "failed to burn slashed funds") + } + + _, code := rt.Send(recipient, builtin.MethodSend, nil, amountExtracted) + builtin.RequireSuccess(rt, code, "failed to send funds") + return nil +} + +// Deposits the received value into the balance held in escrow. +func (a Actor) AddBalance(rt Runtime, providerOrClientAddress *addr.Address) *adt.EmptyValue { + msgValue := rt.Message().ValueReceived() + if msgValue.LessThan(big.Zero()) { + rt.Abortf(exitcode.ErrIllegalArgument, "add balance called with negative value %v", msgValue) + } + + nominal, _ := escrowAddress(rt, *providerOrClientAddress) + + var st State + rt.State().Transaction(&st, func() interface{} { + + err := st.AddEscrowBalance(adt.AsStore(rt), nominal, msgValue) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "adding to escrow table: %v", err) + } + + // ensure there is an entry in the locked table + err = st.AddLockedBalance(adt.AsStore(rt), nominal, big.Zero()) + if err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "adding to locked table: %v", err) + } + + return nil + }) + return nil +} + +type PublishStorageDealsParams struct { + Deals []ClientDealProposal +} + +type PublishStorageDealsReturn struct { + IDs []abi.DealID +} + +// Publish a new set of storage deals (not yet included in a sector). +func (a Actor) PublishStorageDeals(rt Runtime, params *PublishStorageDealsParams) *PublishStorageDealsReturn { + + // Deal message must have a From field identical to the provider of all the deals. + // This allows us to retain and verify only the client's signature in each deal proposal itself. + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + if len(params.Deals) == 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "empty deals parameter") + } + + // All deals should have the same provider so get worker once + providerRaw := params.Deals[0].Proposal.Provider + provider, ok := rt.ResolveAddress(providerRaw) + if !ok { + rt.Abortf(exitcode.ErrNotFound, "failed to resolve provider address %v", providerRaw) + } + + _, worker := builtin.RequestMinerControlAddrs(rt, provider) + if worker != rt.Message().Caller() { + rt.Abortf(exitcode.ErrForbidden, "caller is not provider %v", provider) + } + + for _, deal := range params.Deals { + // Check VerifiedClient allowed cap and deduct PieceSize from cap. + // Either the DealSize is within the available DataCap of the VerifiedClient + // or this message will fail. We do not allow a deal that is partially verified. + if deal.Proposal.VerifiedDeal { + _, code := rt.Send( + builtin.VerifiedRegistryActorAddr, + builtin.MethodsVerifiedRegistry.UseBytes, + &verifreg.UseBytesParams{ + Address: deal.Proposal.Client, + DealSize: big.NewIntUnsigned(uint64(deal.Proposal.PieceSize)), + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to add verified deal for client: %v", deal.Proposal.Client) + } + } + + var newDealIds []abi.DealID + var st State + rt.State().Transaction(&st, func() interface{} { + proposals, err := AsDealProposalArray(adt.AsStore(rt), st.Proposals) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to load proposals array: %s", err) + } + + pending, err := adt.AsMap(adt.AsStore(rt), st.PendingProposals) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load pending proposals map: %s", err) + + dealOps, err := AsSetMultimap(adt.AsStore(rt), st.DealOpsByEpoch) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to load deal ids set: %s", err) + } + + // All storage proposals will be added in an atomic transaction; this operation will be unrolled if any of them fails. + for di, deal := range params.Deals { + validateDeal(rt, deal) + + if deal.Proposal.Provider != provider && deal.Proposal.Provider != providerRaw { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot publish deals from different providers at the same time") + } + + client, ok := rt.ResolveAddress(deal.Proposal.Client) + if !ok { + rt.Abortf(exitcode.ErrNotFound, "failed to resolve client address %v", deal.Proposal.Client) + } + // Normalise provider and client addresses in the proposal stored on chain (after signature verification). + deal.Proposal.Provider = provider + deal.Proposal.Client = client + + st.lockBalanceOrAbort(rt, client, deal.Proposal.ClientCollateral, ClientCollateral) + st.lockBalanceOrAbort(rt, client, deal.Proposal.TotalStorageFee(), ClientStorageFee) + st.lockBalanceOrAbort(rt, provider, deal.Proposal.ProviderCollateral, ProviderCollateral) + + id := st.generateStorageDealID() + + pcid, err := deal.Proposal.Cid() + if err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "failed to take cid of proposal %d: %s", di, err) + } + + has, err := pending.Get(adt.CidKey(pcid), nil) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to check for existence of deal proposal: %v", err) + } + + if has { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot publish duplicate deals") + } + + if err := pending.Put(adt.CidKey(pcid), &deal.Proposal); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "set deal in pending: %v", err) + } + + if err := proposals.Set(id, &deal.Proposal); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "set deal: %v", err) + } + + if err := dealOps.Put(deal.Proposal.StartEpoch, id); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "set deal in ops set: %v", err) + } + + newDealIds = append(newDealIds, id) + } + pendc, err := pending.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush pending proposal set: %w", err) + } + st.PendingProposals = pendc + + propc, err := proposals.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush proposal set: %w", err) + } + st.Proposals = propc + + dipc, err := dealOps.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush deal ids map: %w", err) + } + + st.DealOpsByEpoch = dipc + return nil + }) + + return &PublishStorageDealsReturn{newDealIds} +} + +type VerifyDealsForActivationParams struct { + DealIDs []abi.DealID + SectorExpiry abi.ChainEpoch + SectorStart abi.ChainEpoch +} + +type VerifyDealsForActivationReturn struct { + DealWeight abi.DealWeight + VerifiedDealWeight abi.DealWeight +} + +// Verify that a given set of storage deals is valid for a sector currently being PreCommitted +// and return DealWeight of the set of storage deals given. +// The weight is defined as the sum, over all deals in the set, of the product of deal size and duration. +func (A Actor) VerifyDealsForActivation(rt Runtime, params *VerifyDealsForActivationParams) *VerifyDealsForActivationReturn { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + minerAddr := rt.Message().Caller() + + var st State + rt.State().Readonly(&st) + store := adt.AsStore(rt) + + dealWeight, verifiedWeight, err := ValidateDealsForActivation(&st, store, params.DealIDs, minerAddr, params.SectorExpiry, params.SectorStart) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to validate proposals for activation") + + return &VerifyDealsForActivationReturn{ + DealWeight: dealWeight, + VerifiedDealWeight: verifiedWeight, + } +} + +type ActivateDealsParams struct { + DealIDs []abi.DealID + SectorExpiry abi.ChainEpoch +} + +// Verify that a given set of storage deals is valid for a sector currently being ProveCommitted, +// update the market's internal state accordingly. +func (a Actor) ActivateDeals(rt Runtime, params *ActivateDealsParams) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + minerAddr := rt.Message().Caller() + currEpoch := rt.CurrEpoch() + + var st State + store := adt.AsStore(rt) + + // Update deal states. + rt.State().Transaction(&st, func() interface{} { + _, _, err := ValidateDealsForActivation(&st, store, params.DealIDs, minerAddr, params.SectorExpiry, currEpoch) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to validate proposals for activation") + + states, err := AsDealStateArray(store, st.States) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deal states") + + pending, err := adt.AsMap(adt.AsStore(rt), st.PendingProposals) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "load pending %v", err) + + proposals, err := AsDealProposalArray(adt.AsStore(rt), st.Proposals) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "load proposals %v", err) + + for _, dealID := range params.DealIDs { + // This construction could be replaced with a single "update deal state" state method, possibly batched + // over all deal ids at once. + _, found, err := states.Get(dealID) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to get state for dealId %d", dealID) + if found { + rt.Abortf(exitcode.ErrIllegalArgument, "deal %d already included in another sector", dealID) + } + + proposal, found, err := proposals.Get(dealID) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load proposal for dealId %d", dealID) + if !found { + rt.Abortf(exitcode.ErrNotFound, "dealId %d not found", dealID) + } + + propc, err := proposal.Cid() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get proposal cid %v", err) + } + + has, err := pending.Get(adt.CidKey(propc), nil) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "no pending proposal for %v", err) + } + + if !has { + rt.Abortf(exitcode.ErrIllegalState, "tried to active deal that was not in the pending set (%s)", propc) + } + + err = states.Set(dealID, &DealState{ + SectorStartEpoch: currEpoch, + LastUpdatedEpoch: epochUndefined, + SlashEpoch: epochUndefined, + }) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to set deal state %d", dealID) + } + + st.States, err = states.Root() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to flush deal states") + return nil + }) + + return nil +} + +type ComputeDataCommitmentParams struct { + DealIDs []abi.DealID + SectorType abi.RegisteredSealProof +} + +func (a Actor) ComputeDataCommitment(rt Runtime, params *ComputeDataCommitmentParams) *cbg.CborCid { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + + pieces := make([]abi.PieceInfo, 0) + var st State + rt.State().Transaction(&st, func() interface{} { + for _, dealID := range params.DealIDs { + deal := st.mustGetDeal(rt, dealID) + pieces = append(pieces, abi.PieceInfo{ + PieceCID: deal.PieceCID, + Size: deal.PieceSize, + }) + } + return nil + }) + + commd, err := rt.Syscalls().ComputeUnsealedSectorCID(params.SectorType, pieces) + if err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "failed to compute unsealed sector CID: %s", err) + } + + return (*cbg.CborCid)(&commd) +} + +type OnMinerSectorsTerminateParams struct { + DealIDs []abi.DealID +} + +// Terminate a set of deals in response to their containing sector being terminated. +// Slash provider collateral, refund client collateral, and refund partial unpaid escrow +// amount to client. +func (a Actor) OnMinerSectorsTerminate(rt Runtime, params *OnMinerSectorsTerminateParams) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + minerAddr := rt.Message().Caller() + + var st State + rt.State().Transaction(&st, func() interface{} { + proposals, err := AsDealProposalArray(adt.AsStore(rt), st.Proposals) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "load proposals: %v", err) + } + + states, err := AsDealStateArray(adt.AsStore(rt), st.States) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "load states: %v", err) + } + + for _, dealID := range params.DealIDs { + deal, found, err := proposals.Get(dealID) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get deal: %v", err) + } + // deal could have terminated and hence deleted before the sector is terminated. + // we should simply continue instead of aborting execution here if a deal is not found. + if !found { + continue + } + + Assert(deal.Provider == minerAddr) + + // do not slash expired deals + if deal.EndEpoch <= rt.CurrEpoch() { + continue + } + + state, found, err := states.Get(dealID) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get deal: %v", err) + } + if !found { + rt.Abortf(exitcode.ErrIllegalState, "no state found for deal in sector being terminated") + } + + // mark the deal for slashing here. + // actual releasing of locked funds for the client and slashing of provider collateral happens in CronTick. + state.SlashEpoch = rt.CurrEpoch() + + if err := states.Set(dealID, state); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "set deal: %v", err) + } + } + + st.States, err = states.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush states: %s", err) + } + return nil + }) + return nil +} + +func (a Actor) CronTick(rt Runtime, params *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.CronActorAddr) + amountSlashed := big.Zero() + + var timedOutVerifiedDeals []*DealProposal + + var st State + rt.State().Transaction(&st, func() interface{} { + dbe, err := AsSetMultimap(adt.AsStore(rt), st.DealOpsByEpoch) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to load deal opts set: %s", err) + } + + updatesNeeded := make(map[abi.ChainEpoch][]abi.DealID) + + states, err := AsDealStateArray(adt.AsStore(rt), st.States) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get state state: %v", err) + } + + et, err := adt.AsBalanceTable(adt.AsStore(rt), st.EscrowTable) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "loading escrow table: %s", err) + } + + lt, err := adt.AsBalanceTable(adt.AsStore(rt), st.LockedTable) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "loading locked balance table: %s", err) + } + + pending, err := adt.AsMap(adt.AsStore(rt), st.PendingProposals) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "loading pending proposals map: %s", err) + } + + for i := st.LastCron + 1; i <= rt.CurrEpoch(); i++ { + if err := dbe.ForEach(i, func(dealID abi.DealID) error { + state, found, err := states.Get(dealID) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to get deal: %d", dealID) + } + + if !found { + return nil + } + + deal := st.mustGetDeal(rt, dealID) + dcid, err := deal.Cid() + if err != nil { + return xerrors.Errorf("failed to get cid for deal proposal: %w", err) + } + if err := pending.Delete(adt.CidKey(dcid)); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete pending proposal: %v", err) + } + + if state.SectorStartEpoch == epochUndefined { + // Not yet appeared in proven sector; check for timeout. + AssertMsg(rt.CurrEpoch() >= deal.StartEpoch, "if sector start is not set, we must be in a timed out state") + + slashed := st.processDealInitTimedOut(rt, et, lt, dealID, deal, state) + if !slashed.IsZero() { + amountSlashed = big.Add(amountSlashed, slashed) + } + if deal.VerifiedDeal { + timedOutVerifiedDeals = append(timedOutVerifiedDeals, deal) + } + return nil + } + + slashAmount, nextEpoch := st.updatePendingDealState(rt, state, deal, dealID, et, lt, rt.CurrEpoch()) + if !slashAmount.IsZero() { + amountSlashed = big.Add(amountSlashed, slashAmount) + } + + if nextEpoch != epochUndefined { + Assert(nextEpoch > rt.CurrEpoch()) + + // TODO: can we avoid having this field? + // https://github.com/filecoin-project/specs-actors/issues/463 + state.LastUpdatedEpoch = rt.CurrEpoch() + + if err := states.Set(dealID, state); err != nil { + rt.Abortf(exitcode.ErrPlaceholder, "failed to get deal: %v", err) + } + + updatesNeeded[nextEpoch] = append(updatesNeeded[nextEpoch], dealID) + } + + return nil + }); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to iterate deals for epoch: %s", err) + } + if err := dbe.RemoveAll(i); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete deals from set: %s", err) + } + } + + // NB: its okay that we're doing a 'random' golang map iteration here + // because HAMTs and AMTs are insertion order independent, the same set of + // data inserted will always produce the same structure, no matter the order + for epoch, deals := range updatesNeeded { + if err := dbe.PutMany(epoch, deals); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to reinsert deal IDs into epoch set: %s", err) + } + } + + ndbec, err := dbe.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to get root of deals by epoch set: %s", err) + } + + ltc, err := lt.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush locked table: %s", err) + } + etc, err := et.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush escrow table: %s", err) + } + st.LockedTable = ltc + st.EscrowTable = etc + + st.DealOpsByEpoch = ndbec + + st.LastCron = rt.CurrEpoch() + + return nil + }) + + for _, d := range timedOutVerifiedDeals { + _, code := rt.Send( + builtin.VerifiedRegistryActorAddr, + builtin.MethodsVerifiedRegistry.RestoreBytes, + &verifreg.RestoreBytesParams{ + Address: d.Client, + DealSize: big.NewIntUnsigned(uint64(d.PieceSize)), + }, + abi.NewTokenAmount(0), + ) + + builtin.RequireSuccess(rt, code, "failed to restore bytes for verified client: %v", d.Client) + } + + _, e := rt.Send(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, amountSlashed) + builtin.RequireSuccess(rt, e, "expected send to burnt funds actor to succeed") + return nil +} + +// +// Exported functions +// + +// Validates a collection of deal proposals for activation, and returns their combined weight, +// split into regular deal weight and verified deal weight. +func ValidateDealsForActivation(st *State, store adt.Store, dealIDs []abi.DealID, minerAddr addr.Address, + sectorExpiry, currEpoch abi.ChainEpoch) (big.Int, big.Int, error) { + + proposals, err := AsDealProposalArray(store, st.Proposals) + if err != nil { + return big.Int{}, big.Int{}, fmt.Errorf("failed to load proposals: %w", err) + } + + totalDealSpaceTime := big.Zero() + totalVerifiedSpaceTime := big.Zero() + for _, dealID := range dealIDs { + proposal, found, err := proposals.Get(dealID) + if err != nil { + return big.Int{}, big.Int{}, fmt.Errorf("failed to load deal %d: %w", dealID, err) + } + if !found { + return big.Int{}, big.Int{}, fmt.Errorf("dealId %d not found", dealID) + } + if err = validateDealCanActivate(proposal, minerAddr, sectorExpiry, currEpoch); err != nil { + return big.Int{}, big.Int{}, fmt.Errorf("cannot activate deal %d: %w", dealID, err) + } + + // Compute deal weight + dealSpaceTime := DealWeight(proposal) + if proposal.VerifiedDeal { + totalVerifiedSpaceTime = big.Add(totalVerifiedSpaceTime, dealSpaceTime) + } else { + totalDealSpaceTime = big.Add(totalDealSpaceTime, dealSpaceTime) + } + } + return totalDealSpaceTime, totalVerifiedSpaceTime, nil +} + +//////////////////////////////////////////////////////////////////////////////// +// Checks +//////////////////////////////////////////////////////////////////////////////// + +func validateDealCanActivate(proposal *DealProposal, minerAddr addr.Address, sectorExpiration, currEpoch abi.ChainEpoch) error { + if proposal.Provider != minerAddr { + return fmt.Errorf("proposal has provider %v, must be %v", proposal.Provider, minerAddr) + } + if currEpoch > proposal.StartEpoch { + return fmt.Errorf("proposal start epoch %d has already elapsed at %d", proposal.StartEpoch, currEpoch) + } + if proposal.EndEpoch > sectorExpiration { + return fmt.Errorf("proposal expiration %d exceeds sector expiration %d", proposal.EndEpoch, sectorExpiration) + } + return nil +} + +func validateDeal(rt Runtime, deal ClientDealProposal) { + if err := dealProposalIsInternallyValid(rt, deal); err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "Invalid deal proposal: %s", err) + } + + proposal := deal.Proposal + + if proposal.EndEpoch <= proposal.StartEpoch { + rt.Abortf(exitcode.ErrIllegalArgument, "proposal end before proposal start") + } + + if rt.CurrEpoch() > proposal.StartEpoch { + rt.Abortf(exitcode.ErrIllegalArgument, "Deal start epoch has already elapsed.") + } + + minDuration, maxDuration := dealDurationBounds(proposal.PieceSize) + if proposal.Duration() < minDuration || proposal.Duration() > maxDuration { + rt.Abortf(exitcode.ErrIllegalArgument, "Deal duration out of bounds.") + } + + minPrice, maxPrice := dealPricePerEpochBounds(proposal.PieceSize, proposal.Duration()) + if proposal.StoragePricePerEpoch.LessThan(minPrice) || proposal.StoragePricePerEpoch.GreaterThan(maxPrice) { + rt.Abortf(exitcode.ErrIllegalArgument, "Storage price out of bounds.") + } + + minProviderCollateral, maxProviderCollateral := dealProviderCollateralBounds(proposal.PieceSize, proposal.Duration()) + if proposal.ProviderCollateral.LessThan(minProviderCollateral) || proposal.ProviderCollateral.GreaterThan(maxProviderCollateral) { + rt.Abortf(exitcode.ErrIllegalArgument, "Provider collateral out of bounds.") + } + + minClientCollateral, maxClientCollateral := dealClientCollateralBounds(proposal.PieceSize, proposal.Duration()) + if proposal.ClientCollateral.LessThan(minClientCollateral) || proposal.ClientCollateral.GreaterThan(maxClientCollateral) { + rt.Abortf(exitcode.ErrIllegalArgument, "Client collateral out of bounds.") + } +} + +// Resolves a provider or client address to the canonical form against which a balance should be held, and +// the designated recipient address of withdrawals (which is the same, for simple account parties). +func escrowAddress(rt Runtime, addr addr.Address) (nominal addr.Address, recipient addr.Address) { + // Resolve the provided address to the canonical form against which the balance is held. + nominal, ok := rt.ResolveAddress(addr) + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "failed to resolve address %v", addr) + } + + codeID, ok := rt.GetActorCodeCID(nominal) + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "no code for address %v", nominal) + } + + if codeID.Equals(builtin.StorageMinerActorCodeID) { + // Storage miner actor entry; implied funds recipient is the associated owner address. + ownerAddr, workerAddr := builtin.RequestMinerControlAddrs(rt, nominal) + rt.ValidateImmediateCallerIs(ownerAddr, workerAddr) + return nominal, ownerAddr + } + + // Ordinary account-style actor entry; funds recipient is just the entry address itself. + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + return nominal, nominal +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_state.go new file mode 100644 index 0000000000..dad50d6f46 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_state.go @@ -0,0 +1,479 @@ +package market + +import ( + "bytes" + "fmt" + + addr "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/ipfs/go-cid" + xerrors "golang.org/x/xerrors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + . "github.com/filecoin-project/specs-actors/actors/util" + "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +const epochUndefined = abi.ChainEpoch(-1) + +// Market mutations +// add / rm balance +// pub deal (always provider) +// activate deal (miner) +// end deal (miner terminate, expire(no activation)) + +// BalanceLockingReason is the reason behind locking an amount. +type BalanceLockingReason int + +const ( + ClientCollateral BalanceLockingReason = iota + ClientStorageFee + ProviderCollateral +) + +type State struct { + Proposals cid.Cid // AMT[DealID]DealProposal + States cid.Cid // AMT[DealID]DealState + + // PendingProposals tracks proposals that have not yet reached their deal start date. + // We track them here to ensure that miners can't publish the same deal proposal twice + PendingProposals cid.Cid // HAMT[DealCid]DealProposal + + // Total amount held in escrow, indexed by actor address (including both locked and unlocked amounts). + EscrowTable cid.Cid // BalanceTable + + // Amount locked, indexed by actor address. + // Note: the amounts in this table do not affect the overall amount in escrow: + // only the _portion_ of the total escrow amount that is locked. + LockedTable cid.Cid // BalanceTable + + NextID abi.DealID + + // Metadata cached for efficient iteration over deals. + DealOpsByEpoch cid.Cid // SetMultimap, HAMT[epoch]Set + LastCron abi.ChainEpoch + + // Total Client Collateral that is locked -> unlocked when deal is terminated + TotalClientLockedCollateral abi.TokenAmount + // Total Provider Collateral that is locked -> unlocked when deal is terminated + TotalProviderLockedCollateral abi.TokenAmount + // Total storage fee that is locked in escrow -> unlocked when payments are made + TotalClientStorageFee abi.TokenAmount +} + +func ConstructState(emptyArrayCid, emptyMapCid, emptyMSetCid cid.Cid) *State { + return &State{ + Proposals: emptyArrayCid, + States: emptyArrayCid, + PendingProposals: emptyMapCid, + EscrowTable: emptyMapCid, + LockedTable: emptyMapCid, + NextID: abi.DealID(0), + DealOpsByEpoch: emptyMSetCid, + LastCron: abi.ChainEpoch(-1), + + TotalClientLockedCollateral: abi.NewTokenAmount(0), + TotalProviderLockedCollateral: abi.NewTokenAmount(0), + TotalClientStorageFee: abi.NewTokenAmount(0), + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Deal state operations +//////////////////////////////////////////////////////////////////////////////// + +func (st *State) updatePendingDealState(rt Runtime, state *DealState, deal *DealProposal, dealID abi.DealID, et, lt *adt.BalanceTable, epoch abi.ChainEpoch) (abi.TokenAmount, abi.ChainEpoch) { + amountSlashed := abi.NewTokenAmount(0) + + everUpdated := state.LastUpdatedEpoch != epochUndefined + everSlashed := state.SlashEpoch != epochUndefined + + Assert(!everUpdated || (state.LastUpdatedEpoch <= epoch)) // if the deal was ever updated, make sure it didn't happen in the future + + // This would be the case that the first callback somehow triggers before it is scheduled to + // This is expected not to be able to happen + if deal.StartEpoch > epoch { + return amountSlashed, epochUndefined + } + + dealEnd := deal.EndEpoch + if everSlashed { + Assert(state.SlashEpoch <= dealEnd) + dealEnd = state.SlashEpoch + } + + elapsedStart := deal.StartEpoch + if everUpdated && state.LastUpdatedEpoch > elapsedStart { + elapsedStart = state.LastUpdatedEpoch + } + + elapsedEnd := dealEnd + if epoch < elapsedEnd { + elapsedEnd = epoch + } + + numEpochsElapsed := elapsedEnd - elapsedStart + + { + // Process deal payment for the elapsed epochs. + totalPayment := big.Mul(big.NewInt(int64(numEpochsElapsed)), deal.StoragePricePerEpoch) + + st.transferBalance(rt, deal.Client, deal.Provider, totalPayment) + } + + if everSlashed { + // unlock client collateral and locked storage fee + paymentRemaining := dealGetPaymentRemaining(deal, state.SlashEpoch) + + // unlock remaining storage fee + if err := st.unlockBalance(lt, deal.Client, paymentRemaining, ClientStorageFee); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unlock remaining client storage fee: %s", err) + } + // unlock client collateral + if err := st.unlockBalance(lt, deal.Client, deal.ClientCollateral, ClientCollateral); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unlock client collateral: %s", err) + } + + // slash provider collateral + amountSlashed = deal.ProviderCollateral + if err := st.slashBalance(et, lt, deal.Provider, amountSlashed, ProviderCollateral); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "slashing balance: %s", err) + } + + st.deleteDeal(rt, dealID) + return amountSlashed, epochUndefined + } + + if epoch >= deal.EndEpoch { + st.processDealExpired(rt, deal, state, lt, dealID) + return amountSlashed, epochUndefined + } + + next := epoch + DealUpdatesInterval + if next > deal.EndEpoch { + next = deal.EndEpoch + } + + return amountSlashed, next +} + +func (st *State) mutateDealProposals(rt Runtime, f func(*DealArray)) { + proposals, err := AsDealProposalArray(adt.AsStore(rt), st.Proposals) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to load deal proposals array: %s", err) + } + + f(proposals) + + rcid, err := proposals.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "flushing deal proposals set failed: %s", err) + } + + st.Proposals = rcid +} + +func (st *State) mutateDealStates(store adt.Store, f func(*DealMetaArray)) error { + states, err := AsDealStateArray(store, st.States) + if err != nil { + return fmt.Errorf("failed to load deal states array: %w", err) + } + + f(states) + + scid, err := states.Root() + if err != nil { + return fmt.Errorf("flushing deal states set failed: %w", err) + } + + st.States = scid + return nil +} + +func (st *State) deleteDeal(rt Runtime, dealID abi.DealID) { + st.mutateDealProposals(rt, func(proposals *DealArray) { + if err := proposals.Delete(uint64(dealID)); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete deal: %v", err) + } + }) + + if err := st.mutateDealStates(adt.AsStore(rt), func(states *DealMetaArray) { + if err := states.Delete(dealID); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete deal state: %v", err) + } + }); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete deal state: %v", err) + } +} + +// Deal start deadline elapsed without appearing in a proven sector. +// Delete deal, slash a portion of provider's collateral, and unlock remaining collaterals +// for both provider and client. +func (st *State) processDealInitTimedOut(rt Runtime, et, lt *adt.BalanceTable, dealID abi.DealID, deal *DealProposal, state *DealState) abi.TokenAmount { + Assert(state.SectorStartEpoch == epochUndefined) + + if err := st.unlockBalance(lt, deal.Client, deal.TotalStorageFee(), ClientStorageFee); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failure unlocking client storage fee: %s", err) + } + if err := st.unlockBalance(lt, deal.Client, deal.ClientCollateral, ClientCollateral); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failure unlocking client collateral: %s", err) + } + + amountSlashed := collateralPenaltyForDealActivationMissed(deal.ProviderCollateral) + amountRemaining := big.Sub(deal.ProviderBalanceRequirement(), amountSlashed) + + if err := st.slashBalance(et, lt, deal.Provider, amountSlashed, ProviderCollateral); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to slash balance: %s", err) + } + + if err := st.unlockBalance(lt, deal.Provider, amountRemaining, ProviderCollateral); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unlock deal provider balance: %s", err) + } + + st.deleteDeal(rt, dealID) + return amountSlashed +} + +// Normal expiration. Delete deal and unlock collaterals for both miner and client. +func (st *State) processDealExpired(rt Runtime, deal *DealProposal, state *DealState, lt *adt.BalanceTable, dealID abi.DealID) { + Assert(state.SectorStartEpoch != epochUndefined) + + // Note: payment has already been completed at this point (_rtProcessDealPaymentEpochsElapsed) + if err := st.unlockBalance(lt, deal.Provider, deal.ProviderCollateral, ProviderCollateral); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed unlocking deal provider balance: %s", err) + } + + if err := st.unlockBalance(lt, deal.Client, deal.ClientCollateral, ClientCollateral); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed unlocking deal client balance: %s", err) + } + + st.deleteDeal(rt, dealID) +} + +func (st *State) generateStorageDealID() abi.DealID { + ret := st.NextID + st.NextID = st.NextID + abi.DealID(1) + return ret +} + +//////////////////////////////////////////////////////////////////////////////// +// Balance table operations +//////////////////////////////////////////////////////////////////////////////// + +func (st *State) MutateBalanceTable(s adt.Store, c *cid.Cid, f func(t *adt.BalanceTable) error) error { + t, err := adt.AsBalanceTable(s, *c) + if err != nil { + return err + } + + if err := f(t); err != nil { + return err + } + + rc, err := t.Root() + if err != nil { + return err + } + + *c = rc + return nil +} + +func (st *State) AddEscrowBalance(s adt.Store, a addr.Address, amount abi.TokenAmount) error { + return st.MutateBalanceTable(s, &st.EscrowTable, func(et *adt.BalanceTable) error { + err := et.AddCreate(a, amount) + if err != nil { + return xerrors.Errorf("failed to add %s to balance table: %w", a, err) + } + return nil + }) +} + +func (st *State) AddLockedBalance(s adt.Store, a addr.Address, amount abi.TokenAmount) error { + return st.MutateBalanceTable(s, &st.LockedTable, func(lt *adt.BalanceTable) error { + err := lt.AddCreate(a, amount) + if err != nil { + return err + } + return nil + }) +} + +func (st *State) GetEscrowBalance(rt Runtime, a addr.Address) abi.TokenAmount { + bt, err := adt.AsBalanceTable(adt.AsStore(rt), st.EscrowTable) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get escrow balance: %v", err) + } + ret, err := bt.Get(a) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get escrow balance: %v", err) + } + return ret +} + +func (st *State) GetLockedBalance(rt Runtime, a addr.Address) abi.TokenAmount { + lt, err := adt.AsBalanceTable(adt.AsStore(rt), st.LockedTable) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get locked balance: %v", err) + } + ret, err := lt.Get(a) + if _, ok := err.(adt.ErrNotFound); ok { + rt.Abortf(exitcode.ErrInsufficientFunds, "failed to get locked balance: %v", err) + } + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get locked balance: %v", err) + } + return ret +} + +func (st *State) maybeLockBalance(rt Runtime, addr addr.Address, amount abi.TokenAmount) error { + Assert(amount.GreaterThanEqual(big.Zero())) + + prevLocked := st.GetLockedBalance(rt, addr) + escrowBalance := st.GetEscrowBalance(rt, addr) + if big.Add(prevLocked, amount).GreaterThan(st.GetEscrowBalance(rt, addr)) { + return xerrors.Errorf("not enough balance to lock for addr %s: %s < %s + %s", addr, escrowBalance, prevLocked, amount) + } + + return st.MutateBalanceTable(adt.AsStore(rt), &st.LockedTable, func(lt *adt.BalanceTable) error { + err := lt.Add(addr, amount) + if err != nil { + return xerrors.Errorf("adding locked balance: %w", err) + } + return nil + }) +} + +// TODO: all these balance table mutations need to happen at the top level and be batched (no flushing after each!) +// https://github.com/filecoin-project/specs-actors/issues/464 +func (st *State) unlockBalance(lt *adt.BalanceTable, addr addr.Address, amount abi.TokenAmount, lockReason BalanceLockingReason) error { + Assert(amount.GreaterThanEqual(big.Zero())) + + err := lt.MustSubtract(addr, amount) + if err != nil { + return xerrors.Errorf("subtracting from locked balance: %v", err) + } + + switch lockReason { + case ClientCollateral: + st.TotalClientLockedCollateral = big.Sub(st.TotalClientLockedCollateral, amount) + case ClientStorageFee: + st.TotalClientStorageFee = big.Sub(st.TotalClientStorageFee, amount) + case ProviderCollateral: + st.TotalProviderLockedCollateral = big.Sub(st.TotalProviderLockedCollateral, amount) + } + + return nil +} + +// move funds from locked in client to available in provider +func (st *State) transferBalance(rt Runtime, fromAddr addr.Address, toAddr addr.Address, amount abi.TokenAmount) { + Assert(amount.GreaterThanEqual(big.Zero())) + + et, err := adt.AsBalanceTable(adt.AsStore(rt), st.EscrowTable) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "loading escrow table: %s", err) + } + lt, err := adt.AsBalanceTable(adt.AsStore(rt), st.LockedTable) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "loading locked balance table: %s", err) + } + + if err := et.MustSubtract(fromAddr, amount); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "subtract from escrow: %v", err) + } + + if err := st.unlockBalance(lt, fromAddr, amount, ClientStorageFee); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "subtract from locked: %v", err) + } + + if err := et.Add(toAddr, amount); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "add to escrow: %v", err) + } + + ltc, err := lt.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush locked table: %s", err) + } + etc, err := et.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush escrow table: %s", err) + } + + st.LockedTable = ltc + st.EscrowTable = etc +} + +func (st *State) slashBalance(et, lt *adt.BalanceTable, addr addr.Address, amount abi.TokenAmount, reason BalanceLockingReason) error { + Assert(amount.GreaterThanEqual(big.Zero())) + + if err := et.MustSubtract(addr, amount); err != nil { + return xerrors.Errorf("subtract from escrow: %v", err) + } + + return st.unlockBalance(lt, addr, amount, reason) +} + +//////////////////////////////////////////////////////////////////////////////// +// Method utility functions +//////////////////////////////////////////////////////////////////////////////// + +func (st *State) mustGetDeal(rt Runtime, dealID abi.DealID) *DealProposal { + proposals, err := AsDealProposalArray(adt.AsStore(rt), st.Proposals) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "get proposal: %v", err) + } + + proposal, found, err := proposals.Get(dealID) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load proposal for dealId %d", dealID) + if !found { + rt.Abortf(exitcode.ErrNotFound, "dealId %d not found", dealID) + } + + return proposal +} + +func (st *State) lockBalanceOrAbort(rt Runtime, addr addr.Address, amount abi.TokenAmount, reason BalanceLockingReason) { + if err := st.maybeLockBalance(rt, addr, amount); err != nil { + rt.Abortf(exitcode.ErrInsufficientFunds, "Insufficient funds available to lock: %s", err) + } + + switch reason { + case ClientCollateral: + st.TotalClientLockedCollateral = big.Add(st.TotalClientLockedCollateral, amount) + case ClientStorageFee: + st.TotalClientStorageFee = big.Add(st.TotalClientStorageFee, amount) + case ProviderCollateral: + st.TotalProviderLockedCollateral = big.Add(st.TotalProviderLockedCollateral, amount) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// State utility functions +//////////////////////////////////////////////////////////////////////////////// + +func dealProposalIsInternallyValid(rt Runtime, proposal ClientDealProposal) error { + // Note: we do not verify the provider signature here, since this is implicit in the + // authenticity of the on-chain message publishing the deal. + buf := bytes.Buffer{} + err := proposal.Proposal.MarshalCBOR(&buf) + if err != nil { + return xerrors.Errorf("proposal signature verification failed to marshal proposal: %w", err) + } + err = rt.Syscalls().VerifySignature(proposal.ClientSignature, proposal.Proposal.Client, buf.Bytes()) + if err != nil { + return xerrors.Errorf("signature proposal invalid: %w", err) + } + return nil +} + +func dealGetPaymentRemaining(deal *DealProposal, epoch abi.ChainEpoch) abi.TokenAmount { + Assert(epoch <= deal.EndEpoch) + + durationRemaining := deal.EndEpoch - (epoch - 1) + Assert(durationRemaining > 0) + + return big.Mul(big.NewInt(int64(durationRemaining)), deal.StoragePricePerEpoch) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_test.go new file mode 100644 index 0000000000..ec8bd07454 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/market_test.go @@ -0,0 +1,1002 @@ +package market_test + +import ( + "bytes" + "context" + "errors" + "testing" + + "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/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func mustCbor(o runtime.CBORMarshaler) []byte { + buf := new(bytes.Buffer) + if err := o.MarshalCBOR(buf); err != nil { + panic(err) + } + + return buf.Bytes() +} + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, market.Actor{}) +} + +func TestRemoveAllError(t *testing.T) { + marketActor := tutil.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), marketActor) + rt := builder.Build(t) + store := adt.AsStore(rt) + + smm := market.MakeEmptySetMultimap(store) + + if err := smm.RemoveAll(42); err != nil { + t.Fatalf("expected no error, got: %s", err) + } +} + +func TestMarketActor(t *testing.T) { + marketActor := tutil.NewIDAddr(t, 100) + owner := tutil.NewIDAddr(t, 101) + provider := tutil.NewIDAddr(t, 102) + worker := tutil.NewIDAddr(t, 103) + client := tutil.NewIDAddr(t, 104) + minerAddrs := &minerAddrs{owner, worker, provider} + + var st market.State + + t.Run("simple construction", func(t *testing.T) { + actor := market.Actor{} + receiver := tutil.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver). + WithCaller(builtin.SystemActorAddr, builtin.InitActorCodeID) + + rt := builder.Build(t) + + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + + ret := rt.Call(actor.Constructor, nil).(*adt.EmptyValue) + assert.Nil(t, ret) + rt.Verify() + + store := adt.AsStore(rt) + + emptyMap, err := adt.MakeEmptyMap(store).Root() + assert.NoError(t, err) + + emptyArray, err := adt.MakeEmptyArray(store).Root() + assert.NoError(t, err) + + emptyMultiMap, err := market.MakeEmptySetMultimap(store).Root() + assert.NoError(t, err) + + var state market.State + rt.GetState(&state) + + assert.Equal(t, emptyArray, state.Proposals) + assert.Equal(t, emptyArray, state.States) + assert.Equal(t, emptyMap, state.EscrowTable) + assert.Equal(t, emptyMap, state.LockedTable) + assert.Equal(t, abi.DealID(0), state.NextID) + assert.Equal(t, emptyMultiMap, state.DealOpsByEpoch) + assert.Equal(t, abi.ChainEpoch(-1), state.LastCron) + }) + + t.Run("AddBalance", func(t *testing.T) { + t.Run("adds to provider escrow funds", func(t *testing.T) { + testCases := []struct { + delta int64 + total int64 + }{ + {10, 10}, + {20, 30}, + {40, 70}, + } + + // Test adding provider funds from both worker and owner address + for _, callerAddr := range []address.Address{owner, worker} { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + for _, tc := range testCases { + rt.SetCaller(callerAddr, builtin.AccountActorCodeID) + rt.SetReceived(abi.NewTokenAmount(tc.delta)) + actor.expectProviderControlAddressesAndValidateCaller(rt, provider, owner, worker) + + rt.Call(actor.AddBalance, &provider) + + rt.Verify() + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(tc.total), st.GetEscrowBalance(rt, provider)) + } + } + }) + + t.Run("fails when called with negative value", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + rt.SetCaller(owner, builtin.AccountActorCodeID) + rt.SetReceived(abi.NewTokenAmount(-1)) + + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.AddBalance, &provider) + }) + + rt.Verify() + }) + + t.Run("fails unless called by an account actor", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + rt.SetReceived(abi.NewTokenAmount(10)) + actor.expectProviderControlAddressesAndValidateCaller(rt, provider, owner, worker) + + rt.SetCaller(provider, builtin.StorageMinerActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + rt.Call(actor.AddBalance, &provider) + }) + + rt.Verify() + }) + + t.Run("adds to non-provider escrow funds", func(t *testing.T) { + testCases := []struct { + delta int64 + total int64 + }{ + {10, 10}, + {20, 30}, + {40, 70}, + } + + // Test adding non-provider funds from both worker and client addresses + for _, callerAddr := range []address.Address{client, worker} { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + for _, tc := range testCases { + rt.SetCaller(callerAddr, builtin.AccountActorCodeID) + rt.SetReceived(abi.NewTokenAmount(tc.delta)) + rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) + + rt.Call(actor.AddBalance, &callerAddr) + + rt.Verify() + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(tc.total), st.GetEscrowBalance(rt, callerAddr)) + } + } + }) + }) + + t.Run("WithdrawBalance", func(t *testing.T) { + startEpoch := abi.ChainEpoch(10) + endEpoch := abi.ChainEpoch(20) + publishEpoch := abi.ChainEpoch(5) + + t.Run("fails with a negative withdraw amount", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + params := market.WithdrawBalanceParams{ + ProviderOrClientAddress: provider, + Amount: abi.NewTokenAmount(-1), + } + + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.WithdrawBalance, ¶ms) + }) + + rt.Verify() + }) + + t.Run("withdraws from provider escrow funds and sends to owner", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + actor.addProviderFunds(rt, abi.NewTokenAmount(20), minerAddrs) + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(20), st.GetEscrowBalance(rt, provider)) + + // worker calls WithdrawBalance, balance is transferred to owner + withdrawAmount := abi.NewTokenAmount(1) + actor.withdrawProviderBalance(rt, withdrawAmount, withdrawAmount, minerAddrs) + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(19), st.GetEscrowBalance(rt, provider)) + }) + + t.Run("withdraws from non-provider escrow funds", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + actor.addParticipantFunds(rt, client, abi.NewTokenAmount(20)) + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(20), st.GetEscrowBalance(rt, client)) + + withdrawAmount := abi.NewTokenAmount(1) + actor.withdrawClientBalance(rt, client, withdrawAmount, withdrawAmount) + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(19), st.GetEscrowBalance(rt, client)) + }) + + t.Run("client withdrawing more than escrow balance limits to available funds", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + actor.addParticipantFunds(rt, client, abi.NewTokenAmount(20)) + + // withdraw amount greater than escrow balance + withdrawAmount := abi.NewTokenAmount(25) + expectedAmount := abi.NewTokenAmount(20) + actor.withdrawClientBalance(rt, client, withdrawAmount, expectedAmount) + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(0), st.GetEscrowBalance(rt, client)) + }) + + t.Run("worker withdrawing more than escrow balance limits to available funds", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + actor.addProviderFunds(rt, abi.NewTokenAmount(20), minerAddrs) + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(20), st.GetEscrowBalance(rt, provider)) + + // withdraw amount greater than escrow balance + withdrawAmount := abi.NewTokenAmount(25) + actualWithdrawn := abi.NewTokenAmount(20) + actor.withdrawProviderBalance(rt, withdrawAmount, actualWithdrawn, minerAddrs) + + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(0), st.GetEscrowBalance(rt, provider)) + }) + + t.Run("balance after withdrawal must ALWAYS be greater than or equal to locked amount", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + // create the deal to publish + deal := actor.generateDealAndAddFunds(rt, client, minerAddrs, startEpoch, endEpoch) + + // publish the deal so that client AND provider collateral is locked + rt.SetEpoch(publishEpoch) + actor.publishDeals(rt, minerAddrs, deal) + rt.GetState(&st) + require.Equal(t, deal.ProviderCollateral, st.GetLockedBalance(rt, provider)) + require.Equal(t, deal.ClientBalanceRequirement(), st.GetLockedBalance(rt, client)) + + withDrawAmt := abi.NewTokenAmount(1) + withDrawableAmt := abi.NewTokenAmount(0) + // client cannot withdraw any funds since all it's balance is locked + actor.withdrawClientBalance(rt, client, withDrawAmt, withDrawableAmt) + // provider cannot withdraw any funds since all it's balance is locked + actor.withdrawProviderBalance(rt, withDrawAmt, withDrawableAmt, minerAddrs) + + // add some more funds to the provider & ensure withdrawal is limited by the locked funds + withDrawAmt = abi.NewTokenAmount(30) + withDrawableAmt = abi.NewTokenAmount(25) + actor.addProviderFunds(rt, withDrawableAmt, minerAddrs) + actor.withdrawProviderBalance(rt, withDrawAmt, withDrawableAmt, minerAddrs) + + // add some more funds to the client & ensure withdrawal is limited by the locked funds + actor.addParticipantFunds(rt, client, withDrawableAmt) + actor.withdrawClientBalance(rt, client, withDrawAmt, withDrawableAmt) + }) + + t.Run("worker balance after withdrawal must account for slashed funds", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + // create the deal to publish + deal := actor.generateDealAndAddFunds(rt, client, minerAddrs, startEpoch, endEpoch) + + // publish the deal + rt.SetEpoch(publishEpoch) + dealID := actor.publishDeals(rt, minerAddrs, deal)[0] + + // activate the deal + actor.activateDeals(rt, []abi.DealID{dealID}, endEpoch+1, provider) + st := actor.getDealState(rt, dealID) + require.EqualValues(t, publishEpoch, st.SectorStartEpoch) + + // slash the deal + rt.SetEpoch(publishEpoch + 1) + actor.terminateDeals(rt, []abi.DealID{dealID}, provider) + st = actor.getDealState(rt, dealID) + require.EqualValues(t, publishEpoch+1, st.SlashEpoch) + + // provider cannot withdraw any funds since all it's balance is locked + withDrawAmt := abi.NewTokenAmount(1) + actualWithdrawn := abi.NewTokenAmount(0) + actor.withdrawProviderBalance(rt, withDrawAmt, actualWithdrawn, minerAddrs) + + // add some more funds to the provider & ensure withdrawal is limited by the locked funds + actor.addProviderFunds(rt, abi.NewTokenAmount(25), minerAddrs) + withDrawAmt = abi.NewTokenAmount(30) + actualWithdrawn = abi.NewTokenAmount(25) + + actor.withdrawProviderBalance(rt, withDrawAmt, actualWithdrawn, minerAddrs) + }) + }) +} + +func TestPublishStorageDeals(t *testing.T) { + marketActor := tutil.NewIDAddr(t, 100) + owner := tutil.NewIDAddr(t, 101) + provider := tutil.NewIDAddr(t, 102) + worker := tutil.NewIDAddr(t, 103) + client := tutil.NewIDAddr(t, 104) + mAddr := &minerAddrs{owner, worker, provider} + var st market.State + + t.Run("publish a deal after activating a previous deal which has a start epoch far in the future", func(t *testing.T) { + startEpoch := abi.ChainEpoch(1000) + endEpoch := abi.ChainEpoch(2000) + publishEpoch := abi.ChainEpoch(1) + + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + deal1 := actor.generateDealAndAddFunds(rt, client, mAddr, startEpoch, endEpoch) + + // publish the deal and activate it + rt.SetEpoch(publishEpoch) + deal1ID := actor.publishDeals(rt, mAddr, deal1)[0] + actor.activateDeals(rt, []abi.DealID{deal1ID}, endEpoch, provider) + st := actor.getDealState(rt, deal1ID) + require.EqualValues(t, publishEpoch, st.SectorStartEpoch) + + // now publish a second deal and activate it + deal2 := actor.generateDealAndAddFunds(rt, client, mAddr, startEpoch+1, endEpoch+1) + rt.SetEpoch(publishEpoch + 1) + deal2ID := actor.publishDeals(rt, mAddr, deal2)[0] + actor.activateDeals(rt, []abi.DealID{deal2ID}, endEpoch+1, provider) + }) + + t.Run("publish multiple deals for different clients and ensure balances are correct", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + client1 := tutil.NewIDAddr(t, 900) + client2 := tutil.NewIDAddr(t, 901) + client3 := tutil.NewIDAddr(t, 902) + + // generate first deal for + deal1 := actor.generateDealAndAddFunds(rt, client1, mAddr, abi.ChainEpoch(42), abi.ChainEpoch(100)) + + // generate second deal + deal2 := actor.generateDealAndAddFunds(rt, client2, mAddr, abi.ChainEpoch(42), abi.ChainEpoch(100)) + + // generate third deal + deal3 := actor.generateDealAndAddFunds(rt, client3, mAddr, abi.ChainEpoch(42), abi.ChainEpoch(100)) + + actor.publishDeals(rt, mAddr, deal1, deal2, deal3) + + // assert locked balance for all clients and provider + providerLocked := big.Sum(deal1.ProviderCollateral, deal2.ProviderCollateral, deal3.ProviderCollateral) + client1Locked := actor.getLockedBalance(rt, client1) + client2Locked := actor.getLockedBalance(rt, client2) + client3Locked := actor.getLockedBalance(rt, client3) + require.EqualValues(t, deal1.ClientBalanceRequirement(), client1Locked) + require.EqualValues(t, deal2.ClientBalanceRequirement(), client2Locked) + require.EqualValues(t, deal3.ClientBalanceRequirement(), client3Locked) + require.EqualValues(t, providerLocked, actor.getLockedBalance(rt, provider)) + + // assert locked funds states + rt.GetState(&st) + totalClientCollateralLocked := big.Sum(deal3.ClientCollateral, deal1.ClientCollateral, deal2.ClientCollateral) + require.EqualValues(t, totalClientCollateralLocked, st.TotalClientLockedCollateral) + require.EqualValues(t, providerLocked, st.TotalProviderLockedCollateral) + totalStorageFee := big.Sum(deal1.TotalStorageFee(), deal2.TotalStorageFee(), deal3.TotalStorageFee()) + require.EqualValues(t, totalStorageFee, st.TotalClientStorageFee) + + // publish two more deals for same clients with same provider + deal4 := actor.generateDealAndAddFunds(rt, client3, mAddr, abi.ChainEpoch(1000), abi.ChainEpoch(10000)) + deal5 := actor.generateDealAndAddFunds(rt, client3, mAddr, abi.ChainEpoch(100), abi.ChainEpoch(1000)) + actor.publishDeals(rt, mAddr, deal4, deal5) + + // assert locked balances for clients and provider + rt.GetState(&st) + providerLocked = big.Sum(providerLocked, deal4.ProviderCollateral, deal5.ProviderCollateral) + require.EqualValues(t, providerLocked, actor.getLockedBalance(rt, provider)) + + client3LockedUpdated := actor.getLockedBalance(rt, client3) + require.EqualValues(t, big.Sum(client3Locked, deal4.ClientBalanceRequirement(), deal5.ClientBalanceRequirement()), client3LockedUpdated) + + client1Locked = actor.getLockedBalance(rt, client1) + client2Locked = actor.getLockedBalance(rt, client2) + require.EqualValues(t, deal1.ClientBalanceRequirement(), client1Locked) + require.EqualValues(t, deal2.ClientBalanceRequirement(), client2Locked) + + // assert locked funds states + totalClientCollateralLocked = big.Sum(totalClientCollateralLocked, deal4.ClientCollateral, deal5.ClientCollateral) + require.EqualValues(t, totalClientCollateralLocked, st.TotalClientLockedCollateral) + require.EqualValues(t, providerLocked, st.TotalProviderLockedCollateral) + + totalStorageFee = big.Sum(totalStorageFee, deal4.TotalStorageFee(), deal5.TotalStorageFee()) + require.EqualValues(t, totalStorageFee, st.TotalClientStorageFee) + + // PUBLISH DEALS with a different provider + provider2 := tutil.NewIDAddr(t, 109) + miner := &minerAddrs{owner, worker, provider2} + + // generate first deal for second provider + deal6 := actor.generateDealAndAddFunds(rt, client1, miner, abi.ChainEpoch(20), abi.ChainEpoch(50)) + + // generate second deal for second provider + deal7 := actor.generateDealAndAddFunds(rt, client1, miner, abi.ChainEpoch(25), abi.ChainEpoch(60)) + + // publish both the deals for the second provider + actor.publishDeals(rt, miner, deal6, deal7) + + // assertions + rt.GetState(&st) + provider2Locked := big.Add(deal6.ProviderCollateral, deal7.ProviderCollateral) + require.EqualValues(t, provider2Locked, actor.getLockedBalance(rt, provider2)) + client1LockedUpdated := actor.getLockedBalance(rt, client1) + require.EqualValues(t, big.Add(deal7.ClientBalanceRequirement(), big.Add(client1Locked, deal6.ClientBalanceRequirement())), client1LockedUpdated) + + // assert first provider's balance as well + require.EqualValues(t, providerLocked, actor.getLockedBalance(rt, provider)) + + totalClientCollateralLocked = big.Add(totalClientCollateralLocked, big.Add(deal6.ClientCollateral, deal7.ClientCollateral)) + require.EqualValues(t, totalClientCollateralLocked, st.TotalClientLockedCollateral) + require.EqualValues(t, big.Add(providerLocked, provider2Locked), st.TotalProviderLockedCollateral) + totalStorageFee = big.Add(totalStorageFee, big.Add(deal6.TotalStorageFee(), deal7.TotalStorageFee())) + require.EqualValues(t, totalStorageFee, st.TotalClientStorageFee) + }) +} + +func TestPublishStorageDealsFailures(t *testing.T) { + marketActor := tutil.NewIDAddr(t, 100) + owner := tutil.NewIDAddr(t, 101) + provider := tutil.NewIDAddr(t, 102) + worker := tutil.NewIDAddr(t, 103) + client := tutil.NewIDAddr(t, 104) + mAddrs := &minerAddrs{owner, worker, provider} + + currentEpoch := abi.ChainEpoch(5) + startEpoch := abi.ChainEpoch(10) + endEpoch := abi.ChainEpoch(20) + + // simple failures because of invalid deal params + { + tcs := map[string]struct { + setup func(*mock.Runtime, *marketActorTestHarness, *market.DealProposal) + exitCode exitcode.ExitCode + signatureVerificationError error + }{ + "deal end after deal start": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.StartEpoch = 10 + d.EndEpoch = 9 + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "current epoch greater than start epoch": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.StartEpoch = currentEpoch - 1 + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "deal duration greater than max deal duration": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.StartEpoch = abi.ChainEpoch(10) + d.EndEpoch = d.StartEpoch + (1 * builtin.EpochsInYear) + 1 + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "negative price per epoch": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.StoragePricePerEpoch = abi.NewTokenAmount(-1) + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "price per epoch greater than total filecoin": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.StoragePricePerEpoch = big.Add(abi.TotalFilecoin, big.NewInt(1)) + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "negative provider collateral": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.ProviderCollateral = big.NewInt(-1) + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "provider collateral greater than max collateral": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.ProviderCollateral = big.Add(abi.TotalFilecoin, big.NewInt(1)) + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "negative client collateral": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.ClientCollateral = big.NewInt(-1) + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "client collateral greater than max collateral": { + setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { + d.ClientCollateral = big.Add(abi.TotalFilecoin, big.NewInt(1)) + }, + exitCode: exitcode.ErrIllegalArgument, + }, + "client does not have enough balance for collateral": { + setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { + a.addParticipantFunds(rt, client, big.Sub(d.ClientBalanceRequirement(), big.NewInt(1))) + a.addProviderFunds(rt, d.ProviderCollateral, mAddrs) + }, + exitCode: exitcode.ErrInsufficientFunds, + }, + "provider does not have enough balance for collateral": { + setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { + a.addParticipantFunds(rt, client, d.ClientBalanceRequirement()) + a.addProviderFunds(rt, big.Sub(d.ProviderCollateral, big.NewInt(1)), mAddrs) + }, + exitCode: exitcode.ErrInsufficientFunds, + }, + "unable to resolve client address": { + setup: func(_ *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { + d.Client = tutil.NewBLSAddr(t, 1) + }, + exitCode: exitcode.ErrNotFound, + }, + "signature is invalid": { + setup: func(_ *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { + + }, + exitCode: exitcode.ErrIllegalArgument, + signatureVerificationError: errors.New("error"), + }, + "no entry for client in locked balance table": { + setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { + a.addProviderFunds(rt, d.ProviderCollateral, mAddrs) + }, + exitCode: exitcode.ErrInsufficientFunds, + }, + "no entry for provider in locked balance table": { + setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { + a.addParticipantFunds(rt, client, d.ClientBalanceRequirement()) + }, + exitCode: exitcode.ErrInsufficientFunds, + }, + } + + for name, tc := range tcs { + t.Run(name, func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + dealProposal := generateDealProposal(client, provider, startEpoch, endEpoch) + rt.SetEpoch(currentEpoch) + tc.setup(rt, actor, &dealProposal) + params := mkPublishStorageParams(dealProposal) + + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectVerifySignature(crypto.Signature{}, dealProposal.Client, mustCbor(&dealProposal), tc.signatureVerificationError) + rt.ExpectAbort(tc.exitCode, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + + rt.Verify() + }) + } + } + + // fails when client or provider has some funds but not enough to cover a deal + { + t.Run("fail when client has some funds but not enough for a deal", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + // + actor.addParticipantFunds(rt, client, abi.NewTokenAmount(100)) + deal1 := generateDealProposal(client, provider, abi.ChainEpoch(42), abi.ChainEpoch(100)) + actor.addProviderFunds(rt, deal1.ProviderCollateral, mAddrs) + params := mkPublishStorageParams(deal1) + + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectVerifySignature(crypto.Signature{}, deal1.Client, mustCbor(&deal1), nil) + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + + rt.Verify() + }) + + t.Run("fail when provider has some funds but not enough for a deal", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + + actor.addProviderFunds(rt, abi.NewTokenAmount(1), mAddrs) + deal1 := generateDealProposal(client, provider, abi.ChainEpoch(42), abi.ChainEpoch(100)) + actor.addParticipantFunds(rt, client, deal1.ClientBalanceRequirement()) + + params := mkPublishStorageParams(deal1) + + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectVerifySignature(crypto.Signature{}, deal1.Client, mustCbor(&deal1), nil) + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + + rt.Verify() + }) + } + + // fail when deals have different providers + { + t.Run("fail when deals have different providers", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + deal1 := actor.generateDealAndAddFunds(rt, client, mAddrs, abi.ChainEpoch(42), abi.ChainEpoch(100)) + m2 := &minerAddrs{owner, worker, tutil.NewIDAddr(t, 1000)} + + deal2 := actor.generateDealAndAddFunds(rt, client, m2, abi.ChainEpoch(1), abi.ChainEpoch(5)) + + params := mkPublishStorageParams(deal1, deal2) + + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectVerifySignature(crypto.Signature{}, deal1.Client, mustCbor(&deal1), nil) + rt.ExpectVerifySignature(crypto.Signature{}, deal2.Client, mustCbor(&deal2), nil) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + + rt.Verify() + }) + + // failures because of incorrect call params + t.Run("fail when caller is not of signable type", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + params := mkPublishStorageParams(generateDealProposal(client, provider, abi.ChainEpoch(1), abi.ChainEpoch(5))) + w := tutil.NewIDAddr(t, 1000) + rt.SetCaller(w, builtin.StorageMinerActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + }) + + t.Run("fail when no deals in params", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + params := mkPublishStorageParams() + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + }) + + t.Run("fail to resolve provider address", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + deal := generateDealProposal(client, provider, abi.ChainEpoch(1), abi.ChainEpoch(5)) + deal.Provider = tutil.NewBLSAddr(t, 100) + + params := mkPublishStorageParams(deal) + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrNotFound, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + }) + + t.Run("caller is not the same as the worker address for miner", func(t *testing.T) { + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + deal := generateDealProposal(client, provider, abi.ChainEpoch(1), abi.ChainEpoch(5)) + params := mkPublishStorageParams(deal) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: tutil.NewIDAddr(t, 999), Owner: owner}, 0) + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + + rt.Verify() + }) + } +} + +func TestMarketActorDeals(t *testing.T) { + marketActor := tutil.NewIDAddr(t, 100) + owner := tutil.NewIDAddr(t, 101) + provider := tutil.NewIDAddr(t, 102) + worker := tutil.NewIDAddr(t, 103) + client := tutil.NewIDAddr(t, 104) + minerAddrs := &minerAddrs{owner, worker, provider} + + var st market.State + + // Test adding provider funds from both worker and owner address + rt, actor := basicMarketSetup(t, marketActor, owner, provider, worker, client) + actor.addProviderFunds(rt, abi.NewTokenAmount(10000), minerAddrs) + rt.GetState(&st) + assert.Equal(t, abi.NewTokenAmount(10000), st.GetEscrowBalance(rt, provider)) + + actor.addParticipantFunds(rt, client, abi.NewTokenAmount(10000)) + + dealProposal := generateDealProposal(client, provider, abi.ChainEpoch(1), abi.ChainEpoch(5)) + params := &market.PublishStorageDealsParams{Deals: []market.ClientDealProposal{market.ClientDealProposal{Proposal: dealProposal}}} + + // First attempt at publishing the deal should work + { + actor.publishDeals(rt, minerAddrs, dealProposal) + } + + // Second attempt at publishing the same deal should fail + { + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) + + rt.ExpectVerifySignature(crypto.Signature{}, client, mustCbor(¶ms.Deals[0].Proposal), nil) + rt.SetCaller(worker, builtin.AccountActorCodeID) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.PublishStorageDeals, params) + }) + + rt.Verify() + } + + dealProposal.Label = "foo" + + // Same deal with a different label should work + { + actor.publishDeals(rt, minerAddrs, dealProposal) + } +} + +type marketActorTestHarness struct { + market.Actor + t testing.TB +} + +func (h *marketActorTestHarness) constructAndVerify(rt *mock.Runtime) { + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + ret := rt.Call(h.Constructor, nil) + assert.Nil(h.t, ret) + rt.Verify() +} + +type minerAddrs struct { + owner address.Address + worker address.Address + provider address.Address +} + +// addProviderFunds is a helper method to setup provider market funds +func (h *marketActorTestHarness) addProviderFunds(rt *mock.Runtime, amount abi.TokenAmount, minerAddrs *minerAddrs) { + rt.SetReceived(amount) + rt.SetAddressActorType(minerAddrs.provider, builtin.StorageMinerActorCodeID) + rt.SetCaller(minerAddrs.owner, builtin.AccountActorCodeID) + h.expectProviderControlAddressesAndValidateCaller(rt, minerAddrs.provider, minerAddrs.owner, minerAddrs.worker) + + rt.Call(h.AddBalance, &minerAddrs.provider) + + rt.Verify() + + rt.SetBalance(big.Add(rt.Balance(), amount)) +} + +// addParticipantFunds is a helper method to setup non-provider storage market participant funds +func (h *marketActorTestHarness) addParticipantFunds(rt *mock.Runtime, addr address.Address, amount abi.TokenAmount) { + rt.SetReceived(amount) + rt.SetCaller(addr, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) + + rt.Call(h.AddBalance, &addr) + + rt.Verify() + + rt.SetBalance(big.Add(rt.Balance(), amount)) +} + +func (h *marketActorTestHarness) expectProviderControlAddressesAndValidateCaller(rt *mock.Runtime, provider address.Address, owner address.Address, worker address.Address) { + rt.ExpectValidateCallerAddr(owner, worker) + + expectRet := &miner.GetControlAddressesReturn{Owner: owner, Worker: worker} + + rt.ExpectSend( + provider, + builtin.MethodsMiner.ControlAddresses, + nil, + big.Zero(), + expectRet, + exitcode.Ok, + ) +} + +func (h *marketActorTestHarness) withdrawProviderBalance(rt *mock.Runtime, withDrawAmt, expectedSend abi.TokenAmount, miner *minerAddrs) { + rt.SetCaller(miner.worker, builtin.AccountActorCodeID) + h.expectProviderControlAddressesAndValidateCaller(rt, miner.provider, miner.owner, miner.worker) + + params := market.WithdrawBalanceParams{ + ProviderOrClientAddress: miner.provider, + Amount: withDrawAmt, + } + + rt.ExpectSend(miner.owner, builtin.MethodSend, nil, expectedSend, nil, exitcode.Ok) + rt.Call(h.WithdrawBalance, ¶ms) + rt.Verify() +} + +func (h *marketActorTestHarness) withdrawClientBalance(rt *mock.Runtime, client address.Address, withDrawAmt, expectedSend abi.TokenAmount) { + rt.SetCaller(client, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) + rt.ExpectSend(client, builtin.MethodSend, nil, expectedSend, nil, exitcode.Ok) + + params := market.WithdrawBalanceParams{ + ProviderOrClientAddress: client, + Amount: withDrawAmt, + } + + rt.Call(h.WithdrawBalance, ¶ms) + rt.Verify() +} + +func (h *marketActorTestHarness) publishDeals(rt *mock.Runtime, minerAddrs *minerAddrs, deals ...market.DealProposal) []abi.DealID { + rt.SetCaller(minerAddrs.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) + rt.ExpectSend( + minerAddrs.provider, + builtin.MethodsMiner.ControlAddresses, + nil, + big.Zero(), + &miner.GetControlAddressesReturn{Owner: minerAddrs.owner, Worker: minerAddrs.worker}, + exitcode.Ok, + ) + + var params market.PublishStorageDealsParams + + for _, deal := range deals { + // create a client proposal with a valid signature + buf := bytes.Buffer{} + require.NoError(h.t, deal.MarshalCBOR(&buf), "failed to marshal deal proposal") + sig := crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("does not matter")} + clientProposal := market.ClientDealProposal{deal, sig} + params.Deals = append(params.Deals, clientProposal) + + // expect a call to verify the above signature + rt.ExpectVerifySignature(sig, deal.Client, buf.Bytes(), nil) + } + + ret := rt.Call(h.PublishStorageDeals, ¶ms) + rt.Verify() + + resp, ok := ret.(*market.PublishStorageDealsReturn) + require.True(h.t, ok, "unexpected type returned from call to PublishStorageDeals") + require.Len(h.t, resp.IDs, len(deals)) + + // assert state after publishing the deals + dealIds := resp.IDs + for i, deaId := range dealIds { + expected := deals[i] + p := h.getDealProposal(rt, deaId) + + require.Equal(h.t, expected.StartEpoch, p.StartEpoch) + require.Equal(h.t, expected.EndEpoch, p.EndEpoch) + require.Equal(h.t, expected.PieceCID, p.PieceCID) + require.Equal(h.t, expected.PieceSize, p.PieceSize) + require.Equal(h.t, expected.Client, p.Client) + require.Equal(h.t, expected.Provider, p.Provider) + require.Equal(h.t, expected.Label, p.Label) + require.Equal(h.t, expected.VerifiedDeal, p.VerifiedDeal) + require.Equal(h.t, expected.StoragePricePerEpoch, p.StoragePricePerEpoch) + require.Equal(h.t, expected.ClientCollateral, p.ClientCollateral) + require.Equal(h.t, expected.ProviderCollateral, p.ProviderCollateral) + } + + return resp.IDs +} + +func (h *marketActorTestHarness) activateDeals(rt *mock.Runtime, dealIDs []abi.DealID, sectorExpiry abi.ChainEpoch, minerAddr address.Address) { + rt.SetCaller(minerAddr, builtin.StorageMinerActorCodeID) + rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) + + params := &market.ActivateDealsParams{DealIDs: dealIDs, SectorExpiry: sectorExpiry} + + ret := rt.Call(h.ActivateDeals, params) + rt.Verify() + + require.Nil(h.t, ret) +} + +func (h *marketActorTestHarness) getDealProposal(rt *mock.Runtime, dealID abi.DealID) *market.DealProposal { + var st market.State + rt.GetState(&st) + + deals, err := market.AsDealProposalArray(adt.AsStore(rt), st.Proposals) + require.NoError(h.t, err) + + d, found, err := deals.Get(dealID) + require.NoError(h.t, err) + require.True(h.t, found) + require.NotNil(h.t, d) + + return d +} + +func (h *marketActorTestHarness) getLockedBalance(rt *mock.Runtime, addr address.Address) abi.TokenAmount { + var st market.State + rt.GetState(&st) + + return st.GetLockedBalance(rt, addr) +} + +func (h *marketActorTestHarness) getDealState(rt *mock.Runtime, dealID abi.DealID) *market.DealState { + var st market.State + rt.GetState(&st) + + states, err := market.AsDealStateArray(adt.AsStore(rt), st.States) + require.NoError(h.t, err) + + s, found, err := states.Get(dealID) + require.NoError(h.t, err) + require.True(h.t, found) + require.NotNil(h.t, s) + + return s +} + +func (h *marketActorTestHarness) terminateDeals(rt *mock.Runtime, dealIDs []abi.DealID, minerAddr address.Address) { + rt.SetCaller(minerAddr, builtin.StorageMinerActorCodeID) + rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) + + params := &market.OnMinerSectorsTerminateParams{DealIDs: dealIDs} + + ret := rt.Call(h.OnMinerSectorsTerminate, params) + rt.Verify() + + require.Nil(h.t, ret) +} + +func (h *marketActorTestHarness) generateDealAndAddFunds(rt *mock.Runtime, client address.Address, minerAddrs *minerAddrs, + startEpoch, endEpoch abi.ChainEpoch) market.DealProposal { + deal4 := generateDealProposal(client, minerAddrs.provider, startEpoch, endEpoch) + h.addProviderFunds(rt, deal4.ProviderCollateral, minerAddrs) + h.addParticipantFunds(rt, client, deal4.ClientBalanceRequirement()) + return deal4 +} + +func generateDealProposal(client, provider address.Address, startEpoch, endEpoch abi.ChainEpoch) market.DealProposal { + pieceCid := tutil.MakeCID("1") + pieceSize := abi.PaddedPieceSize(2048) + storagePerEpoch := big.NewInt(10) + clientCollateral := big.NewInt(10) + providerCollateral := big.NewInt(10) + + return market.DealProposal{pieceCid, pieceSize, false, client, provider, "label", startEpoch, + endEpoch, storagePerEpoch, providerCollateral, clientCollateral} +} + +func basicMarketSetup(t *testing.T, ma, owner, provider, worker, client address.Address) (*mock.Runtime, *marketActorTestHarness) { + builder := mock.NewBuilder(context.Background(), ma). + WithCaller(builtin.SystemActorAddr, builtin.InitActorCodeID). + WithActorType(owner, builtin.AccountActorCodeID). + WithActorType(worker, builtin.AccountActorCodeID). + WithActorType(provider, builtin.StorageMinerActorCodeID). + WithActorType(client, builtin.AccountActorCodeID) + + rt := builder.Build(t) + + actor := marketActorTestHarness{t: t} + actor.constructAndVerify(rt) + + return rt, &actor +} + +func mkPublishStorageParams(proposals ...market.DealProposal) *market.PublishStorageDealsParams { + m := &market.PublishStorageDealsParams{} + for _, p := range proposals { + m.Deals = append(m.Deals, market.ClientDealProposal{Proposal: p}) + } + return m +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/policy.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/policy.go new file mode 100644 index 0000000000..bdbe4b85c0 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/policy.go @@ -0,0 +1,42 @@ +package market + +import ( + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" +) + +// DealUpdatesInterval is the number of blocks between payouts for deals +const DealUpdatesInterval = 100 + +// Bounds (inclusive) on deal duration +func dealDurationBounds(size abi.PaddedPieceSize) (min abi.ChainEpoch, max abi.ChainEpoch) { + // Cryptoeconomic modelling to date has used an assumption of a maximum deal duration of up to one year. + // It very likely can be much longer, but we're not sure yet. + return abi.ChainEpoch(0), abi.ChainEpoch(1 * builtin.EpochsInYear) // PARAM_FINISH +} + +func dealPricePerEpochBounds(size abi.PaddedPieceSize, duration abi.ChainEpoch) (min abi.TokenAmount, max abi.TokenAmount) { + return abi.NewTokenAmount(0), abi.TotalFilecoin // PARAM_FINISH +} + +func dealProviderCollateralBounds(pieceSize abi.PaddedPieceSize, duration abi.ChainEpoch) (min abi.TokenAmount, max abi.TokenAmount) { + return abi.NewTokenAmount(0), abi.TotalFilecoin // PARAM_FINISH +} + +func dealClientCollateralBounds(pieceSize abi.PaddedPieceSize, duration abi.ChainEpoch) (min abi.TokenAmount, max abi.TokenAmount) { + return abi.NewTokenAmount(0), abi.TotalFilecoin // PARAM_FINISH +} + +// Penalty to provider deal collateral if the deadline expires before sector commitment. +func collateralPenaltyForDealActivationMissed(providerCollateral abi.TokenAmount) abi.TokenAmount { + return providerCollateral // PARAM_FINISH +} + +// Computes the weight for a deal proposal, which is a function of its size and duration. +func DealWeight(proposal *DealProposal) abi.DealWeight { + dealDuration := big.NewInt(int64(proposal.Duration())) + dealSize := big.NewIntUnsigned(uint64(proposal.PieceSize)) + dealSpaceTime := big.Mul(dealDuration, dealSize) + return dealSpaceTime +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/set_multimap.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/set_multimap.go new file mode 100644 index 0000000000..049d986550 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/set_multimap.go @@ -0,0 +1,159 @@ +package market + +import ( + "reflect" + + cid "github.com/ipfs/go-cid" + "github.com/ipfs/go-hamt-ipld" + errors "github.com/pkg/errors" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type SetMultimap struct { + mp *adt.Map + store adt.Store +} + +// Interprets a store as a HAMT-based map of HAMT-based sets with root `r`. +func AsSetMultimap(s adt.Store, r cid.Cid) (*SetMultimap, error) { + m, err := adt.AsMap(s, r) + if err != nil { + return nil, err + } + return &SetMultimap{mp: m, store: s}, nil +} + +// Creates a new map backed by an empty HAMT and flushes it to the store. +func MakeEmptySetMultimap(s adt.Store) *SetMultimap { + m := adt.MakeEmptyMap(s) + return &SetMultimap{m, s} +} + +// Returns the root cid of the underlying HAMT. +func (mm *SetMultimap) Root() (cid.Cid, error) { + return mm.mp.Root() +} + +func (mm *SetMultimap) Put(epoch abi.ChainEpoch, v abi.DealID) error { + // Load the hamt under key, or initialize a new empty one if not found. + k := adt.UIntKey(uint64(epoch)) + set, found, err := mm.get(k) + if err != nil { + return err + } + if !found { + set = adt.MakeEmptySet(mm.store) + } + + // Add to the set. + if err = set.Put(dealKey(v)); err != nil { + return errors.Wrapf(err, "failed to add key to set %v", epoch) + } + + src, err := set.Root() + if err != nil { + return xerrors.Errorf("failed to flush set root: %w", err) + } + // Store the new set root under key. + newSetRoot := cbg.CborCid(src) + err = mm.mp.Put(k, &newSetRoot) + if err != nil { + return errors.Wrapf(err, "failed to store set") + } + return nil +} + +func (mm *SetMultimap) PutMany(epoch abi.ChainEpoch, vs []abi.DealID) error { + // Load the hamt under key, or initialize a new empty one if not found. + k := adt.UIntKey(uint64(epoch)) + set, found, err := mm.get(k) + if err != nil { + return err + } + if !found { + set = adt.MakeEmptySet(mm.store) + } + + // Add to the set. + for _, v := range vs { + if err = set.Put(dealKey(v)); err != nil { + return errors.Wrapf(err, "failed to add key to set %v", epoch) + } + } + + src, err := set.Root() + if err != nil { + return xerrors.Errorf("failed to flush set root: %w", err) + } + // Store the new set root under key. + newSetRoot := cbg.CborCid(src) + err = mm.mp.Put(k, &newSetRoot) + if err != nil { + return errors.Wrapf(err, "failed to store set") + } + return nil +} + +// Removes all values for a key. +func (mm *SetMultimap) RemoveAll(key abi.ChainEpoch) error { + err := mm.mp.Delete(adt.UIntKey(uint64(key))) + if err != nil && !xerrors.Is(err, hamt.ErrNotFound) { + return xerrors.Errorf("failed to delete set key %v: %w", key, err) + } + return nil +} + +// Iterates all entries for a key, iteration halts if the function returns an error. +func (mm *SetMultimap) ForEach(epoch abi.ChainEpoch, fn func(id abi.DealID) error) error { + set, found, err := mm.get(adt.UIntKey(uint64(epoch))) + if err != nil { + return err + } + if found { + return set.ForEach(func(k string) error { + v, err := parseDealKey(k) + if err != nil { + return err + } + return fn(v) + }) + } + return nil +} + +func (mm *SetMultimap) get(key adt.Keyer) (*adt.Set, bool, error) { + var setRoot cbg.CborCid + found, err := mm.mp.Get(key, &setRoot) + if err != nil { + return nil, false, errors.Wrapf(err, "failed to load set key %v", key) + } + var set *adt.Set + if found { + set, err = adt.AsSet(mm.store, cid.Cid(setRoot)) + if err != nil { + return nil, false, err + } + } + return set, found, nil +} + +func dealKey(e abi.DealID) adt.Keyer { + return adt.UIntKey(uint64(e)) +} + +func parseDealKey(s string) (abi.DealID, error) { + key, err := adt.ParseUIntKey(s) + return abi.DealID(key), err +} + +func init() { + // Check that DealID is indeed an unsigned integer to confirm that dealKey is making the right interpretation. + var e abi.DealID + if reflect.TypeOf(e).Kind() != reflect.Uint64 { + panic("incorrect sector number encoding") + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/types.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/types.go new file mode 100644 index 0000000000..affe5b5608 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/market/types.go @@ -0,0 +1,89 @@ +package market + +import ( + "github.com/filecoin-project/specs-actors/actors/abi" + . "github.com/filecoin-project/specs-actors/actors/util/adt" + + "github.com/ipfs/go-cid" +) + +// A specialization of a array to deals. +// It is an error to query for a key that doesn't exist. +type DealArray struct { + *Array +} + +// Interprets a store as balance table with root `r`. +func AsDealProposalArray(s Store, r cid.Cid) (*DealArray, error) { + a, err := AsArray(s, r) + if err != nil { + return nil, err + } + return &DealArray{a}, nil +} + +// Returns the root cid of underlying AMT. +func (t *DealArray) Root() (cid.Cid, error) { + return t.Array.Root() +} + +// Gets the deal for a key. The entry must have been previously initialized. +func (t *DealArray) Get(id abi.DealID) (*DealProposal, bool, error) { + var value DealProposal + found, err := t.Array.Get(uint64(id), &value) + return &value, found, err +} + +func (t *DealArray) Set(k abi.DealID, value *DealProposal) error { + return t.Array.Set(uint64(k), value) +} + +func (t *DealArray) Delete(key uint64) error { + return t.Array.Delete(key) +} + +// A specialization of a array to deals. +// It is an error to query for a key that doesn't exist. +type DealMetaArray struct { + *Array +} + +// Interprets a store as balance table with root `r`. +func AsDealStateArray(s Store, r cid.Cid) (*DealMetaArray, error) { + dsa, err := AsArray(s, r) + if err != nil { + return nil, err + } + + return &DealMetaArray{dsa}, nil +} + +// Returns the root cid of underlying AMT. +func (t *DealMetaArray) Root() (cid.Cid, error) { + return t.Array.Root() +} + +// Gets the deal for a key. The entry must have been previously initialized. +func (t *DealMetaArray) Get(id abi.DealID) (*DealState, bool, error) { + var value DealState + found, err := t.Array.Get(uint64(id), &value) + if err != nil { + return nil, false, err // The errors from Map carry good information, no need to wrap here. + } + if !found { + return &DealState{ + SectorStartEpoch: epochUndefined, + LastUpdatedEpoch: epochUndefined, + SlashEpoch: epochUndefined, + }, false, nil + } + return &value, true, nil +} + +func (t *DealMetaArray) Set(k abi.DealID, value *DealState) error { + return t.Array.Set(uint64(k), value) +} + +func (t *DealMetaArray) Delete(id abi.DealID) error { + return t.Array.Delete(uint64(id)) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/methods.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/methods.go new file mode 100644 index 0000000000..181f27390d --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/methods.go @@ -0,0 +1,108 @@ +package builtin + +import ( + abi "github.com/filecoin-project/specs-actors/actors/abi" +) + +const ( + MethodSend = abi.MethodNum(0) + MethodConstructor = abi.MethodNum(1) + + // TODO fin: remove this once canonical method numbers are finalized + // https://github.com/filecoin-project/specs-actors/issues/461 + MethodPlaceholder = abi.MethodNum(1 << 30) +) + +var MethodsAccount = struct { + Constructor abi.MethodNum + PubkeyAddress abi.MethodNum +}{MethodConstructor, 2} + +var MethodsInit = struct { + Constructor abi.MethodNum + Exec abi.MethodNum +}{MethodConstructor, 2} + +var MethodsCron = struct { + Constructor abi.MethodNum + EpochTick abi.MethodNum +}{MethodConstructor, 2} + +var MethodsReward = struct { + Constructor abi.MethodNum + AwardBlockReward abi.MethodNum + ThisEpochReward abi.MethodNum + UpdateNetworkKPI abi.MethodNum +}{MethodConstructor, 2, 3, 4} + +var MethodsMultisig = struct { + Constructor abi.MethodNum + Propose abi.MethodNum + Approve abi.MethodNum + Cancel abi.MethodNum + AddSigner abi.MethodNum + RemoveSigner abi.MethodNum + SwapSigner abi.MethodNum + ChangeNumApprovalsThreshold abi.MethodNum +}{MethodConstructor, 2, 3, 4, 5, 6, 7, 8} + +var MethodsPaych = struct { + Constructor abi.MethodNum + UpdateChannelState abi.MethodNum + Settle abi.MethodNum + Collect abi.MethodNum +}{MethodConstructor, 2, 3, 4} + +var MethodsMarket = struct { + Constructor abi.MethodNum + AddBalance abi.MethodNum + WithdrawBalance abi.MethodNum + PublishStorageDeals abi.MethodNum + VerifyDealsForActivation abi.MethodNum + ActivateDeals abi.MethodNum + OnMinerSectorsTerminate abi.MethodNum + ComputeDataCommitment abi.MethodNum + CronTick abi.MethodNum +}{MethodConstructor, 2, 3, 4, 5, 6, 7, 8, 9} + +var MethodsPower = struct { + Constructor abi.MethodNum + CreateMiner abi.MethodNum + UpdateClaimedPower abi.MethodNum + EnrollCronEvent abi.MethodNum + OnEpochTickEnd abi.MethodNum + UpdatePledgeTotal abi.MethodNum + OnConsensusFault abi.MethodNum + SubmitPoRepForBulkVerify abi.MethodNum + CurrentTotalPower abi.MethodNum +}{MethodConstructor, 2, 3, 4, 5, 6, 7, 8, 9} + +var MethodsMiner = struct { + Constructor abi.MethodNum + ControlAddresses abi.MethodNum + ChangeWorkerAddress abi.MethodNum + ChangePeerID abi.MethodNum + SubmitWindowedPoSt abi.MethodNum + PreCommitSector abi.MethodNum + ProveCommitSector abi.MethodNum + ExtendSectorExpiration abi.MethodNum + TerminateSectors abi.MethodNum + DeclareFaults abi.MethodNum + DeclareFaultsRecovered abi.MethodNum + OnDeferredCronEvent abi.MethodNum + CheckSectorProven abi.MethodNum + AddLockedFund abi.MethodNum + ReportConsensusFault abi.MethodNum + WithdrawBalance abi.MethodNum + ConfirmSectorProofsValid abi.MethodNum + ChangeMultiaddrs abi.MethodNum +}{MethodConstructor, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + +var MethodsVerifiedRegistry = struct { + Constructor abi.MethodNum + AddVerifier abi.MethodNum + RemoveVerifier abi.MethodNum + AddVerifiedClient abi.MethodNum + UseBytes abi.MethodNum + RestoreBytes abi.MethodNum +}{MethodConstructor, 2, 3, 4, 5, 6} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/cbor_gen.go new file mode 100644 index 0000000000..67c4b0ecbf --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/cbor_gen.go @@ -0,0 +1,2645 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package miner + +import ( + "fmt" + "io" + + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{144}); err != nil { + return err + } + + // t.Info (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.Info); err != nil { + return xerrors.Errorf("failed to write cid field t.Info: %w", err) + } + + // t.PreCommitDeposits (big.Int) (struct) + if err := t.PreCommitDeposits.MarshalCBOR(w); err != nil { + return err + } + + // t.LockedFunds (big.Int) (struct) + if err := t.LockedFunds.MarshalCBOR(w); err != nil { + return err + } + + // t.VestingFunds (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.VestingFunds); err != nil { + return xerrors.Errorf("failed to write cid field t.VestingFunds: %w", err) + } + + // t.InitialPledgeRequirement (big.Int) (struct) + if err := t.InitialPledgeRequirement.MarshalCBOR(w); err != nil { + return err + } + + // t.PreCommittedSectors (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.PreCommittedSectors); err != nil { + return xerrors.Errorf("failed to write cid field t.PreCommittedSectors: %w", err) + } + + // t.Sectors (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.Sectors); err != nil { + return xerrors.Errorf("failed to write cid field t.Sectors: %w", err) + } + + // t.ProvingPeriodStart (abi.ChainEpoch) (int64) + if t.ProvingPeriodStart >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ProvingPeriodStart))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.ProvingPeriodStart)-1)); err != nil { + return err + } + } + + // t.NewSectors (bitfield.BitField) (struct) + if err := t.NewSectors.MarshalCBOR(w); err != nil { + return err + } + + // t.SectorExpirations (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.SectorExpirations); err != nil { + return xerrors.Errorf("failed to write cid field t.SectorExpirations: %w", err) + } + + // t.Deadlines (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.Deadlines); err != nil { + return xerrors.Errorf("failed to write cid field t.Deadlines: %w", err) + } + + // t.Faults (bitfield.BitField) (struct) + if err := t.Faults.MarshalCBOR(w); err != nil { + return err + } + + // t.FaultEpochs (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.FaultEpochs); err != nil { + return xerrors.Errorf("failed to write cid field t.FaultEpochs: %w", err) + } + + // t.Recoveries (bitfield.BitField) (struct) + if err := t.Recoveries.MarshalCBOR(w); err != nil { + return err + } + + // t.PostSubmissions (bitfield.BitField) (struct) + if err := t.PostSubmissions.MarshalCBOR(w); err != nil { + return err + } + + // t.NextDeadlineToProcessFaults (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NextDeadlineToProcessFaults))); err != nil { + return err + } + + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 16 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Info (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Info: %w", err) + } + + t.Info = c + + } + // t.PreCommitDeposits (big.Int) (struct) + + { + + if err := t.PreCommitDeposits.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.PreCommitDeposits: %w", err) + } + + } + // t.LockedFunds (big.Int) (struct) + + { + + if err := t.LockedFunds.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.LockedFunds: %w", err) + } + + } + // t.VestingFunds (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.VestingFunds: %w", err) + } + + t.VestingFunds = c + + } + // t.InitialPledgeRequirement (big.Int) (struct) + + { + + if err := t.InitialPledgeRequirement.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.InitialPledgeRequirement: %w", err) + } + + } + // t.PreCommittedSectors (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.PreCommittedSectors: %w", err) + } + + t.PreCommittedSectors = c + + } + // t.Sectors (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Sectors: %w", err) + } + + t.Sectors = c + + } + // t.ProvingPeriodStart (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.ProvingPeriodStart = abi.ChainEpoch(extraI) + } + // t.NewSectors (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.NewSectors = new(bitfield.BitField) + if err := t.NewSectors.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.NewSectors pointer: %w", err) + } + } + + } + // t.SectorExpirations (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.SectorExpirations: %w", err) + } + + t.SectorExpirations = c + + } + // t.Deadlines (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Deadlines: %w", err) + } + + t.Deadlines = c + + } + // t.Faults (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Faults = new(bitfield.BitField) + if err := t.Faults.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Faults pointer: %w", err) + } + } + + } + // t.FaultEpochs (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.FaultEpochs: %w", err) + } + + t.FaultEpochs = c + + } + // t.Recoveries (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Recoveries = new(bitfield.BitField) + if err := t.Recoveries.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Recoveries pointer: %w", err) + } + } + + } + // t.PostSubmissions (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.PostSubmissions = new(bitfield.BitField) + if err := t.PostSubmissions.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.PostSubmissions pointer: %w", err) + } + } + + } + // t.NextDeadlineToProcessFaults (uint64) (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.NextDeadlineToProcessFaults = uint64(extra) + + } + return nil +} + +func (t *MinerInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{136}); err != nil { + return err + } + + // t.Owner (address.Address) (struct) + if err := t.Owner.MarshalCBOR(w); err != nil { + return err + } + + // t.Worker (address.Address) (struct) + if err := t.Worker.MarshalCBOR(w); err != nil { + return err + } + + // t.PendingWorkerKey (miner.WorkerKeyChange) (struct) + if err := t.PendingWorkerKey.MarshalCBOR(w); err != nil { + return err + } + + // t.PeerId ([]uint8) (slice) + if len(t.PeerId) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.PeerId was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.PeerId)))); err != nil { + return err + } + if _, err := w.Write(t.PeerId); err != nil { + return err + } + + // t.Multiaddrs ([][]uint8) (slice) + if len(t.Multiaddrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Multiaddrs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Multiaddrs)))); err != nil { + return err + } + for _, v := range t.Multiaddrs { + if len(v) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field v was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(v)))); err != nil { + return err + } + if _, err := w.Write(v); err != nil { + return err + } + } + + // t.SealProofType (abi.RegisteredSealProof) (int64) + if t.SealProofType >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealProofType))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealProofType)-1)); err != nil { + return err + } + } + + // t.SectorSize (abi.SectorSize) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorSize))); err != nil { + return err + } + + // t.WindowPoStPartitionSectors (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.WindowPoStPartitionSectors))); err != nil { + return err + } + + return nil +} + +func (t *MinerInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 8 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Owner (address.Address) (struct) + + { + + if err := t.Owner.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Owner: %w", err) + } + + } + // t.Worker (address.Address) (struct) + + { + + if err := t.Worker.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Worker: %w", err) + } + + } + // t.PendingWorkerKey (miner.WorkerKeyChange) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.PendingWorkerKey = new(WorkerKeyChange) + if err := t.PendingWorkerKey.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.PendingWorkerKey pointer: %w", err) + } + } + + } + // t.PeerId ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.PeerId: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.PeerId = make([]byte, extra) + if _, err := io.ReadFull(br, t.PeerId); err != nil { + return err + } + // t.Multiaddrs ([][]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Multiaddrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Multiaddrs = make([][]uint8, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Multiaddrs[i]: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Multiaddrs[i] = make([]byte, extra) + if _, err := io.ReadFull(br, t.Multiaddrs[i]); err != nil { + return err + } + } + } + + // t.SealProofType (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProofType = abi.RegisteredSealProof(extraI) + } + // t.SectorSize (abi.SectorSize) (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.SectorSize = abi.SectorSize(extra) + + } + // t.WindowPoStPartitionSectors (uint64) (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.WindowPoStPartitionSectors = uint64(extra) + + } + return nil +} + +func (t *Deadlines) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Due ([36]*bitfield.BitField) (array) + if len(t.Due) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Due was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Due)))); err != nil { + return err + } + for _, v := range t.Due { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *Deadlines) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Due ([36]*bitfield.BitField) (array) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Due: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra != 36 { + return fmt.Errorf("expected array to have 36 elements") + } + + t.Due = [36]*bitfield.BitField{} + + for i := 0; i < int(extra); i++ { + + var v bitfield.BitField + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Due[i] = &v + } + + return nil +} + +func (t *SectorPreCommitOnChainInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{133}); err != nil { + return err + } + + // t.Info (miner.SectorPreCommitInfo) (struct) + if err := t.Info.MarshalCBOR(w); err != nil { + return err + } + + // t.PreCommitDeposit (big.Int) (struct) + if err := t.PreCommitDeposit.MarshalCBOR(w); err != nil { + return err + } + + // t.PreCommitEpoch (abi.ChainEpoch) (int64) + if t.PreCommitEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.PreCommitEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.PreCommitEpoch)-1)); err != nil { + return err + } + } + + // t.DealWeight (big.Int) (struct) + if err := t.DealWeight.MarshalCBOR(w); err != nil { + return err + } + + // t.VerifiedDealWeight (big.Int) (struct) + if err := t.VerifiedDealWeight.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SectorPreCommitOnChainInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 5 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Info (miner.SectorPreCommitInfo) (struct) + + { + + if err := t.Info.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Info: %w", err) + } + + } + // t.PreCommitDeposit (big.Int) (struct) + + { + + if err := t.PreCommitDeposit.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.PreCommitDeposit: %w", err) + } + + } + // t.PreCommitEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.PreCommitEpoch = abi.ChainEpoch(extraI) + } + // t.DealWeight (big.Int) (struct) + + { + + if err := t.DealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.DealWeight: %w", err) + } + + } + // t.VerifiedDealWeight (big.Int) (struct) + + { + + if err := t.VerifiedDealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.VerifiedDealWeight: %w", err) + } + + } + return nil +} + +func (t *SectorPreCommitInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{136}); err != nil { + return err + } + + // t.SealProof (abi.RegisteredSealProof) (int64) + if t.SealProof >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealProof))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealProof)-1)); err != nil { + return err + } + } + + // t.SectorNumber (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorNumber))); err != nil { + return err + } + + // t.SealedCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.SealedCID); err != nil { + return xerrors.Errorf("failed to write cid field t.SealedCID: %w", err) + } + + // t.SealRandEpoch (abi.ChainEpoch) (int64) + if t.SealRandEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealRandEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealRandEpoch)-1)); err != nil { + return err + } + } + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.Expiration (abi.ChainEpoch) (int64) + if t.Expiration >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Expiration))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.Expiration)-1)); err != nil { + return err + } + } + + // t.ReplaceCapacity (bool) (bool) + if err := cbg.WriteBool(w, t.ReplaceCapacity); err != nil { + return err + } + + // t.ReplaceSector (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ReplaceSector))); err != nil { + return err + } + + return nil +} + +func (t *SectorPreCommitInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 8 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SealProof (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProof = abi.RegisteredSealProof(extraI) + } + // t.SectorNumber (abi.SectorNumber) (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.SectorNumber = abi.SectorNumber(extra) + + } + // t.SealedCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.SealedCID: %w", err) + } + + t.SealedCID = c + + } + // t.SealRandEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealRandEpoch = abi.ChainEpoch(extraI) + } + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = abi.DealID(val) + } + + // t.Expiration (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Expiration = abi.ChainEpoch(extraI) + } + // t.ReplaceCapacity (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.ReplaceCapacity = false + case 21: + t.ReplaceCapacity = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.ReplaceSector (abi.SectorNumber) (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.ReplaceSector = abi.SectorNumber(extra) + + } + return nil +} + +func (t *SectorOnChainInfo) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{137}); err != nil { + return err + } + + // t.SectorNumber (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorNumber))); err != nil { + return err + } + + // t.SealProof (abi.RegisteredSealProof) (int64) + if t.SealProof >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealProof))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealProof)-1)); err != nil { + return err + } + } + + // t.SealedCID (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.SealedCID); err != nil { + return xerrors.Errorf("failed to write cid field t.SealedCID: %w", err) + } + + // t.DealIDs ([]abi.DealID) (slice) + if len(t.DealIDs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.DealIDs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.Activation (abi.ChainEpoch) (int64) + if t.Activation >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Activation))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.Activation)-1)); err != nil { + return err + } + } + + // t.Expiration (abi.ChainEpoch) (int64) + if t.Expiration >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Expiration))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.Expiration)-1)); err != nil { + return err + } + } + + // t.DealWeight (big.Int) (struct) + if err := t.DealWeight.MarshalCBOR(w); err != nil { + return err + } + + // t.VerifiedDealWeight (big.Int) (struct) + if err := t.VerifiedDealWeight.MarshalCBOR(w); err != nil { + return err + } + + // t.InitialPledge (big.Int) (struct) + if err := t.InitialPledge.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SectorOnChainInfo) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 9 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SectorNumber (abi.SectorNumber) (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.SectorNumber = abi.SectorNumber(extra) + + } + // t.SealProof (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProof = abi.RegisteredSealProof(extraI) + } + // t.SealedCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.SealedCID: %w", err) + } + + t.SealedCID = c + + } + // t.DealIDs ([]abi.DealID) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.DealIDs = make([]abi.DealID, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = abi.DealID(val) + } + + // t.Activation (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Activation = abi.ChainEpoch(extraI) + } + // t.Expiration (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Expiration = abi.ChainEpoch(extraI) + } + // t.DealWeight (big.Int) (struct) + + { + + if err := t.DealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.DealWeight: %w", err) + } + + } + // t.VerifiedDealWeight (big.Int) (struct) + + { + + if err := t.VerifiedDealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.VerifiedDealWeight: %w", err) + } + + } + // t.InitialPledge (big.Int) (struct) + + { + + if err := t.InitialPledge.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.InitialPledge: %w", err) + } + + } + return nil +} + +func (t *WorkerKeyChange) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.NewWorker (address.Address) (struct) + if err := t.NewWorker.MarshalCBOR(w); err != nil { + return err + } + + // t.EffectiveAt (abi.ChainEpoch) (int64) + if t.EffectiveAt >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.EffectiveAt))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.EffectiveAt)-1)); err != nil { + return err + } + } + return nil +} + +func (t *WorkerKeyChange) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.NewWorker (address.Address) (struct) + + { + + if err := t.NewWorker.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.NewWorker: %w", err) + } + + } + // t.EffectiveAt (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.EffectiveAt = abi.ChainEpoch(extraI) + } + return nil +} + +func (t *SubmitWindowedPoStParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.Deadline (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Deadline))); err != nil { + return err + } + + // t.Partitions ([]uint64) (slice) + if len(t.Partitions) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Partitions was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Partitions)))); err != nil { + return err + } + for _, v := range t.Partitions { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil { + return err + } + } + + // t.Proofs ([]abi.PoStProof) (slice) + if len(t.Proofs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Proofs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Proofs)))); err != nil { + return err + } + for _, v := range t.Proofs { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.Skipped (bitfield.BitField) (struct) + if err := t.Skipped.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SubmitWindowedPoStParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Deadline (uint64) (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.Deadline = uint64(extra) + + } + // t.Partitions ([]uint64) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Partitions: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Partitions = make([]uint64, extra) + } + + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.Partitions slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.Partitions was not a uint, instead got %d", maj) + } + + t.Partitions[i] = uint64(val) + } + + // t.Proofs ([]abi.PoStProof) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Proofs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Proofs = make([]abi.PoStProof, extra) + } + + for i := 0; i < int(extra); i++ { + + var v abi.PoStProof + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Proofs[i] = v + } + + // t.Skipped (bitfield.BitField) (struct) + + { + + if err := t.Skipped.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Skipped: %w", err) + } + + } + return nil +} + +func (t *TerminateSectorsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Sectors (bitfield.BitField) (struct) + if err := t.Sectors.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *TerminateSectorsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Sectors (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Sectors = new(bitfield.BitField) + if err := t.Sectors.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Sectors pointer: %w", err) + } + } + + } + return nil +} + +func (t *ChangePeerIDParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.NewID ([]uint8) (slice) + if len(t.NewID) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.NewID was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.NewID)))); err != nil { + return err + } + if _, err := w.Write(t.NewID); err != nil { + return err + } + return nil +} + +func (t *ChangePeerIDParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.NewID ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.NewID: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.NewID = make([]byte, extra) + if _, err := io.ReadFull(br, t.NewID); err != nil { + return err + } + return nil +} + +func (t *ChangeMultiaddrsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.NewMultiaddrs ([][]uint8) (slice) + if len(t.NewMultiaddrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.NewMultiaddrs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.NewMultiaddrs)))); err != nil { + return err + } + for _, v := range t.NewMultiaddrs { + if len(v) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field v was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(v)))); err != nil { + return err + } + if _, err := w.Write(v); err != nil { + return err + } + } + return nil +} + +func (t *ChangeMultiaddrsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.NewMultiaddrs ([][]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.NewMultiaddrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.NewMultiaddrs = make([][]uint8, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.NewMultiaddrs[i]: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.NewMultiaddrs[i] = make([]byte, extra) + if _, err := io.ReadFull(br, t.NewMultiaddrs[i]); err != nil { + return err + } + } + } + + return nil +} + +func (t *ProveCommitSectorParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.SectorNumber (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorNumber))); err != nil { + return err + } + + // t.Proof ([]uint8) (slice) + if len(t.Proof) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Proof was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Proof)))); err != nil { + return err + } + if _, err := w.Write(t.Proof); err != nil { + return err + } + return nil +} + +func (t *ProveCommitSectorParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SectorNumber (abi.SectorNumber) (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.SectorNumber = abi.SectorNumber(extra) + + } + // t.Proof ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Proof: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Proof = make([]byte, extra) + if _, err := io.ReadFull(br, t.Proof); err != nil { + return err + } + return nil +} + +func (t *ChangeWorkerAddressParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.NewWorker (address.Address) (struct) + if err := t.NewWorker.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *ChangeWorkerAddressParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.NewWorker (address.Address) (struct) + + { + + if err := t.NewWorker.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.NewWorker: %w", err) + } + + } + return nil +} + +func (t *ExtendSectorExpirationParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.SectorNumber (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorNumber))); err != nil { + return err + } + + // t.NewExpiration (abi.ChainEpoch) (int64) + if t.NewExpiration >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NewExpiration))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.NewExpiration)-1)); err != nil { + return err + } + } + return nil +} + +func (t *ExtendSectorExpirationParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SectorNumber (abi.SectorNumber) (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.SectorNumber = abi.SectorNumber(extra) + + } + // t.NewExpiration (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.NewExpiration = abi.ChainEpoch(extraI) + } + return nil +} + +func (t *DeclareFaultsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Faults ([]miner.FaultDeclaration) (slice) + if len(t.Faults) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Faults was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Faults)))); err != nil { + return err + } + for _, v := range t.Faults { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *DeclareFaultsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Faults ([]miner.FaultDeclaration) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Faults: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Faults = make([]FaultDeclaration, extra) + } + + for i := 0; i < int(extra); i++ { + + var v FaultDeclaration + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Faults[i] = v + } + + return nil +} + +func (t *DeclareFaultsRecoveredParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.Recoveries ([]miner.RecoveryDeclaration) (slice) + if len(t.Recoveries) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Recoveries was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Recoveries)))); err != nil { + return err + } + for _, v := range t.Recoveries { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *DeclareFaultsRecoveredParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Recoveries ([]miner.RecoveryDeclaration) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Recoveries: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Recoveries = make([]RecoveryDeclaration, extra) + } + + for i := 0; i < int(extra); i++ { + + var v RecoveryDeclaration + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Recoveries[i] = v + } + + return nil +} + +func (t *ReportConsensusFaultParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.BlockHeader1 ([]uint8) (slice) + if len(t.BlockHeader1) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.BlockHeader1 was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.BlockHeader1)))); err != nil { + return err + } + if _, err := w.Write(t.BlockHeader1); err != nil { + return err + } + + // t.BlockHeader2 ([]uint8) (slice) + if len(t.BlockHeader2) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.BlockHeader2 was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.BlockHeader2)))); err != nil { + return err + } + if _, err := w.Write(t.BlockHeader2); err != nil { + return err + } + + // t.BlockHeaderExtra ([]uint8) (slice) + if len(t.BlockHeaderExtra) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.BlockHeaderExtra was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.BlockHeaderExtra)))); err != nil { + return err + } + if _, err := w.Write(t.BlockHeaderExtra); err != nil { + return err + } + return nil +} + +func (t *ReportConsensusFaultParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.BlockHeader1 ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.BlockHeader1: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.BlockHeader1 = make([]byte, extra) + if _, err := io.ReadFull(br, t.BlockHeader1); err != nil { + return err + } + // t.BlockHeader2 ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.BlockHeader2: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.BlockHeader2 = make([]byte, extra) + if _, err := io.ReadFull(br, t.BlockHeader2); err != nil { + return err + } + // t.BlockHeaderExtra ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.BlockHeaderExtra: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.BlockHeaderExtra = make([]byte, extra) + if _, err := io.ReadFull(br, t.BlockHeaderExtra); err != nil { + return err + } + return nil +} + +func (t *GetControlAddressesReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Owner (address.Address) (struct) + if err := t.Owner.MarshalCBOR(w); err != nil { + return err + } + + // t.Worker (address.Address) (struct) + if err := t.Worker.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *GetControlAddressesReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Owner (address.Address) (struct) + + { + + if err := t.Owner.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Owner: %w", err) + } + + } + // t.Worker (address.Address) (struct) + + { + + if err := t.Worker.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Worker: %w", err) + } + + } + return nil +} + +func (t *CheckSectorProvenParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.SectorNumber (abi.SectorNumber) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorNumber))); err != nil { + return err + } + + return nil +} + +func (t *CheckSectorProvenParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SectorNumber (abi.SectorNumber) (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.SectorNumber = abi.SectorNumber(extra) + + } + return nil +} + +func (t *WithdrawBalanceParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.AmountRequested (big.Int) (struct) + if err := t.AmountRequested.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *WithdrawBalanceParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.AmountRequested (big.Int) (struct) + + { + + if err := t.AmountRequested.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.AmountRequested: %w", err) + } + + } + return nil +} + +func (t *CronEventPayload) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.EventType (miner.CronEventType) (int64) + if t.EventType >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.EventType))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.EventType)-1)); err != nil { + return err + } + } + + // t.Sectors (bitfield.BitField) (struct) + if err := t.Sectors.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *CronEventPayload) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.EventType (miner.CronEventType) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.EventType = CronEventType(extraI) + } + // t.Sectors (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Sectors = new(bitfield.BitField) + if err := t.Sectors.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Sectors pointer: %w", err) + } + } + + } + return nil +} + +func (t *FaultDeclaration) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Deadline (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Deadline))); err != nil { + return err + } + + // t.Sectors (bitfield.BitField) (struct) + if err := t.Sectors.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *FaultDeclaration) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Deadline (uint64) (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.Deadline = uint64(extra) + + } + // t.Sectors (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Sectors = new(bitfield.BitField) + if err := t.Sectors.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Sectors pointer: %w", err) + } + } + + } + return nil +} + +func (t *RecoveryDeclaration) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Deadline (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Deadline))); err != nil { + return err + } + + // t.Sectors (bitfield.BitField) (struct) + if err := t.Sectors.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *RecoveryDeclaration) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Deadline (uint64) (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.Deadline = uint64(extra) + + } + // t.Sectors (bitfield.BitField) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Sectors = new(bitfield.BitField) + if err := t.Sectors.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Sectors pointer: %w", err) + } + } + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines.go new file mode 100644 index 0000000000..9b52d25923 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines.go @@ -0,0 +1,284 @@ +package miner + +import ( + "fmt" + "math" + "sort" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/specs-actors/actors/abi" +) + +// Deadline calculations with respect to a current epoch. +// "Deadline" refers to the window during which proofs may be submitted. +// Windows are non-overlapping ranges [Open, Close), but the challenge epoch for a window occurs before +// the window opens. +// The current epoch may not necessarily lie within the deadline or proving period represented here. +type DeadlineInfo struct { + CurrentEpoch abi.ChainEpoch // Epoch at which this info was calculated. + PeriodStart abi.ChainEpoch // First epoch of the proving period (<= CurrentEpoch). + Index uint64 // A deadline index, in [0..WPoStProvingPeriodDeadlines) unless period elapsed. + Open abi.ChainEpoch // First epoch from which a proof may be submitted, inclusive (>= CurrentEpoch). + Close abi.ChainEpoch // First epoch from which a proof may no longer be submitted, exclusive (>= Open). + Challenge abi.ChainEpoch // Epoch at which to sample the chain for challenge (< Open). + FaultCutoff abi.ChainEpoch // First epoch at which a fault declaration is rejected (< Open). +} + +// Whether the proving period has begun. +func (d *DeadlineInfo) PeriodStarted() bool { + return d.CurrentEpoch >= d.PeriodStart +} + +// Whether the proving period has elapsed. +func (d *DeadlineInfo) PeriodElapsed() bool { + return d.CurrentEpoch >= d.NextPeriodStart() +} + +// Whether the current deadline is currently open. +func (d *DeadlineInfo) IsOpen() bool { + return d.CurrentEpoch >= d.Open && d.CurrentEpoch < d.Close +} + +// Whether the current deadline has already closed. +func (d *DeadlineInfo) HasElapsed() bool { + return d.CurrentEpoch >= d.Close +} + +// Whether the deadline's fault cutoff has passed. +func (d *DeadlineInfo) FaultCutoffPassed() bool { + return d.CurrentEpoch >= d.FaultCutoff +} + +// The last epoch in the proving period. +func (d *DeadlineInfo) PeriodEnd() abi.ChainEpoch { + return d.PeriodStart + WPoStProvingPeriod - 1 +} + +// The first epoch in the next proving period. +func (d *DeadlineInfo) NextPeriodStart() abi.ChainEpoch { + return d.PeriodStart + WPoStProvingPeriod +} + +// Calculates the deadline at some epoch for a proving period and returns the deadline-related calculations. +func ComputeProvingPeriodDeadline(periodStart, currEpoch abi.ChainEpoch) *DeadlineInfo { + periodProgress := currEpoch - periodStart + if periodProgress >= WPoStProvingPeriod { + // Proving period has completely elapsed. + return NewDeadlineInfo(periodStart, WPoStPeriodDeadlines, currEpoch) + } + deadlineIdx := uint64(periodProgress / WPoStChallengeWindow) + if periodProgress < 0 { // Period not yet started. + deadlineIdx = 0 + } + return NewDeadlineInfo(periodStart, deadlineIdx, currEpoch) +} + +// Returns deadline-related calculations for a deadline in some proving period and the current epoch. +func NewDeadlineInfo(periodStart abi.ChainEpoch, deadlineIdx uint64, currEpoch abi.ChainEpoch) *DeadlineInfo { + if deadlineIdx < WPoStPeriodDeadlines { + deadlineOpen := periodStart + (abi.ChainEpoch(deadlineIdx) * WPoStChallengeWindow) + return &DeadlineInfo{ + CurrentEpoch: currEpoch, + PeriodStart: periodStart, + Index: deadlineIdx, + Open: deadlineOpen, + Close: deadlineOpen + WPoStChallengeWindow, + Challenge: deadlineOpen - WPoStChallengeLookback, + FaultCutoff: deadlineOpen - FaultDeclarationCutoff, + } + } else { + // Return deadline info for a no-duration deadline immediately after the last real one. + afterLastDeadline := periodStart + WPoStProvingPeriod + return &DeadlineInfo{ + CurrentEpoch: currEpoch, + PeriodStart: periodStart, + Index: deadlineIdx, + Open: afterLastDeadline, + Close: afterLastDeadline, + Challenge: afterLastDeadline, + FaultCutoff: 0, + } + } +} + +// Computes the first partition index and number of sectors for a deadline. +// Partitions are numbered globally for the miner, not per-deadline. +// If the deadline has no sectors, the first partition index is the index that a partition at that deadline would +// have, if non-empty (and sectorCount is zero). +func PartitionsForDeadline(d *Deadlines, partitionSize, deadlineIdx uint64) (firstPartition, sectorCount uint64, _ error) { + if deadlineIdx >= WPoStPeriodDeadlines { + return 0, 0, fmt.Errorf("invalid deadline index %d for %d deadlines", deadlineIdx, WPoStPeriodDeadlines) + } + var partitionCountSoFar uint64 + for i := uint64(0); i < WPoStPeriodDeadlines; i++ { + partitionCount, thisSectorCount, err := DeadlineCount(d, partitionSize, i) + if err != nil { + return 0, 0, err + } + if i == deadlineIdx { + return partitionCountSoFar, thisSectorCount, nil + } + partitionCountSoFar += partitionCount + } + return 0, 0, nil +} + +// Counts the partitions (including up to one partial) and sectors at a deadline. +func DeadlineCount(d *Deadlines, partitionSize, deadlineIdx uint64) (partitionCount, sectorCount uint64, err error) { + if deadlineIdx >= WPoStPeriodDeadlines { + return 0, 0, fmt.Errorf("invalid deadline index %d for %d deadlines", deadlineIdx, WPoStPeriodDeadlines) + } + sectorCount, err = d.Due[deadlineIdx].Count() + if err != nil { + return 0, 0, err + } + + partitionCount = sectorCount / partitionSize + if sectorCount%partitionSize != 0 { + partitionCount++ + } + return +} + +// Computes a bitfield of the sector numbers included in a sequence of partitions due at some deadline. +// Fails if any partition is not due at the provided deadline. +func ComputePartitionsSectors(d *Deadlines, partitionSize uint64, deadlineIndex uint64, partitions []uint64) ([]*abi.BitField, error) { + deadlineFirstPartition, deadlineSectorCount, err := PartitionsForDeadline(d, partitionSize, deadlineIndex) + if err != nil { + return nil, fmt.Errorf("failed to count partitions for deadline %d: %w", deadlineIndex, err) + } + // ceil(deadlineSectorCount / partitionSize) + deadlinePartitionCount := (deadlineSectorCount + partitionSize - 1) / partitionSize + + // Work out which sector numbers the partitions correspond to. + deadlineSectors := d.Due[deadlineIndex] + partitionsSectors := make([]*abi.BitField, len(partitions)) + for i, pIdx := range partitions { + if pIdx < deadlineFirstPartition || pIdx >= deadlineFirstPartition+deadlinePartitionCount { + return nil, fmt.Errorf("invalid partition %d at deadline %d with first %d, count %d", + pIdx, deadlineIndex, deadlineFirstPartition, deadlinePartitionCount) + } + + // Slice out the sectors corresponding to this partition from the deadline's sector bitfield. + sectorOffset := (pIdx - deadlineFirstPartition) * partitionSize + sectorCount := min64(partitionSize, deadlineSectorCount-sectorOffset) + partitionSectors, err := deadlineSectors.Slice(sectorOffset, sectorCount) + if err != nil { + return nil, fmt.Errorf("failed to slice deadline %d, size %d, offset %d, count %d", + deadlineIndex, deadlineSectorCount, sectorOffset, sectorCount) + } + partitionsSectors[i] = partitionSectors + } + return partitionsSectors, nil +} + +// Assigns a sequence of sector numbers to deadlines by: +// - filling any non-full partitions, in round-robin order across the deadlines +// - repeatedly adding a new partition to the deadline with the fewest partitions +// When multiple partitions share the minimal sector count, one is chosen at random (from a seed). +func AssignNewSectors(deadlines *Deadlines, partitionSize uint64, newSectors []uint64, seed abi.Randomness) error { + nextNewSector := uint64(0) + // The first deadline is left empty since it's more difficult for a miner to orchestrate proofs. + // The set of sectors due at the deadline isn't known until the proving period actually starts and any + // new sectors are assigned to it (here). + // Practically, a miner must also wait for some probabilistic finality after that before beginning proof + // calculations. + // It's left empty so a miner has at least one challenge duration to prepare for proving after new sectors + // are assigned. + firstAssignableDeadline := uint64(1) + + // Assigns up to `count` sectors to `deadline` and advances `nextNewSector`. + assignToDeadline := func(count uint64, deadline uint64) error { + countToAdd := min64(count, uint64(len(newSectors))-nextNewSector) + sectorsToAdd := newSectors[nextNewSector : nextNewSector+countToAdd] + err := deadlines.AddToDeadline(deadline, sectorsToAdd...) + if err != nil { + return fmt.Errorf("failed to add %d sectors to deadline %d: %w", countToAdd, deadline, err) + } + nextNewSector += countToAdd + return nil + } + + // Iterate deadlines and fill any partial partitions. There's no great advantage to filling more- or less- + // full ones first, so they're filled in sequence order. + // Meanwhile, record the partition count at each deadline. + deadlinePartitionCounts := make([]uint64, WPoStPeriodDeadlines) + for i := uint64(0); i < WPoStPeriodDeadlines && nextNewSector < uint64(len(newSectors)); i++ { + if i < firstAssignableDeadline { + // Mark unassignable deadlines as "full" so nothing more will be assigned. + deadlinePartitionCounts[i] = math.MaxUint64 + continue + } + partitionCount, sectorCount, err := DeadlineCount(deadlines, partitionSize, i) + if err != nil { + return fmt.Errorf("failed to count sectors in partition %d: %w", i, err) + } + deadlinePartitionCounts[i] = partitionCount + + gap := partitionSize - (sectorCount % partitionSize) + if gap != partitionSize { + err = assignToDeadline(gap, i) + if err != nil { + return err + } + } + } + + // While there remain new sectors to assign, fill a new partition in one of the deadlines that is least full. + // Do this by maintaining a slice of deadline indexes sorted by partition count. + // Shuffling this slice to re-sort as weights change is O(n^2). + // For a large number of partitions, a heap would be the way to do this in O(n*log n), but for small numbers + // is probably overkill. + // A miner onboarding a monumental 1EiB of 32GiB sectors uniformly throughout a year will fill 40 partitions + // per proving period (40^2=1600). With 64GiB sectors, half that (20^2=400). + // TODO: randomize assignment among equally-full deadlines https://github.com/filecoin-project/specs-actors/issues/432 + + dlIdxs := make([]uint64, WPoStPeriodDeadlines) + for i := range dlIdxs { + dlIdxs[i] = uint64(i) + } + + sortDeadlines := func() { + // Order deadline indexes by corresponding partition count (then secondarily by index) to form a queue. + sort.SliceStable(dlIdxs, func(i, j int) bool { + idxI, idxJ := dlIdxs[i], dlIdxs[j] + countI, countJ := deadlinePartitionCounts[idxI], deadlinePartitionCounts[idxJ] + if countI == countJ { + return idxI < idxJ + } + return countI < countJ + }) + } + + sortDeadlines() + for nextNewSector < uint64(len(newSectors)) { + // Assign a full partition to the least-full deadline. + targetDeadline := dlIdxs[0] + err := assignToDeadline(partitionSize, targetDeadline) + if err != nil { + return err + } + deadlinePartitionCounts[targetDeadline]++ + // Re-sort the queue. + // Only the first element has changed, the remainder is still sorted, so with an insertion-sort under + // the hood this will be linear. + sortDeadlines() + } + return nil +} + +// FindDeadline returns the deadline index for a given sector number. +// It returns an error if the sector number is not tracked by deadlines. +func FindDeadline(deadlines *Deadlines, sectorNum abi.SectorNumber) (uint64, error) { + for deadlineIdx, sectorNums := range deadlines.Due { + found, err := sectorNums.IsSet(uint64(sectorNum)) + if err != nil { + return 0, err + } + if found { + return uint64(deadlineIdx), nil + } + } + return 0, xerrors.New("sectorNum not due at any deadline") +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines_test.go new file mode 100644 index 0000000000..e60d878735 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/deadlines_test.go @@ -0,0 +1,613 @@ +package miner_test + +import ( + "testing" + + "github.com/filecoin-project/go-bitfield" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" +) + +func TestProvingPeriodDeadlines(t *testing.T) { + PP := miner.WPoStProvingPeriod + CW := miner.WPoStChallengeWindow + DLS := miner.WPoStPeriodDeadlines + + t.Run("pre-open", func(t *testing.T) { + curr := abi.ChainEpoch(0) // Current is before the period opens. + { + periodStart := miner.FaultDeclarationCutoff + 1 + di := miner.ComputeProvingPeriodDeadline(periodStart, curr) + assert.Equal(t, uint64(0), di.Index) + assert.Equal(t, periodStart, di.Open) + + assert.False(t, di.PeriodStarted()) + assert.False(t, di.IsOpen()) + assert.False(t, di.HasElapsed()) + assert.False(t, di.FaultCutoffPassed()) + assert.Equal(t, periodStart+miner.WPoStProvingPeriod-1, di.PeriodEnd()) + assert.Equal(t, periodStart+miner.WPoStProvingPeriod, di.NextPeriodStart()) + } + { + periodStart := miner.FaultDeclarationCutoff - 1 + di := miner.ComputeProvingPeriodDeadline(periodStart, curr) + assert.True(t, di.FaultCutoffPassed()) + } + }) + + t.Run("offset zero", func(t *testing.T) { + firstPeriodStart := abi.ChainEpoch(0) + + // First proving period. + di := assertDeadlineInfo(t, 0, firstPeriodStart, 0, 0) + assert.Equal(t, -miner.WPoStChallengeLookback, di.Challenge) + assert.Equal(t, -miner.FaultDeclarationCutoff, di.FaultCutoff) + assert.True(t, di.IsOpen()) + assert.True(t, di.FaultCutoffPassed()) + + assertDeadlineInfo(t, 1, firstPeriodStart, 0, 0) + // Final epoch of deadline 0. + assertDeadlineInfo(t, CW-1, firstPeriodStart, 0, 0) + // First epoch of deadline 1 + assertDeadlineInfo(t, CW, firstPeriodStart, 1, CW) + assertDeadlineInfo(t, CW+1, firstPeriodStart, 1, CW) + // Final epoch of deadline 1 + assertDeadlineInfo(t, CW*2-1, firstPeriodStart, 1, CW) + // First epoch of deadline 2 + assertDeadlineInfo(t, CW*2, firstPeriodStart, 2, CW*2) + + // Last epoch of last deadline + assertDeadlineInfo(t, PP-1, firstPeriodStart, DLS-1, PP-CW) + + // Second proving period + // First epoch of deadline 0 + secondPeriodStart := PP + di = assertDeadlineInfo(t, PP, secondPeriodStart, 0, PP) + assert.Equal(t, PP-miner.WPoStChallengeLookback, di.Challenge) + assert.Equal(t, PP-miner.FaultDeclarationCutoff, di.FaultCutoff) + + // Final epoch of deadline 0. + assertDeadlineInfo(t, PP+CW-1, secondPeriodStart, 0, PP+0) + // First epoch of deadline 1 + assertDeadlineInfo(t, PP+CW, secondPeriodStart, 1, PP+CW) + assertDeadlineInfo(t, PP+CW+1, secondPeriodStart, 1, PP+CW) + }) + + t.Run("offset non-zero", func(t *testing.T) { + offset := CW*2 + 2 // Arbitrary not aligned with challenge window. + initialPPStart := offset - PP + firstDlIndex := miner.WPoStPeriodDeadlines - uint64(offset/CW) - 1 + firstDlOpen := initialPPStart + CW*abi.ChainEpoch(firstDlIndex) + + require.True(t, offset < PP) + require.True(t, initialPPStart < 0) + require.True(t, firstDlOpen < 0) + + // Incomplete initial proving period. + // At epoch zero, the initial deadlines in the period have already passed and we're part way through + // another one. + di := assertDeadlineInfo(t, 0, initialPPStart, firstDlIndex, firstDlOpen) + assert.Equal(t, firstDlOpen-miner.WPoStChallengeLookback, di.Challenge) + assert.Equal(t, firstDlOpen-miner.FaultDeclarationCutoff, di.FaultCutoff) + assert.True(t, di.IsOpen()) + assert.True(t, di.FaultCutoffPassed()) + + // Epoch 1 + assertDeadlineInfo(t, 1, initialPPStart, firstDlIndex, firstDlOpen) + + // Epoch 2 rolls over to third-last challenge window + assertDeadlineInfo(t, 2, initialPPStart, firstDlIndex+1, firstDlOpen+CW) + assertDeadlineInfo(t, 3, initialPPStart, firstDlIndex+1, firstDlOpen+CW) + + // Last epoch of second-last window. + assertDeadlineInfo(t, 2+CW-1, initialPPStart, firstDlIndex+1, firstDlOpen+CW) + // First epoch of last challenge window. + assertDeadlineInfo(t, 2+CW, initialPPStart, firstDlIndex+2, firstDlOpen+CW*2) + // Last epoch of last challenge window. + assert.Equal(t, miner.WPoStPeriodDeadlines-1, firstDlIndex+2) + assertDeadlineInfo(t, 2+2*CW-1, initialPPStart, firstDlIndex+2, firstDlOpen+CW*2) + + // First epoch of next proving period. + assertDeadlineInfo(t, 2+2*CW, initialPPStart+PP, 0, initialPPStart+PP) + assertDeadlineInfo(t, 2+2*CW+1, initialPPStart+PP, 0, initialPPStart+PP) + }) + + t.Run("period expired", func(t *testing.T) { + offset := abi.ChainEpoch(1) + d := miner.ComputeProvingPeriodDeadline(offset, offset+miner.WPoStProvingPeriod) + assert.True(t, d.PeriodStarted()) + assert.True(t, d.PeriodElapsed()) + assert.Equal(t, miner.WPoStPeriodDeadlines, d.Index) + assert.False(t, d.IsOpen()) + assert.True(t, d.HasElapsed()) + assert.True(t, d.FaultCutoffPassed()) + assert.Equal(t, offset+miner.WPoStProvingPeriod-1, d.PeriodEnd()) + assert.Equal(t, offset+miner.WPoStProvingPeriod, d.NextPeriodStart()) + }) +} + +func assertDeadlineInfo(t *testing.T, current, periodStart abi.ChainEpoch, expectedIndex uint64, expectedDeadlineOpen abi.ChainEpoch) *miner.DeadlineInfo { + expected := makeDeadline(current, periodStart, expectedIndex, expectedDeadlineOpen) + actual := miner.ComputeProvingPeriodDeadline(periodStart, current) + assert.True(t, actual.PeriodStarted()) + assert.True(t, actual.IsOpen()) + assert.False(t, actual.HasElapsed()) + assert.Equal(t, expected, actual) + return actual +} + +func makeDeadline(currEpoch, periodStart abi.ChainEpoch, index uint64, deadlineOpen abi.ChainEpoch) *miner.DeadlineInfo { + return &miner.DeadlineInfo{ + CurrentEpoch: currEpoch, + PeriodStart: periodStart, + Index: index, + Open: deadlineOpen, + Close: deadlineOpen + miner.WPoStChallengeWindow, + Challenge: deadlineOpen - miner.WPoStChallengeLookback, + FaultCutoff: deadlineOpen - miner.FaultDeclarationCutoff, + } +} + +func TestPartitionsForDeadline(t *testing.T) { + const partSize = uint64(1000) + + t.Run("empty deadlines", func(t *testing.T) { + dl := buildDeadlines(t, []uint64{}) + firstIndex, sectorCount, err := miner.PartitionsForDeadline(dl, partSize, 0) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, uint64(0), sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, miner.WPoStPeriodDeadlines-1) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, uint64(0), sectorCount) + }) + + t.Run("single sector at first deadline", func(t *testing.T) { + dl := buildDeadlines(t, []uint64{1}) + firstIndex, sectorCount, err := miner.PartitionsForDeadline(dl, partSize, 0) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, uint64(1), sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 1) + require.NoError(t, err) + assert.Equal(t, uint64(1), firstIndex) + assert.Zero(t, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, miner.WPoStPeriodDeadlines-1) + require.NoError(t, err) + assert.Equal(t, uint64(1), firstIndex) + assert.Zero(t, sectorCount) + }) + + t.Run("single sector at non-first deadline", func(t *testing.T) { + dl := buildDeadlines(t, []uint64{0, 1}) + firstIndex, sectorCount, err := miner.PartitionsForDeadline(dl, partSize, 0) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, uint64(0), sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 1) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, uint64(1), sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 2) + require.NoError(t, err) + assert.Equal(t, uint64(1), firstIndex) + assert.Equal(t, uint64(0), sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, miner.WPoStPeriodDeadlines-1) + require.NoError(t, err) + assert.Equal(t, uint64(1), firstIndex) + assert.Equal(t, uint64(0), sectorCount) + }) + + t.Run("deadlines with one full partitions", func(t *testing.T) { + dl := NewDeadlinesBuilder(t).addToAll(partSize).Deadlines + firstIndex, sectorCount, err := miner.PartitionsForDeadline(dl, partSize, 0) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, partSize, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 1) + require.NoError(t, err) + assert.Equal(t, uint64(1), firstIndex) + assert.Equal(t, partSize, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, miner.WPoStPeriodDeadlines-1) + require.NoError(t, err) + assert.Equal(t, miner.WPoStPeriodDeadlines-1, firstIndex) + assert.Equal(t, partSize, sectorCount) + }) + + t.Run("partial partitions", func(t *testing.T) { + dl := buildDeadlines(t, []uint64{ + 0: partSize - 1, + 1: partSize, + 2: partSize - 2, + 3: partSize, + 4: partSize - 3, + 5: partSize, + }) + firstIndex, sectorCount, err := miner.PartitionsForDeadline(dl, partSize, 0) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, partSize-1, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 1) + require.NoError(t, err) + assert.Equal(t, uint64(1), firstIndex) + assert.Equal(t, partSize, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 2) + require.NoError(t, err) + assert.Equal(t, uint64(2), firstIndex) + assert.Equal(t, partSize-2, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 5) + require.NoError(t, err) + assert.Equal(t, uint64(5), firstIndex) + assert.Equal(t, partSize, sectorCount) + }) + + t.Run("multiple partitions", func(t *testing.T) { + dl := buildDeadlines(t, []uint64{ + 0: partSize, // 1 partition 1 total + 1: partSize * 2, // 2 partitions 3 total + 2: partSize*4 - 1, // 4 partitions 7 total + 3: partSize * 6, // 6 partitions 13 total + 4: partSize*8 - 1, // 8 partitions 21 total + 5: partSize * 9, // 9 partitions 30 total + }) + + firstIndex, sectorCount, err := miner.PartitionsForDeadline(dl, partSize, 0) + require.NoError(t, err) + assert.Equal(t, uint64(0), firstIndex) + assert.Equal(t, partSize, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 1) + require.NoError(t, err) + assert.Equal(t, uint64(1), firstIndex) + assert.Equal(t, partSize*2, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 2) + require.NoError(t, err) + assert.Equal(t, uint64(3), firstIndex) + assert.Equal(t, partSize*4-1, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 3) + require.NoError(t, err) + assert.Equal(t, uint64(7), firstIndex) + assert.Equal(t, partSize*6, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 4) + require.NoError(t, err) + assert.Equal(t, uint64(13), firstIndex) + assert.Equal(t, partSize*8-1, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, 5) + require.NoError(t, err) + assert.Equal(t, uint64(21), firstIndex) + assert.Equal(t, partSize*9, sectorCount) + + firstIndex, sectorCount, err = miner.PartitionsForDeadline(dl, partSize, miner.WPoStPeriodDeadlines-1) + require.NoError(t, err) + assert.Equal(t, uint64(30), firstIndex) + assert.Equal(t, uint64(0), sectorCount) + }) +} + +func TestComputePartitionsSectors(t *testing.T) { + const partSize = uint64(1000) + + t.Run("no partitions due at empty deadline", func(t *testing.T) { + dls := miner.ConstructDeadlines() + dls.Due[1] = bfSeq(0, 1) + + // No partitions at deadline 0 + _, err := miner.ComputePartitionsSectors(dls, partSize, 0, []uint64{0}) + require.Error(t, err) + + // No partitions at deadline 2 + _, err = miner.ComputePartitionsSectors(dls, partSize, 2, []uint64{0}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 2, []uint64{1}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 2, []uint64{2}) + require.Error(t, err) + }) + t.Run("single sector", func(t *testing.T) { + dls := miner.ConstructDeadlines() + dls.Due[1] = bfSeq(0, 1) + partitions, err := miner.ComputePartitionsSectors(dls, partSize, 1, []uint64{0}) + require.NoError(t, err) + assert.Equal(t, 1, len(partitions)) + assertBfEqual(t, bfSeq(0, 1), partitions[0]) + }) + t.Run("full partition", func(t *testing.T) { + dls := miner.ConstructDeadlines() + dls.Due[10] = bfSeq(1234, partSize) + partitions, err := miner.ComputePartitionsSectors(dls, partSize, 10, []uint64{0}) + require.NoError(t, err) + assert.Equal(t, 1, len(partitions)) + assertBfEqual(t, bfSeq(1234, partSize), partitions[0]) + }) + t.Run("full plus partial partition", func(t *testing.T) { + dls := miner.ConstructDeadlines() + dls.Due[10] = bfSeq(5555, partSize+1) + partitions, err := miner.ComputePartitionsSectors(dls, partSize, 10, []uint64{0}) // First partition + require.NoError(t, err) + assert.Equal(t, 1, len(partitions)) + assertBfEqual(t, bfSeq(5555, partSize), partitions[0]) + + partitions, err = miner.ComputePartitionsSectors(dls, partSize, 10, []uint64{1}) // Second partition + require.NoError(t, err) + assert.Equal(t, 1, len(partitions)) + assertBfEqual(t, bfSeq(5555+partSize, 1), partitions[0]) + + partitions, err = miner.ComputePartitionsSectors(dls, partSize, 10, []uint64{0, 1}) // Both partitions + require.NoError(t, err) + assert.Equal(t, 2, len(partitions)) + assertBfEqual(t, bfSeq(5555, partSize), partitions[0]) + assertBfEqual(t, bfSeq(5555+partSize, 1), partitions[1]) + }) + t.Run("multiple partitions", func(t *testing.T) { + dls := miner.ConstructDeadlines() + dls.Due[1] = bfSeq(0, 3*partSize+1) + partitions, err := miner.ComputePartitionsSectors(dls, partSize, 1, []uint64{0, 1, 2, 3}) + require.NoError(t, err) + assert.Equal(t, 4, len(partitions)) + assertBfEqual(t, bfSeq(0, partSize), partitions[0]) + assertBfEqual(t, bfSeq(1*partSize, partSize), partitions[1]) + assertBfEqual(t, bfSeq(2*partSize, partSize), partitions[2]) + assertBfEqual(t, bfSeq(3*partSize, 1), partitions[3]) + }) + t.Run("partitions numbered across deadlines", func(t *testing.T) { + dls := miner.ConstructDeadlines() + dls.Due[1] = bfSeq(0, 3*partSize+1) + dls.Due[3] = bfSeq(3*partSize+1, 1) + dls.Due[5] = bfSeq(3*partSize+1+1, 2*partSize) + + partitions, err := miner.ComputePartitionsSectors(dls, partSize, 1, []uint64{0, 1, 2, 3}) + require.NoError(t, err) + assert.Equal(t, 4, len(partitions)) + + partitions, err = miner.ComputePartitionsSectors(dls, partSize, 3, []uint64{4}) + require.NoError(t, err) + assert.Equal(t, 1, len(partitions)) + assertBfEqual(t, bfSeq(3*partSize+1, 1), partitions[0]) + + partitions, err = miner.ComputePartitionsSectors(dls, partSize, 5, []uint64{5, 6}) + require.NoError(t, err) + assert.Equal(t, 2, len(partitions)) + assertBfEqual(t, bfSeq(3*partSize+1+1, partSize), partitions[0]) + assertBfEqual(t, bfSeq(3*partSize+1+1+partSize, partSize), partitions[1]) + + // Mismatched deadline/partition pairs + _, err = miner.ComputePartitionsSectors(dls, partSize, 1, []uint64{4}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 2, []uint64{4}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 3, []uint64{0}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 3, []uint64{3}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 3, []uint64{5}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 4, []uint64{5}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 5, []uint64{0}) + require.Error(t, err) + _, err = miner.ComputePartitionsSectors(dls, partSize, 5, []uint64{7}) + require.Error(t, err) + }) +} + +func TestAssignNewSectors(t *testing.T) { + partSize := uint64(4) + seed := abi.Randomness([]byte{}) + + assign := func(deadlines *miner.Deadlines, sectors []uint64) *miner.Deadlines { + require.NoError(t, miner.AssignNewSectors(deadlines, partSize, sectors, seed)) + return deadlines + } + + t.Run("initial assignment", func(t *testing.T) { + { + deadlines := assign(miner.ConstructDeadlines(), seq(0, 0)) + NewDeadlinesBuilder(t).verify(deadlines) + } + { + deadlines := assign(miner.ConstructDeadlines(), seq(0, 1)) + NewDeadlinesBuilder(t, 0, 1).verify(deadlines) + } + { + deadlines := assign(miner.ConstructDeadlines(), seq(0, 15)) + NewDeadlinesBuilder(t, 0, 4, 4, 4, 3).verify(deadlines) + } + { + deadlines := assign(miner.ConstructDeadlines(), seq(0, (miner.WPoStPeriodDeadlines-1)*partSize+1)) + NewDeadlinesBuilder(t).addToAllFrom(1, partSize).addTo(1, 1).verify(deadlines) + } + }) + t.Run("incremental assignment", func(t *testing.T) { + { + // Add one sector at a time. + deadlines := NewDeadlinesBuilder(t, 0, 1).Deadlines + assign(deadlines, seq(1, 1)) + NewDeadlinesBuilder(t, 0, 2).verify(deadlines) + assign(deadlines, seq(2, 1)) + NewDeadlinesBuilder(t, 0, 3).verify(deadlines) + assign(deadlines, seq(3, 1)) + NewDeadlinesBuilder(t, 0, 4).verify(deadlines) + assign(deadlines, seq(4, 1)) + NewDeadlinesBuilder(t, 0, 4, 1).verify(deadlines) + } + { + // Add one partition at a time. + deadlines := miner.ConstructDeadlines() + assign(deadlines, seq(0, 4)) + NewDeadlinesBuilder(t, 0, 4).verify(deadlines) + assign(deadlines, seq(4, 4)) + NewDeadlinesBuilder(t, 0, 4, 4).verify(deadlines) + assign(deadlines, seq(2*4, 4)) + NewDeadlinesBuilder(t, 0, 4, 4, 4).verify(deadlines) + assign(deadlines, seq(3*4, 4)) + NewDeadlinesBuilder(t, 0, 4, 4, 4, 4).verify(deadlines) + } + { + // Add lots + deadlines := miner.ConstructDeadlines() + assign(deadlines, seq(0, 2*partSize+1)) + NewDeadlinesBuilder(t, 0, partSize, partSize, 1).verify(deadlines) + assign(deadlines, seq(2*partSize+1, partSize)) + NewDeadlinesBuilder(t, 0, partSize, partSize, partSize, 1).verify(deadlines) + } + }) + t.Run("fill partial partitions first", func(t *testing.T) { + { + b := NewDeadlinesBuilder(t, 0, 4, 3, 1) + deadlines := assign(b.Deadlines, seq(b.NextSectorIdx, 4)) + + NewDeadlinesBuilder(t, 0, 4, 3, 1). + addTo(2, 1). // Fill the first partial partition + addTo(3, 3). // Fill the next partial partition + verify(deadlines) + } + { + b := NewDeadlinesBuilder(t, 0, 9, 8, 7, 4, 1) + deadlines := assign(b.Deadlines, seq(b.NextSectorIdx, 7)) + + NewDeadlinesBuilder(t, 0, 9, 8, 7, 4, 1). + addTo(1, 3). // Fill the first partial partition, in deadline 1 + addTo(3, 1). // Fill the next partial partition + addTo(5, 3). // Fill the final partial partition + verify(deadlines) + } + }) + t.Run("fill less full deadlines first", func(t *testing.T) { + { + b := NewDeadlinesBuilder(t, 0, 12, 4, 4, 8). + addToAllFrom(5, 100) // Fill trailing deadlines so we can just use the first few. + deadlines := b.Deadlines + assign(deadlines, seq(b.NextSectorIdx, 20)) + + NewDeadlinesBuilder(t, 0, 12, 4, 4, 8). + addToAllFrom(5, 100). + addTo(2, 4). + addTo(3, 4). + addTo(2, 4). + addTo(3, 4). + addTo(4, 4). + verify(deadlines) + } + }) + // TODO: a final test including partial and full partitions that exercises both filling the partials first, + // then prioritising the less full deadlines. + // https://github.com/filecoin-project/specs-actors/issues/439 +} + +// +// Deadlines Utils +// + +func assertBfEqual(t *testing.T, expected, actual *bitfield.BitField) { + ex, err := expected.All(1 << 20) + require.NoError(t, err) + ac, err := actual.All(1 << 20) + require.NoError(t, err) + assert.Equal(t, ex, ac) +} + +func assertDeadlinesEqual(t *testing.T, expected, actual *miner.Deadlines) { + for i := range expected.Due { + ex, err := expected.Due[i].All(1 << 20) + require.NoError(t, err) + ac, err := actual.Due[i].All(1 << 20) + require.NoError(t, err) + assert.Equal(t, ex, ac, "mismatched deadlines at index %d", i) + } +} + +// Creates a bitfield with a sequence of `count` values from `first. +func bfSeq(first uint64, count uint64) *abi.BitField { + values := seq(first, count) + return bitfield.NewFromSet(values) +} + +// Creates a slice of integers with a sequence of `count` values from `first. +func seq(first uint64, count uint64) []uint64 { + values := make([]uint64, count) + for i := range values { + values[i] = first + uint64(i) + } + return values +} + +// accepts an array were the value at each index indicates how many sectors are in the partition of the returned Deadlines +// Example: +// gen := [miner.WPoStPeriodDeadlines]uint64{1, 42, 89, 0} returns a deadline with: +// 1 sectors at deadlineIdx 0 +// 42 sectors at deadlineIdx 1 +// 89 sectors at deadlineIdx 2 +// 0 sectors at deadlineIdx 3-47 +func buildDeadlines(t *testing.T, gen []uint64) *miner.Deadlines { + return NewDeadlinesBuilder(t).addToFrom(0, gen...).Deadlines +} + +// A builder for initialising a Deadlines with sectors assigned. +type DeadlinesBuilder struct { + Deadlines *miner.Deadlines + NextSectorIdx uint64 + t *testing.T +} + +// Creates a new builder, with optional initial sector counts. +func NewDeadlinesBuilder(t *testing.T, counts ...uint64) *DeadlinesBuilder { + b := &DeadlinesBuilder{miner.ConstructDeadlines(), 0, t} + b.addToFrom(0, counts...) + return b +} + +// Assigns count new sectors to deadline idx. +func (b *DeadlinesBuilder) addTo(idx uint64, count uint64) *DeadlinesBuilder { + nums := seq(b.NextSectorIdx, count) + b.NextSectorIdx += count + require.NoError(b.t, b.Deadlines.AddToDeadline(idx, nums...)) + return b +} + +// Assigns counts[i] new sectors to deadlines sequentially from first. +func (b *DeadlinesBuilder) addToFrom(first uint64, counts ...uint64) *DeadlinesBuilder { + for i, c := range counts { + b.addTo(first+uint64(i), c) + } + return b +} + +// Assigns count new sectors to every deadline. +func (b *DeadlinesBuilder) addToAll(count uint64) *DeadlinesBuilder { + for i := range b.Deadlines.Due { + b.addTo(uint64(i), count) + } + return b +} + +// Assigns count new sectors to every deadline from first until the last. +func (b *DeadlinesBuilder) addToAllFrom(first uint64, count uint64) *DeadlinesBuilder { + for i := first; i < miner.WPoStPeriodDeadlines; i++ { + b.addTo(i, count) + } + return b +} + +// Verifies that deadlines match this builder as expected values. +func (b *DeadlinesBuilder) verify(actual *miner.Deadlines) { + assertDeadlinesEqual(b.t, b.Deadlines, actual) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations.go new file mode 100644 index 0000000000..cd011d97bf --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations.go @@ -0,0 +1,37 @@ +package miner + +import ( + "sort" + + "github.com/filecoin-project/specs-actors/actors/abi" +) + +type sectorEpochSet struct { + epoch abi.ChainEpoch + sectors []uint64 +} + +// Takes a slice of sector infos and returns sector info sets grouped and +// sorted by expiration epoch. +// +// Note: While each sector set is sorted by epoch, the order of per-epoch sector +// sets is maintained. +func groupSectorsByExpiration(sectors []*SectorOnChainInfo) []sectorEpochSet { + sectorsByExpiration := make(map[abi.ChainEpoch][]uint64) + + for _, sector := range sectors { + sectorsByExpiration[sector.Expiration] = append(sectorsByExpiration[sector.Expiration], uint64(sector.SectorNumber)) + } + + sectorEpochSets := make([]sectorEpochSet, 0, len(sectorsByExpiration)) + + // This map iteration is non-deterministic but safe because we sort by epoch below. + for expiration, sectors := range sectorsByExpiration { + sectorEpochSets = append(sectorEpochSets, sectorEpochSet{expiration, sectors}) + } + + sort.Slice(sectorEpochSets, func(i, j int) bool { + return sectorEpochSets[i].epoch < sectorEpochSets[j].epoch + }) + return sectorEpochSets +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations_test.go new file mode 100644 index 0000000000..df82dffd88 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/expirations_test.go @@ -0,0 +1,39 @@ +package miner + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestExpirations(t *testing.T) { + sectors := []*SectorOnChainInfo{{ + Expiration: 0, + SectorNumber: 1, + }, { + Expiration: 0, + SectorNumber: 2, + }, { + Expiration: 2, + SectorNumber: 3, + }, { + Expiration: 0, + SectorNumber: 4, + }} + result := groupSectorsByExpiration(sectors) + expected := []sectorEpochSet{{ + epoch: 0, + sectors: []uint64{1, 2, 4}, + }, { + epoch: 2, + sectors: []uint64{3}, + }} + require.Equal(t, expected, result) +} + +func TestExpirationsEmpty(t *testing.T) { + sectors := []*SectorOnChainInfo{} + result := groupSectorsByExpiration(sectors) + expected := []sectorEpochSet{} + require.Equal(t, expected, result) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_actor.go new file mode 100644 index 0000000000..dab50d20c7 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_actor.go @@ -0,0 +1,2190 @@ +package miner + +import ( + "bytes" + "encoding/binary" + "fmt" + + addr "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + market "github.com/filecoin-project/specs-actors/actors/builtin/market" + power "github.com/filecoin-project/specs-actors/actors/builtin/power" + crypto "github.com/filecoin-project/specs-actors/actors/crypto" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + . "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Runtime = vmr.Runtime + +type CronEventType int64 + +const ( + CronEventWorkerKeyChange CronEventType = iota + CronEventPreCommitExpiry + CronEventProvingPeriod +) + +type CronEventPayload struct { + EventType CronEventType + Sectors *abi.BitField +} + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.ControlAddresses, + 3: a.ChangeWorkerAddress, + 4: a.ChangePeerID, + 5: a.SubmitWindowedPoSt, + 6: a.PreCommitSector, + 7: a.ProveCommitSector, + 8: a.ExtendSectorExpiration, + 9: a.TerminateSectors, + 10: a.DeclareFaults, + 11: a.DeclareFaultsRecovered, + 12: a.OnDeferredCronEvent, + 13: a.CheckSectorProven, + 14: a.AddLockedFund, + 15: a.ReportConsensusFault, + 16: a.WithdrawBalance, + 17: a.ConfirmSectorProofsValid, + 18: a.ChangeMultiaddrs, + } +} + +var _ abi.Invokee = Actor{} + +///////////////// +// Constructor // +///////////////// + +// Storage miner actors are created exclusively by the storage power actor. In order to break a circular dependency +// between the two, the construction parameters are defined in the power actor. +type ConstructorParams = power.MinerConstructorParams + +func (a Actor) Constructor(rt Runtime, params *ConstructorParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.InitActorAddr) + + _, ok := SupportedProofTypes[params.SealProofType] + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "proof type %d not allowed for new miner actors", params.SealProofType) + } + + owner := resolveOwnerAddress(rt, params.OwnerAddr) + worker := resolveWorkerAddress(rt, params.WorkerAddr) + + emptyMap, err := adt.MakeEmptyMap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to construct initial state: %v", err) + } + + emptyArray, err := adt.MakeEmptyArray(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to construct initial state: %v", err) + } + + emptyDeadlines := ConstructDeadlines() + emptyDeadlinesCid := rt.Store().Put(emptyDeadlines) + + currEpoch := rt.CurrEpoch() + offset, err := assignProvingPeriodOffset(rt.Message().Receiver(), currEpoch, rt.Syscalls().HashBlake2b) + builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to assign proving period offset") + periodStart := nextProvingPeriodStart(currEpoch, offset) + Assert(periodStart > currEpoch) + + info, err := ConstructMinerInfo(owner, worker, params.PeerId, params.Multiaddrs, params.SealProofType) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed to construct initial miner info") + infoCid := rt.Store().Put(info) + + state, err := ConstructState(infoCid, periodStart, emptyArray, emptyMap, emptyDeadlinesCid) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed to construct state") + rt.State().Create(state) + + // Register cron callback for epoch before the first proving period starts. + enrollCronEvent(rt, periodStart-1, &CronEventPayload{ + EventType: CronEventProvingPeriod, + }) + return nil +} + +///////////// +// Control // +///////////// + +type GetControlAddressesReturn struct { + Owner addr.Address + Worker addr.Address +} + +func (a Actor) ControlAddresses(rt Runtime, _ *adt.EmptyValue) *GetControlAddressesReturn { + rt.ValidateImmediateCallerAcceptAny() + var st State + rt.State().Readonly(&st) + info := getMinerInfo(rt, &st) + return &GetControlAddressesReturn{ + Owner: info.Owner, + Worker: info.Worker, + } +} + +type ChangeWorkerAddressParams struct { + NewWorker addr.Address +} + +func (a Actor) ChangeWorkerAddress(rt Runtime, params *ChangeWorkerAddressParams) *adt.EmptyValue { + var effectiveEpoch abi.ChainEpoch + var st State + rt.State().Transaction(&st, func() interface{} { + info := getMinerInfo(rt, &st) + + rt.ValidateImmediateCallerIs(info.Owner) + + worker := resolveWorkerAddress(rt, params.NewWorker) + + effectiveEpoch = rt.CurrEpoch() + WorkerKeyChangeDelay + + // This may replace another pending key change. + info.PendingWorkerKey = &WorkerKeyChange{ + NewWorker: worker, + EffectiveAt: effectiveEpoch, + } + err := st.SaveInfo(adt.AsStore(rt), info) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not save miner info") + return nil + }) + + cronPayload := CronEventPayload{ + EventType: CronEventWorkerKeyChange, + } + enrollCronEvent(rt, effectiveEpoch, &cronPayload) + return nil +} + +type ChangePeerIDParams struct { + NewID abi.PeerID +} + +func (a Actor) ChangePeerID(rt Runtime, params *ChangePeerIDParams) *adt.EmptyValue { + var st State + rt.State().Transaction(&st, func() interface{} { + info := getMinerInfo(rt, &st) + + rt.ValidateImmediateCallerIs(info.Worker) + info.PeerId = params.NewID + err := st.SaveInfo(adt.AsStore(rt), info) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not save miner info") + return nil + }) + return nil +} + +type ChangeMultiaddrsParams struct { + NewMultiaddrs []abi.Multiaddrs +} + +func (a Actor) ChangeMultiaddrs(rt Runtime, params *ChangeMultiaddrsParams) *adt.EmptyValue { + var st State + rt.State().Transaction(&st, func() interface{} { + info := getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker) + info.Multiaddrs = params.NewMultiaddrs + err := st.SaveInfo(adt.AsStore(rt), info) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not save miner info") + return nil + }) + return nil +} + +////////////////// +// WindowedPoSt // +////////////////// + +// Information submitted by a miner to provide a Window PoSt. +type SubmitWindowedPoStParams struct { + // The deadline index which the submission targets. + Deadline uint64 + // The partition indices being proven. + // Partitions are counted across all deadlines, such that all partition indices in the second deadline are greater + // than the partition numbers in the first deadlines. + Partitions []uint64 + // Array of proofs, one per distinct registered proof type present in the sectors being proven. + // In the usual case of a single proof type, this array will always have a single element (independent of number of partitions). + Proofs []abi.PoStProof + // Sectors skipped while proving that weren't already declared faulty + Skipped abi.BitField +} + +// Invoked by miner's worker address to submit their fallback post +func (a Actor) SubmitWindowedPoSt(rt Runtime, params *SubmitWindowedPoStParams) *adt.EmptyValue { + currEpoch := rt.CurrEpoch() + store := adt.AsStore(rt) + var st State + var newFaultSectors []*SectorOnChainInfo + var recoveredSectors []*SectorOnChainInfo + penalty := abi.NewTokenAmount(0) + + // Get the total power/reward. We need these to compute penalties. + epochReward := requestCurrentEpochBlockReward(rt) + pwrTotal := requestCurrentTotalPower(rt) + + var info *MinerInfo + rt.State().Transaction(&st, func() interface{} { + info = getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker) + + // Validate that the miner didn't try to prove too many partitions at once. + partitionSize := info.WindowPoStPartitionSectors + submissionPartitionLimit := windowPoStMessagePartitionsMax(partitionSize) + if uint64(len(params.Partitions)) > submissionPartitionLimit { + rt.Abortf(exitcode.ErrIllegalArgument, "too many partitions %d, limit %d", len(params.Partitions), submissionPartitionLimit) + } + + // Load and check deadline. + currDeadline := st.DeadlineInfo(currEpoch) + deadlines, err := st.LoadDeadlines(adt.AsStore(rt)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines") + + // Double check that the current proving period has started. This should only happen if the cron actor wasn't invoked. + if !currDeadline.PeriodStarted() { + rt.Abortf(exitcode.ErrIllegalState, "proving period %d not yet open at %d", currDeadline.PeriodStart, currEpoch) + } + + // The miner may only submit a proof for the current deadline. + if params.Deadline != currDeadline.Index { + rt.Abortf(exitcode.ErrIllegalArgument, "invalid deadline %d at epoch %d, expected %d", + params.Deadline, currEpoch, currDeadline.Index) + } + + // Detect and mark faults from any missed deadlines (doesn't including the current deadline). + // Traverse earlier submissions and enact detected faults. + // This isn't strictly necessary, but keeps the power table up to date eagerly and can force payment + // of penalties if locked pledge drops too low. + detectedFaultSectors, detectedFaultPenalty := detectFaultsThisPeriod(rt, &st, store, currDeadline, deadlines, epochReward, pwrTotal.QualityAdjPower) + penalty = big.Add(penalty, detectedFaultPenalty) + newFaultSectors = append(newFaultSectors, detectedFaultSectors...) + + // Add skipped as faults + skippedFaultSectors, skippedPenalty := processSkippedFaults(rt, &st, store, currDeadline, info, deadlines, epochReward, pwrTotal.QualityAdjPower, ¶ms.Skipped) + penalty = big.Add(penalty, skippedPenalty) + newFaultSectors = append(newFaultSectors, skippedFaultSectors...) + + // Work out which sectors are due in the declared partitions at this deadline. + partitionsSectors, err := ComputePartitionsSectors(deadlines, partitionSize, currDeadline.Index, params.Partitions) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to compute partitions sectors at deadline %d, partitions %s", + currDeadline.Index, params.Partitions) + + provenSectors, err := bitfield.MultiMerge(partitionsSectors...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to union %d partitions of sectors", len(partitionsSectors)) + + // Load sector infos, substituting a known-good sector for known-faulty sectors. + // NOTE: ErrIllegalState isn't quite correct. This can fail if the user submits a proof for a partition + // with only faulty sectors. Ideally we'd distinguish between the two cases, but that's tricky to do at the moment. + sectorInfos, declaredRecoveries, err := st.LoadSectorInfosForProof(store, provenSectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load proven sector info") + + // Verify the proof. + // A failed verification doesn't immediately cause a penalty; the miner can try again. + verifyWindowedPost(rt, currDeadline.Challenge, sectorInfos, params.Proofs) + + // Record the successful submission + postedPartitions := bitfield.NewFromSet(params.Partitions) + contains, err := abi.BitFieldContainsAny(st.PostSubmissions, postedPartitions) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to intersect post partitions") + if contains { + rt.Abortf(exitcode.ErrIllegalArgument, "duplicate PoSt partition") + } + err = st.AddPoStSubmissions(postedPartitions) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to record submissions for partitions %s", params.Partitions) + + // If the PoSt was successful, restore declared recoveries. + err = st.RemoveFaults(store, declaredRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove recoveries from faults") + + err = st.RemoveRecoveries(declaredRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove recoveries") + + // Load info for recovered sectors for recovery of power outside this state transaction. + empty, err := declaredRecoveries.IsEmpty() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check if bitfield was empty: %s") + + if !empty { + sectorsByNumber := make(map[abi.SectorNumber]*SectorOnChainInfo, len(sectorInfos)) + for _, s := range sectorInfos { + sectorsByNumber[s.SectorNumber] = s + } + + _ = declaredRecoveries.ForEach(func(i uint64) error { + recoveredSectors = append(recoveredSectors, sectorsByNumber[abi.SectorNumber(i)]) + return nil + }) + } + return nil + }) + + // Restore power for recovered sectors. Remove power for new faults. + requestUpdateSectorPower(rt, info.SectorSize, recoveredSectors, newFaultSectors) + // Burn penalties. + burnFundsAndNotifyPledgeChange(rt, penalty) + return nil +} + +/////////////////////// +// Sector Commitment // +/////////////////////// + +// Proposals must be posted on chain via sma.PublishStorageDeals before PreCommitSector. +// Optimization: PreCommitSector could contain a list of deals that are not published yet. +func (a Actor) PreCommitSector(rt Runtime, params *SectorPreCommitInfo) *adt.EmptyValue { + if params.Expiration <= rt.CurrEpoch() { + rt.Abortf(exitcode.ErrIllegalArgument, "sector expiration %v must be after now (%v)", params.Expiration, rt.CurrEpoch()) + } + if params.SealRandEpoch >= rt.CurrEpoch() { + rt.Abortf(exitcode.ErrIllegalArgument, "seal challenge epoch %v must be before now %v", params.SealRandEpoch, rt.CurrEpoch()) + } + challengeEarliest := sealChallengeEarliest(rt.CurrEpoch(), params.SealProof) + if params.SealRandEpoch < challengeEarliest { + // The subsequent commitment proof can't possibly be accepted because the seal challenge will be deemed + // too old. Note that passing this check doesn't guarantee the proof will be soon enough, depending on + // when it arrives. + rt.Abortf(exitcode.ErrIllegalArgument, "seal challenge epoch %v too old, must be after %v", params.SealRandEpoch, challengeEarliest) + } + if params.ReplaceCapacity && len(params.DealIDs) == 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace sector without committing deals") + } + + // gather information from other actors + epochReward := requestCurrentEpochBlockReward(rt) + pwrTotal := requestCurrentTotalPower(rt) + dealWeight := requestDealWeight(rt, params.DealIDs, rt.CurrEpoch(), params.Expiration) + circulatingSupply := rt.TotalFilCircSupply() + + store := adt.AsStore(rt) + var st State + newlyVestedAmount := rt.State().Transaction(&st, func() interface{} { + info := getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker) + if params.SealProof != info.SealProofType { + rt.Abortf(exitcode.ErrIllegalArgument, "sector seal proof %v must match miner seal proof type %d", params.SealProof, info.SealProofType) + } + + _, preCommitFound, err := st.GetPrecommittedSector(store, params.SectorNumber) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check pre-commit %v", params.SectorNumber) + if preCommitFound { + rt.Abortf(exitcode.ErrIllegalArgument, "sector %v already pre-committed", params.SectorNumber) + } + + sectorFound, err := st.HasSectorNo(store, params.SectorNumber) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check sector %v", params.SectorNumber) + if sectorFound { + rt.Abortf(exitcode.ErrIllegalArgument, "sector %v already committed", params.SectorNumber) + } + + validateExpiration(rt, &st, rt.CurrEpoch(), params.Expiration, params.SealProof) + + depositMinimum := big.Zero() + if params.ReplaceCapacity { + replaceSector := validateReplaceSector(rt, &st, store, params) + // Note the replaced sector's initial pledge as a lower bound for the new sector's deposit + depositMinimum = replaceSector.InitialPledge + } + + newlyVestedFund, err := st.UnlockVestedFunds(store, rt.CurrEpoch()) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to vest funds") + availableBalance := st.GetAvailableBalance(rt.CurrentBalance()) + duration := params.Expiration - rt.CurrEpoch() + + sectorWeight := QAPowerForWeight(info.SectorSize, duration, dealWeight.DealWeight, dealWeight.VerifiedDealWeight) + depositReq := big.Max( + precommitDeposit(sectorWeight, pwrTotal.QualityAdjPower, pwrTotal.PledgeCollateral, epochReward, circulatingSupply), + depositMinimum, + ) + if availableBalance.LessThan(depositReq) { + rt.Abortf(exitcode.ErrInsufficientFunds, "insufficient funds for pre-commit deposit: %v", depositReq) + } + + st.AddPreCommitDeposit(depositReq) + st.AssertBalanceInvariants(rt.CurrentBalance()) + + if err := st.PutPrecommittedSector(store, &SectorPreCommitOnChainInfo{ + Info: *params, + PreCommitDeposit: depositReq, + PreCommitEpoch: rt.CurrEpoch(), + DealWeight: dealWeight.DealWeight, + VerifiedDealWeight: dealWeight.VerifiedDealWeight, + }); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to write pre-committed sector %v: %v", params.SectorNumber, err) + } + + return newlyVestedFund + }).(abi.TokenAmount) + + notifyPledgeChanged(rt, newlyVestedAmount.Neg()) + + bf := abi.NewBitField() + bf.Set(uint64(params.SectorNumber)) + + // Request deferred Cron check for PreCommit expiry check. + cronPayload := CronEventPayload{ + EventType: CronEventPreCommitExpiry, + Sectors: bf, + } + + msd, ok := MaxSealDuration[params.SealProof] + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "no max seal duration set for proof type: %d", params.SealProof) + } + + // The +1 here is critical for the batch verification of proofs. Without it, if a proof arrived exactly on the + // due epoch, ProveCommitSector would accept it, then the expiry event would remove it, and then + // ConfirmSectorProofsValid would fail to find it. + expiryBound := rt.CurrEpoch() + msd + 1 + enrollCronEvent(rt, expiryBound, &cronPayload) + + return nil +} + +type ProveCommitSectorParams struct { + SectorNumber abi.SectorNumber + Proof []byte +} + +// Checks state of the corresponding sector pre-commitment, then schedules the proof to be verified in bulk +// by the power actor. +// If valid, the power actor will call ConfirmSectorProofsValid at the end of the same epoch as this message. +func (a Actor) ProveCommitSector(rt Runtime, params *ProveCommitSectorParams) *adt.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + + store := adt.AsStore(rt) + var st State + rt.State().Readonly(&st) + + // Verify locked funds are are at least the sum of sector initial pledges. + // Note that this call does not actually compute recent vesting, so the reported locked funds may be + // slightly higher than the true amount (i.e. slightly in the miner's favour). + // Computing vesting here would be almost always redundant since vesting is quantized to ~daily units. + // Vesting will be at most one proving period old if computed in the cron callback. + verifyPledgeMeetsInitialRequirements(rt, &st) + + sectorNo := params.SectorNumber + precommit, found, err := st.GetPrecommittedSector(store, sectorNo) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load pre-committed sector %v", sectorNo) + if !found { + rt.Abortf(exitcode.ErrNotFound, "no pre-committed sector %v", sectorNo) + } + + msd, ok := MaxSealDuration[precommit.Info.SealProof] + if !ok { + rt.Abortf(exitcode.ErrIllegalState, "no max seal duration for proof type: %d", precommit.Info.SealProof) + } + proveCommitDue := precommit.PreCommitEpoch + msd + if rt.CurrEpoch() > proveCommitDue { + rt.Abortf(exitcode.ErrIllegalArgument, "commitment proof for %d too late at %d, due %d", sectorNo, rt.CurrEpoch(), proveCommitDue) + } + + svi := getVerifyInfo(rt, &SealVerifyStuff{ + SealedCID: precommit.Info.SealedCID, + InteractiveEpoch: precommit.PreCommitEpoch + PreCommitChallengeDelay, + SealRandEpoch: precommit.Info.SealRandEpoch, + Proof: params.Proof, + DealIDs: precommit.Info.DealIDs, + SectorNumber: precommit.Info.SectorNumber, + RegisteredSealProof: precommit.Info.SealProof, + }) + + _, code := rt.Send( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.SubmitPoRepForBulkVerify, + svi, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to submit proof for bulk verification") + return nil +} + +func (a Actor) ConfirmSectorProofsValid(rt Runtime, params *builtin.ConfirmSectorProofsParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.StoragePowerActorAddr) + + var st State + rt.State().Readonly(&st) + store := adt.AsStore(rt) + info := getMinerInfo(rt, &st) + // Committed-capacity sectors licensed for early removal by new sectors being proven. + var replaceSectors []*SectorOnChainInfo + replaceSectorKeys := map[abi.SectorNumber]struct{}{} // For de-duplication + var preCommits []*SectorPreCommitOnChainInfo + for _, sectorNo := range params.Sectors { + precommit, found, err := st.GetPrecommittedSector(store, sectorNo) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load pre-committed sector %v", sectorNo) + if !found || err != nil { + // This relies on the precommit having been checked in ProveCommitSector and not removed (expired) before + // this call. This in turn relies on the call from the power actor reliably coming in the same + // epoch as ProveCommitSector. + + // TODO #564 log: "failed to get precommitted sector on sector %d, dropping from prove commit set" + continue + } + + if precommit.Info.ReplaceCapacity { + replaceSector := precommit.Info.ReplaceSector + info, exists, err := st.GetSector(store, replaceSector) + if err != nil { + // TODO #564 log "failed to check sector %d, dropping from prove commit set" + continue + } + faulty, err := st.Faults.IsSet(uint64(replaceSector)) + if err != nil { + // TODO #564 log "failed to check sector %d fault state, dropping from prove commit set" + continue + } + _, set := replaceSectorKeys[replaceSector] + // It doesn't matter if the committed-capacity sector no longer exists, or if multiple sectors attempt to + // replace the same committed-capacity sector, so long as we don't try to terminate it more than once. + // It just represents a lost opportunity to terminate a committed sector early. + // Similarly, if faulty, allow the new sector commitment to proceed but just decline to terminate the + // committed-capacity one. + if exists && !set && !faulty { + replaceSectorKeys[replaceSector] = struct{}{} + replaceSectors = append(replaceSectors, info) + } + } + + // Check (and activate) storage deals associated to sector. Abort if checks failed. + // TODO: we should batch these calls... + // https://github.com/filecoin-project/specs-actors/issues/474 + _, code := rt.Send( + builtin.StorageMarketActorAddr, + builtin.MethodsMarket.ActivateDeals, + &market.ActivateDealsParams{ + DealIDs: precommit.Info.DealIDs, + SectorExpiry: precommit.Info.Expiration, + }, + abi.NewTokenAmount(0), + ) + if code != exitcode.Ok { + // TODO #564 log: "failed to activate deals on sector %d, dropping from prove commit set" + continue + } + + preCommits = append(preCommits, precommit) + } + + // When all prove commits have failed abort early + if len(preCommits) == 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "all prove commits failed to validate") + } + + // This transaction should replace the one inside the loop above. + // Migrate state mutations into here. + totalPledge := big.Zero() + newSectors := make([]*SectorOnChainInfo, 0) + newlyVestedAmount := rt.State().Transaction(&st, func() interface{} { + err := scheduleReplaceSectorsExpiration(rt, &st, store, replaceSectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to replace sector expirations") + + newSectorNos := make([]abi.SectorNumber, 0, len(preCommits)) + for _, precommit := range preCommits { + // initial pledge is precommit deposit + initialPledge := precommit.PreCommitDeposit + totalPledge = big.Add(totalPledge, initialPledge) + newSectorInfo := SectorOnChainInfo{ + SectorNumber: precommit.Info.SectorNumber, + SealProof: precommit.Info.SealProof, + SealedCID: precommit.Info.SealedCID, + DealIDs: precommit.Info.DealIDs, + Expiration: precommit.Info.Expiration, + Activation: precommit.PreCommitEpoch, + DealWeight: precommit.DealWeight, + VerifiedDealWeight: precommit.VerifiedDealWeight, + InitialPledge: initialPledge, + } + newSectors = append(newSectors, &newSectorInfo) + newSectorNos = append(newSectorNos, newSectorInfo.SectorNumber) + } + + err = st.PutSectors(store, newSectors...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to put new sectors") + + err = st.DeletePrecommittedSectors(store, newSectorNos...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to delete precommited sectors") + + err = st.AddSectorExpirations(store, newSectors...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add new sector expirations") + + err = st.AddNewSectors(newSectorNos...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add new sectors to new sectors bitfield") + + // Add sector and pledge lock-up to miner state + newlyVestedFund, err := st.UnlockVestedFunds(store, rt.CurrEpoch()) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to vest new funds: %s", err) + } + + // Unlock deposit for successful proofs, make it available for lock-up as initial pledge. + st.AddPreCommitDeposit(totalPledge.Neg()) + st.AddInitialPledgeRequirement(totalPledge) + + // Lock up initial pledge for new sectors. + availableBalance := st.GetAvailableBalance(rt.CurrentBalance()) + if availableBalance.LessThan(totalPledge) { + rt.Abortf(exitcode.ErrInsufficientFunds, "insufficient funds for aggregate initial pledge requirement %s, available: %s", totalPledge, availableBalance) + } + if err := st.AddLockedFunds(store, rt.CurrEpoch(), totalPledge, &PledgeVestingSpec); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to add aggregate pledge: %v", err) + } + st.AssertBalanceInvariants(rt.CurrentBalance()) + + return newlyVestedFund + }).(abi.TokenAmount) + + // Request power and pledge update for activated sector. + requestUpdateSectorPower(rt, info.SectorSize, newSectors, nil) + notifyPledgeChanged(rt, big.Sub(totalPledge, newlyVestedAmount)) + + return nil +} + +type CheckSectorProvenParams struct { + SectorNumber abi.SectorNumber +} + +func (a Actor) CheckSectorProven(rt Runtime, params *CheckSectorProvenParams) *adt.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + + var st State + rt.State().Readonly(&st) + store := adt.AsStore(rt) + sectorNo := params.SectorNumber + + if _, found, err := st.GetSector(store, sectorNo); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to load proven sector %v", sectorNo) + } else if !found { + rt.Abortf(exitcode.ErrNotFound, "sector %v not proven", sectorNo) + } + return nil +} + +///////////////////////// +// Sector Modification // +///////////////////////// + +type ExtendSectorExpirationParams struct { + SectorNumber abi.SectorNumber + NewExpiration abi.ChainEpoch +} + +func (a Actor) ExtendSectorExpiration(rt Runtime, params *ExtendSectorExpirationParams) *adt.EmptyValue { + var st State + rt.State().Readonly(&st) + info := getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker) + + store := adt.AsStore(rt) + sectorNo := params.SectorNumber + oldSector, found, err := st.GetSector(store, sectorNo) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sector %v", sectorNo) + if !found { + rt.Abortf(exitcode.ErrNotFound, "no such sector %v", sectorNo) + } + if params.NewExpiration < oldSector.Expiration { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot reduce sector expiration to %d from %d", + params.NewExpiration, oldSector.Expiration) + } + + validateExpiration(rt, &st, oldSector.Activation, params.NewExpiration, oldSector.SealProof) + + newSector := *oldSector + newSector.Expiration = params.NewExpiration + qaPowerDelta := big.Sub(QAPowerForSector(info.SectorSize, &newSector), QAPowerForSector(info.SectorSize, oldSector)) + + _, code := rt.Send( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.UpdateClaimedPower, + &power.UpdateClaimedPowerParams{ + RawByteDelta: big.Zero(), // Sector size has not changed + QualityAdjustedDelta: qaPowerDelta, + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to modify sector weight") + + // Store new sector expiry. + rt.State().Transaction(&st, func() interface{} { + err = st.PutSectors(store, &newSector) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update sector %v", sectorNo) + + // move expiration from old epoch to new + err = st.RemoveSectorExpirations(store, oldSector) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove sector expiration %v at %d", sectorNo, oldSector.Expiration) + err = st.AddSectorExpirations(store, &newSector) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add sector expiration %v at %d", sectorNo, newSector.Expiration) + return nil + }) + return nil +} + +type TerminateSectorsParams struct { + Sectors *abi.BitField +} + +func (a Actor) TerminateSectors(rt Runtime, params *TerminateSectorsParams) *adt.EmptyValue { + var st State + rt.State().Readonly(&st) + info := getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker) + + epochReward := requestCurrentEpochBlockReward(rt) + pwrTotal := requestCurrentTotalPower(rt) + // Note: this cannot terminate pre-committed but un-proven sectors. + // They must be allowed to expire (and deposit burnt). + terminateSectors(rt, params.Sectors, power.SectorTerminationManual, epochReward, pwrTotal.QualityAdjPower) + return nil +} + +//////////// +// Faults // +//////////// + +type DeclareFaultsParams struct { + Faults []FaultDeclaration +} + +type FaultDeclaration struct { + Deadline uint64 // In range [0..WPoStPeriodDeadlines) + Sectors *abi.BitField +} + +func (a Actor) DeclareFaults(rt Runtime, params *DeclareFaultsParams) *adt.EmptyValue { + if uint64(len(params.Faults)) > WPoStPeriodDeadlines { + rt.Abortf(exitcode.ErrIllegalArgument, "too many declarations %d, max %d", len(params.Faults), WPoStPeriodDeadlines) + } + + currEpoch := rt.CurrEpoch() + store := adt.AsStore(rt) + var st State + var declaredFaultSectors []*SectorOnChainInfo + var detectedFaultSectors []*SectorOnChainInfo + penalty := abi.NewTokenAmount(0) + + epochReward := requestCurrentEpochBlockReward(rt) + pwrTotal := requestCurrentTotalPower(rt) + + var info *MinerInfo + rt.State().Transaction(&st, func() interface{} { + info = getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker) + + currDeadline := st.DeadlineInfo(currEpoch) + deadlines, err := st.LoadDeadlines(adt.AsStore(rt)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines") + + // Traverse earlier submissions and enact detected faults. + // This is necessary to move the NextDeadlineToProcessFaults index past the deadline that this recovery + // is targeting, so that the recovery won't be declared failed next time it's checked during this proving period. + detectedFaultSectors, penalty = detectFaultsThisPeriod(rt, &st, store, currDeadline, deadlines, epochReward, pwrTotal.QualityAdjPower) + + var decaredSectors []*abi.BitField + for _, decl := range params.Faults { + targetDeadline, err := declarationDeadlineInfo(st.ProvingPeriodStart, decl.Deadline, currEpoch) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid fault declaration deadline") + + err = validateFRDeclaration(deadlines, targetDeadline, decl.Sectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid fault declaration") + decaredSectors = append(decaredSectors, decl.Sectors) + } + + allDeclared, err := bitfield.MultiMerge(decaredSectors...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to union faults") + + // Split declarations into declarations of new faults, and retraction of declared recoveries. + retractedRecoveries, err := bitfield.IntersectBitField(st.Recoveries, allDeclared) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to intersect sectors with recoveries") + + newFaults, err := bitfield.SubtractBitField(allDeclared, retractedRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to subtract recoveries from sectors") + + empty, err := newFaults.IsEmpty() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check if bitfield was empty") + + if !empty { + // Check new fault are really new. + contains, err := abi.BitFieldContainsAny(st.Faults, newFaults) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to intersect existing faults") + if contains { + // This could happen if attempting to declare a fault for a deadline that's already passed, + // detected and added to Faults above. + // The miner must for the fault detection at proving period end, or submit again omitting + // sectors in deadlines that have passed. + // Alternatively, we could subtract the just-detected faults from new faults. + rt.Abortf(exitcode.ErrIllegalArgument, "attempted to re-declare fault") + } + + // Add new faults to state and charge fee. + // Note: this sets the fault epoch for all declarations to be the beginning of this proving period, + // even if some sectors have already been proven in this period. + // It would better to use the target deadline's proving period start (which may be the one subsequent + // to the current). + err = st.AddFaults(store, newFaults, st.ProvingPeriodStart) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add faults") + + // Note: this charges a fee for all declarations, even if the sectors have already been proven + // in this proving period. This discourages early declaration compared with waiting for + // the proving period to roll over. + // It would be better to charge a fee for this proving period only if the target deadline has + // not already passed. If it _has_ already passed then either: + // - the miner submitted PoSt successfully and should not be penalised more relative to + // submitting this declaration after the proving period rolls over, or + // - the miner failed to submit PoSt and will be penalised at the proving period end + // In either case, the miner will pay a fee for the subsequent proving period at the start + // of that period, unless faults are recovered sooner. + + // Load info for sectors. + declaredFaultSectors, err = st.LoadSectorInfos(store, newFaults) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load fault sectors") + + // Unlock penalty for declared faults. + declaredPenalty, err := unlockDeclaredFaultPenalty(&st, store, info.SectorSize, currEpoch, epochReward, pwrTotal.QualityAdjPower, declaredFaultSectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to charge fault fee") + penalty = big.Add(penalty, declaredPenalty) + } + + // Remove faulty recoveries + empty, err = retractedRecoveries.IsEmpty() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check if bitfield was empty") + + if !empty { + err = st.RemoveRecoveries(retractedRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove recoveries") + } + return nil + }) + + // Remove power for new faulty sectors. + requestUpdateSectorPower(rt, info.SectorSize, nil, append(detectedFaultSectors, declaredFaultSectors...)) + burnFundsAndNotifyPledgeChange(rt, penalty) + + return nil +} + +type DeclareFaultsRecoveredParams struct { + Recoveries []RecoveryDeclaration +} + +type RecoveryDeclaration struct { + Deadline uint64 // In range [0..WPoStPeriodDeadlines) + Sectors *abi.BitField +} + +func (a Actor) DeclareFaultsRecovered(rt Runtime, params *DeclareFaultsRecoveredParams) *adt.EmptyValue { + if uint64(len(params.Recoveries)) > WPoStPeriodDeadlines { + rt.Abortf(exitcode.ErrIllegalArgument, "too many declarations %d, max %d", len(params.Recoveries), WPoStPeriodDeadlines) + } + + var detectedFaultSectors []*SectorOnChainInfo + penalty := abi.NewTokenAmount(0) + + epochReward := requestCurrentEpochBlockReward(rt) + pwrTotal := requestCurrentTotalPower(rt) + + currEpoch := rt.CurrEpoch() + store := adt.AsStore(rt) + var st State + var info *MinerInfo + rt.State().Transaction(&st, func() interface{} { + info = getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker) + + currDeadline := st.DeadlineInfo(currEpoch) + deadlines, err := st.LoadDeadlines(adt.AsStore(rt)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines") + + // Traverse earlier submissions and enact detected faults. + // This is necessary to move the NextDeadlineToProcessFaults index past the deadline that this recovery + // is targeting, so that the recovery won't be declared failed next time it's checked during this proving period. + detectedFaultSectors, penalty = detectFaultsThisPeriod(rt, &st, store, currDeadline, deadlines, epochReward, pwrTotal.QualityAdjPower) + + var declaredSectors []*abi.BitField + for _, decl := range params.Recoveries { + targetDeadline, err := declarationDeadlineInfo(st.ProvingPeriodStart, decl.Deadline, currEpoch) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid recovery declaration deadline") + + err = validateFRDeclaration(deadlines, targetDeadline, decl.Sectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid recovery declaration") + declaredSectors = append(declaredSectors, decl.Sectors) + } + + allRecoveries, err := bitfield.MultiMerge(declaredSectors...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to union recoveries") + + contains, err := abi.BitFieldContainsAll(st.Faults, allRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check recoveries are faulty") + if !contains { + rt.Abortf(exitcode.ErrIllegalArgument, "declared recoveries not currently faulty") + } + contains, err = abi.BitFieldContainsAny(st.Recoveries, allRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to intersect new recoveries") + if contains { + rt.Abortf(exitcode.ErrIllegalArgument, "sector already declared recovered") + } + + err = st.AddRecoveries(allRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid recoveries") + return nil + }) + + // Remove power for new faulty sectors. + requestUpdateSectorPower(rt, info.SectorSize, nil, detectedFaultSectors) + burnFundsAndNotifyPledgeChange(rt, penalty) + + // Power is not restored yet, but when the recovered sectors are successfully PoSted. + return nil +} + +/////////////////////// +// Pledge Collateral // +/////////////////////// + +// Locks up some amount of a the miner's unlocked balance (including any received alongside the invoking message). +func (a Actor) AddLockedFund(rt Runtime, amountToLock *abi.TokenAmount) *adt.EmptyValue { + store := adt.AsStore(rt) + var st State + newlyVested := rt.State().Transaction(&st, func() interface{} { + info := getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Worker, info.Owner, builtin.RewardActorAddr) + + newlyVestedFund, err := st.UnlockVestedFunds(store, rt.CurrEpoch()) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to vest funds") + + availableBalance := st.GetAvailableBalance(rt.CurrentBalance()) + if availableBalance.LessThan(*amountToLock) { + rt.Abortf(exitcode.ErrInsufficientFunds, "insufficient funds to lock, available: %v, requested: %v", availableBalance, *amountToLock) + } + + if err := st.AddLockedFunds(store, rt.CurrEpoch(), *amountToLock, &PledgeVestingSpec); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to lock pledge: %v", err) + } + return newlyVestedFund + }).(abi.TokenAmount) + + notifyPledgeChanged(rt, big.Sub(*amountToLock, newlyVested)) + return nil +} + +type ReportConsensusFaultParams struct { + BlockHeader1 []byte + BlockHeader2 []byte + BlockHeaderExtra []byte +} + +func (a Actor) ReportConsensusFault(rt Runtime, params *ReportConsensusFaultParams) *adt.EmptyValue { + // Note: only the first reporter of any fault is rewarded. + // Subsequent invocations fail because the target miner has been removed. + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + reporter := rt.Message().Caller() + + fault, err := rt.Syscalls().VerifyConsensusFault(params.BlockHeader1, params.BlockHeader2, params.BlockHeaderExtra) + if err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "fault not verified: %s", err) + } + + // Elapsed since the fault (i.e. since the higher of the two blocks) + faultAge := rt.CurrEpoch() - fault.Epoch + if faultAge <= 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "invalid fault epoch %v ahead of current %v", fault.Epoch, rt.CurrEpoch()) + } + + // Reward reporter with a share of the miner's current balance. + slasherReward := RewardForConsensusSlashReport(faultAge, rt.CurrentBalance()) + _, code := rt.Send(reporter, builtin.MethodSend, nil, slasherReward) + builtin.RequireSuccess(rt, code, "failed to reward reporter") + + var st State + rt.State().Readonly(&st) + + // Notify power actor with lock-up total being removed. + _, code = rt.Send( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.OnConsensusFault, + &st.LockedFunds, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to notify power actor on consensus fault") + + // close deals and burn funds + terminateMiner(rt) + + return nil +} + +type WithdrawBalanceParams struct { + AmountRequested abi.TokenAmount +} + +func (a Actor) WithdrawBalance(rt Runtime, params *WithdrawBalanceParams) *adt.EmptyValue { + var st State + if params.AmountRequested.LessThan(big.Zero()) { + rt.Abortf(exitcode.ErrIllegalArgument, "negative fund requested for withdrawal: %s", params.AmountRequested) + } + var info *MinerInfo + newlyVestedAmount := rt.State().Transaction(&st, func() interface{} { + info = getMinerInfo(rt, &st) + rt.ValidateImmediateCallerIs(info.Owner) + newlyVestedFund, err := st.UnlockVestedFunds(adt.AsStore(rt), rt.CurrEpoch()) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to vest fund: %v", err) + } + + // Verify locked funds are are at least the sum of sector initial pledges after vesting. + verifyPledgeMeetsInitialRequirements(rt, &st) + + return newlyVestedFund + }).(abi.TokenAmount) + + currBalance := rt.CurrentBalance() + amountWithdrawn := big.Min(st.GetAvailableBalance(currBalance), params.AmountRequested) + Assert(amountWithdrawn.LessThanEqual(currBalance)) + + _, code := rt.Send(info.Owner, builtin.MethodSend, nil, amountWithdrawn) + builtin.RequireSuccess(rt, code, "failed to withdraw balance") + + pledgeDelta := newlyVestedAmount.Neg() + notifyPledgeChanged(rt, pledgeDelta) + + st.AssertBalanceInvariants(rt.CurrentBalance()) + return nil +} + +////////// +// Cron // +////////// + +func (a Actor) OnDeferredCronEvent(rt Runtime, payload *CronEventPayload) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.StoragePowerActorAddr) + + switch payload.EventType { + case CronEventProvingPeriod: + handleProvingPeriod(rt) + case CronEventPreCommitExpiry: + if payload.Sectors != nil { + checkPrecommitExpiry(rt, payload.Sectors) + } + case CronEventWorkerKeyChange: + commitWorkerKeyChange(rt) + } + + return nil +} + +//////////////////////////////////////////////////////////////////////////////// +// Utility functions & helpers +//////////////////////////////////////////////////////////////////////////////// + +// Invoked at the end of each proving period, at the end of the epoch before the next one starts. +func handleProvingPeriod(rt Runtime) { + store := adt.AsStore(rt) + + epochReward := requestCurrentEpochBlockReward(rt) + pwrTotal := requestCurrentTotalPower(rt) + + var st State + { + // Vest locked funds. + // This happens first so that any subsequent penalties are taken from locked pledge, rather than free funds. + newlyVestedAmount := rt.State().Transaction(&st, func() interface{} { + newlyVestedFund, err := st.UnlockVestedFunds(store, rt.CurrEpoch()) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to vest funds") + return newlyVestedFund + }).(abi.TokenAmount) + + notifyPledgeChanged(rt, newlyVestedAmount.Neg()) + } + + // Note: because the cron actor is not invoked on epochs with empty tipsets, the current epoch is not necessarily + // exactly the final epoch of the period; it may be slightly later (i.e. in the subsequent period). + // Further, this method is invoked once *before* the first proving period starts, after the actor is first + // constructed; this is detected by !deadline.PeriodStarted(). + // Use deadline.PeriodEnd() rather than rt.CurrEpoch unless certain of the desired semantics. + deadline := NewDeadlineInfo(0, 0, 0) + var info *MinerInfo + { + // Detect and penalize missing proofs. + var detectedFaultSectors []*SectorOnChainInfo + currEpoch := rt.CurrEpoch() + penalty := abi.NewTokenAmount(0) + rt.State().Transaction(&st, func() interface{} { + info = getMinerInfo(rt, &st) + deadline = st.DeadlineInfo(currEpoch) + if deadline.PeriodStarted() { // Skip checking faults on the first, incomplete period. + deadlines, err := st.LoadDeadlines(store) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines") + detectedFaultSectors, penalty = processMissingPoStFaults(rt, &st, store, deadlines, + deadline.PeriodStart, WPoStPeriodDeadlines, deadline.PeriodEnd(), epochReward, + pwrTotal.QualityAdjPower) + } + return nil + }) + + // Remove power for new faults, and burn penalties. + requestUpdateSectorPower(rt, info.SectorSize, nil, detectedFaultSectors) + burnFundsAndNotifyPledgeChange(rt, penalty) + } + + { + // Expire sectors that are due. + expiredSectors := abi.NewBitField() + rt.State().Transaction(&st, func() interface{} { + var err error + expiredSectors, err = popSectorExpirations(&st, store, deadline.PeriodEnd()) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load expired sectors") + return nil + }) + + // Terminate expired sectors (sends messages to power and market actors). + terminateSectors(rt, expiredSectors, power.SectorTerminationExpired, epochReward, pwrTotal.QualityAdjPower) + } + + { + // Terminate sectors with faults that are too old, and pay fees for ongoing faults. + expiredFaults := abi.NewBitField() + ongoingFaults := abi.NewBitField() + ongoingFaultPenalty := abi.NewTokenAmount(0) + rt.State().Transaction(&st, func() interface{} { + var err error + expiredFaults, ongoingFaults, err = popExpiredFaults(&st, store, deadline.PeriodEnd()-FaultMaxAge) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load fault epochs") + + // Load info for ongoing faults. + // TODO: this is potentially super expensive for a large miner with ongoing faults + // https://github.com/filecoin-project/specs-actors/issues/411 + ongoingFaultInfos, err := st.LoadSectorInfos(store, ongoingFaults) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load fault sectors") + + // Unlock penalty for ongoing faults. + ongoingFaultPenalty, err = unlockDeclaredFaultPenalty(&st, store, info.SectorSize, deadline.PeriodEnd(), epochReward, pwrTotal.QualityAdjPower, ongoingFaultInfos) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to charge fault fee") + return nil + }) + + terminateSectors(rt, expiredFaults, power.SectorTerminationFaulty, epochReward, pwrTotal.QualityAdjPower) + burnFundsAndNotifyPledgeChange(rt, ongoingFaultPenalty) + } + + { + // Establish new proving sets and clear proofs. + rt.State().Transaction(&st, func() interface{} { + deadlines, err := st.LoadDeadlines(store) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines") + + // Assign new sectors to deadlines. + newSectors, err := st.NewSectors.All(NewSectorsPerPeriodMax) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to expand new sectors") + + if len(newSectors) > 0 { + //if period end is not in the future, get randomness from previous epoch + randomnessEpoch := minEpoch(deadline.PeriodEnd(), rt.CurrEpoch()-ElectionLookback) + assignmentSeed := rt.GetRandomness(crypto.DomainSeparationTag_WindowedPoStDeadlineAssignment, randomnessEpoch, nil) + err = AssignNewSectors(deadlines, info.WindowPoStPartitionSectors, newSectors, assignmentSeed) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to assign new sectors to deadlines") + + // Store updated deadline state. + err = st.SaveDeadlines(store, deadlines) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to store new deadlines") + + st.NewSectors = abi.NewBitField() + } + + // Reset PoSt submissions for next period. + err = st.ClearPoStSubmissions() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to clear PoSt submissions") + + // Set new proving period start. + if deadline.PeriodStarted() { + st.ProvingPeriodStart = st.ProvingPeriodStart + WPoStProvingPeriod + } + return nil + }) + } + + // Schedule cron callback for next period + nextPeriodEnd := st.ProvingPeriodStart + WPoStProvingPeriod - 1 + enrollCronEvent(rt, nextPeriodEnd, &CronEventPayload{ + EventType: CronEventProvingPeriod, + }) +} + +// Detects faults from PoSt submissions that have not arrived in schedule earlier in the current proving period. +func detectFaultsThisPeriod(rt Runtime, st *State, store adt.Store, currDeadline *DeadlineInfo, deadlines *Deadlines, epochReward abi.TokenAmount, currentTotalPower abi.StoragePower) ([]*SectorOnChainInfo, abi.TokenAmount) { + if currDeadline.PeriodElapsed() { + // A cron event has not yet processed the previous proving period and established the next one. + // This is possible in the first non-empty epoch of a proving period if there was an empty tipset on the + // last epoch of the previous period. + // The period must be reset before processing missing-post faults. + rt.Abortf(exitcode.ErrIllegalState, "proving period at %d elapsed, next one not yet opened", currDeadline.PeriodStart) + } + return processMissingPoStFaults(rt, st, store, deadlines, currDeadline.PeriodStart, currDeadline.Index, currDeadline.CurrentEpoch, epochReward, currentTotalPower) +} + +// Discovers how skipped faults declared during post intersect with existing faults and recoveries, then unlocks funds +// and returns the penalty to be paid and the sector infos needed to deduct power. +// - Skipped faults that are not in the current deadline will trigger an error. +// - Skipped faults that have previously been marked recovered, will be penalized as a retracted recovery but will not +// result in a change in power (the power has already been removed). +// - Skipped faults that are already declared, but not recovered will be ignored. +// - The rest will be penalized as undeclared faults and have their power removed. +func processSkippedFaults(rt Runtime, st *State, store adt.Store, currDeadline *DeadlineInfo, minerInfo *MinerInfo, deadlines *Deadlines, epochReward abi.TokenAmount, currentTotalPower abi.StoragePower, skipped *bitfield.BitField) ([]*SectorOnChainInfo, abi.TokenAmount) { + empty, err := skipped.IsEmpty() + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed to check if skipped sectors is empty") + if empty { + return nil, abi.NewTokenAmount(0) + } + + currEpoch := rt.CurrEpoch() + var newFaultSectors []*SectorOnChainInfo + + // Check that the declared sectors are actually due at the deadline. + deadlineSectors := deadlines.Due[currDeadline.Index] + contains, err := abi.BitFieldContainsAll(deadlineSectors, skipped) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not check if skipped faults are in deadline") + if !contains { + rt.Abortf(exitcode.ErrIllegalArgument, "skipped faults contains sectors not due in deadline %d", currDeadline.Index) + } + + // Find all skipped faults that have been labeled recovered + retractedRecoveries, err := bitfield.IntersectBitField(st.Recoveries, skipped) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to intersect sectors with recoveries") + + // Ignore skipped faults that are already faults + newFaults, err := bitfield.SubtractBitField(skipped, st.Faults) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to subtract existing faults from skipped") + + // Add Faults + err = st.AddFaults(store, newFaults, currDeadline.PeriodStart) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add skipped faults") + + // Remove faulty recoveries + err = st.RemoveRecoveries(retractedRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove recoveries") + + // Load info for sectors. + newFaultSectors, err = st.LoadSectorInfos(store, newFaults) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load fault sectors") + + // load info for retractions + retractedRecoveryInfos, err := st.LoadSectorInfos(store, retractedRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load retracted recovery secrtors") + + // Penalize new skipped faults and retracted recoveries + // This differs from declaring faults "on time", where retracting recoveries doesn't attract an extra penalty + penalizeFaultSectors := append(newFaultSectors, retractedRecoveryInfos...) + penalty, err := unlockUndeclaredFaultPenalty(st, store, minerInfo.SectorSize, currEpoch, epochReward, currentTotalPower, penalizeFaultSectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to charge fault fee") + + // Return only new faulty sectors (excluding retracted recoveries) for power updates + return newFaultSectors, penalty +} + +// Detects faults from missing PoSt submissions that did not arrive by some deadline, and moves +// the NextDeadlineToProcessFaults index up to that deadline. +func processMissingPoStFaults(rt Runtime, st *State, store adt.Store, deadlines *Deadlines, periodStart abi.ChainEpoch, beforeDeadline uint64, currEpoch abi.ChainEpoch, epochReward abi.TokenAmount, currentTotalPower abi.StoragePower) ([]*SectorOnChainInfo, abi.TokenAmount) { + // This method must be called to process the end of one proving period before moving on to the process something + // the next. Usually, sinceDeadline would be <= beforeDeadline since the former is updated to match the latter + // and the call during proving period cron will set NextDeadlineToProcessFaults back to zero. + // In the odd case where the proving period's penultimate tipset is empty, this method must be invoked by the cron + // callback before allowing any fault/recovery declaration or PoSt to do partial processing. + AssertMsg(st.NextDeadlineToProcessFaults <= beforeDeadline, "invalid next-deadline %d after before-deadline %d while detecting faults", + st.NextDeadlineToProcessFaults, beforeDeadline) + + info := getMinerInfo(rt, st) + detectedFaults, failedRecoveries, err := computeFaultsFromMissingPoSts(info.WindowPoStPartitionSectors, st.Faults, st.Recoveries, st.PostSubmissions, deadlines, st.NextDeadlineToProcessFaults, beforeDeadline) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to compute detected faults") + st.NextDeadlineToProcessFaults = beforeDeadline % WPoStPeriodDeadlines + + err = st.AddFaults(store, detectedFaults, periodStart) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to record new faults") + + err = st.RemoveRecoveries(failedRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to record failed recoveries") + + // Load info for sectors. + // TODO: this is potentially super expensive for a large miner failing to submit proofs. + // https://github.com/filecoin-project/specs-actors/issues/411 + detectedFaultSectors, err := st.LoadSectorInfos(store, detectedFaults) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load fault sectors") + failedRecoverySectors, err := st.LoadSectorInfos(store, failedRecoveries) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load failed recovery sectors") + + // Unlock sector penalty for all undeclared faults. + penalizedSectors := append(detectedFaultSectors, failedRecoverySectors...) + penalty, err := unlockUndeclaredFaultPenalty(st, store, info.SectorSize, currEpoch, epochReward, currentTotalPower, penalizedSectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to charge sector penalty") + return detectedFaultSectors, penalty +} + +// Computes the sectors that were expected to be present in partitions of a PoSt submission but were not, in the +// deadlines from sinceDeadline (inclusive) to beforeDeadline (exclusive). +func computeFaultsFromMissingPoSts(partitionSize uint64, faults, recoveries, postSubmissions *abi.BitField, deadlines *Deadlines, sinceDeadline, beforeDeadline uint64) (detectedFaults, failedRecoveries *abi.BitField, err error) { + // TODO: Iterating this bitfield and keeping track of what partitions we're expecting could remove the + // need to expand this into a potentially-giant map. But it's tricksy. + // https://github.com/filecoin-project/specs-actors/issues/477 + submissions, err := postSubmissions.AllMap(activePartitionsMax(partitionSize)) + if err != nil { + return nil, nil, fmt.Errorf("failed to expand submissions: %w", err) + } + + deadlineFirstPartition := uint64(0) + var fGroups, rGroups []*abi.BitField + for dlIdx := uint64(0); dlIdx < beforeDeadline; dlIdx++ { + dlPartCount, dlSectorCount, err := DeadlineCount(deadlines, partitionSize, dlIdx) + if err != nil { + return nil, nil, fmt.Errorf("failed to count deadline %d partitions: %w", dlIdx, err) + } + if dlIdx < sinceDeadline { + deadlineFirstPartition += dlPartCount + continue + } + deadlineSectors := deadlines.Due[dlIdx] + for dlPartIdx := uint64(0); dlPartIdx < dlPartCount; dlPartIdx++ { + if !submissions[deadlineFirstPartition+dlPartIdx] { + // No PoSt received in prior period. + partFirstSectorIdx := dlPartIdx * partitionSize + partSectorCount := min64(partitionSize, dlSectorCount-partFirstSectorIdx) + + partitionSectors, err := deadlineSectors.Slice(partFirstSectorIdx, partSectorCount) + if err != nil { + return nil, nil, fmt.Errorf("failed to slice deadline %d partition %d sectors %d..%d: %w", + dlIdx, dlPartIdx, partFirstSectorIdx, partFirstSectorIdx+dlPartCount, err) + } + + // Record newly-faulty sectors. + newFaults, err := bitfield.SubtractBitField(partitionSectors, faults) + if err != nil { + return nil, nil, fmt.Errorf("bitfield subtract failed: %s", err) + } + fGroups = append(fGroups, newFaults) + + // Record failed recoveries. + // By construction, these are already faulty and thus not in newFaults. + failedRecovery, err := bitfield.IntersectBitField(partitionSectors, recoveries) + if err != nil { + return nil, nil, fmt.Errorf("bitfield intersect failed: %s", err) + } + rGroups = append(rGroups, failedRecovery) + } + } + + deadlineFirstPartition += dlPartCount + } + detectedFaults, err = bitfield.MultiMerge(fGroups...) + if err != nil { + return nil, nil, fmt.Errorf("failed to union detected fault groups: %w", err) + } + failedRecoveries, err = bitfield.MultiMerge(rGroups...) + if err != nil { + return nil, nil, fmt.Errorf("failed to union failed recovery groups: %w", err) + } + return +} + +// Check expiry is exactly *the epoch before* the start of a proving period. +func validateExpiration(rt Runtime, st *State, activation, expiration abi.ChainEpoch, sealProof abi.RegisteredSealProof) { + // expiration cannot exceed MaxSectorExpirationExtension from now + if expiration > rt.CurrEpoch()+MaxSectorExpirationExtension { + rt.Abortf(exitcode.ErrIllegalArgument, "invalid expiration %d, cannot be more than %d past current epoch %d", + expiration, MaxSectorExpirationExtension, rt.CurrEpoch()) + } + + // total sector lifetime cannot exceed SectorMaximumLifetime for the sector's seal proof + if expiration-activation > sealProof.SectorMaximumLifetime() { + rt.Abortf(exitcode.ErrIllegalArgument, "invalid expiration %d, total sector lifetime (%d) cannot exceed %d after activation %d", + expiration, expiration-activation, sealProof.SectorMaximumLifetime(), activation) + } + + // ensure expiration is one epoch before a proving period boundary + periodOffset := st.ProvingPeriodStart % WPoStProvingPeriod + expiryOffset := (expiration + 1) % WPoStProvingPeriod + if expiryOffset != periodOffset { + rt.Abortf(exitcode.ErrIllegalArgument, "invalid expiration %d, must be immediately before proving period boundary %d mod %d", + expiration, periodOffset, WPoStProvingPeriod) + } +} + +func validateReplaceSector(rt Runtime, st *State, store adt.Store, params *SectorPreCommitInfo) *SectorOnChainInfo { + replaceSector, found, err := st.GetSector(store, params.ReplaceSector) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sector %v", params.SectorNumber) + if !found { + rt.Abortf(exitcode.ErrNotFound, "no such sector %v to replace", params.ReplaceSector) + } + + if len(replaceSector.DealIDs) > 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace sector %v which has deals", params.ReplaceSector) + } + if params.SealProof != replaceSector.SealProof { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace sector %v seal proof %v with seal proof %v", + params.ReplaceSector, replaceSector.SealProof, params.SealProof) + } + if params.Expiration < replaceSector.Expiration { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace sector %v expiration %v with sooner expiration %v", + params.ReplaceSector, replaceSector.Expiration, params.Expiration) + } + faulty, err := st.Faults.IsSet(uint64(params.ReplaceSector)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check fault for sector %v", params.ReplaceSector) + if faulty { + // Note: the sector might still fault later, in which case we should not license its termination. + rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace faulty sector %v", params.ReplaceSector) + } + return replaceSector +} + +// scheduleReplaceSectorsExpiration re-schedules sector expirations at the end +// of the current proving period. +// +// This function also updates the Expiration field of the passed-in sector +// slice, in-place. +func scheduleReplaceSectorsExpiration(rt Runtime, st *State, store adt.Store, replaceSectors []*SectorOnChainInfo) error { + if len(replaceSectors) == 0 { + return nil + } + + // Mark replaced sectors for on-time expiration at the end of the current proving period. + // They can't be removed right now because they may yet be challenged for Window PoSt in this period, + // and the deadline assignments can't be changed mid-period. + // If their initial pledge hasn't finished vesting yet, it just continues vesting (like other termination paths). + // Note that a sector's weight and power were calculated from its lifetime when the sector was first + // committed, but are not recalculated here. We only get away with this because we know the replaced sector + // has no deals and so its power does not vary with lifetime. + // That's a very brittle constraint, and would be much better with two-phase termination (where we could + // deduct power immediately). + // See https://github.com/filecoin-project/specs-actors/issues/535 + deadlineInfo := st.DeadlineInfo(rt.CurrEpoch()) + newExpiration := deadlineInfo.PeriodEnd() + + if err := st.RemoveSectorExpirations(store, replaceSectors...); err != nil { + return xerrors.Errorf("when removing expirations for replacement: %w", err) + } + + for _, sector := range replaceSectors { + sector.Expiration = newExpiration + } + + if err := st.PutSectors(store, replaceSectors...); err != nil { + return xerrors.Errorf("when updating sector expirations: %w", err) + } + + if err := st.AddSectorExpirations(store, replaceSectors...); err != nil { + return xerrors.Errorf("when replacing sector expirations: %w", err) + } + return nil +} + +// Removes and returns sector numbers that expire at or before an epoch. +func popSectorExpirations(st *State, store adt.Store, epoch abi.ChainEpoch) (*abi.BitField, error) { + var expiredEpochs []abi.ChainEpoch + var expiredSectors []*abi.BitField + errDone := fmt.Errorf("done") + err := st.ForEachSectorExpiration(store, func(expiry abi.ChainEpoch, sectors *abi.BitField) error { + if expiry > epoch { + return errDone + } + expiredSectors = append(expiredSectors, sectors) + expiredEpochs = append(expiredEpochs, expiry) + return nil + }) + if err != nil && err != errDone { + return nil, err + } + err = st.ClearSectorExpirations(store, expiredEpochs...) + if err != nil { + return nil, fmt.Errorf("failed to clear sector expirations %s: %w", expiredEpochs, err) + } + + allExpiries, err := bitfield.MultiMerge(expiredSectors...) + if err != nil { + return nil, fmt.Errorf("failed to union expired sectors: %w", err) + } + return allExpiries, err +} + +// Removes and returns sector numbers that were faulty at or before an epoch, and returns the sector +// numbers for other ongoing faults. +func popExpiredFaults(st *State, store adt.Store, latestTermination abi.ChainEpoch) (*abi.BitField, *abi.BitField, error) { + var expiredEpochs []abi.ChainEpoch + var expiredFaults []*abi.BitField + var ongoingFaults []*abi.BitField + errDone := fmt.Errorf("done") + err := st.ForEachFaultEpoch(store, func(faultStart abi.ChainEpoch, faults *abi.BitField) error { + if faultStart <= latestTermination { + expiredFaults = append(expiredFaults, faults) + expiredEpochs = append(expiredEpochs, faultStart) + } else { + ongoingFaults = append(ongoingFaults, faults) + } + return nil + }) + if err != nil && err != errDone { + return nil, nil, nil + } + err = st.ClearFaultEpochs(store, expiredEpochs...) + if err != nil { + return nil, nil, fmt.Errorf("failed to clear fault epochs %s: %w", expiredEpochs, err) + } + + allExpiries, err := bitfield.MultiMerge(expiredFaults...) + if err != nil { + return nil, nil, fmt.Errorf("failed to union expired faults: %w", err) + } + allOngoing, err := bitfield.MultiMerge(ongoingFaults...) + if err != nil { + return nil, nil, fmt.Errorf("failed to union ongoing faults: %w", err) + } + + return allExpiries, allOngoing, err +} + +func checkPrecommitExpiry(rt Runtime, sectors *abi.BitField) { + store := adt.AsStore(rt) + var st State + + // initialize here to add together for all sectors and minimize calls across actors + depositToBurn := abi.NewTokenAmount(0) + rt.State().Transaction(&st, func() interface{} { + var sectorNos []abi.SectorNumber + err := sectors.ForEach(func(i uint64) error { + sectorNo := abi.SectorNumber(i) + sector, found, err := st.GetPrecommittedSector(store, sectorNo) + if err != nil { + return err + } + if !found { + // already committed/deleted + return nil + } + + // mark it for deletion + sectorNos = append(sectorNos, sectorNo) + + // increment deposit to burn + depositToBurn = big.Add(depositToBurn, sector.PreCommitDeposit) + return nil + }) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check pre-commit expiries") + + // Actually delete it. + if len(sectorNos) > 0 { + err = st.DeletePrecommittedSectors(store, sectorNos...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to delete pre-commits") + } + + st.PreCommitDeposits = big.Sub(st.PreCommitDeposits, depositToBurn) + Assert(st.PreCommitDeposits.GreaterThanEqual(big.Zero())) + return nil + }) + + // This deposit was locked separately to pledge collateral so there's no pledge change here. + burnFunds(rt, depositToBurn) +} + +// TODO: red flag that this method is potentially super expensive +// https://github.com/filecoin-project/specs-actors/issues/483 +func terminateSectors(rt Runtime, sectorNos *abi.BitField, terminationType power.SectorTermination, epochReward abi.TokenAmount, currentTotalPower abi.StoragePower) { + currentEpoch := rt.CurrEpoch() + empty, err := sectorNos.IsEmpty() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to count sectors") + } + if empty { + return + } + + store := adt.AsStore(rt) + var st State + + var dealIDs []abi.DealID + var terminatedSectors []*SectorOnChainInfo + var faultySectors []*SectorOnChainInfo + penalty := abi.NewTokenAmount(0) + var info *MinerInfo + rt.State().Transaction(&st, func() interface{} { + info = getMinerInfo(rt, &st) + maxAllowedFaults, err := st.GetMaxAllowedFaults(store) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load fault max") + + // Narrow faults to just the set that are expiring, before expanding to a map. + faults, err := bitfield.IntersectBitField(sectorNos, st.Faults) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load faults") + + faultsMap, err := faults.AllMap(maxAllowedFaults) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to expand faults") + } + + // sectors we're not terminating because they either don't exist or have expired. + var notTerminatedSectorNos []uint64 + pledgeRequirementToRemove := abi.NewTokenAmount(0) + err = sectorNos.ForEach(func(sectorNo uint64) error { + sector, found, err := st.GetSector(store, abi.SectorNumber(sectorNo)) + if err != nil { + return fmt.Errorf("failed to load sector %v: %w", sectorNo, err) + } + + // If the sector wasn't found, skip termination. It may + // have already expired, have been terminated due to a + // faults, etc. + if !found { + notTerminatedSectorNos = append(notTerminatedSectorNos, sectorNo) + return nil + } + + // If we're terminating the sector because it expired, + // make sure it has actually expired. + // + // We can hit this case if the sector was changed + // somehow but the termination wasn't removed from the + // SectorExpirations queue. + // + // TODO: This should not be possible. We should consider + // failing in this case. + if terminationType == power.SectorTerminationExpired && currentEpoch < sector.Expiration { + notTerminatedSectorNos = append(notTerminatedSectorNos, sectorNo) + return nil + } + + dealIDs = append(dealIDs, sector.DealIDs...) + terminatedSectors = append(terminatedSectors, sector) + + _, fault := faultsMap[sectorNo] + if fault { + faultySectors = append(faultySectors, sector) + } + + pledgeRequirementToRemove = big.Add(pledgeRequirementToRemove, sector.InitialPledge) + return nil + }) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sector metadata") + + terminatedSectorNos, err := bitfield.SubtractBitField(sectorNos, bitfield.NewFromSet(notTerminatedSectorNos)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to subtract skipped sector set") + + // lower initial pledge requirement + st.AddInitialPledgeRequirement(pledgeRequirementToRemove.Neg()) + + deadlines, err := st.LoadDeadlines(store) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines") + + err = removeTerminatedSectors(&st, store, deadlines, terminatedSectorNos) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete sectors: %v", err) + } + + err = st.SaveDeadlines(store, deadlines) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to store new deadlines") + + if terminationType != power.SectorTerminationExpired { + + // Remove scheduled expirations. + err = st.RemoveSectorExpirations(store, terminatedSectors...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove expirations for terminated sectors") + + // Unlock penalty. + penalty, err = unlockTerminationPenalty(&st, store, info.SectorSize, rt.CurrEpoch(), epochReward, currentTotalPower, terminatedSectors) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unlock penalty %s", err) + } + } + return nil + }) + + // TODO: could we compress the multiple calls to power actor into one sector termination call? + // https://github.com/filecoin-project/specs-actors/issues/478 + // Compute the power delta as if recovering all the currently-faulty sectors before terminating all of them. + requestUpdateSectorPower(rt, info.SectorSize, faultySectors, terminatedSectors) + requestTerminateDeals(rt, dealIDs) + + burnFundsAndNotifyPledgeChange(rt, penalty) +} + +// Removes a group sectors from the sector set and its number from all sector collections in state. +func removeTerminatedSectors(st *State, store adt.Store, deadlines *Deadlines, sectors *abi.BitField) error { + err := st.DeleteSectors(store, sectors) + if err != nil { + return err + } + err = st.RemoveNewSectors(sectors) + if err != nil { + return err + } + err = deadlines.RemoveFromAllDeadlines(sectors) + if err != nil { + return err + } + err = st.RemoveFaults(store, sectors) + if err != nil { + return err + } + err = st.RemoveRecoveries(sectors) + return err +} + +func enrollCronEvent(rt Runtime, eventEpoch abi.ChainEpoch, callbackPayload *CronEventPayload) { + payload := new(bytes.Buffer) + err := callbackPayload.MarshalCBOR(payload) + if err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "failed to serialize payload: %v", err) + } + _, code := rt.Send( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.EnrollCronEvent, + &power.EnrollCronEventParams{ + EventEpoch: eventEpoch, + Payload: payload.Bytes(), + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to enroll cron event") +} + +func requestUpdateSectorPower(rt Runtime, sectorSize abi.SectorSize, sectorsAdded, sectorsRemoved []*SectorOnChainInfo) (rawDelta, qaDelta big.Int) { + if len(sectorsAdded)+len(sectorsRemoved) == 0 { + return + } + addRawPower, addQAPower := PowerForSectors(sectorSize, sectorsAdded) + remRawPower, remQAPower := PowerForSectors(sectorSize, sectorsRemoved) + rawDelta = big.Sub(addRawPower, remRawPower) + qaDelta = big.Sub(addQAPower, remQAPower) + + _, code := rt.Send( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.UpdateClaimedPower, + &power.UpdateClaimedPowerParams{ + RawByteDelta: rawDelta, + QualityAdjustedDelta: qaDelta, + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to update power for sectors added %v, removed %v", sectorsAdded, sectorsRemoved) + return +} + +func requestTerminateDeals(rt Runtime, dealIDs []abi.DealID) { + if len(dealIDs) == 0 { + return + } + _, code := rt.Send( + builtin.StorageMarketActorAddr, + builtin.MethodsMarket.OnMinerSectorsTerminate, + &market.OnMinerSectorsTerminateParams{ + DealIDs: dealIDs, + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to terminate deals %v, exit code %v", dealIDs, code) +} + +func requestTerminateAllDeals(rt Runtime, st *State) { //nolint:deadcode,unused + // TODO: red flag this is an ~unbounded computation. + // Transform into an idempotent partial computation that can be progressed on each invocation. + // https://github.com/filecoin-project/specs-actors/issues/483 + dealIds := []abi.DealID{} + if err := st.ForEachSector(adt.AsStore(rt), func(sector *SectorOnChainInfo) { + dealIds = append(dealIds, sector.DealIDs...) + }); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to traverse sectors for termination: %v", err) + } + + requestTerminateDeals(rt, dealIds) +} + +func verifyWindowedPost(rt Runtime, challengeEpoch abi.ChainEpoch, sectors []*SectorOnChainInfo, proofs []abi.PoStProof) { + minerActorID, err := addr.IDFromAddress(rt.Message().Receiver()) + AssertNoError(err) // Runtime always provides ID-addresses + + // Regenerate challenge randomness, which must match that generated for the proof. + var addrBuf bytes.Buffer + err = rt.Message().Receiver().MarshalCBOR(&addrBuf) + AssertNoError(err) + postRandomness := rt.GetRandomness(crypto.DomainSeparationTag_WindowedPoStChallengeSeed, challengeEpoch, addrBuf.Bytes()) + + sectorProofInfo := make([]abi.SectorInfo, len(sectors)) + for i, s := range sectors { + sectorProofInfo[i] = s.AsSectorInfo() + } + + // Get public inputs + pvInfo := abi.WindowPoStVerifyInfo{ + Randomness: abi.PoStRandomness(postRandomness), + Proofs: proofs, + ChallengedSectors: sectorProofInfo, + Prover: abi.ActorID(minerActorID), + } + + // Verify the PoSt Proof + if err := rt.Syscalls().VerifyPoSt(pvInfo); err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "invalid PoSt %+v: %s", pvInfo, err) + } +} + +// SealVerifyParams is the structure of information that must be sent with a +// message to commit a sector. Most of this information is not needed in the +// state tree but will be verified in sm.CommitSector. See SealCommitment for +// data stored on the state tree for each sector. +type SealVerifyStuff struct { + SealedCID cid.Cid // CommR + InteractiveEpoch abi.ChainEpoch // Used to derive the interactive PoRep challenge. + abi.RegisteredSealProof + Proof []byte + DealIDs []abi.DealID + abi.SectorNumber + SealRandEpoch abi.ChainEpoch // Used to tie the seal to a chain. +} + +func getVerifyInfo(rt Runtime, params *SealVerifyStuff) *abi.SealVerifyInfo { + if rt.CurrEpoch() <= params.InteractiveEpoch { + rt.Abortf(exitcode.ErrForbidden, "too early to prove sector") + } + + // Check randomness. + challengeEarliest := sealChallengeEarliest(rt.CurrEpoch(), params.RegisteredSealProof) + if params.SealRandEpoch < challengeEarliest { + rt.Abortf(exitcode.ErrIllegalArgument, "seal epoch %v too old, expected >= %v", params.SealRandEpoch, challengeEarliest) + } + + commD := requestUnsealedSectorCID(rt, params.RegisteredSealProof, params.DealIDs) + + minerActorID, err := addr.IDFromAddress(rt.Message().Receiver()) + AssertNoError(err) // Runtime always provides ID-addresses + + buf := new(bytes.Buffer) + err = rt.Message().Receiver().MarshalCBOR(buf) + AssertNoError(err) + + svInfoRandomness := rt.GetRandomness(crypto.DomainSeparationTag_SealRandomness, params.SealRandEpoch, buf.Bytes()) + svInfoInteractiveRandomness := rt.GetRandomness(crypto.DomainSeparationTag_InteractiveSealChallengeSeed, params.InteractiveEpoch, buf.Bytes()) + + return &abi.SealVerifyInfo{ + SealProof: params.RegisteredSealProof, + SectorID: abi.SectorID{ + Miner: abi.ActorID(minerActorID), + Number: params.SectorNumber, + }, + DealIDs: params.DealIDs, + InteractiveRandomness: abi.InteractiveSealRandomness(svInfoInteractiveRandomness), + Proof: params.Proof, + Randomness: abi.SealRandomness(svInfoRandomness), + SealedCID: params.SealedCID, + UnsealedCID: commD, + } +} + +// Closes down this miner by erasing its power, terminating all its deals and burning its funds +func terminateMiner(rt Runtime) { + var st State + rt.State().Readonly(&st) + + requestTerminateAllDeals(rt, &st) + + // Delete the actor and burn all remaining funds + rt.DeleteActor(builtin.BurntFundsActorAddr) +} + +// Requests the storage market actor compute the unsealed sector CID from a sector's deals. +func requestUnsealedSectorCID(rt Runtime, proofType abi.RegisteredSealProof, dealIDs []abi.DealID) cid.Cid { + ret, code := rt.Send( + builtin.StorageMarketActorAddr, + builtin.MethodsMarket.ComputeDataCommitment, + &market.ComputeDataCommitmentParams{ + SectorType: proofType, + DealIDs: dealIDs, + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed request for unsealed sector CID for deals %v", dealIDs) + var unsealedCID cbg.CborCid + AssertNoError(ret.Into(&unsealedCID)) + return cid.Cid(unsealedCID) +} + +func requestDealWeight(rt Runtime, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch) market.VerifyDealsForActivationReturn { + var dealWeights market.VerifyDealsForActivationReturn + ret, code := rt.Send( + builtin.StorageMarketActorAddr, + builtin.MethodsMarket.VerifyDealsForActivation, + &market.VerifyDealsForActivationParams{ + DealIDs: dealIDs, + SectorStart: sectorStart, + SectorExpiry: sectorExpiry, + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to verify deals and get deal weight") + AssertNoError(ret.Into(&dealWeights)) + return dealWeights + +} + +func commitWorkerKeyChange(rt Runtime) *adt.EmptyValue { + var st State + rt.State().Transaction(&st, func() interface{} { + info := getMinerInfo(rt, &st) + if info.PendingWorkerKey == nil { + rt.Abortf(exitcode.ErrIllegalState, "No pending key change.") + } + + if info.PendingWorkerKey.EffectiveAt > rt.CurrEpoch() { + rt.Abortf(exitcode.ErrIllegalState, "Too early for key change. Current: %v, Change: %v)", rt.CurrEpoch(), info.PendingWorkerKey.EffectiveAt) + } + + info.Worker = info.PendingWorkerKey.NewWorker + info.PendingWorkerKey = nil + err := st.SaveInfo(adt.AsStore(rt), info) + builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to save miner info") + + return nil + }) + return nil +} + +// Requests the current epoch target block reward from the reward actor. +func requestCurrentEpochBlockReward(rt Runtime) abi.TokenAmount { + rwret, code := rt.Send(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero()) + builtin.RequireSuccess(rt, code, "failed to check epoch reward") + epochReward := abi.NewTokenAmount(0) + err := rwret.Into(&epochReward) + builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to unmarshal epoch reward value") + return epochReward +} + +// Requests the current network total power and pledge from the power actor. +func requestCurrentTotalPower(rt Runtime) *power.CurrentTotalPowerReturn { + pwret, code := rt.Send(builtin.StoragePowerActorAddr, builtin.MethodsPower.CurrentTotalPower, nil, big.Zero()) + builtin.RequireSuccess(rt, code, "failed to check current power") + var pwr power.CurrentTotalPowerReturn + err := pwret.Into(&pwr) + builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to unmarshal power total value") + return &pwr +} + +// Verifies that the total locked balance exceeds the sum of sector initial pledges. +func verifyPledgeMeetsInitialRequirements(rt Runtime, st *State) { + if st.LockedFunds.LessThan(st.InitialPledgeRequirement) { + rt.Abortf(exitcode.ErrInsufficientFunds, "locked funds insufficient to cover initial pledges (%v < %v)", + st.LockedFunds, st.InitialPledgeRequirement) + } +} + +// Resolves an address to an ID address and verifies that it is address of an account or multisig actor. +func resolveOwnerAddress(rt Runtime, raw addr.Address) addr.Address { + resolved, ok := rt.ResolveAddress(raw) + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "unable to resolve address %v", raw) + } + Assert(resolved.Protocol() == addr.ID) + + ownerCode, ok := rt.GetActorCodeCID(resolved) + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "no code for address %v", resolved) + } + if !builtin.IsPrincipal(ownerCode) { + rt.Abortf(exitcode.ErrIllegalArgument, "owner actor type must be a principal, was %v", ownerCode) + } + return resolved +} + +// Resolves an address to an ID address and verifies that it is address of an account actor with an associated BLS key. +// The worker must be BLS since the worker key will be used alongside a BLS-VRF. +func resolveWorkerAddress(rt Runtime, raw addr.Address) addr.Address { + resolved, ok := rt.ResolveAddress(raw) + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "unable to resolve address %v", raw) + } + Assert(resolved.Protocol() == addr.ID) + + ownerCode, ok := rt.GetActorCodeCID(resolved) + if !ok { + rt.Abortf(exitcode.ErrIllegalArgument, "no code for address %v", resolved) + } + if ownerCode != builtin.AccountActorCodeID { + rt.Abortf(exitcode.ErrIllegalArgument, "worker actor type must be an account, was %v", ownerCode) + } + + if raw.Protocol() != addr.BLS { + ret, code := rt.Send(resolved, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero()) + builtin.RequireSuccess(rt, code, "failed to fetch account pubkey from %v", resolved) + var pubkey addr.Address + err := ret.Into(&pubkey) + if err != nil { + rt.Abortf(exitcode.ErrSerialization, "failed to deserialize address result: %v", ret) + } + if pubkey.Protocol() != addr.BLS { + rt.Abortf(exitcode.ErrIllegalArgument, "worker account %v must have BLS pubkey, was %v", resolved, pubkey.Protocol()) + } + } + return resolved +} + +func burnFundsAndNotifyPledgeChange(rt Runtime, amt abi.TokenAmount) { + burnFunds(rt, amt) + notifyPledgeChanged(rt, amt.Neg()) +} + +func burnFunds(rt Runtime, amt abi.TokenAmount) { + if amt.GreaterThan(big.Zero()) { + _, code := rt.Send(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, amt) + builtin.RequireSuccess(rt, code, "failed to burn funds") + } +} + +func notifyPledgeChanged(rt Runtime, pledgeDelta abi.TokenAmount) { + if !pledgeDelta.IsZero() { + _, code := rt.Send(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero()) + builtin.RequireSuccess(rt, code, "failed to update total pledge") + } +} + +// Assigns proving period offset randomly in the range [0, WPoStProvingPeriod) by hashing +// the actor's address and current epoch. +func assignProvingPeriodOffset(myAddr addr.Address, currEpoch abi.ChainEpoch, hash func(data []byte) [32]byte) (abi.ChainEpoch, error) { + offsetSeed := bytes.Buffer{} + err := myAddr.MarshalCBOR(&offsetSeed) + if err != nil { + return 0, fmt.Errorf("failed to serialize address: %w", err) + } + + err = binary.Write(&offsetSeed, binary.BigEndian, currEpoch) + if err != nil { + return 0, fmt.Errorf("failed to serialize epoch: %w", err) + } + + digest := hash(offsetSeed.Bytes()) + var offset uint64 + err = binary.Read(bytes.NewBuffer(digest[:]), binary.BigEndian, &offset) + if err != nil { + return 0, fmt.Errorf("failed to interpret digest: %w", err) + } + + offset = offset % uint64(WPoStProvingPeriod) + return abi.ChainEpoch(offset), nil +} + +// Computes the epoch at which a proving period should start such that it is greater than the current epoch, and +// has a defined offset from being an exact multiple of WPoStProvingPeriod. +// A miner is exempt from Winow PoSt until the first full proving period starts. +func nextProvingPeriodStart(currEpoch abi.ChainEpoch, offset abi.ChainEpoch) abi.ChainEpoch { + currModulus := currEpoch % WPoStProvingPeriod + var periodProgress abi.ChainEpoch // How far ahead is currEpoch from previous offset boundary. + if currModulus >= offset { + periodProgress = currModulus - offset + } else { + periodProgress = WPoStProvingPeriod - (offset - currModulus) + } + + periodStart := currEpoch - periodProgress + WPoStProvingPeriod + Assert(periodStart > currEpoch) + return periodStart +} + +// Computes deadline information for a fault or recovery declaration. +// If the deadline has not yet elapsed, the declaration is taken as being for the current proving period. +// If the deadline has elapsed, it's instead taken as being for the next proving period after the current epoch. +func declarationDeadlineInfo(periodStart abi.ChainEpoch, deadlineIdx uint64, currEpoch abi.ChainEpoch) (*DeadlineInfo, error) { + if deadlineIdx >= WPoStPeriodDeadlines { + return nil, fmt.Errorf("invalid deadline %d, must be < %d", deadlineIdx, WPoStPeriodDeadlines) + } + + deadline := NewDeadlineInfo(periodStart, deadlineIdx, currEpoch) + // While deadline is in the past, roll over to the next proving period.. + for deadline.HasElapsed() { + deadline = NewDeadlineInfo(deadline.NextPeriodStart(), deadlineIdx, currEpoch) + } + return deadline, nil +} + +// Checks that a fault or recovery declaration of sectors at a specific deadline is valid and not within +// the exclusion window for the deadline. +func validateFRDeclaration(deadlines *Deadlines, deadline *DeadlineInfo, declaredSectors *abi.BitField) error { + if deadline.FaultCutoffPassed() { + return fmt.Errorf("late fault or recovery declaration at %v", deadline) + } + + // Check that the declared sectors are actually due at the deadline. + deadlineSectors := deadlines.Due[deadline.Index] + contains, err := abi.BitFieldContainsAll(deadlineSectors, declaredSectors) + if err != nil { + return fmt.Errorf("failed to check sectors at deadline: %w", err) + } + if !contains { + return fmt.Errorf("sectors not all due at deadline %d", deadline.Index) + } + return nil +} + +// qaPowerForSectors sums the quality adjusted power of all sectors +func qaPowerForSectors(sectorSize abi.SectorSize, sectors []*SectorOnChainInfo) abi.StoragePower { + power := big.Zero() + for _, s := range sectors { + power = big.Add(power, QAPowerForSector(sectorSize, s)) + } + return power +} + +func unlockDeclaredFaultPenalty(st *State, store adt.Store, sectorSize abi.SectorSize, currEpoch abi.ChainEpoch, epochTargetReward abi.TokenAmount, networkQAPower abi.StoragePower, sectors []*SectorOnChainInfo) (abi.TokenAmount, error) { + totalQAPower := qaPowerForSectors(sectorSize, sectors) + fee := PledgePenaltyForDeclaredFault(epochTargetReward, networkQAPower, totalQAPower) + return st.UnlockUnvestedFunds(store, currEpoch, fee) +} + +func unlockUndeclaredFaultPenalty(st *State, store adt.Store, sectorSize abi.SectorSize, currEpoch abi.ChainEpoch, epochTargetReward abi.TokenAmount, networkQAPower abi.StoragePower, sectors []*SectorOnChainInfo) (abi.TokenAmount, error) { + totalQAPower := qaPowerForSectors(sectorSize, sectors) + fee := PledgePenaltyForUndeclaredFault(epochTargetReward, networkQAPower, totalQAPower) + return st.UnlockUnvestedFunds(store, currEpoch, fee) +} + +func unlockTerminationPenalty(st *State, store adt.Store, sectorSize abi.SectorSize, curEpoch abi.ChainEpoch, epochTargetReward abi.TokenAmount, networkQAPower abi.StoragePower, sectors []*SectorOnChainInfo) (abi.TokenAmount, error) { + totalFee := big.Zero() + for _, s := range sectors { + sectorPower := QAPowerForSector(sectorSize, s) + fee := PledgePenaltyForTermination(s.InitialPledge, curEpoch-s.Activation, epochTargetReward, networkQAPower, sectorPower) + totalFee = big.Add(fee, totalFee) + } + return totalFee, nil +} + +// Returns the sum of the raw byte and quality-adjusted power for sectors. +func PowerForSectors(sectorSize abi.SectorSize, sectors []*SectorOnChainInfo) (rawBytePower, qaPower big.Int) { + rawBytePower = big.Mul(big.NewIntUnsigned(uint64(sectorSize)), big.NewIntUnsigned(uint64(len(sectors)))) + qaPower = qaPowerForSectors(sectorSize, sectors) + return +} + +// The oldest seal challenge epoch that will be accepted in the current epoch. +func sealChallengeEarliest(currEpoch abi.ChainEpoch, proof abi.RegisteredSealProof) abi.ChainEpoch { + return currEpoch - ChainFinality - MaxSealDuration[proof] +} + +func getMinerInfo(rt Runtime, st *State) *MinerInfo { + info, err := st.GetInfo(adt.AsStore(rt)) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not read miner info") + return info +} + +func min64(a, b uint64) uint64 { + if a < b { + return a + } + return b +} + +func minEpoch(a, b abi.ChainEpoch) abi.ChainEpoch { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_internal_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_internal_test.go new file mode 100644 index 0000000000..2b47c27111 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_internal_test.go @@ -0,0 +1,164 @@ +package miner + +import ( + "testing" + + "github.com/minio/blake2b-simd" + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + tutils "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestAssignProvingPeriodBoundary(t *testing.T) { + addr1 := tutils.NewActorAddr(t, "a") + addr2 := tutils.NewActorAddr(t, "b") + startEpoch := abi.ChainEpoch(1) + + // ensure the values are different for different addresses + b1, err := assignProvingPeriodOffset(addr1, startEpoch, blake2b.Sum256) + assert.NoError(t, err) + assert.True(t, b1 >= 0) + assert.True(t, b1 < WPoStProvingPeriod) + + b2, err := assignProvingPeriodOffset(addr2, startEpoch, blake2b.Sum256) + assert.NoError(t, err) + assert.True(t, b2 >= 0) + assert.True(t, b2 < WPoStProvingPeriod) + + assert.NotEqual(t, b1, b2) + + // Ensure boundaries are always less than a proving period. + for i := 0; i < 10_000; i++ { + boundary, err := assignProvingPeriodOffset(addr1, abi.ChainEpoch(i), blake2b.Sum256) + assert.NoError(t, err) + assert.True(t, boundary >= 0) + assert.True(t, boundary < WPoStProvingPeriod) + } +} + +func TestNextProvingPeriodStart(t *testing.T) { + // At epoch zero... + curr := e(0) + // ... with offset zero, the first period start skips one period ahead, ... + assert.Equal(t, WPoStProvingPeriod, nextProvingPeriodStart(curr, 0)) + + // ... and all non-zero offsets are simple. + assert.Equal(t, e(1), nextProvingPeriodStart(curr, 1)) + assert.Equal(t, e(10), nextProvingPeriodStart(curr, 10)) + assert.Equal(t, WPoStProvingPeriod-1, nextProvingPeriodStart(curr, WPoStProvingPeriod-1)) + + // At epoch 1, offsets 0 and 1 start a long way forward, but offsets 2 and later start soon. + curr = 1 + assert.Equal(t, WPoStProvingPeriod, nextProvingPeriodStart(curr, 0)) + assert.Equal(t, WPoStProvingPeriod+1, nextProvingPeriodStart(curr, 1)) + assert.Equal(t, e(2), nextProvingPeriodStart(curr, 2)) + assert.Equal(t, e(3), nextProvingPeriodStart(curr, 3)) + assert.Equal(t, WPoStProvingPeriod-1, nextProvingPeriodStart(curr, WPoStProvingPeriod-1)) + + // An arbitrary mid-period epoch. + curr = 123 + assert.Equal(t, WPoStProvingPeriod, nextProvingPeriodStart(curr, 0)) + assert.Equal(t, WPoStProvingPeriod+1, nextProvingPeriodStart(curr, 1)) + assert.Equal(t, WPoStProvingPeriod+122, nextProvingPeriodStart(curr, 122)) + assert.Equal(t, WPoStProvingPeriod+123, nextProvingPeriodStart(curr, 123)) + assert.Equal(t, e(124), nextProvingPeriodStart(curr, 124)) + assert.Equal(t, WPoStProvingPeriod-1, nextProvingPeriodStart(curr, WPoStProvingPeriod-1)) + + // The final epoch in the chain's first full period + curr = WPoStProvingPeriod - 1 + assert.Equal(t, WPoStProvingPeriod, nextProvingPeriodStart(curr, 0)) + assert.Equal(t, WPoStProvingPeriod+1, nextProvingPeriodStart(curr, 1)) + assert.Equal(t, WPoStProvingPeriod+2, nextProvingPeriodStart(curr, 2)) + assert.Equal(t, WPoStProvingPeriod+WPoStProvingPeriod-2, nextProvingPeriodStart(curr, WPoStProvingPeriod-2)) + assert.Equal(t, WPoStProvingPeriod+WPoStProvingPeriod-1, nextProvingPeriodStart(curr, WPoStProvingPeriod-1)) + + // Into the chain's second period + curr = WPoStProvingPeriod + assert.Equal(t, 2*WPoStProvingPeriod, nextProvingPeriodStart(curr, 0)) + assert.Equal(t, WPoStProvingPeriod+1, nextProvingPeriodStart(curr, 1)) + assert.Equal(t, WPoStProvingPeriod+2, nextProvingPeriodStart(curr, 2)) + assert.Equal(t, WPoStProvingPeriod+WPoStProvingPeriod-1, nextProvingPeriodStart(curr, WPoStProvingPeriod-1)) + + curr = WPoStProvingPeriod + 234 + assert.Equal(t, 2*WPoStProvingPeriod, nextProvingPeriodStart(curr, 0)) + assert.Equal(t, 2*WPoStProvingPeriod+1, nextProvingPeriodStart(curr, 1)) + assert.Equal(t, 2*WPoStProvingPeriod+233, nextProvingPeriodStart(curr, 233)) + assert.Equal(t, 2*WPoStProvingPeriod+234, nextProvingPeriodStart(curr, 234)) + assert.Equal(t, WPoStProvingPeriod+235, nextProvingPeriodStart(curr, 235)) + assert.Equal(t, WPoStProvingPeriod+WPoStProvingPeriod-1, nextProvingPeriodStart(curr, WPoStProvingPeriod-1)) +} + +type e = abi.ChainEpoch + +func TestFaultFeeInvariants(t *testing.T) { + t.Run("Undeclared faults are more expensive than declared faults", func(t *testing.T) { + epochReward := abi.NewTokenAmount(1_000) + networkPower := abi.NewStoragePower(100 << 50) + faultySectorPower := abi.NewStoragePower(1 << 50) + + ff := PledgePenaltyForDeclaredFault(epochReward, networkPower, faultySectorPower) + sp := PledgePenaltyForUndeclaredFault(epochReward, networkPower, faultySectorPower) + assert.True(t, sp.GreaterThan(ff)) + }) + + t.Run("Declared and Undeclared fault penalties are linear over sectorQAPower term", func(t *testing.T) { + epochReward := abi.NewTokenAmount(1_000) + networkPower := abi.NewStoragePower(100 << 50) + faultySectorAPower := abi.NewStoragePower(1 << 50) + faultySectorBPower := abi.NewStoragePower(19 << 50) + faultySectorCPower := abi.NewStoragePower(63 << 50) + totalFaultPower := big.Add(big.Add(faultySectorAPower, faultySectorBPower), faultySectorCPower) + + // Declared faults + ffA := PledgePenaltyForDeclaredFault(epochReward, networkPower, faultySectorAPower) + ffB := PledgePenaltyForDeclaredFault(epochReward, networkPower, faultySectorBPower) + ffC := PledgePenaltyForDeclaredFault(epochReward, networkPower, faultySectorCPower) + + ffAll := PledgePenaltyForDeclaredFault(epochReward, networkPower, totalFaultPower) + + // Because we can introduce rounding error between 1 and zero for every penalty calculation + // we can at best expect n calculations of 1 power to be within n of 1 calculation of n powers. + diff := big.Sub(ffAll, big.Add(ffC, big.Add(ffA, ffB))) + assert.True(t, diff.GreaterThanEqual(big.Zero())) + assert.True(t, diff.LessThan(big.NewInt(3))) + + // Undeclared faults + spA := PledgePenaltyForUndeclaredFault(epochReward, networkPower, faultySectorAPower) + spB := PledgePenaltyForUndeclaredFault(epochReward, networkPower, faultySectorBPower) + spC := PledgePenaltyForUndeclaredFault(epochReward, networkPower, faultySectorCPower) + + spAll := PledgePenaltyForUndeclaredFault(epochReward, networkPower, totalFaultPower) + + // Because we can introduce rounding error between 1 and zero for every penalty calculation + // we can at best expect n calculations of 1 power to be within n of 1 calculation of n powers. + diff = big.Sub(spAll, big.Add(spC, big.Add(spA, spB))) + assert.True(t, diff.GreaterThanEqual(big.Zero())) + assert.True(t, diff.LessThan(big.NewInt(3))) + + }) +} + +func TestQuantizeUp(t *testing.T) { + t.Run("zero offset", func(t *testing.T) { + assert.Equal(t, abi.ChainEpoch(50), quantizeUp(42, 10, 0)) + assert.Equal(t, abi.ChainEpoch(16000), quantizeUp(16000, 100, 0)) + assert.Equal(t, abi.ChainEpoch(0), quantizeUp(-5, 10, 0)) + assert.Equal(t, abi.ChainEpoch(-50), quantizeUp(-50, 10, 0)) + assert.Equal(t, abi.ChainEpoch(-50), quantizeUp(-53, 10, 0)) + }) + + t.Run("non zero offset", func(t *testing.T) { + assert.Equal(t, abi.ChainEpoch(6), quantizeUp(4, 5, 1)) + assert.Equal(t, abi.ChainEpoch(1), quantizeUp(0, 5, 1)) + assert.Equal(t, abi.ChainEpoch(-4), quantizeUp(-6, 5, 1)) + assert.Equal(t, abi.ChainEpoch(4), quantizeUp(2, 10, 4)) + }) + + t.Run("offset seed bigger than unit is normalized", func(t *testing.T) { + assert.Equal(t, abi.ChainEpoch(13), quantizeUp(9, 5, 28)) // offset should be 3 + assert.Equal(t, abi.ChainEpoch(10000), quantizeUp(10000, 100, 2000000)) + }) + +} \ No newline at end of file diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state.go new file mode 100644 index 0000000000..5a9eb0c860 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state.go @@ -0,0 +1,1164 @@ +package miner + +import ( + "fmt" + "reflect" + + addr "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + cid "github.com/ipfs/go-cid" + errors "github.com/pkg/errors" + xerrors "golang.org/x/xerrors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + . "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +// Balance of Miner Actor should be greater than or equal to +// the sum of PreCommitDeposits and LockedFunds. +// Excess balance as computed by st.GetAvailableBalance will be +// withdrawable or usable for pre-commit deposit or pledge lock-up. +type State struct { + // Information not related to sectors. + Info cid.Cid + + PreCommitDeposits abi.TokenAmount // Total funds locked as PreCommitDeposits + LockedFunds abi.TokenAmount // Total unvested funds locked as pledge collateral + VestingFunds cid.Cid // Array, AMT[ChainEpoch]TokenAmount + InitialPledgeRequirement abi.TokenAmount // Sum of initial pledge requirements of all active sectors + + // Sectors that have been pre-committed but not yet proven. + PreCommittedSectors cid.Cid // Map, HAMT[SectorNumber]SectorPreCommitOnChainInfo + + // Information for all proven and not-yet-expired sectors. + Sectors cid.Cid // Array, AMT[SectorNumber]SectorOnChainInfo (sparse) + + // The first epoch in this miner's current proving period. This is the first epoch in which a PoSt for a + // partition at the miner's first deadline may arrive. Alternatively, it is after the last epoch at which + // a PoSt for the previous window is valid. + // Always greater than zero, his may be greater than the current epoch for genesis miners in the first + // WPoStProvingPeriod epochs of the chain; the epochs before the first proving period starts are exempt from Window + // PoSt requirements. + // Updated at the end of every period by a power actor cron event. + ProvingPeriodStart abi.ChainEpoch + + // Sector numbers prove-committed since period start, to be added to Deadlines at next proving period boundary. + NewSectors *abi.BitField + + // Sector numbers indexed by expiry epoch (which are on proving period boundaries). + // Invariant: Keys(Sectors) == union(SectorExpirations.Values()) + SectorExpirations cid.Cid // Array, AMT[ChainEpoch]Bitfield + + // The sector numbers due for PoSt at each deadline in the current proving period, frozen at period start. + // New sectors are added and expired ones removed at proving period boundary. + // Faults are not subtracted from this in state, but on the fly. + Deadlines cid.Cid + + // All currently known faulty sectors, mutated eagerly. + // These sectors are exempt from inclusion in PoSt. + Faults *abi.BitField + + // Faulty sector numbers indexed by the start epoch of the proving period in which detected. + // Used to track fault durations for eventual sector termination. + // At most 14 entries, b/c sectors faulty longer expire. + // Invariant: Faults == union(FaultEpochs.Values()) + FaultEpochs cid.Cid // AMT[ChainEpoch]Bitfield + + // Faulty sectors that will recover when next included in a valid PoSt. + // Invariant: Recoveries ⊆ Faults. + Recoveries *abi.BitField + + // Records successful PoSt submission in the current proving period by partition number. + // The presence of a partition number indicates on-time PoSt received. + PostSubmissions *abi.BitField + + // The index of the next deadline for which faults should been detected and processed (after it's closed). + // The proving period cron handler will always reset this to 0, for the subsequent period. + // Eager fault detection processing on fault/recovery declarations or PoSt may set a smaller number, + // indicating partial progress, from which subsequent processing should continue. + // In the range [0, WPoStProvingPeriodDeadlines). + NextDeadlineToProcessFaults uint64 +} + +type MinerInfo struct { + // Account that owns this miner. + // - Income and returned collateral are paid to this address. + // - This address is also allowed to change the worker address for the miner. + Owner addr.Address // Must be an ID-address. + + // Worker account for this miner. + // The associated pubkey-type address is used to sign blocks and messages on behalf of this miner. + Worker addr.Address // Must be an ID-address. + + PendingWorkerKey *WorkerKeyChange + + // Byte array representing a Libp2p identity that should be used when connecting to this miner. + PeerId abi.PeerID + + // Slice of byte arrays representing Libp2p multi-addresses used for establishing a connection with this miner. + Multiaddrs []abi.Multiaddrs + + // The proof type used by this miner for sealing sectors. + SealProofType abi.RegisteredSealProof + + // Amount of space in each sector committed by this miner. + // This is computed from the proof type and represented here redundantly. + SectorSize abi.SectorSize + + // The number of sectors in each Window PoSt partition (proof). + // This is computed from the proof type and represented here redundantly. + WindowPoStPartitionSectors uint64 +} + +type WorkerKeyChange struct { + NewWorker addr.Address // Must be an ID address + EffectiveAt abi.ChainEpoch +} + +// Information provided by a miner when pre-committing a sector. +type SectorPreCommitInfo struct { + SealProof abi.RegisteredSealProof + SectorNumber abi.SectorNumber + SealedCID cid.Cid // CommR + SealRandEpoch abi.ChainEpoch + DealIDs []abi.DealID + Expiration abi.ChainEpoch + ReplaceCapacity bool // Whether to replace a "committed capacity" no-deal sector (requires non-empty DealIDs) + ReplaceSector abi.SectorNumber // The committed capacity sector to replace +} + +// Information stored on-chain for a pre-committed sector. +type SectorPreCommitOnChainInfo struct { + Info SectorPreCommitInfo + PreCommitDeposit abi.TokenAmount + PreCommitEpoch abi.ChainEpoch + DealWeight abi.DealWeight // Integral of active deals over sector lifetime + VerifiedDealWeight abi.DealWeight // Integral of active verified deals over sector lifetime +} + +// Information stored on-chain for a proven sector. +type SectorOnChainInfo struct { + SectorNumber abi.SectorNumber + SealProof abi.RegisteredSealProof // The seal proof type implies the PoSt proof/s + SealedCID cid.Cid // CommR + DealIDs []abi.DealID + Activation abi.ChainEpoch // Epoch during which the sector proof was accepted + Expiration abi.ChainEpoch // Epoch during which the sector expires + DealWeight abi.DealWeight // Integral of active deals over sector lifetime + VerifiedDealWeight abi.DealWeight // Integral of active verified deals over sector lifetime + InitialPledge abi.TokenAmount // Pledge collected to commit this sector +} + +func ConstructState(infoCid cid.Cid, periodStart abi.ChainEpoch, emptyArrayCid, emptyMapCid, emptyDeadlinesCid cid.Cid) (*State, error) { + + return &State{ + Info: infoCid, + + PreCommitDeposits: abi.NewTokenAmount(0), + LockedFunds: abi.NewTokenAmount(0), + VestingFunds: emptyArrayCid, + InitialPledgeRequirement: abi.NewTokenAmount(0), + + PreCommittedSectors: emptyMapCid, + Sectors: emptyArrayCid, + ProvingPeriodStart: periodStart, + NewSectors: abi.NewBitField(), + SectorExpirations: emptyArrayCid, + Deadlines: emptyDeadlinesCid, + Faults: abi.NewBitField(), + FaultEpochs: emptyArrayCid, + Recoveries: abi.NewBitField(), + PostSubmissions: abi.NewBitField(), + }, nil +} + +func ConstructMinerInfo(owner addr.Address, worker addr.Address, pid []byte, multiAddrs [][]byte, sealProofType abi.RegisteredSealProof) (*MinerInfo, error) { + + sectorSize, err := sealProofType.SectorSize() + if err != nil { + return nil, err + } + + partitionSectors, err := sealProofType.WindowPoStPartitionSectors() + if err != nil { + return nil, err + } + return &MinerInfo{ + Owner: owner, + Worker: worker, + PendingWorkerKey: nil, + PeerId: pid, + Multiaddrs: multiAddrs, + SealProofType: sealProofType, + SectorSize: sectorSize, + WindowPoStPartitionSectors: partitionSectors, + }, nil +} + +func (st *State) GetInfo(store adt.Store) (*MinerInfo, error) { + var info MinerInfo + if err := store.Get(store.Context(), st.Info, &info); err != nil { + return nil, xerrors.Errorf("failed to get miner info %w", err) + } + return &info, nil +} + +func (st *State) SaveInfo(store adt.Store, info *MinerInfo) error { + c, err := store.Put(store.Context(), info) + if err != nil { + return err + } + st.Info = c + return nil +} + +// Returns deadline calculations for the current proving period. +func (st *State) DeadlineInfo(currEpoch abi.ChainEpoch) *DeadlineInfo { + return ComputeProvingPeriodDeadline(st.ProvingPeriodStart, currEpoch) +} + +func (st *State) GetSectorCount(store adt.Store) (uint64, error) { + arr, err := adt.AsArray(store, st.Sectors) + if err != nil { + return 0, err + } + + return arr.Length(), nil +} + +func (st *State) GetMaxAllowedFaults(store adt.Store) (uint64, error) { + sectorCount, err := st.GetSectorCount(store) + if err != nil { + return 0, err + } + return 2 * sectorCount, nil +} + +func (st *State) PutPrecommittedSector(store adt.Store, info *SectorPreCommitOnChainInfo) error { + precommitted, err := adt.AsMap(store, st.PreCommittedSectors) + if err != nil { + return err + } + + err = precommitted.Put(SectorKey(info.Info.SectorNumber), info) + if err != nil { + return errors.Wrapf(err, "failed to store precommitment for %v", info) + } + st.PreCommittedSectors, err = precommitted.Root() + return err +} + +func (st *State) GetPrecommittedSector(store adt.Store, sectorNo abi.SectorNumber) (*SectorPreCommitOnChainInfo, bool, error) { + precommitted, err := adt.AsMap(store, st.PreCommittedSectors) + if err != nil { + return nil, false, err + } + + var info SectorPreCommitOnChainInfo + found, err := precommitted.Get(SectorKey(sectorNo), &info) + if err != nil { + return nil, false, errors.Wrapf(err, "failed to load precommitment for %v", sectorNo) + } + return &info, found, nil +} + +func (st *State) DeletePrecommittedSectors(store adt.Store, sectorNos ...abi.SectorNumber) error { + precommitted, err := adt.AsMap(store, st.PreCommittedSectors) + if err != nil { + return err + } + + for _, sectorNo := range sectorNos { + err = precommitted.Delete(SectorKey(sectorNo)) + if err != nil { + return xerrors.Errorf("failed to delete precommitment for %v: %w", sectorNo, err) + } + } + st.PreCommittedSectors, err = precommitted.Root() + return err +} + +func (st *State) HasSectorNo(store adt.Store, sectorNo abi.SectorNumber) (bool, error) { + sectors, err := adt.AsArray(store, st.Sectors) + if err != nil { + return false, err + } + + var info SectorOnChainInfo + found, err := sectors.Get(uint64(sectorNo), &info) + if err != nil { + return false, xerrors.Errorf("failed to get sector %v: %w", sectorNo, err) + } + return found, nil +} + +func (st *State) PutSectors(store adt.Store, newSectors ...*SectorOnChainInfo) error { + sectors, err := adt.AsArray(store, st.Sectors) + if err != nil { + return xerrors.Errorf("failed to load sectors: %w", err) + } + + for _, sector := range newSectors { + if err := sectors.Set(uint64(sector.SectorNumber), sector); err != nil { + return xerrors.Errorf("failed to put sector %v: %w", sector, err) + } + } + + st.Sectors, err = sectors.Root() + if err != nil { + return xerrors.Errorf("failed to persist sectors: %w", err) + } + return nil +} + +func (st *State) GetSector(store adt.Store, sectorNo abi.SectorNumber) (*SectorOnChainInfo, bool, error) { + sectors, err := adt.AsArray(store, st.Sectors) + if err != nil { + return nil, false, err + } + + var info SectorOnChainInfo + found, err := sectors.Get(uint64(sectorNo), &info) + if err != nil { + return nil, false, errors.Wrapf(err, "failed to get sector %v", sectorNo) + } + return &info, found, nil +} + +func (st *State) DeleteSectors(store adt.Store, sectorNos *abi.BitField) error { + sectors, err := adt.AsArray(store, st.Sectors) + if err != nil { + return err + } + err = sectorNos.ForEach(func(sectorNo uint64) error { + if err = sectors.Delete(sectorNo); err != nil { + return errors.Wrapf(err, "failed to delete sector %v", sectorNos) + } + return nil + }) + if err != nil { + return err + } + + st.Sectors, err = sectors.Root() + return err +} + +// Iterates sectors. +// The pointer provided to the callback is not safe for re-use. Copy the pointed-to value in full to hold a reference. +func (st *State) ForEachSector(store adt.Store, f func(*SectorOnChainInfo)) error { + sectors, err := adt.AsArray(store, st.Sectors) + if err != nil { + return err + } + var sector SectorOnChainInfo + return sectors.ForEach(§or, func(idx int64) error { + f(§or) + return nil + }) +} + +// Adds some sector numbers to the new sectors bitfield. +func (st *State) AddNewSectors(sectorNos ...abi.SectorNumber) (err error) { + ns := abi.NewBitField() + for _, sector := range sectorNos { + ns.Set(uint64(sector)) + } + st.NewSectors, err = bitfield.MergeBitFields(st.NewSectors, ns) + if err != nil { + return err + } + + count, err := st.NewSectors.Count() + if err != nil { + return err + } + if count > NewSectorsPerPeriodMax { + return fmt.Errorf("too many new sectors %d, max %d", count, NewSectorsPerPeriodMax) + } + return nil +} + +// Removes some sector numbers from the new sectors bitfield, if present. +func (st *State) RemoveNewSectors(sectorNos *abi.BitField) (err error) { + st.NewSectors, err = bitfield.SubtractBitField(st.NewSectors, sectorNos) + return err +} + +// Gets the sector numbers expiring at some epoch. +func (st *State) GetSectorExpirations(store adt.Store, expiry abi.ChainEpoch) (*abi.BitField, error) { + arr, err := adt.AsArray(store, st.SectorExpirations) + if err != nil { + return nil, err + } + + bf := abi.NewBitField() + _, err = arr.Get(uint64(expiry), bf) + if err != nil { + return nil, err + } + + return bf, nil +} + +// Iterates sector expiration groups in order. +// Note that the sectors bitfield provided to the callback is not safe to store. +func (st *State) ForEachSectorExpiration(store adt.Store, f func(expiry abi.ChainEpoch, sectors *abi.BitField) error) error { + arr, err := adt.AsArray(store, st.SectorExpirations) + if err != nil { + return err + } + + var bf bitfield.BitField + return arr.ForEach(&bf, func(i int64) error { + bfCopy, err := bf.Copy() + if err != nil { + return err + } + return f(abi.ChainEpoch(i), bfCopy) + }) +} + +// Adds some sector numbers to the set expiring at an epoch. +// The sector numbers are given as uint64s to avoid pointless conversions. +func (st *State) AddSectorExpirations(store adt.Store, sectors ...*SectorOnChainInfo) error { + if len(sectors) == 0 { + return nil + } + + arr, err := adt.AsArray(store, st.SectorExpirations) + if err != nil { + return xerrors.Errorf("failed to load sector expirations: %w", err) + } + + for _, epochSet := range groupSectorsByExpiration(sectors) { + bf := new(abi.BitField) + _, err = arr.Get(uint64(epochSet.epoch), bf) + if err != nil { + return xerrors.Errorf("failed to lookup sector expirations at epoch %v: %w", epochSet.epoch, err) + } + + bf, err = bitfield.MergeBitFields(bf, bitfield.NewFromSet(epochSet.sectors)) + if err != nil { + return xerrors.Errorf("failed to update sector expirations at epoch %v: %w", epochSet.epoch, err) + } + count, err := bf.Count() + if err != nil { + return xerrors.Errorf("failed to count sector expirations at epoch %v: %w", epochSet.epoch, err) + } + if count > SectorsMax { + return fmt.Errorf("too many sectors at expiration %d, %d, max %d", epochSet.epoch, count, SectorsMax) + } + + if err = arr.Set(uint64(epochSet.epoch), bf); err != nil { + return xerrors.Errorf("failed to set sector expirations at epoch %v: %w", epochSet.epoch, err) + } + } + + st.SectorExpirations, err = arr.Root() + if err != nil { + return xerrors.Errorf("failed to persist sector expirations: %w", err) + } + return nil +} + +// Removes some sector numbers from the set expiring at an epoch. +func (st *State) RemoveSectorExpirations(store adt.Store, sectors ...*SectorOnChainInfo) error { + if len(sectors) == 0 { + return nil + } + + arr, err := adt.AsArray(store, st.SectorExpirations) + if err != nil { + return xerrors.Errorf("failed to load sector expirations: %w", err) + } + + for _, epochSet := range groupSectorsByExpiration(sectors) { + bf := new(abi.BitField) + _, err = arr.Get(uint64(epochSet.epoch), bf) + if err != nil { + return xerrors.Errorf("failed to lookup sector expirations at epoch %v: %w", epochSet.epoch, err) + } + + bf, err = bitfield.SubtractBitField(bf, bitfield.NewFromSet(epochSet.sectors)) + if err != nil { + return xerrors.Errorf("failed to update sector expirations at epoch %v: %w", epochSet.epoch, err) + } + + if empty, err := bf.IsEmpty(); err != nil { + return xerrors.Errorf("corrupted sector expirations bitfield at epoch %v: %w", epochSet.epoch, err) + } else if empty { + if err := arr.Delete(uint64(epochSet.epoch)); err != nil { + return xerrors.Errorf("failed to delete sector expirations at epoch %v: %w", epochSet.epoch, err) + } + } else if err = arr.Set(uint64(epochSet.epoch), bf); err != nil { + return xerrors.Errorf("failed to set sector expirations at epoch %v: %w", epochSet.epoch, err) + } + } + + st.SectorExpirations, err = arr.Root() + if err != nil { + return xerrors.Errorf("failed to persist sector expirations: %w", err) + } + return nil +} + +// Removes all sector numbers from the set expiring some epochs. +func (st *State) ClearSectorExpirations(store adt.Store, expirations ...abi.ChainEpoch) error { + arr, err := adt.AsArray(store, st.SectorExpirations) + if err != nil { + return err + } + + for _, exp := range expirations { + err = arr.Delete(uint64(exp)) + if err != nil { + return err + } + } + + st.SectorExpirations, err = arr.Root() + return err +} + +// Adds sectors numbers to faults and fault epochs. +func (st *State) AddFaults(store adt.Store, sectorNos *abi.BitField, faultEpoch abi.ChainEpoch) (err error) { + empty, err := sectorNos.IsEmpty() + if err != nil { + return err + } + if empty { + return nil + } + + { + st.Faults, err = bitfield.MergeBitFields(st.Faults, sectorNos) + if err != nil { + return err + } + + count, err := st.Faults.Count() + if err != nil { + return err + } + if count > SectorsMax { + return fmt.Errorf("too many faults %d, max %d", count, SectorsMax) + } + } + + { + epochFaultArr, err := adt.AsArray(store, st.FaultEpochs) + if err != nil { + return err + } + + bf := abi.NewBitField() + _, err = epochFaultArr.Get(uint64(faultEpoch), bf) + if err != nil { + return err + } + + bf, err = bitfield.MergeBitFields(bf, sectorNos) + if err != nil { + return err + } + + if err = epochFaultArr.Set(uint64(faultEpoch), bf); err != nil { + return err + } + + st.FaultEpochs, err = epochFaultArr.Root() + if err != nil { + return err + } + } + + return nil +} + +// Removes sector numbers from faults and fault epochs, if present. +func (st *State) RemoveFaults(store adt.Store, sectorNos *abi.BitField) error { + if empty, err := sectorNos.IsEmpty(); err != nil { + return err + } else if empty { + return nil + } + + if newFaults, err := bitfield.SubtractBitField(st.Faults, sectorNos); err != nil { + return err + } else { + st.Faults = newFaults + } + + arr, err := adt.AsArray(store, st.FaultEpochs) + if err != nil { + return err + } + + type change struct { + index uint64 + value *abi.BitField + } + + var ( + epochsChanged []change + epochsDeleted []uint64 + ) + + epochFaultsOld := &abi.BitField{} + err = arr.ForEach(epochFaultsOld, func(i int64) error { + countOld, err := epochFaultsOld.Count() + if err != nil { + return err + } + + epochFaultsNew, err := bitfield.SubtractBitField(epochFaultsOld, sectorNos) + if err != nil { + return err + } + + countNew, err := epochFaultsNew.Count() + if err != nil { + return err + } + + if countNew == 0 { + epochsDeleted = append(epochsDeleted, uint64(i)) + } else if countOld != countNew { + epochsChanged = append(epochsChanged, change{index: uint64(i), value: epochFaultsNew}) + } + + return nil + }) + if err != nil { + return err + } + + err = arr.BatchDelete(epochsDeleted) + if err != nil { + return err + } + + for _, change := range epochsChanged { + err = arr.Set(change.index, change.value) + if err != nil { + return err + } + } + + st.FaultEpochs, err = arr.Root() + return err +} + +// Iterates faults by declaration epoch, in order. +func (st *State) ForEachFaultEpoch(store adt.Store, cb func(epoch abi.ChainEpoch, faults *abi.BitField) error) error { + arr, err := adt.AsArray(store, st.FaultEpochs) + if err != nil { + return err + } + + var bf bitfield.BitField + return arr.ForEach(&bf, func(i int64) error { + bfCopy, err := bf.Copy() + if err != nil { + return err + } + return cb(abi.ChainEpoch(i), bfCopy) + }) +} + +func (st *State) ClearFaultEpochs(store adt.Store, epochs ...abi.ChainEpoch) error { + arr, err := adt.AsArray(store, st.FaultEpochs) + if err != nil { + return err + } + + for _, exp := range epochs { + err = arr.Delete(uint64(exp)) + if err != nil { + return nil + } + } + + st.FaultEpochs, err = arr.Root() + return err +} + +// Adds sectors to recoveries. +func (st *State) AddRecoveries(sectorNos *abi.BitField) (err error) { + empty, err := sectorNos.IsEmpty() + if err != nil { + return err + } + if empty { + return nil + } + st.Recoveries, err = bitfield.MergeBitFields(st.Recoveries, sectorNos) + if err != nil { + return err + } + + count, err := st.Recoveries.Count() + if err != nil { + return err + } + if count > SectorsMax { + return fmt.Errorf("too many recoveries %d, max %d", count, SectorsMax) + } + return nil +} + +// Removes sectors from recoveries, if present. +func (st *State) RemoveRecoveries(sectorNos *abi.BitField) (err error) { + empty, err := sectorNos.IsEmpty() + if err != nil { + return err + } + if empty { + return nil + } + st.Recoveries, err = bitfield.SubtractBitField(st.Recoveries, sectorNos) + return err +} + +// Loads sector info for a sequence of sectors. +func (st *State) LoadSectorInfos(store adt.Store, sectors *abi.BitField) ([]*SectorOnChainInfo, error) { + var sectorInfos []*SectorOnChainInfo + err := sectors.ForEach(func(i uint64) error { + sectorOnChain, found, err := st.GetSector(store, abi.SectorNumber(i)) + if err != nil { + return xerrors.Errorf("failed to load sector %d: %w", i, err) + } else if !found { + return fmt.Errorf("can't find sector %d", i) + } + sectorInfos = append(sectorInfos, sectorOnChain) + return nil + }) + return sectorInfos, err +} + +// Loads info for a set of sectors to be proven. +// If any of the sectors are declared faulty and not to be recovered, info for the first non-faulty sector is substituted instead. +// If any of the sectors are declared recovered, they are returned from this method. +func (st *State) LoadSectorInfosForProof(store adt.Store, provenSectors *abi.BitField) (sectorInfos []*SectorOnChainInfo, recoveries *bitfield.BitField, err error) { + // Extract a fault set relevant to the sectors being submitted, for expansion into a map. + declaredFaults, err := bitfield.IntersectBitField(provenSectors, st.Faults) + if err != nil { + return nil, nil, xerrors.Errorf("failed to intersect proof sectors with faults: %w", err) + } + + recoveries, err = bitfield.IntersectBitField(declaredFaults, st.Recoveries) + if err != nil { + return nil, nil, xerrors.Errorf("failed to intersect recoveries with faults: %w", err) + } + + expectedFaults, err := bitfield.SubtractBitField(declaredFaults, recoveries) + if err != nil { + return nil, nil, xerrors.Errorf("failed to subtract recoveries from faults: %w", err) + } + + nonFaults, err := bitfield.SubtractBitField(provenSectors, expectedFaults) + if err != nil { + return nil, nil, xerrors.Errorf("failed to diff bitfields: %w", err) + } + + empty, err := nonFaults.IsEmpty() + if err != nil { + return nil, nil, xerrors.Errorf("failed to check if bitfield was empty: %w", err) + } + if empty { + return nil, nil, xerrors.Errorf("no non-faulty sectors in partitions: %w", err) + } + + // Select a non-faulty sector as a substitute for faulty ones. + goodSectorNo, err := nonFaults.First() + if err != nil { + return nil, nil, xerrors.Errorf("failed to get first good sector: %w", err) + } + + // Load sector infos + sectorInfos, err = st.LoadSectorInfosWithFaultMask(store, provenSectors, expectedFaults, abi.SectorNumber(goodSectorNo)) + if err != nil { + return nil, nil, xerrors.Errorf("failed to load sector infos: %w", err) + } + return +} + +// Loads sector info for a sequence of sectors, substituting info for a stand-in sector for any that are faulty. +func (st *State) LoadSectorInfosWithFaultMask(store adt.Store, sectors *abi.BitField, faults *abi.BitField, faultStandIn abi.SectorNumber) ([]*SectorOnChainInfo, error) { + standInInfo, found, err := st.GetSector(store, faultStandIn) + if err != nil { + return nil, fmt.Errorf("failed to load stand-in sector %d: %v", faultStandIn, err) + } else if !found { + return nil, fmt.Errorf("can't find stand-in sector %d", faultStandIn) + } + + // Expand faults into a map for quick lookups. + // The faults bitfield should already be a subset of the sectors bitfield. + sectorCount, err := sectors.Count() + if err != nil { + return nil, err + } + faultSet, err := faults.AllMap(sectorCount) + if err != nil { + return nil, fmt.Errorf("failed to expand faults: %w", err) + } + + // Load the sector infos, masking out fault sectors with a good one. + sectorInfos := make([]*SectorOnChainInfo, 0, sectorCount) + err = sectors.ForEach(func(i uint64) error { + sector := standInInfo + faulty := faultSet[i] + if !faulty { + sectorOnChain, found, err := st.GetSector(store, abi.SectorNumber(i)) + if err != nil { + return xerrors.Errorf("failed to load sector %d: %w", i, err) + } else if !found { + return fmt.Errorf("can't find sector %d", i) + } + sector = sectorOnChain + } + sectorInfos = append(sectorInfos, sector) + return nil + }) + return sectorInfos, err +} + +// Adds partition numbers to the set of PoSt submissions +func (st *State) AddPoStSubmissions(partitionNos *abi.BitField) (err error) { + st.PostSubmissions, err = bitfield.MergeBitFields(st.PostSubmissions, partitionNos) + return err +} + +// Removes all PoSt submissions +func (st *State) ClearPoStSubmissions() error { + st.PostSubmissions = abi.NewBitField() + return nil +} + +func (st *State) LoadDeadlines(store adt.Store) (*Deadlines, error) { + var deadlines Deadlines + if err := store.Get(store.Context(), st.Deadlines, &deadlines); err != nil { + return nil, fmt.Errorf("failed to load deadlines (%s): %w", st.Deadlines, err) + } + + return &deadlines, nil +} + +func (st *State) SaveDeadlines(store adt.Store, deadlines *Deadlines) error { + c, err := store.Put(store.Context(), deadlines) + if err != nil { + return err + } + st.Deadlines = c + return nil +} + +// +// PoSt Deadlines and partitions +// + +type Deadlines struct { + // A bitfield of sector numbers due at each deadline. + // The sectors for each deadline are logically grouped into sequential partitions for proving. + Due [WPoStPeriodDeadlines]*abi.BitField +} + +func ConstructDeadlines() *Deadlines { + d := &Deadlines{Due: [WPoStPeriodDeadlines]*abi.BitField{}} + for i := range d.Due { + d.Due[i] = abi.NewBitField() + } + return d +} + +// Adds sector numbers to a deadline. +// The sector numbers are given as uint64 to avoid pointless conversions for bitfield use. +func (d *Deadlines) AddToDeadline(deadline uint64, newSectors ...uint64) (err error) { + ns := bitfield.NewFromSet(newSectors) + d.Due[deadline], err = bitfield.MergeBitFields(d.Due[deadline], ns) + return err +} + +// Removes sector numbers from all deadlines. +func (d *Deadlines) RemoveFromAllDeadlines(sectorNos *abi.BitField) (err error) { + for i := range d.Due { + d.Due[i], err = bitfield.SubtractBitField(d.Due[i], sectorNos) + if err != nil { + return err + } + } + return nil +} + +// +// Funds and vesting +// + +func (st *State) AddPreCommitDeposit(amount abi.TokenAmount) { + newTotal := big.Add(st.PreCommitDeposits, amount) + AssertMsg(newTotal.GreaterThanEqual(big.Zero()), "negative pre-commit deposit %s after adding %s to prior %s", + newTotal, amount, st.PreCommitDeposits) + st.PreCommitDeposits = newTotal +} + +func (st *State) AddInitialPledgeRequirement(amount abi.TokenAmount) { + newTotal := big.Add(st.InitialPledgeRequirement, amount) + AssertMsg(newTotal.GreaterThanEqual(big.Zero()), "negative initial pledge %s after adding %s to prior %s", + newTotal, amount, st.InitialPledgeRequirement) + st.InitialPledgeRequirement = newTotal +} + +func (st *State) AddLockedFunds(store adt.Store, currEpoch abi.ChainEpoch, vestingSum abi.TokenAmount, spec *VestSpec) error { + AssertMsg(vestingSum.GreaterThanEqual(big.Zero()), "negative vesting sum %s", vestingSum) + vestingFunds, err := adt.AsArray(store, st.VestingFunds) + if err != nil { + return err + } + + // Nothing unlocks here, this is just the start of the clock. + vestBegin := currEpoch + spec.InitialDelay + vestPeriod := big.NewInt(int64(spec.VestPeriod)) + vestedSoFar := big.Zero() + for e := vestBegin + spec.StepDuration; vestedSoFar.LessThan(vestingSum); e += spec.StepDuration { + vestEpoch := quantizeUp(e, spec.Quantization, st.ProvingPeriodStart) + elapsed := vestEpoch - vestBegin + + targetVest := big.Zero() //nolint:ineffassign + if elapsed < spec.VestPeriod { + // Linear vesting, PARAM_FINISH + targetVest = big.Div(big.Mul(vestingSum, big.NewInt(int64(elapsed))), vestPeriod) + } else { + targetVest = vestingSum + } + + vestThisTime := big.Sub(targetVest, vestedSoFar) + vestedSoFar = targetVest + + // Load existing entry, else set a new one + key := EpochKey(vestEpoch) + lockedFundEntry := big.Zero() + _, err = vestingFunds.Get(key, &lockedFundEntry) + if err != nil { + return err + } + + lockedFundEntry = big.Add(lockedFundEntry, vestThisTime) + err = vestingFunds.Set(key, &lockedFundEntry) + if err != nil { + return err + } + } + + st.VestingFunds, err = vestingFunds.Root() + if err != nil { + return err + } + st.LockedFunds = big.Add(st.LockedFunds, vestingSum) + + return nil +} + +// Unlocks an amount of funds that have *not yet vested*, if possible. +// The soonest-vesting entries are unlocked first. +// Returns the amount actually unlocked. +func (st *State) UnlockUnvestedFunds(store adt.Store, currEpoch abi.ChainEpoch, target abi.TokenAmount) (abi.TokenAmount, error) { + vestingFunds, err := adt.AsArray(store, st.VestingFunds) + if err != nil { + return big.Zero(), err + } + + amountUnlocked := abi.NewTokenAmount(0) + lockedEntry := abi.NewTokenAmount(0) + var toDelete []uint64 + var finished = fmt.Errorf("finished") + + // Iterate vestingFunds are in order of release. + err = vestingFunds.ForEach(&lockedEntry, func(k int64) error { + if amountUnlocked.LessThan(target) { + if k >= int64(currEpoch) { + unlockAmount := big.Min(big.Sub(target, amountUnlocked), lockedEntry) + amountUnlocked = big.Add(amountUnlocked, unlockAmount) + lockedEntry = big.Sub(lockedEntry, unlockAmount) + + if lockedEntry.IsZero() { + toDelete = append(toDelete, uint64(k)) + } else { + if err = vestingFunds.Set(uint64(k), &lockedEntry); err != nil { + return err + } + } + } + return nil + } else { + return finished + } + }) + + if err != nil && err != finished { + return big.Zero(), err + } + + err = deleteMany(vestingFunds, toDelete) + if err != nil { + return big.Zero(), errors.Wrapf(err, "failed to delete locked fund during slash: %v", err) + } + + st.LockedFunds = big.Sub(st.LockedFunds, amountUnlocked) + Assert(st.LockedFunds.GreaterThanEqual(big.Zero())) + st.VestingFunds, err = vestingFunds.Root() + if err != nil { + return big.Zero(), err + } + + return amountUnlocked, nil +} + +// Unlocks all vesting funds that have vested before the provided epoch. +// Returns the amount unlocked. +func (st *State) UnlockVestedFunds(store adt.Store, currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + vestingFunds, err := adt.AsArray(store, st.VestingFunds) + if err != nil { + return big.Zero(), err + } + + amountUnlocked := abi.NewTokenAmount(0) + lockedEntry := abi.NewTokenAmount(0) + var toDelete []uint64 + var finished = fmt.Errorf("finished") + + // Iterate vestingFunds in order of release. + err = vestingFunds.ForEach(&lockedEntry, func(k int64) error { + if k < int64(currEpoch) { + amountUnlocked = big.Add(amountUnlocked, lockedEntry) + toDelete = append(toDelete, uint64(k)) + } else { + return finished // stop iterating + } + return nil + }) + + if err != nil && err != finished { + return big.Zero(), err + } + + err = deleteMany(vestingFunds, toDelete) + if err != nil { + return big.Zero(), errors.Wrapf(err, "failed to delete locked fund during vest: %v", err) + } + + st.LockedFunds = big.Sub(st.LockedFunds, amountUnlocked) + Assert(st.LockedFunds.GreaterThanEqual(big.Zero())) + st.VestingFunds, err = vestingFunds.Root() + if err != nil { + return big.Zero(), err + } + + return amountUnlocked, nil +} + +// CheckVestedFunds returns the amount of vested funds that have vested before the provided epoch. +func (st *State) CheckVestedFunds(store adt.Store, currEpoch abi.ChainEpoch) (abi.TokenAmount, error) { + vestingFunds, err := adt.AsArray(store, st.VestingFunds) + if err != nil { + return big.Zero(), err + } + + amountUnlocked := abi.NewTokenAmount(0) + lockedEntry := abi.NewTokenAmount(0) + var finished = fmt.Errorf("finished") + + // Iterate vestingFunds in order of release. + err = vestingFunds.ForEach(&lockedEntry, func(k int64) error { + if k < int64(currEpoch) { + amountUnlocked = big.Add(amountUnlocked, lockedEntry) + } else { + return finished // stop iterating + } + return nil + }) + if err != nil && err != finished { + return big.Zero(), err + } + + return amountUnlocked, nil +} + +func (st *State) GetAvailableBalance(actorBalance abi.TokenAmount) abi.TokenAmount { + availableBal := big.Sub(big.Sub(actorBalance, st.LockedFunds), st.PreCommitDeposits) + Assert(availableBal.GreaterThanEqual(big.Zero())) + return availableBal +} + +func (st *State) AssertBalanceInvariants(balance abi.TokenAmount) { + Assert(st.PreCommitDeposits.GreaterThanEqual(big.Zero())) + Assert(st.LockedFunds.GreaterThanEqual(big.Zero())) + Assert(balance.GreaterThanEqual(big.Add(st.PreCommitDeposits, st.LockedFunds))) +} + +// +// Sectors +// + +func (s *SectorOnChainInfo) AsSectorInfo() abi.SectorInfo { + return abi.SectorInfo{ + SealProof: s.SealProof, + SectorNumber: s.SectorNumber, + SealedCID: s.SealedCID, + } +} + +// +// Misc helpers +// + +func deleteMany(arr *adt.Array, keys []uint64) error { + // If AMT exposed a batch delete we could save some writes here. + for _, i := range keys { + err := arr.Delete(i) + if err != nil { + return err + } + } + return nil +} + +// Rounds e to the nearest exact multiple of the quantization unit offset by +// offsetSeed % unit, rounding up. +// This function is equivalent to `unit * ceil(e - (offsetSeed % unit) / unit) + (offsetSeed % unit)` +// with the variables/operations are over real numbers instead of ints. +// Precondition: unit >= 0 else behaviour is undefined +func quantizeUp(e abi.ChainEpoch, unit abi.ChainEpoch, offsetSeed abi.ChainEpoch) abi.ChainEpoch { + offset := offsetSeed % unit + + remainder := (e - offset) % unit + quotient := (e - offset) / unit + // Don't round if epoch falls on a quantization epoch + if remainder == 0 { + return unit*quotient + offset + } + // Negative truncating division rounds up + if e-offset < 0 { + return unit*quotient + offset + } + return unit*(quotient+1) + offset + +} + +func SectorKey(e abi.SectorNumber) adt.Keyer { + return adt.UIntKey(uint64(e)) +} + +func EpochKey(e abi.ChainEpoch) uint64 { + return uint64(e) +} + +func init() { + // Check that ChainEpoch is indeed an unsigned integer to confirm that SectorKey is making the right interpretation. + var e abi.SectorNumber + if reflect.TypeOf(e).Kind() != reflect.Uint64 { + panic("incorrect sector number encoding") + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state_test.go new file mode 100644 index 0000000000..c6c7c35fb3 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_state_test.go @@ -0,0 +1,1089 @@ +package miner_test + +import ( + "context" + "fmt" + "testing" + + "github.com/filecoin-project/go-bitfield" + cid "github.com/ipfs/go-cid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/support/ipld" + tutils "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestPrecommittedSectorsStore(t *testing.T) { + t.Run("Put, get and delete", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + sectorNo := abi.SectorNumber(1) + + pc1 := newSectorPreCommitOnChainInfo(sectorNo, tutils.MakeCID("1"), abi.NewTokenAmount(1), abi.ChainEpoch(1)) + harness.putPreCommit(pc1) + assert.Equal(t, pc1, harness.getPreCommit(sectorNo)) + + pc2 := newSectorPreCommitOnChainInfo(sectorNo, tutils.MakeCID("2"), abi.NewTokenAmount(1), abi.ChainEpoch(1)) + harness.putPreCommit(pc2) + assert.Equal(t, pc2, harness.getPreCommit(sectorNo)) + + harness.deletePreCommit(sectorNo) + assert.False(t, harness.hasPreCommit(sectorNo)) + }) + + t.Run("Delete nonexistent value returns an error", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + sectorNo := abi.SectorNumber(1) + err := harness.s.DeletePrecommittedSectors(harness.store, sectorNo) + assert.Error(t, err) + }) + + t.Run("Get nonexistent value returns false", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + sectorNo := abi.SectorNumber(1) + assert.False(t, harness.hasPreCommit(sectorNo)) + }) +} + +func TestSectorsStore(t *testing.T) { + t.Run("Put get and delete", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNo := abi.SectorNumber(1) + sectorInfo1 := newSectorOnChainInfo(sectorNo, tutils.MakeCID("1"), big.NewInt(1), abi.ChainEpoch(1)) + sectorInfo2 := newSectorOnChainInfo(sectorNo, tutils.MakeCID("2"), big.NewInt(2), abi.ChainEpoch(2)) + + harness.putSector(sectorInfo1) + assert.True(t, harness.hasSectorNo(sectorNo)) + out := harness.getSector(sectorNo) + assert.Equal(t, sectorInfo1, out) + + harness.putSector(sectorInfo2) + out = harness.getSector(sectorNo) + assert.Equal(t, sectorInfo2, out) + + harness.deleteSectors(uint64(sectorNo)) + assert.False(t, harness.hasSectorNo(sectorNo)) + }) + + t.Run("Delete nonexistent value returns an error", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNo := abi.SectorNumber(1) + bf := abi.NewBitField() + bf.Set(uint64(sectorNo)) + + assert.Error(t, harness.s.DeleteSectors(harness.store, bf)) + }) + + t.Run("Get nonexistent value returns false", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNo := abi.SectorNumber(1) + assert.False(t, harness.hasSectorNo(sectorNo)) + }) + + t.Run("Iterate and Delete multiple sector", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + // set of sectors, the larger numbers here are not significant + sectorNos := []uint64{100, 200, 300, 400, 500, 600, 700, 800, 900, 1000} + + // put all the sectors in the store + for _, s := range sectorNos { + i := int64(0) + harness.putSector(newSectorOnChainInfo(abi.SectorNumber(s), tutils.MakeCID(fmt.Sprintf("%d", i)), big.NewInt(i), abi.ChainEpoch(i))) + i++ + } + + sectorNoIdx := 0 + err := harness.s.ForEachSector(harness.store, func(si *miner.SectorOnChainInfo) { + require.Equal(t, abi.SectorNumber(sectorNos[sectorNoIdx]), si.SectorNumber) + sectorNoIdx++ + }) + assert.NoError(t, err) + + // ensure we iterated over the expected number of sectors + assert.Equal(t, len(sectorNos), sectorNoIdx) + + harness.deleteSectors(sectorNos...) + for _, s := range sectorNos { + assert.False(t, harness.hasSectorNo(abi.SectorNumber(s))) + } + }) +} + +func TestNewSectorsBitField(t *testing.T) { + t.Run("Add new sectors happy path", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + // set of sectors, the larger numbers here are not significant + sectorNos := []abi.SectorNumber{100, 200, 300, 400, 500, 600, 700, 800, 900, 1000} + harness.addNewSectors(sectorNos...) + assert.Equal(t, uint64(len(sectorNos)), harness.getNewSectorCount()) + }) + + t.Run("Add new sectors excludes duplicates", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNos := []abi.SectorNumber{1, 1, 2, 2, 3, 4, 5} + harness.addNewSectors(sectorNos...) + assert.Equal(t, uint64(5), harness.getNewSectorCount()) + }) + + t.Run("Remove sectors happy path", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNos := []abi.SectorNumber{1, 2, 3, 4, 5} + harness.addNewSectors(sectorNos...) + assert.Equal(t, uint64(len(sectorNos)), harness.getNewSectorCount()) + + harness.removeNewSectors(1, 3, 5) + assert.Equal(t, uint64(2), harness.getNewSectorCount()) + + sm, err := harness.s.NewSectors.All(uint64(len(sectorNos))) + assert.NoError(t, err) + assert.Equal(t, []uint64{2, 4}, sm) + }) + + t.Run("Add New sectors errors when adding too many new sectors", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + tooManySectors := make([]abi.SectorNumber, miner.NewSectorsPerPeriodMax+1) + for i := abi.SectorNumber(0); i < miner.NewSectorsPerPeriodMax+1; i++ { + tooManySectors[i] = i + } + + err := harness.s.AddNewSectors(tooManySectors...) + assert.Error(t, err) + + // sanity check nothing was added + // For omission reason see: https://github.com/filecoin-project/specs-actors/issues/300 + //assert.Equal(t, uint64(0), actorHarness.getNewSectorCount()) + }) +} + +func TestSectorExpirationStore(t *testing.T) { + exp1 := abi.ChainEpoch(10) + exp2 := abi.ChainEpoch(20) + sectorExpirations := map[abi.ChainEpoch][]uint64{ + exp1: {1, 2, 3, 4, 5}, + exp2: {6, 7, 8, 9, 10}, + } + + t.Run("Round trip add get sector expirations", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + harness.addSectorExpiration(exp1, sectorExpirations[exp1]...) + harness.addSectorExpiration(exp2, sectorExpirations[exp2]...) + + assert.Equal(t, sectorExpirations[exp1], harness.getSectorExpirations(exp1)) + assert.Equal(t, sectorExpirations[exp2], harness.getSectorExpirations(exp2)) + + // return nothing if there are no sectors at the epoch + assert.Empty(t, harness.getSectorExpirations(abi.ChainEpoch(0))) + + // remove the first sector from expiration set 1 + harness.removeSectorExpiration(exp1, sectorExpirations[exp1][0]) + assert.Equal(t, sectorExpirations[exp1][1:], harness.getSectorExpirations(exp1)) + assert.Equal(t, sectorExpirations[exp2], harness.getSectorExpirations(exp2)) // No change + + // remove all sectors from expiration set 2 + harness.removeSectorExpiration(exp2, sectorExpirations[exp2]...) + assert.Empty(t, harness.getSectorExpirations(exp2)) + + // Remove remainder + harness.removeSectorExpiration(exp1, sectorExpirations[exp1][1:]...) + err := harness.s.ForEachSectorExpiration(harness.store, func(epoch abi.ChainEpoch, expirations *abi.BitField) error { + assert.Fail(t, "unexpected expiration epoch: %v", epoch) + return nil + }) + require.NoError(t, err) + }) + + t.Run("Iteration by expiration", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + harness.addSectorExpiration(exp1, sectorExpirations[exp1]...) + harness.addSectorExpiration(exp2, sectorExpirations[exp2]...) + + var prevCallbackArg *abi.BitField + found := map[abi.ChainEpoch][]uint64{} + err := harness.s.ForEachSectorExpiration(harness.store, func(epoch abi.ChainEpoch, expirations *abi.BitField) error { + sectors, err := expirations.All(100) + require.NoError(t, err) + found[epoch] = sectors + + // Check that bitfield pointer argument is newly allocated, not re-used + assert.True(t, prevCallbackArg != expirations) + prevCallbackArg = expirations + return nil + }) + assert.NoError(t, err) + assert.Equal(t, sectorExpirations, found) + }) + + t.Run("Adding sectors at expiry merges with existing", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + mergedSectors := []uint64{21, 22, 23, 24, 25} + harness.addSectorExpiration(exp1, sectorExpirations[exp1]...) + harness.addSectorExpiration(exp1, mergedSectors...) + + merged := harness.getSectorExpirations(exp1) + assert.Equal(t, append(sectorExpirations[exp1], mergedSectors...), merged) + }) + + t.Run("clear sectors by expirations", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + harness.addSectorExpiration(exp1, sectorExpirations[exp1]...) + harness.addSectorExpiration(exp2, sectorExpirations[exp2]...) + + // ensure clearing works + harness.clearSectorExpiration(exp1, exp2) + empty1 := harness.getSectorExpirations(exp1) + assert.Empty(t, empty1) + + empty2 := harness.getSectorExpirations(exp2) + assert.Empty(t, empty2) + }) +} + +func TestFaultStore(t *testing.T) { + fault1 := abi.ChainEpoch(10) + fault2 := abi.ChainEpoch(20) + sectorFaults := map[abi.ChainEpoch][]uint64{ + fault1: {1, 2, 3, 4, 5}, + fault2: {6, 7, 8, 9, 10, 11}, + } + + t.Run("Add/remove all", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + harness.addFaults(fault1, sectorFaults[fault1]...) + harness.addFaults(fault2, sectorFaults[fault2]...) + + found := map[abi.ChainEpoch][]uint64{} + var prevCallbackArg *abi.BitField + err := harness.s.ForEachFaultEpoch(harness.store, func(epoch abi.ChainEpoch, faults *abi.BitField) error { + sectors, err := faults.All(100) + require.NoError(t, err) + found[epoch] = sectors + + // Assert the bitfield pointer is pointing to a distinct object on different calls, so that holding on + // to the reference is safe. + assert.True(t, faults != prevCallbackArg) + prevCallbackArg = faults + return nil + }) + require.NoError(t, err) + assert.Equal(t, sectorFaults, found) + + // remove all the faults + harness.removeFaults(sectorFaults[fault1]...) + harness.removeFaults(sectorFaults[fault2]...) + err = harness.s.ForEachFaultEpoch(harness.store, func(epoch abi.ChainEpoch, faults *abi.BitField) error { + assert.Fail(t, "unexpected fault epoch: %v", epoch) + return nil + }) + require.NoError(t, err) + }) + + t.Run("Add/remove some", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + harness.addFaults(fault1, sectorFaults[fault1]...) + harness.addFaults(fault2, sectorFaults[fault2]...) + + found := map[abi.ChainEpoch][]uint64{} + err := harness.s.ForEachFaultEpoch(harness.store, func(epoch abi.ChainEpoch, faults *abi.BitField) error { + sectors, err := faults.All(100) + require.NoError(t, err) + found[epoch] = sectors + return nil + }) + require.NoError(t, err) + assert.Equal(t, sectorFaults, found) + + // remove the faults + harness.removeFaults(sectorFaults[fault1][1:]...) + harness.removeFaults(sectorFaults[fault2][2:]...) + + found = map[abi.ChainEpoch][]uint64{} + err = harness.s.ForEachFaultEpoch(harness.store, func(epoch abi.ChainEpoch, faults *abi.BitField) error { + sectors, err := faults.All(100) + require.NoError(t, err) + found[epoch] = sectors + return nil + }) + require.NoError(t, err) + expected := map[abi.ChainEpoch][]uint64{ + fault1: {1}, + fault2: {6, 7}, + } + assert.Equal(t, expected, found) // FOIXME + }) + + t.Run("Clear all", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + harness.addFaults(fault1, []uint64{1, 2, 3, 4, 5}...) + harness.addFaults(fault2, []uint64{6, 7, 8, 9, 10, 11}...) + + // now clear all the faults + err := harness.s.ClearFaultEpochs(harness.store, fault1, fault2) + require.NoError(t, err) + + err = harness.s.ForEachFaultEpoch(harness.store, func(epoch abi.ChainEpoch, faults *abi.BitField) error { + assert.Fail(t, "unexpected fault epoch: %v", epoch) + return nil + }) + require.NoError(t, err) + }) +} + +func TestRecoveriesBitfield(t *testing.T) { + t.Run("Add new recoveries happy path", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + // set of sectors, the larger numbers here are not significant + sectorNos := []uint64{100, 200, 300, 400, 500, 600, 700, 800, 900, 1000} + harness.addRecoveries(sectorNos...) + assert.Equal(t, uint64(len(sectorNos)), harness.getRecoveriesCount()) + }) + + t.Run("Add new recoveries excludes duplicates", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNos := []uint64{1, 1, 2, 2, 3, 4, 5} + harness.addRecoveries(sectorNos...) + assert.Equal(t, uint64(5), harness.getRecoveriesCount()) + }) + + t.Run("Remove recoveries happy path", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNos := []uint64{1, 2, 3, 4, 5} + harness.addRecoveries(sectorNos...) + assert.Equal(t, uint64(len(sectorNos)), harness.getRecoveriesCount()) + + harness.removeRecoveries(1, 3, 5) + assert.Equal(t, uint64(2), harness.getRecoveriesCount()) + + recoveries, err := harness.s.Recoveries.All(uint64(len(sectorNos))) + assert.NoError(t, err) + assert.Equal(t, []uint64{2, 4}, recoveries) + }) +} + +func TestPostSubmissionsBitfield(t *testing.T) { + t.Run("Add new submission happy path", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + // set of sectors, the larger numbers here are not significant + partitionNos := []uint64{10, 20, 30, 40} + harness.addPoStSubmissions(partitionNos...) + assert.Equal(t, uint64(len(partitionNos)), harness.getPoStSubmissionsCount()) + }) + + t.Run("Add new submission excludes duplicates", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNos := []uint64{1, 1, 2, 2, 3, 4, 5} + harness.addPoStSubmissions(sectorNos...) + assert.Equal(t, uint64(5), harness.getPoStSubmissionsCount()) + }) + + t.Run("Clear submission happy path", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + + sectorNos := []uint64{1, 2, 3, 4, 5} + harness.addPoStSubmissions(sectorNos...) + assert.Equal(t, uint64(len(sectorNos)), harness.getPoStSubmissionsCount()) + + harness.clearPoStSubmissions() + assert.Equal(t, uint64(0), harness.getPoStSubmissionsCount()) + }) +} + +func TestVesting_AddLockedFunds_Table(t *testing.T) { + vestStartDelay := abi.ChainEpoch(10) + vestSum := int64(100) + + testcase := []struct { + desc string + vspec *miner.VestSpec + periodStart abi.ChainEpoch + vepocs []int64 + }{ + { + desc: "vest funds in a single epoch", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 1, + StepDuration: 1, + Quantization: 1, + }, + vepocs: []int64{0, 0, 100, 0}, + }, + { + desc: "vest funds with period=2", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 2, + StepDuration: 1, + Quantization: 1, + }, + vepocs: []int64{0, 0, 50, 50, 0}, + }, + { + desc: "vest funds with period=2 quantization=2", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 2, + StepDuration: 1, + Quantization: 2, + }, + vepocs: []int64{0, 0, 0, 100, 0}, + }, + {desc: "vest funds with period=3", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 3, + StepDuration: 1, + Quantization: 1, + }, + vepocs: []int64{0, 0, 33, 33, 34, 0}, + }, + { + desc: "vest funds with period=3 quantization=2", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 3, + StepDuration: 1, + Quantization: 2, + }, + vepocs: []int64{0, 0, 0, 66, 0, 34, 0}, + }, + {desc: "vest funds with period=2 step=2", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 2, + StepDuration: 2, + Quantization: 1, + }, + vepocs: []int64{0, 0, 0, 100, 0}, + }, + { + desc: "vest funds with period=5 step=2", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 2, + Quantization: 1, + }, + vepocs: []int64{0, 0, 0, 40, 0, 40, 0, 20, 0}, + }, + { + desc: "vest funds with delay=1 period=5 step=2", + vspec: &miner.VestSpec{ + InitialDelay: 1, + VestPeriod: 5, + StepDuration: 2, + Quantization: 1, + }, + vepocs: []int64{0, 0, 0, 0, 40, 0, 40, 0, 20, 0}, + }, + { + desc: "vest funds with period=5 step=2 quantization=2", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 2, + Quantization: 2, + }, + vepocs: []int64{0, 0, 0, 40, 0, 40, 0, 20, 0}, + }, + { + desc: "vest funds with period=5 step=3 quantization=1", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 3, + Quantization: 1, + }, + vepocs: []int64{0, 0, 0, 0, 60, 0, 0, 40, 0}, + }, + { + desc: "vest funds with period=5 step=3 quantization=2", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 3, + Quantization: 2, + }, + vepocs: []int64{0, 0, 0, 0, 0, 80, 0, 20, 0}, + }, + { + desc: "(step greater than period) vest funds with period=5 step=6 quantization=1", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 6, + Quantization: 1, + }, + vepocs: []int64{0, 0, 0, 0, 0, 0, 0, 100, 0}, + }, + { + desc: "vest funds with delay=5 period=5 step=1 quantization=1", + vspec: &miner.VestSpec{ + InitialDelay: 5, + VestPeriod: 5, + StepDuration: 1, + Quantization: 1, + }, + vepocs: []int64{0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 0}, + }, + { + desc: "vest funds with offset 0", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 10, + StepDuration: 2, + Quantization: 2, + }, + vepocs: []int64{0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 20}, + }, + { + desc: "vest funds with offset 1", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 10, + StepDuration: 2, + Quantization: 2, + }, + periodStart: abi.ChainEpoch(1), + // start epoch is at 11 instead of 10 so vepocs are shifted by one from above case + vepocs: []int64{0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 20}, + }, + { + desc: "vest funds with proving period start > quantization unit", + vspec: &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 10, + StepDuration: 2, + Quantization: 2, + }, + // 55 % 2 = 1 so expect same vepocs with offset 1 as in previous case + periodStart: abi.ChainEpoch(55), + vepocs: []int64{0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 20}, + }, + } + for _, tc := range testcase { + t.Run(tc.desc, func(t *testing.T) { + harness := constructStateHarness(t, tc.periodStart) + vestStart := tc.periodStart + vestStartDelay + + harness.addLockedFunds(vestStart, abi.NewTokenAmount(vestSum), tc.vspec) + assert.Equal(t, abi.NewTokenAmount(vestSum), harness.s.LockedFunds) + + var totalVested int64 + for e, v := range tc.vepocs { + assert.Equal(t, abi.NewTokenAmount(v), harness.unlockVestedFunds(vestStart+abi.ChainEpoch(e))) + totalVested += v + assert.Equal(t, vestSum-totalVested, harness.s.LockedFunds.Int64()) + } + + assert.Equal(t, abi.NewTokenAmount(vestSum), abi.NewTokenAmount(totalVested)) + assert.True(t, harness.vestingFundsStoreEmpty()) + assert.Zero(t, harness.s.LockedFunds.Int64()) + }) + } +} + +func TestVestingFunds_AddLockedFunds(t *testing.T) { + t.Run("LockedFunds increases with sequential calls", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + vspec := &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 1, + StepDuration: 1, + Quantization: 1, + } + + vestStart := abi.ChainEpoch(10) + vestSum := abi.NewTokenAmount(100) + + harness.addLockedFunds(vestStart, vestSum, vspec) + assert.Equal(t, vestSum, harness.s.LockedFunds) + + harness.addLockedFunds(vestStart, vestSum, vspec) + assert.Equal(t, big.Mul(vestSum, big.NewInt(2)), harness.s.LockedFunds) + }) + + t.Run("Vests when quantize, step duration, and vesting period are coprime", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + vspec := &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 27, + StepDuration: 5, + Quantization: 7, + } + vestStart := abi.ChainEpoch(10) + vestSum := abi.NewTokenAmount(100) + harness.addLockedFunds(vestStart, vestSum, vspec) + assert.Equal(t, vestSum, harness.s.LockedFunds) + + totalVested := abi.NewTokenAmount(0) + for e := vestStart; e <= 43; e++ { + amountVested := harness.unlockVestedFunds(e) + switch e { + case 22: + assert.Equal(t, abi.NewTokenAmount(40), amountVested) + totalVested = big.Add(totalVested, amountVested) + case 29: + assert.Equal(t, abi.NewTokenAmount(26), amountVested) + totalVested = big.Add(totalVested, amountVested) + case 36: + assert.Equal(t, abi.NewTokenAmount(26), amountVested) + totalVested = big.Add(totalVested, amountVested) + case 43: + assert.Equal(t, abi.NewTokenAmount(8), amountVested) + totalVested = big.Add(totalVested, amountVested) + default: + assert.Equal(t, abi.NewTokenAmount(0), amountVested) + } + } + assert.Equal(t, vestSum, totalVested) + assert.Zero(t, harness.s.LockedFunds.Int64()) + assert.True(t, harness.vestingFundsStoreEmpty()) + }) +} + +func TestVestingFunds_UnvestedFunds(t *testing.T) { + t.Run("Unlock unvested funds leaving bucket with non-zero tokens", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + vspec := &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 1, + Quantization: 1, + } + vestStart := abi.ChainEpoch(100) + vestSum := abi.NewTokenAmount(100) + + harness.addLockedFunds(vestStart, vestSum, vspec) + + amountUnlocked := harness.unlockUnvestedFunds(vestStart, big.NewInt(39)) + assert.Equal(t, big.NewInt(39), amountUnlocked) + + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart)) + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart+1)) + + // expected to be zero due to unlocking of UNvested funds + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart+2)) + // expected to be non-zero due to unlocking of UNvested funds + assert.Equal(t, abi.NewTokenAmount(1), harness.unlockVestedFunds(vestStart+3)) + + assert.Equal(t, abi.NewTokenAmount(20), harness.unlockVestedFunds(vestStart+4)) + assert.Equal(t, abi.NewTokenAmount(20), harness.unlockVestedFunds(vestStart+5)) + assert.Equal(t, abi.NewTokenAmount(20), harness.unlockVestedFunds(vestStart+6)) + + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart+7)) + + assert.Zero(t, harness.s.LockedFunds.Int64()) + assert.True(t, harness.vestingFundsStoreEmpty()) + }) + + t.Run("Unlock unvested funds leaving bucket with zero tokens", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + vspec := &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 1, + Quantization: 1, + } + vestStart := abi.ChainEpoch(100) + vestSum := abi.NewTokenAmount(100) + + harness.addLockedFunds(vestStart, vestSum, vspec) + + amountUnlocked := harness.unlockUnvestedFunds(vestStart, big.NewInt(40)) + assert.Equal(t, big.NewInt(40), amountUnlocked) + + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart)) + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart+1)) + + // expected to be zero due to unlocking of UNvested funds + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart+2)) + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart+3)) + + assert.Equal(t, abi.NewTokenAmount(20), harness.unlockVestedFunds(vestStart+4)) + assert.Equal(t, abi.NewTokenAmount(20), harness.unlockVestedFunds(vestStart+5)) + assert.Equal(t, abi.NewTokenAmount(20), harness.unlockVestedFunds(vestStart+6)) + + assert.Equal(t, abi.NewTokenAmount(0), harness.unlockVestedFunds(vestStart+7)) + + assert.Zero(t, harness.s.LockedFunds.Int64()) + assert.True(t, harness.vestingFundsStoreEmpty()) + }) + + t.Run("Unlock all unvested funds", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + vspec := &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 5, + StepDuration: 1, + Quantization: 1, + } + vestStart := abi.ChainEpoch(10) + vestSum := abi.NewTokenAmount(100) + harness.addLockedFunds(vestStart, vestSum, vspec) + unvestedFunds := harness.unlockUnvestedFunds(vestStart, vestSum) + assert.Equal(t, vestSum, unvestedFunds) + + assert.Zero(t, harness.s.LockedFunds.Int64()) + assert.True(t, harness.vestingFundsStoreEmpty()) + }) + + t.Run("Unlock unvested funds value greater than LockedFunds", func(t *testing.T) { + harness := constructStateHarness(t, abi.ChainEpoch(0)) + vspec := &miner.VestSpec{ + InitialDelay: 0, + VestPeriod: 1, + StepDuration: 1, + Quantization: 1, + } + vestStart := abi.ChainEpoch(10) + vestSum := abi.NewTokenAmount(100) + harness.addLockedFunds(vestStart, vestSum, vspec) + unvestedFunds := harness.unlockUnvestedFunds(vestStart, abi.NewTokenAmount(200)) + assert.Equal(t, vestSum, unvestedFunds) + + assert.Zero(t, harness.s.LockedFunds.Int64()) + assert.True(t, harness.vestingFundsStoreEmpty()) + + }) + +} + +type stateHarness struct { + t testing.TB + + s *miner.State + store adt.Store +} + +// +// Vesting Store +// + +func (h *stateHarness) addLockedFunds(epoch abi.ChainEpoch, sum abi.TokenAmount, spec *miner.VestSpec) { + err := h.s.AddLockedFunds(h.store, epoch, sum, spec) + require.NoError(h.t, err) +} + +func (h *stateHarness) unlockUnvestedFunds(epoch abi.ChainEpoch, target abi.TokenAmount) abi.TokenAmount { + amount, err := h.s.UnlockUnvestedFunds(h.store, epoch, target) + require.NoError(h.t, err) + return amount +} + +func (h *stateHarness) unlockVestedFunds(epoch abi.ChainEpoch) abi.TokenAmount { + amount, err := h.s.UnlockVestedFunds(h.store, epoch) + require.NoError(h.t, err) + return amount +} + +func (h *stateHarness) vestingFundsStoreEmpty() bool { + vestingFunds, err := adt.AsArray(h.store, h.s.VestingFunds) + require.NoError(h.t, err) + empty := true + lockedEntry := abi.NewTokenAmount(0) + err = vestingFunds.ForEach(&lockedEntry, func(k int64) error { + empty = false + return nil + }) + require.NoError(h.t, err) + return empty +} + +// +// PostSubmissions Bitfield +// + +func (h *stateHarness) addPoStSubmissions(partitionNos ...uint64) { + err := h.s.AddPoStSubmissions(bitfield.NewFromSet(partitionNos)) + require.NoError(h.t, err) +} + +func (h *stateHarness) clearPoStSubmissions() { + err := h.s.ClearPoStSubmissions() + require.NoError(h.t, err) +} + +func (h *stateHarness) getPoStSubmissionsCount() uint64 { + count, err := h.s.PostSubmissions.Count() + require.NoError(h.t, err) + return count +} + +// +// Recoveries Bitfield +// + +func (h *stateHarness) addRecoveries(sectorNos ...uint64) { + bf := bitfield.NewFromSet(sectorNos) + err := h.s.AddRecoveries(bf) + require.NoError(h.t, err) +} + +func (h *stateHarness) removeRecoveries(sectorNos ...uint64) { + bf := bitfield.NewFromSet(sectorNos) + err := h.s.RemoveRecoveries(bf) + require.NoError(h.t, err) +} + +func (h *stateHarness) getRecoveriesCount() uint64 { + count, err := h.s.Recoveries.Count() + require.NoError(h.t, err) + return count +} + +// +// Faults Store +// + +func (h *stateHarness) addFaults(epoch abi.ChainEpoch, sectorNos ...uint64) { + bf := bitfield.NewFromSet(sectorNos) + err := h.s.AddFaults(h.store, bf, epoch) + require.NoError(h.t, err) +} + +func (h *stateHarness) removeFaults(sectorNos ...uint64) { + bf := bitfield.NewFromSet(sectorNos) + err := h.s.RemoveFaults(h.store, bf) + require.NoError(h.t, err) +} + +// +// Sector Expiration Store +// + +func (h *stateHarness) getSectorExpirations(expiry abi.ChainEpoch) []uint64 { + bf, err := h.s.GetSectorExpirations(h.store, expiry) + require.NoError(h.t, err) + sectors, err := bf.All(miner.SectorsMax) + require.NoError(h.t, err) + return sectors +} + +func (h *stateHarness) addSectorExpiration(expiry abi.ChainEpoch, sectorNos ...uint64) { + infos := make([]*miner.SectorOnChainInfo, len(sectorNos)) + for i, sectorNo := range sectorNos { + infos[i] = &miner.SectorOnChainInfo{ + SectorNumber: abi.SectorNumber(sectorNo), + Expiration: expiry, + } + } + err := h.s.AddSectorExpirations(h.store, infos...) + require.NoError(h.t, err) +} + +func (h *stateHarness) removeSectorExpiration(expiry abi.ChainEpoch, sectorNos ...uint64) { + infos := make([]*miner.SectorOnChainInfo, len(sectorNos)) + for i, sectorNo := range sectorNos { + infos[i] = &miner.SectorOnChainInfo{ + SectorNumber: abi.SectorNumber(sectorNo), + Expiration: expiry, + } + } + err := h.s.RemoveSectorExpirations(h.store, infos...) + require.NoError(h.t, err) +} + +func (h *stateHarness) clearSectorExpiration(excitations ...abi.ChainEpoch) { + err := h.s.ClearSectorExpirations(h.store, excitations...) + require.NoError(h.t, err) +} + +// +// NewSectors BitField Assertions +// + +func (h *stateHarness) addNewSectors(sectorNos ...abi.SectorNumber) { + err := h.s.AddNewSectors(sectorNos...) + require.NoError(h.t, err) +} + +// makes a bit field from the passed sector numbers +func (h *stateHarness) removeNewSectors(sectorNos ...uint64) { + bf := bitfield.NewFromSet(sectorNos) + err := h.s.RemoveNewSectors(bf) + require.NoError(h.t, err) +} + +func (h *stateHarness) getNewSectorCount() uint64 { + out, err := h.s.NewSectors.Count() + require.NoError(h.t, err) + return out +} + +// +// Sector Store Assertion Operations +// + +func (h *stateHarness) hasSectorNo(sectorNo abi.SectorNumber) bool { + found, err := h.s.HasSectorNo(h.store, sectorNo) + require.NoError(h.t, err) + return found +} + +func (h *stateHarness) putSector(sector *miner.SectorOnChainInfo) { + err := h.s.PutSectors(h.store, sector) + require.NoError(h.t, err) +} + +func (h *stateHarness) getSector(sectorNo abi.SectorNumber) *miner.SectorOnChainInfo { + sectors, found, err := h.s.GetSector(h.store, sectorNo) + require.NoError(h.t, err) + assert.True(h.t, found) + assert.NotNil(h.t, sectors) + return sectors +} + +// makes a bit field from the passed sector numbers +func (h *stateHarness) deleteSectors(sectorNos ...uint64) { + bf := bitfield.NewFromSet(sectorNos) + err := h.s.DeleteSectors(h.store, bf) + require.NoError(h.t, err) +} + +// +// Precommit Store Operations +// + +func (h *stateHarness) putPreCommit(info *miner.SectorPreCommitOnChainInfo) { + err := h.s.PutPrecommittedSector(h.store, info) + require.NoError(h.t, err) +} + +func (h *stateHarness) getPreCommit(sectorNo abi.SectorNumber) *miner.SectorPreCommitOnChainInfo { + out, found, err := h.s.GetPrecommittedSector(h.store, sectorNo) + require.NoError(h.t, err) + assert.True(h.t, found) + return out +} + +func (h *stateHarness) hasPreCommit(sectorNo abi.SectorNumber) bool { + _, found, err := h.s.GetPrecommittedSector(h.store, sectorNo) + require.NoError(h.t, err) + return found +} + +func (h *stateHarness) deletePreCommit(sectorNo abi.SectorNumber) { + err := h.s.DeletePrecommittedSectors(h.store, sectorNo) + require.NoError(h.t, err) +} + +func constructStateHarness(t *testing.T, periodBoundary abi.ChainEpoch) *stateHarness { + // store init + store := ipld.NewADTStore(context.Background()) + emptyMap, err := adt.MakeEmptyMap(store).Root() + require.NoError(t, err) + + emptyArray, err := adt.MakeEmptyArray(store).Root() + require.NoError(t, err) + + emptyDeadlines := miner.ConstructDeadlines() + emptyDeadlinesCid, err := store.Put(context.Background(), emptyDeadlines) + require.NoError(t, err) + + // state field init + owner := tutils.NewBLSAddr(t, 1) + worker := tutils.NewBLSAddr(t, 2) + + testSealProofType := abi.RegisteredSealProof_StackedDrg2KiBV1 + + sectorSize, err := testSealProofType.SectorSize() + require.NoError(t, err) + + partitionSectors, err := testSealProofType.WindowPoStPartitionSectors() + require.NoError(t, err) + + info := miner.MinerInfo{ + Owner: owner, + Worker: worker, + PendingWorkerKey: nil, + PeerId: abi.PeerID("peer"), + Multiaddrs: testMultiaddrs, + SealProofType: testSealProofType, + SectorSize: sectorSize, + WindowPoStPartitionSectors: partitionSectors, + } + infoCid, err := store.Put(context.Background(), &info) + require.NoError(t, err) + + state, err := miner.ConstructState(infoCid, periodBoundary, emptyArray, emptyMap, emptyDeadlinesCid) + require.NoError(t, err) + + // assert NewSectors bitfield was constructed correctly (empty) + newSectorsCount, err := state.NewSectors.Count() + assert.NoError(t, err) + assert.Equal(t, uint64(0), newSectorsCount) + + return &stateHarness{ + t: t, + + s: state, + store: store, + } +} + +// +// Type Construction Methods +// + +// returns a unique SectorPreCommitOnChainInfo with each invocation with SectorNumber set to `sectorNo`. +func newSectorPreCommitOnChainInfo(sectorNo abi.SectorNumber, sealed cid.Cid, deposit abi.TokenAmount, epoch abi.ChainEpoch) *miner.SectorPreCommitOnChainInfo { + info := newSectorPreCommitInfo(sectorNo, sealed) + return &miner.SectorPreCommitOnChainInfo{ + Info: *info, + PreCommitDeposit: deposit, + PreCommitEpoch: epoch, + DealWeight: big.Zero(), + VerifiedDealWeight: big.Zero(), + } +} + +const ( + sectorSealRandEpochValue = abi.ChainEpoch(1) + sectorExpiration = abi.ChainEpoch(1) +) + +// returns a unique SectorOnChainInfo with each invocation with SectorNumber set to `sectorNo`. +func newSectorOnChainInfo(sectorNo abi.SectorNumber, sealed cid.Cid, weight big.Int, activation abi.ChainEpoch) *miner.SectorOnChainInfo { + return &miner.SectorOnChainInfo{ + SectorNumber: sectorNo, + SealProof: abi.RegisteredSealProof_StackedDrg32GiBV1, + SealedCID: sealed, + DealIDs: nil, + Activation: activation, + Expiration: sectorExpiration, + DealWeight: weight, + VerifiedDealWeight: weight, + InitialPledge: abi.NewTokenAmount(0), + } +} + +// returns a unique SectorPreCommitInfo with each invocation with SectorNumber set to `sectorNo`. +func newSectorPreCommitInfo(sectorNo abi.SectorNumber, sealed cid.Cid) *miner.SectorPreCommitInfo { + return &miner.SectorPreCommitInfo{ + SealProof: abi.RegisteredSealProof_StackedDrg32GiBV1, + SectorNumber: sectorNo, + SealedCID: sealed, + SealRandEpoch: sectorSealRandEpochValue, + DealIDs: nil, + Expiration: sectorExpiration, + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_test.go new file mode 100644 index 0000000000..f066fe7f58 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/miner_test.go @@ -0,0 +1,2091 @@ +package miner_test + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "testing" + + addr "github.com/filecoin-project/go-address" + bitfield "github.com/filecoin-project/go-bitfield" + cid "github.com/ipfs/go-cid" + "github.com/minio/blake2b-simd" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + cbg "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +var testPid abi.PeerID +var testMultiaddrs []abi.Multiaddrs + +// A balance for use in tests where the miner's low balance is not interesting. +var bigBalance = big.Mul(big.NewInt(1000), big.NewInt(1e18)) + +func init() { + testPid = abi.PeerID("peerID") + + testMultiaddrs = []abi.Multiaddrs{ + {1}, + {2}, + } + + miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ + abi.RegisteredSealProof_StackedDrg2KiBV1: {}, + } +} + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, miner.Actor{}) +} + +func TestConstruction(t *testing.T) { + actor := miner.Actor{} + owner := tutil.NewIDAddr(t, 100) + worker := tutil.NewIDAddr(t, 101) + workerKey := tutil.NewBLSAddr(t, 0) + receiver := tutil.NewIDAddr(t, 1000) + builder := mock.NewBuilder(context.Background(), receiver). + WithActorType(owner, builtin.AccountActorCodeID). + WithActorType(worker, builtin.AccountActorCodeID). + WithHasher(blake2b.Sum256). + WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + + t.Run("simple construction", func(t *testing.T) { + rt := builder.Build(t) + params := miner.ConstructorParams{ + OwnerAddr: owner, + WorkerAddr: worker, + SealProofType: abi.RegisteredSealProof_StackedDrg2KiBV1, + PeerId: testPid, + Multiaddrs: testMultiaddrs, + } + + provingPeriodStart := abi.ChainEpoch(2386) // This is just set from running the code. + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + // Fetch worker pubkey. + rt.ExpectSend(worker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &workerKey, exitcode.Ok) + // Register proving period cron. + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.EnrollCronEvent, + makeProvingPeriodCronEventParams(t, provingPeriodStart-1), big.Zero(), nil, exitcode.Ok) + ret := rt.Call(actor.Constructor, ¶ms) + + assert.Nil(t, ret) + rt.Verify() + + var st miner.State + rt.GetState(&st) + info, err := st.GetInfo(adt.AsStore(rt)) + require.NoError(t, err) + assert.Equal(t, params.OwnerAddr, info.Owner) + assert.Equal(t, params.WorkerAddr, info.Worker) + assert.Equal(t, params.PeerId, info.PeerId) + assert.Equal(t, params.Multiaddrs, info.Multiaddrs) + assert.Equal(t, abi.RegisteredSealProof_StackedDrg2KiBV1, info.SealProofType) + assert.Equal(t, abi.SectorSize(2048), info.SectorSize) + assert.Equal(t, uint64(2), info.WindowPoStPartitionSectors) + assert.Equal(t, provingPeriodStart, st.ProvingPeriodStart) + + assert.Equal(t, big.Zero(), st.PreCommitDeposits) + assert.Equal(t, big.Zero(), st.LockedFunds) + assert.True(t, st.VestingFunds.Defined()) + assert.True(t, st.PreCommittedSectors.Defined()) + assertEmptyBitfield(t, st.NewSectors) + assert.True(t, st.SectorExpirations.Defined()) + assert.True(t, st.Deadlines.Defined()) + assertEmptyBitfield(t, st.Faults) + assert.True(t, st.FaultEpochs.Defined()) + assertEmptyBitfield(t, st.Recoveries) + assertEmptyBitfield(t, st.PostSubmissions) + + var deadlines miner.Deadlines + assert.True(t, rt.Store().Get(st.Deadlines, &deadlines)) + for i := uint64(0); i < miner.WPoStPeriodDeadlines; i++ { + assertEmptyBitfield(t, deadlines.Due[i]) + } + }) +} + +// Tests for fetching and manipulating miner addresses. +func TestControlAddresses(t *testing.T) { + actor := newHarness(t, 0) + builder := builderForHarness(actor) + + t.Run("get addresses", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + o, w := actor.controlAddresses(rt) + assert.Equal(t, actor.owner, o) + assert.Equal(t, actor.worker, w) + }) + + // TODO: test changing worker (with delay), changing peer id + // https://github.com/filecoin-project/specs-actors/issues/479 +} + +// Test for sector precommitment and proving. +func TestCommitments(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + + // TODO more tests + // - Concurrent attempts to upgrade the same CC sector (one should succeed) + // - Insufficient funds for pre-commit, for prove-commit + // - CC sector targeted for upgrade expires naturally before the upgrade is proven + + t.Run("valid precommit then provecommit", func(t *testing.T) { + actor := newHarness(t, periodOffset) + rt := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()). + Build(t) + precommitEpoch := periodOffset + 1 + rt.SetEpoch(precommitEpoch) + actor.constructAndVerify(rt) + deadline := actor.deadline(rt) + + // Make a good commitment for the proof to target. + sectorNo := abi.SectorNumber(100) + precommit := makePreCommit(sectorNo, precommitEpoch-1, deadline.PeriodEnd(), nil) + actor.preCommitSector(rt, precommit) + + // assert precommit exists and meets expectations + onChainPrecommit := actor.getPreCommit(rt, sectorNo) + + // expect precommit deposit to be initial pledge calculated at precommit time + sectorSize, err := precommit.SealProof.SectorSize() + require.NoError(t, err) + + // deal weights mocked by actor harness for market actor must be set in precommit onchain info + assert.Equal(t, big.NewInt(int64(sectorSize/2)), onChainPrecommit.DealWeight) + assert.Equal(t, big.NewInt(int64(sectorSize/2)), onChainPrecommit.VerifiedDealWeight) + + qaPower := miner.QAPowerForWeight(sectorSize, precommit.Expiration-precommitEpoch, onChainPrecommit.DealWeight, onChainPrecommit.VerifiedDealWeight) + expectedDeposit := miner.InitialPledgeForPower(qaPower, actor.networkQAPower, actor.networkPledge, actor.epochReward, rt.TotalFilCircSupply()) + assert.Equal(t, expectedDeposit, onChainPrecommit.PreCommitDeposit) + + // expect total precommit deposit to equal our new deposit + st := getState(rt) + assert.Equal(t, expectedDeposit, st.PreCommitDeposits) + + // run prove commit logic + rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay + 1) + rt.SetBalance(big.Mul(big.NewInt(1000), big.NewInt(1e18))) + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(sectorNo), proveCommitConf{}) + st = getState(rt) + + // expect precommit to have been removed + _, found, err := st.GetPrecommittedSector(rt.AdtStore(), sectorNo) + require.NoError(t, err) + require.False(t, found) + + // expect deposit to have been transferred to initial pledges + expectedInitialPledge := expectedDeposit + assert.Equal(t, big.Zero(), st.PreCommitDeposits) + assert.Equal(t, expectedInitialPledge, st.InitialPledgeRequirement) + + // expect new onchain sector + onChainSector := actor.getSector(rt, sectorNo) + + // expect deal weights to be transfered to on chain info + assert.Equal(t, onChainPrecommit.DealWeight, onChainSector.DealWeight) + assert.Equal(t, onChainPrecommit.VerifiedDealWeight, onChainSector.VerifiedDealWeight) + + // expect activation epoch to be precommit + assert.Equal(t, precommitEpoch, onChainSector.Activation) + + // expect initial plege of sector to be set + assert.Equal(t, expectedInitialPledge, onChainSector.InitialPledge) + + // expect locked initial pledge of sector to be the same as precommit deposit + assert.Equal(t, expectedInitialPledge, st.LockedFunds) + }) + + t.Run("invalid pre-commit rejected", func(t *testing.T) { + actor := newHarness(t, periodOffset) + rt := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()). + Build(t) + precommitEpoch := periodOffset + 1 + rt.SetEpoch(precommitEpoch) + actor.constructAndVerify(rt) + deadline := actor.deadline(rt) + challengeEpoch := precommitEpoch - 1 + + oldSector := actor.commitAndProveSectors(rt, 1, 100, nil)[0] + + // Good commitment. + actor.preCommitSector(rt, makePreCommit(101, challengeEpoch, deadline.PeriodEnd(), nil)) + + // Duplicate pre-commit sector ID + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, makePreCommit(101, challengeEpoch, deadline.PeriodEnd(), nil)) + }) + rt.Reset() + + // Sector ID already committed + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, makePreCommit(oldSector.SectorNumber, challengeEpoch, deadline.PeriodEnd(), nil)) + }) + rt.Reset() + + // Bad seal proof type + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + pc := makePreCommit(101, challengeEpoch, deadline.PeriodEnd(), nil) + pc.SealProof = abi.RegisteredSealProof_StackedDrg8MiBV1 + actor.preCommitSector(rt, pc) + }) + rt.Reset() + + // Expires at current epoch + rt.SetEpoch(deadline.PeriodEnd()) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, makePreCommit(101, challengeEpoch, deadline.PeriodEnd(), nil)) + }) + rt.Reset() + + // Expires before current epoch + expiration := deadline.PeriodEnd() + rt.SetEpoch(expiration + 1) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, makePreCommit(101, challengeEpoch, deadline.PeriodEnd(), nil)) + }) + rt.Reset() + + // Expires not on period end + expiration = deadline.PeriodEnd() - 1 + rt.SetEpoch(precommitEpoch) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, makePreCommit(101, challengeEpoch, expiration, nil)) + }) + rt.Reset() + + // Errors when expiry too far in the future + rt.SetEpoch(precommitEpoch) + expiration = deadline.PeriodEnd() + miner.WPoStProvingPeriod*(miner.MaxSectorExpirationExtension/miner.WPoStProvingPeriod+1) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, makePreCommit(101, challengeEpoch, deadline.PeriodEnd()-1, nil)) + }) + }) + + t.Run("valid committed capacity upgrade", func(t *testing.T) { + actor := newHarness(t, periodOffset) + rt := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()). + Build(t) + actor.constructAndVerify(rt) + + // Commit a sector to upgrade + oldSector := actor.commitAndProveSectors(rt, 1, 100, nil)[0] + + // Reduce the epoch reward so that a new sector's initial pledge would otherwise be lesser. + actor.epochReward = big.Div(actor.epochReward, big.NewInt(2)) + + challengeEpoch := rt.Epoch() - 1 + upgradeParams := makePreCommit(200, challengeEpoch, oldSector.Expiration, []abi.DealID{1}) + upgradeParams.ReplaceCapacity = true + upgradeParams.ReplaceSector = oldSector.SectorNumber + upgrade := actor.preCommitSector(rt, upgradeParams) + + // Check new pre-commit in state + assert.True(t, upgrade.Info.ReplaceCapacity) + assert.Equal(t, upgradeParams.ReplaceSector, upgrade.Info.ReplaceSector) + // Require new sector's pledge to be at least that of the old sector. + assert.Equal(t, oldSector.InitialPledge, upgrade.PreCommitDeposit) + + // Old sector is unchanged + oldSectorAgain := actor.getSector(rt, oldSector.SectorNumber) + assert.Equal(t, oldSector, oldSectorAgain) + + // Deposit and pledge as expected + st := getState(rt) + assert.Equal(t, st.PreCommitDeposits, upgrade.PreCommitDeposit) + assert.Equal(t, st.InitialPledgeRequirement, oldSector.InitialPledge) + assert.Equal(t, st.LockedFunds, oldSector.InitialPledge) + + // Prove new sector + rt.SetEpoch(upgrade.PreCommitEpoch + miner.PreCommitChallengeDelay + 1) + newSector := actor.proveCommitSectorAndConfirm(rt, &upgrade.Info, upgrade.PreCommitEpoch, + makeProveCommit(upgrade.Info.SectorNumber), proveCommitConf{}) + + // Both sectors have pledge + st = getState(rt) + assert.Equal(t, big.Zero(), st.PreCommitDeposits) + assert.Equal(t, st.InitialPledgeRequirement, big.Add(oldSector.InitialPledge, newSector.InitialPledge)) + assert.Equal(t, st.LockedFunds, big.Add(oldSector.InitialPledge, newSector.InitialPledge)) + + // The old sector's expiration has changed to the end of this proving period + deadline := actor.deadline(rt) + oldSectorAgain = actor.getSector(rt, oldSector.SectorNumber) + assert.Equal(t, deadline.PeriodEnd(), oldSectorAgain.Expiration) + + // Both sectors are currently listed as new, because deadlines not yet assigned + assertBfEqual(t, bitfield.NewFromSet([]uint64{100, 200}), st.NewSectors) + + // Roll forward to PP cron and expect old sector removed without penalty + completeProvingPeriod(rt, actor, true, nil, []*miner.SectorOnChainInfo{oldSectorAgain}) + + // The old sector is gone, only the new sector is assigned to a deadline. + st = getState(rt) + sectors := actor.collectSectors(rt) + assert.Equal(t, 1, len(sectors)) + assert.Nil(t, sectors[oldSector.SectorNumber]) + assert.Equal(t, newSector, sectors[newSector.SectorNumber]) + + expirations := actor.collectExpirations(rt) + assert.Equal(t, 1, len(expirations)) + assert.Equal(t, []uint64{200}, expirations[newSector.Expiration]) + + provingSet := actor.collectProvingSet(rt) + assert.Equal(t, map[uint64]struct{}{200: {}}, provingSet) + assertBfEqual(t, bitfield.NewFromSet([]uint64{}), st.NewSectors) // No new sectors + + // Old sector's pledge still locked (not penalized), but no longer contributes to minimum requirement. + assert.Equal(t, st.InitialPledgeRequirement, newSector.InitialPledge) + assert.Equal(t, st.LockedFunds, big.Add(oldSector.InitialPledge, newSector.InitialPledge)) + }) + + t.Run("invalid committed capacity upgrade rejected", func(t *testing.T) { + actor := newHarness(t, periodOffset) + rt := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()). + Build(t) + actor.constructAndVerify(rt) + + // Commit sectors to target upgrade. The first has no deals, the second has a deal. + oldSectors := actor.commitAndProveSectors(rt, 2, 100, [][]abi.DealID{nil, {10}}) + + challengeEpoch := rt.Epoch() - 1 + upgradeParams := makePreCommit(200, challengeEpoch, oldSectors[0].Expiration, []abi.DealID{20}) + upgradeParams.ReplaceCapacity = true + upgradeParams.ReplaceSector = oldSectors[0].SectorNumber + + { // Must have deals + params := *upgradeParams + params.DealIDs = nil + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, ¶ms) + }) + rt.Reset() + } + { // Old sector cannot have deals + params := *upgradeParams + params.ReplaceSector = oldSectors[1].SectorNumber + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, ¶ms) + }) + rt.Reset() + } + { // Target sector must exist + params := *upgradeParams + params.ReplaceSector = 999 + rt.ExpectAbort(exitcode.ErrNotFound, func() { + actor.preCommitSector(rt, ¶ms) + }) + rt.Reset() + } + { // Expiration must not be sooner than target + params := *upgradeParams + params.Expiration = params.Expiration - miner.WPoStProvingPeriod + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, ¶ms) + }) + rt.Reset() + } + { // Target must not be faulty + params := *upgradeParams + st := getState(rt) + st.Faults.Set(uint64(params.ReplaceSector)) + rt.ReplaceState(st) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.preCommitSector(rt, ¶ms) + }) + st.Faults = abi.NewBitField() + rt.ReplaceState(st) + rt.Reset() + } + + // Demonstrate that the params are otherwise ok + actor.preCommitSector(rt, upgradeParams) + rt.Verify() + }) + + t.Run("faulty committed capacity sector not replaced", func(t *testing.T) { + actor := newHarness(t, periodOffset) + rt := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()). + Build(t) + actor.constructAndVerify(rt) + + // Commit a sector to target upgrade + oldSector := actor.commitAndProveSectors(rt, 1, 100, nil)[0] + + // Complete proving period + // June 2020: it is impossible to declare fault for a sector not yet assigned to a deadline + completeProvingPeriod(rt, actor, true, nil, nil) + + // Pre-commit a sector to replace the existing one + challengeEpoch := rt.Epoch() - 1 + upgradeParams := makePreCommit(200, challengeEpoch, oldSector.Expiration, []abi.DealID{20}) + upgradeParams.ReplaceCapacity = true + upgradeParams.ReplaceSector = oldSector.SectorNumber + + upgrade := actor.preCommitSector(rt, upgradeParams) + + // Declare the old sector faulty + _, qaPower := powerForSectors(actor.sectorSize, []*miner.SectorOnChainInfo{oldSector}) + fee := miner.PledgePenaltyForDeclaredFault(actor.epochReward, actor.networkQAPower, qaPower) + actor.declareFaults(rt, actor.networkQAPower, fee, oldSector) + + rt.SetEpoch(upgrade.PreCommitEpoch + miner.PreCommitChallengeDelay + 1) + // Proof is initially denied because the fault fee has reduced locked funds. + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + actor.proveCommitSectorAndConfirm(rt, &upgrade.Info, upgrade.PreCommitEpoch, + makeProveCommit(upgrade.Info.SectorNumber), proveCommitConf{}) + }) + rt.Reset() + + // Prove the new sector + actor.addLockedFund(rt, fee) + newSector := actor.proveCommitSectorAndConfirm(rt, &upgrade.Info, upgrade.PreCommitEpoch, + makeProveCommit(upgrade.Info.SectorNumber), proveCommitConf{}) + + // The old sector's expiration has *not* changed + oldSectorAgain := actor.getSector(rt, oldSector.SectorNumber) + assert.Equal(t, oldSector.Expiration, oldSectorAgain.Expiration) + + // Roll forward to PP cron. The faulty old sector pays a fee, but is not terminated. + completeProvingPeriod(rt, actor, true, []*miner.SectorOnChainInfo{oldSector}, nil) + + // Both sectors remain + sectors := actor.collectSectors(rt) + assert.Equal(t, 2, len(sectors)) + assert.Equal(t, oldSector, sectors[oldSector.SectorNumber]) + assert.Equal(t, newSector, sectors[newSector.SectorNumber]) + expirations := actor.collectExpirations(rt) + assert.Equal(t, 1, len(expirations)) + assert.Equal(t, []uint64{100, 200}, expirations[newSector.Expiration]) + }) + + t.Run("invalid proof rejected", func(t *testing.T) { + actor := newHarness(t, periodOffset) + rt := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()). + Build(t) + precommitEpoch := periodOffset + 1 + rt.SetEpoch(precommitEpoch) + actor.constructAndVerify(rt) + deadline := actor.deadline(rt) + + // Make a good commitment for the proof to target. + sectorNo := abi.SectorNumber(100) + precommit := makePreCommit(sectorNo, precommitEpoch-1, deadline.PeriodEnd(), nil) + actor.preCommitSector(rt, precommit) + + // Sector pre-commitment missing. + rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay + 1) + rt.ExpectAbort(exitcode.ErrNotFound, func() { + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(sectorNo+1), proveCommitConf{}) + }) + rt.Reset() + + // Too late. + rt.SetEpoch(precommitEpoch + miner.MaxSealDuration[precommit.SealProof] + 1) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(sectorNo), proveCommitConf{}) + }) + rt.Reset() + + // TODO: too early to prove sector + // TODO: seal rand epoch too old + // TODO: commitment expires before proof + // https://github.com/filecoin-project/specs-actors/issues/479 + + // Set the right epoch for all following tests + rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay + 1) + + // Invalid deals (market ActivateDeals aborts) + verifyDealsExit := make(map[abi.SectorNumber]exitcode.ExitCode) + verifyDealsExit[precommit.SectorNumber] = exitcode.ErrIllegalArgument + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(sectorNo), proveCommitConf{ + verifyDealsExit: verifyDealsExit, + }) + }) + rt.Reset() + + // Invalid seal proof + /* TODO: how should this test work? + // https://github.com/filecoin-project/specs-actors/issues/479 + rt.ExpectAbort(exitcode.ErrIllegalState, func() { + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(sectorNo), proveCommitConf{ + verifySealErr: fmt.Errorf("for testing"), + }) + }) + rt.Reset() + */ + + // Good proof + rt.SetBalance(big.Mul(big.NewInt(1000), big.NewInt(1e18))) + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(sectorNo), proveCommitConf{}) + st := getState(rt) + // Verify new sectors + newSectors, err := st.NewSectors.All(miner.SectorsMax) + require.NoError(t, err) + assert.Equal(t, []uint64{uint64(sectorNo)}, newSectors) + // Verify pledge lock-up + assert.True(t, st.LockedFunds.GreaterThan(big.Zero())) + rt.Reset() + + // Duplicate proof (sector no-longer pre-committed) + rt.ExpectAbort(exitcode.ErrNotFound, func() { + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(sectorNo), proveCommitConf{}) + }) + rt.Reset() + }) +} + +func TestWindowPost(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + precommitEpoch := abi.ChainEpoch(1) + builder := builderForHarness(actor). + WithEpoch(precommitEpoch). + WithBalance(bigBalance, big.Zero()) + + t.Run("test proof", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + store := rt.AdtStore() + _ = actor.commitAndProveSectors(rt, 1, 100, nil) + + // Skip to end of proving period, cron adds sectors to proving set. + actor.advancePastProvingPeriodWithCron(rt) + st := getState(rt) + + // Iterate deadlines in the proving period, setting epoch to the first in each deadline. + // Submit a window post for all partitions due at each deadline when necessary. + deadline := actor.deadline(rt) + for !deadline.PeriodElapsed() { + st = getState(rt) + deadlines, err := st.LoadDeadlines(store) + require.NoError(t, err) + + infos, partitions := actor.computePartitions(rt, deadlines, deadline.Index) + if len(infos) > 0 { + actor.submitWindowPoSt(rt, deadline, partitions, infos, nil) + } + + rt.SetEpoch(deadline.Close + 1) + deadline = actor.deadline(rt) + } + + // Oops, went one epoch too far, rewind to last epoch of last deadline window for the cron. + rt.SetEpoch(rt.Epoch() - 1) + + empty, err := st.PostSubmissions.IsEmpty() + require.NoError(t, err) + assert.False(t, empty, "no post submission") + }) + + runTillFirstDeadline := func(rt *mock.Runtime) (*miner.DeadlineInfo, []*miner.SectorOnChainInfo, []uint64) { + actor.constructAndVerify(rt) + + _ = actor.commitAndProveSectors(rt, 4, 100, nil) + + // Skip to end of proving period, cron adds sectors to proving set. + actor.advancePastProvingPeriodWithCron(rt) + st := getState(rt) + + deadlines, err := st.LoadDeadlines(rt.AdtStore()) + require.NoError(t, err) + deadline := actor.deadline(rt) + + // advance to next dealine where we expect the first sectors to appear + rt.SetEpoch(deadline.Close + 1) + deadline = st.DeadlineInfo(rt.Epoch()) + + infos, partitions := actor.computePartitions(rt, deadlines, deadline.Index) + return deadline, infos, partitions + } + + t.Run("successful recoveries recover power", func(t *testing.T) { + rt := builder.Build(t) + deadline, infos, partitions := runTillFirstDeadline(rt) + st := getState(rt) + + // mark all sectors as recovered faults + sectors := bitfield.New() + for _, info := range infos { + sectors.Set(uint64(info.SectorNumber)) + } + err := st.AddFaults(rt.AdtStore(), §ors, rt.Epoch()) + require.NoError(t, err) + err = st.AddRecoveries(§ors) + require.NoError(t, err) + rt.ReplaceState(st) + + rawPower, qaPower := miner.PowerForSectors(actor.sectorSize, infos) + + cfg := &poStConfig{ + expectedRawPowerDelta: rawPower, + expectedQAPowerDelta: qaPower, + expectedPenalty: big.Zero(), + skipped: bitfield.NewFromSet(nil), + } + + actor.submitWindowPoSt(rt, deadline, partitions, infos, cfg) + }) + + t.Run("skipped faults are penalized and adjust power adjusted", func(t *testing.T) { + rt := builder.Build(t) + deadline, infos, partitions := runTillFirstDeadline(rt) + + // skip the first sector in the partition + skipped := bitfield.NewFromSet([]uint64{uint64(infos[0].SectorNumber)}) + + rawPower, qaPower := miner.PowerForSectors(actor.sectorSize, infos[:1]) + + // expected penalty is the fee for an undeclared fault + expectedPenalty := miner.PledgePenaltyForUndeclaredFault(actor.epochReward, actor.networkQAPower, qaPower) + + cfg := &poStConfig{ + skipped: skipped, + expectedRawPowerDelta: rawPower.Neg(), + expectedQAPowerDelta: qaPower.Neg(), + expectedPenalty: expectedPenalty, + } + + actor.submitWindowPoSt(rt, deadline, partitions, infos, cfg) + }) + + t.Run("skipped recoveries are penalized and do not recover power", func(t *testing.T) { + rt := builder.Build(t) + deadline, infos, partitions := runTillFirstDeadline(rt) + st := getState(rt) + + // mark all sectors as recovered faults + sectors := bitfield.NewFromSet([]uint64{uint64(infos[0].SectorNumber)}) + err := st.AddFaults(rt.AdtStore(), sectors, rt.Epoch()) + require.NoError(t, err) + err = st.AddRecoveries(sectors) + require.NoError(t, err) + rt.ReplaceState(st) + + _, qaPower := miner.PowerForSectors(actor.sectorSize, infos[:1]) + + // skip the first sector in the partition + skipped := bitfield.NewFromSet([]uint64{uint64(infos[0].SectorNumber)}) + // expected penalty is the fee for an undeclared fault + expectedPenalty := miner.PledgePenaltyForUndeclaredFault(actor.epochReward, actor.networkQAPower, qaPower) + + cfg := &poStConfig{ + expectedRawPowerDelta: big.Zero(), + expectedQAPowerDelta: big.Zero(), + expectedPenalty: expectedPenalty, + skipped: skipped, + } + + actor.submitWindowPoSt(rt, deadline, partitions, infos, cfg) + }) + + t.Run("skipping a fault from the wrong deadline is an error", func(t *testing.T) { + rt := builder.Build(t) + deadline, infos, partitions := runTillFirstDeadline(rt) + st := getState(rt) + + // look ahead to next deadline to find a sector not in this deadline + deadlines, err := st.LoadDeadlines(rt.AdtStore()) + require.NoError(t, err) + nextDeadline := st.DeadlineInfo(deadline.Close + 1) + nextInfos, _ := actor.computePartitions(rt, deadlines, nextDeadline.Index) + + _, qaPower := miner.PowerForSectors(actor.sectorSize, nextInfos[:1]) + + // skip the first sector in the partition + skipped := bitfield.NewFromSet([]uint64{uint64(nextInfos[0].SectorNumber)}) + // expected penalty is the fee for an undeclared fault + expectedPenalty := miner.PledgePenaltyForUndeclaredFault(actor.epochReward, actor.networkQAPower, qaPower) + + cfg := &poStConfig{ + expectedRawPowerDelta: big.Zero(), + expectedQAPowerDelta: big.Zero(), + expectedPenalty: expectedPenalty, + skipped: skipped, + } + + rt.ExpectAbortConstainsMessage(exitcode.ErrIllegalArgument, "skipped faults contains sectors not due in deadline", func() { + actor.submitWindowPoSt(rt, deadline, partitions, infos, cfg) + }) + }) +} + +func TestProveCommit(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + builder := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()) + + t.Run("aborts if sum of initial pledges exceeds locked funds", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + // prove one sector to establish collateral and locked funds + actor.commitAndProveSectors(rt, 1, 100, nil) + + // preecommit another sector so we may prove it + expiration := 100*miner.WPoStProvingPeriod + periodOffset - 1 + precommitEpoch := rt.Epoch() + 1 + rt.SetEpoch(precommitEpoch) + precommit := makePreCommit(actor.nextSectorNo, rt.Epoch()-1, expiration, nil) + actor.preCommitSector(rt, precommit) + + // alter lock funds to simulate vesting since last prove + st := getState(rt) + st.LockedFunds = big.Div(st.LockedFunds, big.NewInt(2)) + rt.ReplaceState(st) + info := actor.getInfo(rt) + + rt.SetEpoch(precommitEpoch + miner.MaxSealDuration[info.SealProofType] - 1) + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(actor.nextSectorNo), proveCommitConf{}) + }) + rt.Reset() + + // succeeds when locked fund satisfy initial pledge requirement + st.LockedFunds = st.InitialPledgeRequirement + rt.ReplaceState(st) + actor.proveCommitSectorAndConfirm(rt, precommit, precommitEpoch, makeProveCommit(actor.nextSectorNo), proveCommitConf{}) + }) + + t.Run ("drop invalid prove commit while processing valid one", func (t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + // make two precommits + expiration := 100*miner.WPoStProvingPeriod + periodOffset - 1 + precommitEpoch := rt.Epoch() + 1 + rt.SetEpoch(precommitEpoch) + precommitA := makePreCommit(actor.nextSectorNo, rt.Epoch()-1, expiration, nil) + actor.preCommitSector(rt, precommitA) + sectorNoA := actor.nextSectorNo + actor.nextSectorNo++ + precommitB := makePreCommit(actor.nextSectorNo, rt.Epoch()-1, expiration, nil) + actor.preCommitSector(rt, precommitB) + sectorNoB := actor.nextSectorNo + + // handle both prove commits in the same epoch + info := actor.getInfo(rt) + rt.SetEpoch(precommitEpoch + miner.MaxSealDuration[info.SealProofType] - 1) + + actor.proveCommitSector(rt, precommitA, precommitEpoch, makeProveCommit(sectorNoA)) + actor.proveCommitSector(rt, precommitB, precommitEpoch, makeProveCommit(sectorNoB)) + + conf := proveCommitConf { + verifyDealsExit: map[abi.SectorNumber]exitcode.ExitCode{ + sectorNoA: exitcode.ErrIllegalArgument, + }, + } + actor.confirmSectorProofsValid(rt, conf, precommitEpoch, precommitA, precommitB) + }) +} + +func TestProvingPeriodCron(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + builder := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()) + + t.Run("empty periods", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + st := getState(rt) + assert.Equal(t, periodOffset, st.ProvingPeriodStart) + + // First cron invocation just before the first proving period starts. + rt.SetEpoch(periodOffset - 1) + secondCronEpoch := periodOffset + miner.WPoStProvingPeriod - 1 + actor.onProvingPeriodCron(rt, secondCronEpoch, false, nil, nil) + // The proving period start isn't changed, because the period hadn't started yet. + st = getState(rt) + assert.Equal(t, periodOffset, st.ProvingPeriodStart) + + rt.SetEpoch(secondCronEpoch) + actor.onProvingPeriodCron(rt, periodOffset+2*miner.WPoStProvingPeriod-1, false, nil, nil) + // Proving period moves forward + st = getState(rt) + assert.Equal(t, periodOffset+miner.WPoStProvingPeriod, st.ProvingPeriodStart) + }) + + t.Run("first period gets randomness from previous epoch", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + st := getState(rt) + + sectorInfo := actor.commitAndProveSectors(rt, 1, 100, nil) + + // Flag new sectors to trigger request for randomness + rt.Transaction(st, func() interface{} { + st.NewSectors.Set(uint64(sectorInfo[0].SectorNumber)) + return nil + }) + + // First cron invocation just before the first proving period starts + // requires randomness come from current epoch minus lookback + rt.SetEpoch(periodOffset - 1) + secondCronEpoch := periodOffset + miner.WPoStProvingPeriod - 1 + actor.onProvingPeriodCron(rt, secondCronEpoch, true, nil, nil) + + // cron invocation after the proving period starts, requires randomness come from end of proving period + rt.SetEpoch(periodOffset) + actor.advanceProvingPeriodWithoutFaults(rt) + + // triggers a new request for randomness + rt.Transaction(st, func() interface{} { + st.NewSectors.Set(uint64(sectorInfo[0].SectorNumber)) + return nil + }) + + thirdCronEpoch := secondCronEpoch + miner.WPoStProvingPeriod + actor.onProvingPeriodCron(rt, thirdCronEpoch, true, nil, nil) + }) + + // TODO: test cron being called one epoch late because the scheduled epoch had no blocks. +} + +func TestDeclareFaults(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + builder := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()) + + t.Run("declare fault pays fee", func(t *testing.T) { + // Get sector into proving state + rt := builder.Build(t) + actor.constructAndVerify(rt) + precommits := actor.commitAndProveSectors(rt, 1, 100, nil) + + // Skip to end of proving period, cron adds sectors to proving set. + completeProvingPeriod(rt, actor, true, nil, nil) + info := actor.getSector(rt, precommits[0].SectorNumber) + + // Declare the sector as faulted + ss, err := info.SealProof.SectorSize() + require.NoError(t, err) + sectorQAPower := miner.QAPowerForSector(ss, info) + totalQAPower := big.NewInt(1 << 52) + fee := miner.PledgePenaltyForDeclaredFault(actor.epochReward, totalQAPower, sectorQAPower) + + actor.declareFaults(rt, totalQAPower, fee, info) + }) +} + +func TestExtendSectorExpiration(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + precommitEpoch := abi.ChainEpoch(1) + builder := builderForHarness(actor). + WithEpoch(precommitEpoch). + WithBalance(bigBalance, big.Zero()) + + commitSector := func(t *testing.T, rt *mock.Runtime) *miner.SectorOnChainInfo { + actor.constructAndVerify(rt) + sectorInfo := actor.commitAndProveSectors(rt, 1, 100, nil) + return sectorInfo[0] + } + + t.Run("rejects negative extension", func(t *testing.T) { + rt := builder.Build(t) + sector := commitSector(t, rt) + // attempt to shorten epoch + newExpiration := sector.Expiration - abi.ChainEpoch(miner.WPoStProvingPeriod) + params := &miner.ExtendSectorExpirationParams{ + SectorNumber: sector.SectorNumber, + NewExpiration: newExpiration, + } + + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.extendSector(rt, sector, 0, params) + }) + }) + + t.Run("rejects extension to invalid epoch", func(t *testing.T) { + rt := builder.Build(t) + sector := commitSector(t, rt) + + // attempt to extend to an epoch that is not a multiple of the proving period + the commit epoch + extension := 42*miner.WPoStProvingPeriod + 1 + newExpiration := sector.Expiration - abi.ChainEpoch(extension) + params := &miner.ExtendSectorExpirationParams{ + SectorNumber: sector.SectorNumber, + NewExpiration: newExpiration, + } + + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.extendSector(rt, sector, extension, params) + }) + }) + + t.Run("rejects extension too far in future", func(t *testing.T) { + rt := builder.Build(t) + sector := commitSector(t, rt) + + // extend by even proving period after max + rt.SetEpoch(sector.Expiration) + extension := miner.WPoStProvingPeriod * (miner.MaxSectorExpirationExtension/miner.WPoStProvingPeriod + 1) + newExpiration := rt.Epoch() + extension + params := &miner.ExtendSectorExpirationParams{ + SectorNumber: sector.SectorNumber, + NewExpiration: newExpiration, + } + + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.extendSector(rt, sector, extension, params) + }) + }) + + t.Run("rejects extension past max for seal proof", func(t *testing.T) { + rt := builder.Build(t) + sector := commitSector(t, rt) + rt.SetEpoch(sector.Expiration) + + maxLifetime := sector.SealProof.SectorMaximumLifetime() + + // extend sector until just below threshold + extension := miner.WPoStProvingPeriod * (miner.MaxSectorExpirationExtension/miner.WPoStProvingPeriod - 1) + expiration := rt.Epoch() + extension + for ; expiration-sector.Activation < maxLifetime; expiration += extension { + params := &miner.ExtendSectorExpirationParams{ + SectorNumber: sector.SectorNumber, + NewExpiration: expiration, + } + + actor.extendSector(rt, sector, extension, params) + rt.SetEpoch(expiration) + } + + // next extension fails because it extends sector past max lifetime + params := &miner.ExtendSectorExpirationParams{ + SectorNumber: sector.SectorNumber, + NewExpiration: expiration, + } + + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + actor.extendSector(rt, sector, extension, params) + }) + }) + + t.Run("updates expiration with valid params", func(t *testing.T) { + rt := builder.Build(t) + oldSector := commitSector(t, rt) + + extension := 42 * miner.WPoStProvingPeriod + newExpiration := oldSector.Expiration + extension + params := &miner.ExtendSectorExpirationParams{ + SectorNumber: oldSector.SectorNumber, + NewExpiration: newExpiration, + } + + actor.extendSector(rt, oldSector, extension, params) + + // assert sector expiration is set to the new value + st := getState(rt) + newSector := actor.getSector(rt, oldSector.SectorNumber) + assert.Equal(t, newExpiration, newSector.Expiration) + + // assert that an expiration exists at the target epoch + expirations, err := st.GetSectorExpirations(rt.AdtStore(), newExpiration) + require.NoError(t, err) + exists, err := expirations.IsSet(uint64(newSector.SectorNumber)) + require.NoError(t, err) + assert.True(t, exists) + + // assert that the expiration has been removed from the old epoch + expirations, err = st.GetSectorExpirations(rt.AdtStore(), oldSector.Expiration) + require.NoError(t, err) + exists, err = expirations.IsSet(uint64(newSector.SectorNumber)) + require.NoError(t, err) + assert.False(t, exists) + }) +} + +func TestTerminateSectors(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + builder := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()) + + commitSector := func(t *testing.T, rt *mock.Runtime) *miner.SectorOnChainInfo { + actor.constructAndVerify(rt) + precommitEpoch := abi.ChainEpoch(1) + rt.SetEpoch(precommitEpoch) + sectorInfo := actor.commitAndProveSectors(rt, 1, 100, nil) + return sectorInfo[0] + } + + t.Run("removes sector with correct accounting", func(t *testing.T) { + rt := builder.Build(t) + sector := commitSector(t, rt) + + { + // Verify that a sector expiration was registered. + st := getState(rt) + expiration, err := st.GetSectorExpirations(rt.AdtStore(), sector.Expiration) + require.NoError(t, err) + expiringSectorNos, err := expiration.All(1) + require.NoError(t, err) + assert.Len(t, expiringSectorNos, 1) + assert.Equal(t, sector.SectorNumber, abi.SectorNumber(expiringSectorNos[0])) + } + + sectorSize, err := sector.SealProof.SectorSize() + require.NoError(t, err) + sectorPower := miner.QAPowerForSector(sectorSize, sector) + sectorAge := rt.Epoch() - sector.Activation + expectedFee := miner.PledgePenaltyForTermination(sector.InitialPledge, sectorAge, actor.epochReward, actor.networkQAPower, sectorPower) + + sectors := bitfield.New() + sectors.Set(uint64(sector.SectorNumber)) + actor.terminateSectors(rt, §ors, expectedFee) + + { + st := getState(rt) + + // expect sector expiration to have been removed + err = st.ForEachSectorExpiration(rt.AdtStore(), func(expiry abi.ChainEpoch, sectors *abi.BitField) error { + assert.Fail(t, "did not expect to find a sector expiration, found expiration at %s", expiry) + return nil + }) + assert.NoError(t, err) + + // expect sector to have been removed + _, found, err := st.GetSector(rt.AdtStore(), sector.SectorNumber) + require.NoError(t, err) + assert.False(t, found) + + // expect pledge requirement to have been decremented + assert.Equal(t, big.Zero(), st.InitialPledgeRequirement) + } + }) +} + +func TestWithdrawBalance(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + builder := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()) + + t.Run("happy path withdraws funds", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + // withdraw 1% of balance + actor.withdrawFunds(rt, big.Mul(big.NewInt(10), big.NewInt(1e18))) + }) + + t.Run("fails if miner is currently undercollateralized", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + // prove one sector to establish collateral and locked funds + actor.commitAndProveSectors(rt, 1, 100, nil) + + // alter lock funds to simulate vesting since last prove + st := getState(rt) + st.LockedFunds = big.Div(st.LockedFunds, big.NewInt(2)) + rt.ReplaceState(st) + + // withdraw 1% of balance + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + actor.withdrawFunds(rt, big.Mul(big.NewInt(10), big.NewInt(1e18))) + }) + }) +} + +func TestReportConsensusFault(t *testing.T) { + periodOffset := abi.ChainEpoch(100) + actor := newHarness(t, periodOffset) + builder := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()) + + rt := builder.Build(t) + actor.constructAndVerify(rt) + precommitEpoch := abi.ChainEpoch(1) + rt.SetEpoch(precommitEpoch) + dealIDs := [][]abi.DealID{{1, 2}, {3, 4}} + sectorInfo := actor.commitAndProveSectors(rt, 2, 10, dealIDs) + _ = sectorInfo + + params := &miner.ReportConsensusFaultParams{ + BlockHeader1: nil, + BlockHeader2: nil, + BlockHeaderExtra: nil, + } + + // miner should send a single call to terminate the deals for all its sectors + allDeals := []abi.DealID{} + for _, ids := range dealIDs { + allDeals = append(allDeals, ids...) + } + actor.reportConsensusFault(rt, addr.TestAddress, params, allDeals) +} +func TestAddLockedFund(t *testing.T) { + + periodOffset := abi.ChainEpoch(1808) + actor := newHarness(t, periodOffset) + + builder := builderForHarness(actor). + WithBalance(bigBalance, big.Zero()) + + t.Run("funds vest", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + st := getState(rt) + store := rt.AdtStore() + + // Nothing vesting to start + vestingFunds, err := adt.AsArray(store, st.VestingFunds) + require.NoError(t, err) + assert.Equal(t, uint64(0), vestingFunds.Length()) + assert.Equal(t, big.Zero(), st.LockedFunds) + + // Lock some funds with AddLockedFund + amt := abi.NewTokenAmount(600_000) + actor.addLockedFund(rt, amt) + st = getState(rt) + newVestingFunds, err := adt.AsArray(store, st.VestingFunds) + require.NoError(t, err) + require.Equal(t, uint64(7), newVestingFunds.Length()) // 1 day steps over 1 week + + // Vested FIL pays out on epochs with expected offset + lockedEntry := abi.NewTokenAmount(0) + expectedOffset := periodOffset % miner.PledgeVestingSpec.Quantization + err = newVestingFunds.ForEach(&lockedEntry, func(k int64) error { + assert.Equal(t, int64(expectedOffset), k%int64(miner.PledgeVestingSpec.Quantization)) + return nil + }) + require.NoError(t, err) + assert.Equal(t, amt, st.LockedFunds) + + }) + +} + +type actorHarness struct { + a miner.Actor + t testing.TB + + receiver addr.Address // The miner actor's own address + owner addr.Address + worker addr.Address + key addr.Address + + sealProofType abi.RegisteredSealProof + sectorSize abi.SectorSize + partitionSize uint64 + periodOffset abi.ChainEpoch + nextSectorNo abi.SectorNumber + + epochReward abi.TokenAmount + networkPledge abi.TokenAmount + networkRawPower abi.StoragePower + networkQAPower abi.StoragePower +} + +func newHarness(t testing.TB, provingPeriodOffset abi.ChainEpoch) *actorHarness { + sealProofType := abi.RegisteredSealProof_StackedDrg2KiBV1 + sectorSize, err := sealProofType.SectorSize() + require.NoError(t, err) + partitionSectors, err := sealProofType.WindowPoStPartitionSectors() + require.NoError(t, err) + owner := tutil.NewIDAddr(t, 100) + worker := tutil.NewIDAddr(t, 101) + workerKey := tutil.NewBLSAddr(t, 0) + receiver := tutil.NewIDAddr(t, 1000) + reward := big.Mul(big.NewIntUnsigned(100), big.NewIntUnsigned(1e18)) + return &actorHarness{ + t: t, + receiver: receiver, + owner: owner, + worker: worker, + key: workerKey, + + sealProofType: sealProofType, + sectorSize: sectorSize, + partitionSize: partitionSectors, + periodOffset: provingPeriodOffset, + nextSectorNo: 100, + + epochReward: reward, + networkPledge: big.Mul(reward, big.NewIntUnsigned(1000)), + networkRawPower: abi.NewStoragePower(1 << 50), + networkQAPower: abi.NewStoragePower(1 << 50), + } +} + +func (h *actorHarness) constructAndVerify(rt *mock.Runtime) { + params := miner.ConstructorParams{ + OwnerAddr: h.owner, + WorkerAddr: h.worker, + SealProofType: h.sealProofType, + PeerId: testPid, + } + + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + // Fetch worker pubkey. + rt.ExpectSend(h.worker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &h.key, exitcode.Ok) + // Register proving period cron. + nextProvingPeriodEnd := h.periodOffset - 1 + for nextProvingPeriodEnd < rt.Epoch() { + nextProvingPeriodEnd += miner.WPoStProvingPeriod + } + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.EnrollCronEvent, + makeProvingPeriodCronEventParams(h.t, nextProvingPeriodEnd), big.Zero(), nil, exitcode.Ok) + rt.SetCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + ret := rt.Call(h.a.Constructor, ¶ms) + assert.Nil(h.t, ret) + rt.Verify() +} + +// +// State access helpers +// + +func (h *actorHarness) deadline(rt *mock.Runtime) *miner.DeadlineInfo { + st := getState(rt) + return st.DeadlineInfo(rt.Epoch()) +} + +func (h *actorHarness) getPreCommit(rt *mock.Runtime, sno abi.SectorNumber) *miner.SectorPreCommitOnChainInfo { + st := getState(rt) + pc, found, err := st.GetPrecommittedSector(rt.AdtStore(), sno) + require.NoError(h.t, err) + require.True(h.t, found) + return pc +} + +func (h *actorHarness) getSector(rt *mock.Runtime, sno abi.SectorNumber) *miner.SectorOnChainInfo { + st := getState(rt) + sector, found, err := st.GetSector(rt.AdtStore(), sno) + require.NoError(h.t, err) + require.True(h.t, found) + return sector +} + +func (h *actorHarness) getInfo(rt *mock.Runtime) *miner.MinerInfo { + var st miner.State + rt.GetState(&st) + info, err := st.GetInfo(adt.AsStore(rt)) + require.NoError(h.t, err) + return info +} + +// Collects all sector infos into a map. +func (h *actorHarness) collectSectors(rt *mock.Runtime) map[abi.SectorNumber]*miner.SectorOnChainInfo { + sectors := map[abi.SectorNumber]*miner.SectorOnChainInfo{} + st := getState(rt) + _ = st.ForEachSector(rt.AdtStore(), func(info *miner.SectorOnChainInfo) { + sector := *info + sectors[info.SectorNumber] = §or + }) + return sectors +} + +// Collects the sector numbers of all sectors assigned to a deadline. +func (h *actorHarness) collectProvingSet(rt *mock.Runtime) map[uint64]struct{} { + pset := map[uint64]struct{}{} + st := getState(rt) + deadlines, err := st.LoadDeadlines(rt.AdtStore()) + require.NoError(h.t, err) + for _, d := range deadlines.Due { + _ = d.ForEach(func(n uint64) error { + pset[n] = struct{}{} + return nil + }) + } + return pset +} + +// Collects all expirations into a map. +func (h *actorHarness) collectExpirations(rt *mock.Runtime) map[abi.ChainEpoch][]uint64 { + expirations := map[abi.ChainEpoch][]uint64{} + st := getState(rt) + _ = st.ForEachSectorExpiration(rt.AdtStore(), func(expiry abi.ChainEpoch, sectors *abi.BitField) error { + expanded, err := sectors.All(miner.SectorsMax) + require.NoError(h.t, err) + expirations[expiry] = expanded + return nil + }) + return expirations +} + +// +// Actor method calls +// + +func (h *actorHarness) controlAddresses(rt *mock.Runtime) (owner, worker addr.Address) { + rt.ExpectValidateCallerAny() + ret := rt.Call(h.a.ControlAddresses, nil).(*miner.GetControlAddressesReturn) + require.NotNil(h.t, ret) + rt.Verify() + return ret.Owner, ret.Worker +} + +func (h *actorHarness) preCommitSector(rt *mock.Runtime, params *miner.SectorPreCommitInfo) *miner.SectorPreCommitOnChainInfo { + + rt.SetCaller(h.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(h.worker) + + { + pwrTotal := &power.CurrentTotalPowerReturn{ + RawBytePower: h.networkRawPower, + QualityAdjPower: h.networkQAPower, + PledgeCollateral: h.networkPledge, + } + expectQueryNetworkInfo(rt, pwrTotal, h.epochReward) + } + { + sectorSize, err := params.SealProof.SectorSize() + require.NoError(h.t, err) + + vdParams := market.VerifyDealsForActivationParams{ + DealIDs: params.DealIDs, + SectorStart: rt.Epoch(), + SectorExpiry: params.Expiration, + } + + vdReturn := market.VerifyDealsForActivationReturn{ + DealWeight: big.NewInt(int64(sectorSize / 2)), + VerifiedDealWeight: big.NewInt(int64(sectorSize / 2)), + } + rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.VerifyDealsForActivation, &vdParams, big.Zero(), &vdReturn, exitcode.Ok) + } + { + eventPayload := miner.CronEventPayload{ + EventType: miner.CronEventPreCommitExpiry, + Sectors: bitfield.NewFromSet([]uint64{uint64(params.SectorNumber)}), + } + buf := bytes.Buffer{} + err := eventPayload.MarshalCBOR(&buf) + require.NoError(h.t, err) + cronParams := power.EnrollCronEventParams{ + EventEpoch: rt.Epoch() + miner.MaxSealDuration[params.SealProof] + 1, + Payload: buf.Bytes(), + } + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.EnrollCronEvent, &cronParams, big.Zero(), nil, exitcode.Ok) + } + + rt.Call(h.a.PreCommitSector, params) + rt.Verify() + return h.getPreCommit(rt, params.SectorNumber) +} + +// Options for proveCommitSector behaviour. +// Default zero values should let everything be ok. +type proveCommitConf struct { + verifyDealsExit map[abi.SectorNumber]exitcode.ExitCode +} + +func (h *actorHarness) proveCommitSector(rt *mock.Runtime, precommit *miner.SectorPreCommitInfo, precommitEpoch abi.ChainEpoch, + params *miner.ProveCommitSectorParams) { + commd := cbg.CborCid(tutil.MakeCID("commd")) + sealRand := abi.SealRandomness([]byte{1, 2, 3, 4}) + sealIntRand := abi.InteractiveSealRandomness([]byte{5, 6, 7, 8}) + interactiveEpoch := precommitEpoch + miner.PreCommitChallengeDelay + + // Prepare for and receive call to ProveCommitSector + { + cdcParams := market.ComputeDataCommitmentParams{ + DealIDs: precommit.DealIDs, + SectorType: precommit.SealProof, + } + rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.ComputeDataCommitment, &cdcParams, big.Zero(), &commd, exitcode.Ok) + } + { + var buf bytes.Buffer + err := rt.Receiver().MarshalCBOR(&buf) + require.NoError(h.t, err) + rt.ExpectGetRandomness(crypto.DomainSeparationTag_SealRandomness, precommit.SealRandEpoch, buf.Bytes(), abi.Randomness(sealRand)) + rt.ExpectGetRandomness(crypto.DomainSeparationTag_InteractiveSealChallengeSeed, interactiveEpoch, buf.Bytes(), abi.Randomness(sealIntRand)) + } + { + actorId, err := addr.IDFromAddress(h.receiver) + require.NoError(h.t, err) + seal := abi.SealVerifyInfo{ + SectorID: abi.SectorID{ + Miner: abi.ActorID(actorId), + Number: precommit.SectorNumber, + }, + SealedCID: precommit.SealedCID, + SealProof: precommit.SealProof, + Proof: params.Proof, + DealIDs: precommit.DealIDs, + Randomness: sealRand, + InteractiveRandomness: sealIntRand, + UnsealedCID: cid.Cid(commd), + } + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.SubmitPoRepForBulkVerify, &seal, abi.NewTokenAmount(0), nil, exitcode.Ok) + } + rt.SetCaller(h.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAny() + rt.Call(h.a.ProveCommitSector, params) + rt.Verify() +} + +func (h *actorHarness) confirmSectorProofsValid(rt *mock.Runtime, conf proveCommitConf, precommitEpoch abi.ChainEpoch, precommits ...*miner.SectorPreCommitInfo) { + // Prepare for and receive call to ConfirmSectorProofsValid. + var validPrecommits []*miner.SectorPreCommitInfo + var allSectorNumbers []abi.SectorNumber + for _, precommit := range precommits { + allSectorNumbers = append(allSectorNumbers, precommit.SectorNumber) + + vdParams := market.ActivateDealsParams{ + DealIDs: precommit.DealIDs, + SectorExpiry: precommit.Expiration, + } + exit, found := conf.verifyDealsExit[precommit.SectorNumber] + if !found { + exit = exitcode.Ok + validPrecommits = append(validPrecommits, precommit) + } + rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.ActivateDeals, &vdParams, big.Zero(), nil, exit) + } + + // expected pledge is the sum of precommit deposits + if len(validPrecommits) > 0 { + expectPledge := big.Zero() + + expectQAPower := big.Zero() + expectRawPower := big.Zero() + for _, precommit := range validPrecommits { + precommitOnChain := h.getPreCommit(rt, precommit.SectorNumber) + + qaPowerDelta := miner.QAPowerForWeight(h.sectorSize, precommit.Expiration-precommitEpoch, precommitOnChain.DealWeight, precommitOnChain.VerifiedDealWeight) + expectQAPower = big.Add(expectQAPower, qaPowerDelta) + expectRawPower = big.Add(expectRawPower, big.NewIntUnsigned(uint64(h.sectorSize))) + + expectPledge = big.Add(expectPledge, precommitOnChain.PreCommitDeposit) + } + + pcParams := power.UpdateClaimedPowerParams{ + RawByteDelta: expectRawPower, + QualityAdjustedDelta: expectQAPower, + } + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, &pcParams, big.Zero(), nil, exitcode.Ok) + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &expectPledge, big.Zero(), nil, exitcode.Ok) + } + + rt.SetCaller(builtin.StoragePowerActorAddr, builtin.StoragePowerActorCodeID) + rt.ExpectValidateCallerAddr(builtin.StoragePowerActorAddr) + rt.Call(h.a.ConfirmSectorProofsValid, &builtin.ConfirmSectorProofsParams{Sectors: allSectorNumbers}) + rt.Verify() +} + +func (h *actorHarness) proveCommitSectorAndConfirm(rt *mock.Runtime, precommit *miner.SectorPreCommitInfo, precommitEpoch abi.ChainEpoch, + params *miner.ProveCommitSectorParams, conf proveCommitConf) *miner.SectorOnChainInfo { + h.proveCommitSector(rt, precommit, precommitEpoch, params) + h.confirmSectorProofsValid(rt, conf, precommitEpoch, precommit) + + newSector := h.getSector(rt, params.SectorNumber) + return newSector +} + +// Pre-commits and then proves a number of sectors. +// The sectors will expire at the end of lifetimePeriods proving periods after now. +// The runtime epoch will be moved forward to the epoch of commitment proofs. +func (h *actorHarness) commitAndProveSectors(rt *mock.Runtime, n int, lifetimePeriods uint64, dealIDs [][]abi.DealID) []*miner.SectorOnChainInfo { + precommitEpoch := rt.Epoch() + deadline := h.deadline(rt) + expiration := deadline.PeriodEnd() + abi.ChainEpoch(lifetimePeriods)*miner.WPoStProvingPeriod + + // Precommit + precommits := make([]*miner.SectorPreCommitInfo, n) + for i := 0; i < n; i++ { + sectorNo := h.nextSectorNo + var sectorDealIDs []abi.DealID + if dealIDs != nil { + sectorDealIDs = dealIDs[i] + } + precommit := makePreCommit(sectorNo, precommitEpoch-1, expiration, sectorDealIDs) + h.preCommitSector(rt, precommit) + precommits[i] = precommit + h.nextSectorNo++ + } + + rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay + 1) + + // Ensure this this doesn't cross a proving period boundary, else the expected cron call won't be + // invoked, which might mess things up later. + deadline = h.deadline(rt) + require.True(h.t, !deadline.PeriodElapsed()) + + info := []*miner.SectorOnChainInfo{} + for _, pc := range precommits { + sector := h.proveCommitSectorAndConfirm(rt, pc, precommitEpoch, makeProveCommit(pc.SectorNumber), proveCommitConf{}) + info = append(info, sector) + } + rt.Reset() + return info +} + +func (h *actorHarness) advancePastProvingPeriodWithCron(rt *mock.Runtime) { + st := getState(rt) + deadline := st.DeadlineInfo(rt.Epoch()) + rt.SetEpoch(deadline.PeriodEnd()) + nextCron := deadline.NextPeriodStart() + miner.WPoStProvingPeriod - 1 + h.onProvingPeriodCron(rt, nextCron, true, nil, nil) + rt.SetEpoch(deadline.NextPeriodStart()) +} + +type poStConfig struct { + skipped *bitfield.BitField + expectedRawPowerDelta abi.StoragePower + expectedQAPowerDelta abi.StoragePower + expectedPenalty abi.TokenAmount +} + +func (h *actorHarness) submitWindowPoSt(rt *mock.Runtime, deadline *miner.DeadlineInfo, partitions []uint64, infos []*miner.SectorOnChainInfo, poStCfg *poStConfig) { + rt.SetCaller(h.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(h.worker) + + rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), &h.epochReward, exitcode.Ok) + + pwrTotal := power.CurrentTotalPowerReturn{ + QualityAdjPower: h.networkQAPower, + } + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.CurrentTotalPower, nil, big.Zero(), &pwrTotal, exitcode.Ok) + + var registeredPoStProof, err = abi.RegisteredSealProof_StackedDrg2KiBV1.RegisteredWindowPoStProof() + require.NoError(h.t, err) + + proofs := make([]abi.PoStProof, 1) // Number of proofs doesn't depend on partition count + for i := range proofs { + proofs[i].PoStProof = registeredPoStProof + proofs[i].ProofBytes = []byte(fmt.Sprintf("proof%d", i)) + } + challengeRand := abi.SealRandomness([]byte{10, 11, 12, 13}) + + { + var buf bytes.Buffer + err := rt.Receiver().MarshalCBOR(&buf) + require.NoError(h.t, err) + + rt.ExpectGetRandomness(crypto.DomainSeparationTag_WindowedPoStChallengeSeed, deadline.Challenge, buf.Bytes(), abi.Randomness(challengeRand)) + } + { + // find the first non-faulty sector in poSt to replace all faulty sectors. + var goodInfo *miner.SectorOnChainInfo + if poStCfg != nil { + for _, ci := range infos { + contains, err := poStCfg.skipped.IsSet(uint64(ci.SectorNumber)) + require.NoError(h.t, err) + if !contains { + goodInfo = ci + break + } + } + } + actorId, err := addr.IDFromAddress(h.receiver) + require.NoError(h.t, err) + + proofInfos := make([]abi.SectorInfo, len(infos)) + for i, ci := range infos { + si := ci + if poStCfg != nil { + contains, err := poStCfg.skipped.IsSet(uint64(ci.SectorNumber)) + require.NoError(h.t, err) + if contains { + si = goodInfo + } + } + proofInfos[i] = abi.SectorInfo{ + SealProof: si.SealProof, + SectorNumber: si.SectorNumber, + SealedCID: si.SealedCID, + } + } + + vi := abi.WindowPoStVerifyInfo{ + Randomness: abi.PoStRandomness(challengeRand), + Proofs: proofs, + ChallengedSectors: proofInfos, + Prover: abi.ActorID(actorId), + } + rt.ExpectVerifyPoSt(vi, nil) + } + skipped := bitfield.New() + if poStCfg != nil { + // expect power update + if !poStCfg.expectedRawPowerDelta.IsZero() || !poStCfg.expectedQAPowerDelta.IsZero() { + claim := &power.UpdateClaimedPowerParams{ + RawByteDelta: poStCfg.expectedRawPowerDelta, + QualityAdjustedDelta: poStCfg.expectedQAPowerDelta, + } + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, claim, abi.NewTokenAmount(0), + nil, exitcode.Ok) + } + if !poStCfg.expectedPenalty.IsZero() { + rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, poStCfg.expectedPenalty, nil, exitcode.Ok) + } + pledgeDelta := poStCfg.expectedPenalty.Neg() + if !pledgeDelta.IsZero() { + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, + abi.NewTokenAmount(0), nil, exitcode.Ok) + } + skipped = *poStCfg.skipped + } + + params := miner.SubmitWindowedPoStParams{ + Deadline: deadline.Index, + Partitions: partitions, + Proofs: proofs, + Skipped: skipped, + } + + rt.Call(h.a.SubmitWindowedPoSt, ¶ms) + rt.Verify() +} + +func (h *actorHarness) computePartitions(rt *mock.Runtime, deadlines *miner.Deadlines, deadlineIdx uint64) ([]*miner.SectorOnChainInfo, []uint64) { + st := getState(rt) + firstPartIdx, sectorCount, err := miner.PartitionsForDeadline(deadlines, h.partitionSize, deadlineIdx) + require.NoError(h.t, err) + if sectorCount == 0 { + return nil, nil + } + partitionCount, _, err := miner.DeadlineCount(deadlines, h.partitionSize, deadlineIdx) + require.NoError(h.t, err) + + partitions := make([]uint64, partitionCount) + for i := uint64(0); i < partitionCount; i++ { + partitions[i] = firstPartIdx + i + } + + partitionsSectors, err := miner.ComputePartitionsSectors(deadlines, h.partitionSize, deadlineIdx, partitions) + require.NoError(h.t, err) + provenSectors, err := bitfield.MultiMerge(partitionsSectors...) + require.NoError(h.t, err) + infos, _, err := st.LoadSectorInfosForProof(rt.AdtStore(), provenSectors) + require.NoError(h.t, err) + + return infos, partitions +} + +func (h *actorHarness) declareFaults(rt *mock.Runtime, totalQAPower abi.StoragePower, fee abi.TokenAmount, faultSectorInfos ...*miner.SectorOnChainInfo) { + rt.SetCaller(h.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(h.worker) + + ss, err := faultSectorInfos[0].SealProof.SectorSize() + require.NoError(h.t, err) + expectedRawDelta, expectedQADelta := powerForSectors(ss, faultSectorInfos) + expectedRawDelta = expectedRawDelta.Neg() + expectedQADelta = expectedQADelta.Neg() + + expectedTotalPower := &power.CurrentTotalPowerReturn{ + QualityAdjPower: totalQAPower, + } + + expectQueryNetworkInfo(rt, expectedTotalPower, h.epochReward) + + // expect power update + claim := &power.UpdateClaimedPowerParams{ + RawByteDelta: expectedRawDelta, + QualityAdjustedDelta: expectedQADelta, + } + rt.ExpectSend( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.UpdateClaimedPower, + claim, + abi.NewTokenAmount(0), + nil, + exitcode.Ok, + ) + + // expect fee + rt.ExpectSend( + builtin.BurntFundsActorAddr, + builtin.MethodSend, + nil, + fee, + nil, + exitcode.Ok, + ) + + // expect pledge update + pledgeDelta := fee.Neg() + rt.ExpectSend( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.UpdatePledgeTotal, + &pledgeDelta, + abi.NewTokenAmount(0), + nil, + exitcode.Ok, + ) + + // Calculate params from faulted sector infos + st := getState(rt) + params := makeFaultParamsFromFaultingSectors(h.t, st, rt.AdtStore(), faultSectorInfos) + rt.Call(h.a.DeclareFaults, params) + rt.Verify() +} + +func (h *actorHarness) advanceProvingPeriodWithoutFaults(rt *mock.Runtime) { + + // Iterate deadlines in the proving period, setting epoch to the first in each deadline. + // Submit a window post for all partitions due at each deadline when necessary. + deadline := h.deadline(rt) + for !deadline.PeriodElapsed() { + st := getState(rt) + store := rt.AdtStore() + deadlines, err := st.LoadDeadlines(store) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not load deadlines") + + firstPartIdx, sectorCount, err := miner.PartitionsForDeadline(deadlines, h.partitionSize, deadline.Index) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not get partitions for deadline") + if sectorCount != 0 { + partitionCount, _, err := miner.DeadlineCount(deadlines, h.partitionSize, deadline.Index) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not get partition count") + + partitions := make([]uint64, partitionCount) + for i := uint64(0); i < partitionCount; i++ { + partitions[i] = firstPartIdx + i + } + + partitionsSectors, err := miner.ComputePartitionsSectors(deadlines, h.partitionSize, deadline.Index, partitions) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not compute partitions") + provenSectors, err := bitfield.MultiMerge(partitionsSectors...) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not get proven sectors") + infos, _, err := st.LoadSectorInfosForProof(store, provenSectors) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not load sector info for proof") + + h.submitWindowPoSt(rt, deadline, partitions, infos, nil) + } + + rt.SetEpoch(deadline.Close + 1) + deadline = h.deadline(rt) + } + // Rewind one epoch to leave the current epoch as the penultimate one in the proving period, + // ready for proving-period cron. + rt.SetEpoch(rt.Epoch() - 1) +} + +func (h *actorHarness) extendSector(rt *mock.Runtime, sector *miner.SectorOnChainInfo, extension abi.ChainEpoch, params *miner.ExtendSectorExpirationParams) { + rt.SetCaller(h.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(h.worker) + + newSector := *sector + newSector.Expiration += extension + qaDelta := big.Sub(miner.QAPowerForSector(h.sectorSize, &newSector), miner.QAPowerForSector(h.sectorSize, sector)) + + rt.ExpectSend(builtin.StoragePowerActorAddr, + builtin.MethodsPower.UpdateClaimedPower, + &power.UpdateClaimedPowerParams{ + RawByteDelta: big.Zero(), + QualityAdjustedDelta: qaDelta, + }, + abi.NewTokenAmount(0), + nil, + exitcode.Ok, + ) + rt.Call(h.a.ExtendSectorExpiration, params) + rt.Verify() +} + +func (h *actorHarness) terminateSectors(rt *mock.Runtime, sectors *abi.BitField, expectedFee abi.TokenAmount) { + rt.SetCaller(h.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(h.worker) + + dealIDs := []abi.DealID{} + sectorInfos := []*miner.SectorOnChainInfo{} + err := sectors.ForEach(func(secNum uint64) error { + sector := h.getSector(rt, abi.SectorNumber(secNum)) + dealIDs = append(dealIDs, sector.DealIDs...) + + sectorInfos = append(sectorInfos, sector) + return nil + }) + require.NoError(h.t, err) + + { + expectQueryNetworkInfo(rt, &power.CurrentTotalPowerReturn{ + RawBytePower: h.networkRawPower, + QualityAdjPower: h.networkQAPower, + PledgeCollateral: h.networkPledge, + }, h.epochReward) + } + + { + rawPower, qaPower := miner.PowerForSectors(h.sectorSize, sectorInfos) + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, &power.UpdateClaimedPowerParams{ + RawByteDelta: rawPower.Neg(), + QualityAdjustedDelta: qaPower.Neg(), + }, abi.NewTokenAmount(0), nil, exitcode.Ok) + } + if big.Zero().LessThan(expectedFee) { + rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectedFee, nil, exitcode.Ok) + pledgeDelta := expectedFee.Neg() + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero(), nil, exitcode.Ok) + } + + params := &miner.TerminateSectorsParams{Sectors: sectors} + rt.Call(h.a.TerminateSectors, params) + rt.Verify() +} + +func (h *actorHarness) reportConsensusFault(rt *mock.Runtime, from addr.Address, params *miner.ReportConsensusFaultParams, dealIDs []abi.DealID) { + rt.SetCaller(from, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) + + rt.ExpectVerifyConsensusFault(params.BlockHeader1, params.BlockHeader2, params.BlockHeaderExtra, &runtime.ConsensusFault{ + Target: h.receiver, + Epoch: rt.Epoch() - 1, + Type: runtime.ConsensusFaultDoubleForkMining, + }, nil) + + // slash reward + reward := miner.RewardForConsensusSlashReport(1, rt.Balance()) + rt.ExpectSend(from, builtin.MethodSend, nil, reward, nil, exitcode.Ok) + + // power termination + lockedFunds := getState(rt).LockedFunds + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.OnConsensusFault, &lockedFunds, abi.NewTokenAmount(0), nil, exitcode.Ok) + + // expect every deal to be closed out + rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.OnMinerSectorsTerminate, &market.OnMinerSectorsTerminateParams{ + DealIDs: dealIDs, + }, abi.NewTokenAmount(0), nil, exitcode.Ok) + + // expect actor to be deleted + rt.ExpectDeleteActor(builtin.BurntFundsActorAddr) + + rt.Call(h.a.ReportConsensusFault, params) + rt.Verify() +} + +func (h *actorHarness) addLockedFund(rt *mock.Runtime, amt abi.TokenAmount) { + rt.SetCaller(h.worker, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(h.worker, h.owner, builtin.RewardActorAddr) + // expect pledge update + rt.ExpectSend( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.UpdatePledgeTotal, + &amt, + abi.NewTokenAmount(0), + nil, + exitcode.Ok, + ) + + rt.Call(h.a.AddLockedFund, &amt) + rt.Verify() +} + +func (h *actorHarness) onProvingPeriodCron(rt *mock.Runtime, expectedEnrollment abi.ChainEpoch, newSectors bool, + faultySectors []*miner.SectorOnChainInfo, expireSectors []*miner.SectorOnChainInfo) { + rt.ExpectValidateCallerAddr(builtin.StoragePowerActorAddr) + + // Preamble + rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), &h.epochReward, exitcode.Ok) + networkPower := big.NewIntUnsigned(1 << 50) + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.CurrentTotalPower, nil, big.Zero(), + &power.CurrentTotalPowerReturn{ + RawBytePower: networkPower, + QualityAdjPower: networkPower, + PledgeCollateral: h.networkPledge, + }, + exitcode.Ok) + + { + // Detect and penalise missing faults (not yet implemented) + } + + if len(expireSectors) > 0 { + // Expire sectors + rawPower, qaPower := powerForSectors(h.sectorSize, expireSectors) + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, &power.UpdateClaimedPowerParams{ + RawByteDelta: rawPower.Neg(), + QualityAdjustedDelta: qaPower.Neg(), + }, abi.NewTokenAmount(0), nil, exitcode.Ok) + } + + if len(faultySectors) > 0 { + // Process ongoing faulty sectors (not yet implemented) + _, qaFault := powerForSectors(h.sectorSize, faultySectors) + fee := miner.PledgePenaltyForDeclaredFault(h.epochReward, networkPower, qaFault) + rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, fee, nil, exitcode.Ok) + + pledgeDelta := fee.Neg() + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero(), nil, exitcode.Ok) + } + + if newSectors { + // Establish new proving sets + randEpoch := rt.Epoch() - miner.ElectionLookback + rt.ExpectGetRandomness(crypto.DomainSeparationTag_WindowedPoStDeadlineAssignment, randEpoch, nil, bytes.Repeat([]byte{0}, 32)) + } + + // Re-enrollment for next period. + rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.EnrollCronEvent, + makeProvingPeriodCronEventParams(h.t, expectedEnrollment), big.Zero(), nil, exitcode.Ok) + + rt.SetCaller(builtin.StoragePowerActorAddr, builtin.StoragePowerActorCodeID) + rt.Call(h.a.OnDeferredCronEvent, &miner.CronEventPayload{ + EventType: miner.CronEventProvingPeriod, + }) + rt.Verify() +} + +func (h *actorHarness) withdrawFunds(rt *mock.Runtime, amount abi.TokenAmount) { + rt.SetCaller(h.owner, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(h.owner) + + rt.ExpectSend(h.owner, builtin.MethodSend, nil, amount, nil, exitcode.Ok) + + rt.Call(h.a.WithdrawBalance, &miner.WithdrawBalanceParams{ + AmountRequested: amount, + }) + rt.Verify() +} + +// +// Higher-level orchestration +// + +// Completes a proving period by moving the epoch forward to the penultimate one, calling the proving period cron handler, +// and then advancing to the first epoch in the new period. +func completeProvingPeriod(rt *mock.Runtime, h *actorHarness, newSectors bool, faultySectors, expireSectors []*miner.SectorOnChainInfo) { + deadline := h.deadline(rt) + rt.SetEpoch(deadline.PeriodEnd()) + nextCron := deadline.NextPeriodStart() + miner.WPoStProvingPeriod - 1 + h.onProvingPeriodCron(rt, nextCron, newSectors, faultySectors, expireSectors) + rt.SetEpoch(deadline.NextPeriodStart()) +} + +// +// Construction helpers, etc +// + +func builderForHarness(actor *actorHarness) *mock.RuntimeBuilder { + return mock.NewBuilder(context.Background(), actor.receiver). + WithActorType(actor.owner, builtin.AccountActorCodeID). + WithActorType(actor.worker, builtin.AccountActorCodeID). + WithHasher(fixedHasher(uint64(actor.periodOffset))) +} + +func getState(rt *mock.Runtime) *miner.State { + var st miner.State + rt.GetState(&st) + return &st +} + +func makeProvingPeriodCronEventParams(t testing.TB, epoch abi.ChainEpoch) *power.EnrollCronEventParams { + eventPayload := miner.CronEventPayload{EventType: miner.CronEventProvingPeriod} + buf := bytes.Buffer{} + err := eventPayload.MarshalCBOR(&buf) + require.NoError(t, err) + return &power.EnrollCronEventParams{ + EventEpoch: epoch, + Payload: buf.Bytes(), + } +} + +func makePreCommit(sectorNo abi.SectorNumber, challenge, expiration abi.ChainEpoch, dealIDs []abi.DealID) *miner.SectorPreCommitInfo { + return &miner.SectorPreCommitInfo{ + SealProof: abi.RegisteredSealProof_StackedDrg2KiBV1, + SectorNumber: sectorNo, + SealedCID: tutil.MakeCID("commr"), + SealRandEpoch: challenge, + DealIDs: dealIDs, + Expiration: expiration, + } +} + +func makeProveCommit(sectorNo abi.SectorNumber) *miner.ProveCommitSectorParams { + return &miner.ProveCommitSectorParams{ + SectorNumber: sectorNo, + Proof: []byte("proof"), + } +} + +func makeFaultParamsFromFaultingSectors(t testing.TB, st *miner.State, store adt.Store, faultSectorInfos []*miner.SectorOnChainInfo) *miner.DeclareFaultsParams { + deadlines, err := st.LoadDeadlines(store) + require.NoError(t, err) + faultAtDeadline := make(map[uint64][]uint64) + // Find the deadline for each faulty sector which must be provided with the fault declaration + for _, sectorInfo := range faultSectorInfos { + dl, err := miner.FindDeadline(deadlines, sectorInfo.SectorNumber) + require.NoError(t, err) + faultAtDeadline[dl] = append(faultAtDeadline[dl], uint64(sectorInfo.SectorNumber)) + } + params := &miner.DeclareFaultsParams{Faults: []miner.FaultDeclaration{}} + // Group together faults at the same deadline into a bitfield + for dl, sectorNumbers := range faultAtDeadline { + fault := miner.FaultDeclaration{ + Deadline: dl, + Sectors: bitfield.NewFromSet(sectorNumbers), + } + params.Faults = append(params.Faults, fault) + } + return params +} + +func powerForSectors(sectorSize abi.SectorSize, sectors []*miner.SectorOnChainInfo) (rawBytePower, qaPower big.Int) { + rawBytePower = big.Mul(big.NewIntUnsigned(uint64(sectorSize)), big.NewIntUnsigned(uint64(len(sectors)))) + qaPower = big.Zero() + for _, s := range sectors { + qaPower = big.Add(qaPower, miner.QAPowerForSector(sectorSize, s)) + } + return rawBytePower, qaPower +} + +func assertEmptyBitfield(t *testing.T, b *abi.BitField) { + empty, err := b.IsEmpty() + require.NoError(t, err) + assert.True(t, empty) +} + +// Returns a fake hashing function that always arranges the first 8 bytes of the digest to be the binary +// encoding of a target uint64. +func fixedHasher(target uint64) func([]byte) [32]byte { + return func(_ []byte) [32]byte { + var buf bytes.Buffer + err := binary.Write(&buf, binary.BigEndian, target) + if err != nil { + panic(err) + } + var digest [32]byte + copy(digest[:], buf.Bytes()) + return digest + } +} + +func expectQueryNetworkInfo(rt *mock.Runtime, expectedTotalPower *power.CurrentTotalPowerReturn, expectedReward big.Int) { + rt.ExpectSend( + builtin.RewardActorAddr, + builtin.MethodsReward.ThisEpochReward, + nil, + big.Zero(), + &expectedReward, + exitcode.Ok, + ) + + rt.ExpectSend( + builtin.StoragePowerActorAddr, + builtin.MethodsPower.CurrentTotalPower, + nil, + big.Zero(), + expectedTotalPower, + exitcode.Ok, + ) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies.go new file mode 100644 index 0000000000..b470ecf97d --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies.go @@ -0,0 +1,78 @@ +package miner + +import ( + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" +) + +// IP = InitialPledgeFactor * BR(precommit time) +var InitialPledgeFactor = big.NewInt(20) + +// FF = (DeclaredFaultFactorNum / DeclaredFaultFactorDenom) * BR(t) +var DeclaredFaultFactorNum = big.NewInt(214) +var DeclaredFaultFactorDenom = big.NewInt(100) + +// SP = (UndeclaredFaultFactor / DeclaredFaultFactorDenom) * BR(t) +var UndeclaredFaultFactorNum = big.NewInt(5) +var UndeclaredFaultFactorDenom = big.NewInt(1) + +// This is the BR(t) value of the given sector for the current epoch. +// It is the expected reward this sector would pay out over a one day period. +// BR(t) = CurrEpochReward(t) * SectorQualityAdjustedPower * EpochsInDay / TotalNetworkQualityAdjustedPower(t) +func ExpectedDayRewardForPower(epochTargetReward abi.TokenAmount, networkQAPower abi.StoragePower, qaSectorPower abi.StoragePower) abi.TokenAmount { + expectedRewardForProvingPeriod := big.Mul(big.NewInt(builtin.EpochsInDay), epochTargetReward) + return big.Div(big.Mul(qaSectorPower, expectedRewardForProvingPeriod), networkQAPower) +} + +// This is the FF(t) penalty for a sector expected to be in the fault state either because the fault was declared or because +// it has been previously detected by the network. +// FF(t) = DeclaredFaultFactor * BR(t) +func PledgePenaltyForDeclaredFault(epochTargetReward abi.TokenAmount, networkQAPower abi.StoragePower, qaSectorPower abi.StoragePower) abi.TokenAmount { + return big.Div( + big.Mul(DeclaredFaultFactorNum, ExpectedDayRewardForPower(epochTargetReward, networkQAPower, qaSectorPower)), + DeclaredFaultFactorDenom) +} + +// This is the SP(t) penalty for a newly faulty sector that has not been declared. +// SP(t) = UndeclaredFaultFactor * BR(t) +func PledgePenaltyForUndeclaredFault(epochTargetReward abi.TokenAmount, networkQAPower abi.StoragePower, qaSectorPower abi.StoragePower) abi.TokenAmount { + return big.Div( + big.Mul(UndeclaredFaultFactorNum, ExpectedDayRewardForPower(epochTargetReward, networkQAPower, qaSectorPower)), + UndeclaredFaultFactorDenom) +} + +// Penalty to locked pledge collateral for the termination of a sector before scheduled expiry. +// SectorAge is the time between now and the sector's activation. +func PledgePenaltyForTermination(initialPledge abi.TokenAmount, sectorAge abi.ChainEpoch, epochTargetReward abi.TokenAmount, networkQAPower, qaSectorPower abi.StoragePower) abi.TokenAmount { + // max(SP(t), IP + BR(StartEpoch)*min(SectorAgeInDays, 180)) + // where BR(StartEpoch)=IP/InitialPledgeFactor + // and sectorAgeInDays = sectorAge / EpochsInDay + cappedSectorAge := big.NewInt(int64(minEpoch(sectorAge, 180*builtin.EpochsInDay))) + return big.Max( + PledgePenaltyForUndeclaredFault(epochTargetReward, networkQAPower, qaSectorPower), + big.Add( + initialPledge, + big.Div( + big.Mul(initialPledge, cappedSectorAge), + big.Mul(InitialPledgeFactor, big.NewInt(builtin.EpochsInDay))))) +} + +// Computes the pledge requirement for committing new quality-adjusted power to the network, given the current +// total power, total pledge commitment, epoch block reward, and circulating token supply. +// In plain language, the pledge requirement is a multiple of the block reward expected to be earned by the +// newly-committed power, holding the per-epoch block reward constant (though in reality it will change over time). +// The network total pledge and circulating supply parameters are currently unused, but may be included in a +// future calculation. +func InitialPledgeForPower(qaPower abi.StoragePower, networkQAPower abi.StoragePower, networkTotalPledge abi.TokenAmount, epochTargetReward abi.TokenAmount, networkCirculatingSupply abi.TokenAmount) abi.TokenAmount { + // Details here are still subject to change. + // PARAM_FINISH + // https://github.com/filecoin-project/specs-actors/issues/468 + _ = networkCirculatingSupply // TODO: ce use this + _ = networkTotalPledge // TODO: ce use this + + if networkQAPower.IsZero() { + return epochTargetReward + } + return big.Mul(InitialPledgeFactor, ExpectedDayRewardForPower(epochTargetReward, networkQAPower, qaPower)) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies_test.go new file mode 100644 index 0000000000..95d37ff60b --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/monies_test.go @@ -0,0 +1,63 @@ +package miner_test + +import ( + "github.com/filecoin-project/specs-actors/actors/builtin" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" +) + +// Test termination fee +func TestPledgePenaltyForTermination(t *testing.T) { + epochTargetReward := abi.NewTokenAmount(1 << 50) + qaSectorPower := abi.NewStoragePower(1 << 36) + networkQAPower := abi.NewStoragePower(1 << 50) + undeclaredPenalty := miner.PledgePenaltyForUndeclaredFault(epochTargetReward, networkQAPower, qaSectorPower) + + t.Run("when undeclared fault fee exceeds expected reward, returns undeclaraed fault fee", func(t *testing.T) { + // small pledge and means undeclared penalty will be bigger + initialPledge := abi.NewTokenAmount(1 << 10) + sectorAge := 20 * abi.ChainEpoch(builtin.EpochsInDay) + + fee := miner.PledgePenaltyForTermination(initialPledge, sectorAge, epochTargetReward, networkQAPower, qaSectorPower) + + assert.Equal(t, undeclaredPenalty, fee) + }) + + t.Run("when expected reward exceeds undeclared fault fee, returns expected reward", func(t *testing.T) { + // initialPledge equal to undeclaredPenalty guarantees expected reward is greater + initialPledge := undeclaredPenalty + sectorAgeInDays := int64(20) + sectorAge := abi.ChainEpoch(sectorAgeInDays * builtin.EpochsInDay) + + fee := miner.PledgePenaltyForTermination(initialPledge, sectorAge, epochTargetReward, networkQAPower, qaSectorPower) + + // expect fee to be pledge * br * age where br = pledge/initialPledgeFactor + expectedFee := big.Add( + initialPledge, + big.Div( + big.Mul(initialPledge, big.NewInt(sectorAgeInDays)), + miner.InitialPledgeFactor)) + assert.Equal(t, expectedFee, fee) + }) + + t.Run("sector age is capped", func(t *testing.T) { + initialPledge := undeclaredPenalty + sectorAgeInDays := 500 + sectorAge := abi.ChainEpoch(sectorAgeInDays * builtin.EpochsInDay) + + fee := miner.PledgePenaltyForTermination(initialPledge, sectorAge, epochTargetReward, networkQAPower, qaSectorPower) + + // expect fee to be pledge * br * age where br = pledge/initialPledgeFactor + expectedFee := big.Add( + initialPledge, + big.Div( + big.Mul(initialPledge, big.NewInt(180)), + miner.InitialPledgeFactor)) + assert.Equal(t, expectedFee, fee) + }) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/policy.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/policy.go new file mode 100644 index 0000000000..5c76d6f64a --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/miner/policy.go @@ -0,0 +1,196 @@ +package miner + +import ( + "fmt" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + . "github.com/filecoin-project/specs-actors/actors/util" +) + +// The period over which all a miner's active sectors will be challenged. +const WPoStProvingPeriod = abi.ChainEpoch(builtin.EpochsInDay) // 24 hours + +// The duration of a deadline's challenge window, the period before a deadline when the challenge is available. +const WPoStChallengeWindow = abi.ChainEpoch(40 * 60 / builtin.EpochDurationSeconds) // 40 minutes (36 per day) + +// The number of non-overlapping PoSt deadlines in each proving period. +const WPoStPeriodDeadlines = uint64(WPoStProvingPeriod / WPoStChallengeWindow) + +func init() { + // Check that the challenge windows divide the proving period evenly. + if WPoStProvingPeriod%WPoStChallengeWindow != 0 { + panic(fmt.Sprintf("incompatible proving period %d and challenge window %d", WPoStProvingPeriod, WPoStChallengeWindow)) + } + if abi.ChainEpoch(WPoStPeriodDeadlines)*WPoStChallengeWindow != WPoStProvingPeriod { + panic(fmt.Sprintf("incompatible proving period %d and challenge window %d", WPoStProvingPeriod, WPoStChallengeWindow)) + } +} + +// The maximum number of sectors that a miner can have simultaneously active. +// This also bounds the number of faults that can be declared, etc. +// TODO raise this number, carefully +// https://github.com/filecoin-project/specs-actors/issues/470 +const SectorsMax = 32 << 20 // PARAM_FINISH + +// The maximum number of proving partitions a miner can have simultaneously active. +func activePartitionsMax(partitionSectorCount uint64) uint64 { + return (SectorsMax / partitionSectorCount) + WPoStPeriodDeadlines +} + +// The maximum number of partitions that may be submitted in a single message. +// This bounds the size of a list/set of sector numbers that might be instantiated to process a submission. +func windowPoStMessagePartitionsMax(partitionSectorCount uint64) uint64 { + return 100_000 / partitionSectorCount +} + +// The maximum number of new sectors that may be staged by a miner during a single proving period. +const NewSectorsPerPeriodMax = 128 << 10 + +// Epochs after which chain state is final. +const ChainFinality = abi.ChainEpoch(900) + +// List of proof types which can be used when creating new miner actors +var SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ + abi.RegisteredSealProof_StackedDrg32GiBV1: {}, + abi.RegisteredSealProof_StackedDrg64GiBV1: {}, +} + +// Maximum duration to allow for the sealing process for seal algorithms. +// Dependent on algorithm and sector size +var MaxSealDuration = map[abi.RegisteredSealProof]abi.ChainEpoch{ + abi.RegisteredSealProof_StackedDrg32GiBV1: abi.ChainEpoch(10000), // PARAM_FINISH + abi.RegisteredSealProof_StackedDrg2KiBV1: abi.ChainEpoch(10000), + abi.RegisteredSealProof_StackedDrg8MiBV1: abi.ChainEpoch(10000), + abi.RegisteredSealProof_StackedDrg512MiBV1: abi.ChainEpoch(10000), + abi.RegisteredSealProof_StackedDrg64GiBV1: abi.ChainEpoch(10000), +} + +// Number of epochs between publishing the precommit and when the challenge for interactive PoRep is drawn +// used to ensure it is not predictable by miner. +const PreCommitChallengeDelay = abi.ChainEpoch(10) + +// Lookback from the current epoch for state view for leader elections. +const ElectionLookback = abi.ChainEpoch(1) // PARAM_FINISH + +// Lookback from the deadline's challenge window opening from which to sample chain randomness for the challenge seed. +// This lookback exists so that deadline windows can be non-overlapping (which make the programming simpler) +// but without making the miner wait for chain stability before being able to start on PoSt computation. +// The challenge is available this many epochs before the window is actually open to receiving a PoSt. +const WPoStChallengeLookback = abi.ChainEpoch(20) + +// Minimum period before a deadline's challenge window opens that a fault must be declared for that deadline. +// This lookback must not be less than WPoStChallengeLookback lest a malicious miner be able to selectively declare +// faults after learning the challenge value. +const FaultDeclarationCutoff = WPoStChallengeLookback + 10 + +// The maximum age of a fault before the sector is terminated. +const FaultMaxAge = WPoStProvingPeriod*14 - 1 + +// Staging period for a miner worker key change. +// Finality is a harsh delay for a miner who has lost their worker key, as the miner will miss Window PoSts until +// it can be changed. It's the only safe value, though. We may implement a mitigation mechanism such as a second +// key or allowing the owner account to submit PoSts while a key change is pending. +const WorkerKeyChangeDelay = ChainFinality + +// Maximum number of epochs past the current epoch a sector may be set to expire. +// The actual maximum extension will be the minimum of CurrEpoch + MaximumSectorExpirationExtension +// and sector.ActivationEpoch+sealProof.SectorMaximumLifetime() +const MaxSectorExpirationExtension = builtin.EpochsInYear + +var QualityBaseMultiplier = big.NewInt(10) // PARAM_FINISH +var DealWeightMultiplier = big.NewInt(11) // PARAM_FINISH +var VerifiedDealWeightMultiplier = big.NewInt(100) // PARAM_FINISH +const SectorQualityPrecision = 20 + +// DealWeight and VerifiedDealWeight are spacetime occupied by regular deals and verified deals in a sector. +// Sum of DealWeight and VerifiedDealWeight should be less than or equal to total SpaceTime of a sector. +// Sectors full of VerifiedDeals will have a SectorQuality of VerifiedDealWeightMultiplier/QualityBaseMultiplier. +// Sectors full of Deals will have a SectorQuality of DealWeightMultiplier/QualityBaseMultiplier. +// Sectors with neither will have a SectorQuality of QualityBaseMultiplier/QualityBaseMultiplier. +// SectorQuality of a sector is a weighted average of multipliers based on their propotions. +func QualityForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.SectorQuality { + sectorSpaceTime := big.Mul(big.NewIntUnsigned(uint64(size)), big.NewInt(int64(duration))) + totalDealSpaceTime := big.Add(dealWeight, verifiedWeight) + Assert(sectorSpaceTime.GreaterThanEqual(totalDealSpaceTime)) + + weightedBaseSpaceTime := big.Mul(big.Sub(sectorSpaceTime, totalDealSpaceTime), QualityBaseMultiplier) + weightedDealSpaceTime := big.Mul(dealWeight, DealWeightMultiplier) + weightedVerifiedSpaceTime := big.Mul(verifiedWeight, VerifiedDealWeightMultiplier) + weightedSumSpaceTime := big.Add(weightedBaseSpaceTime, big.Add(weightedDealSpaceTime, weightedVerifiedSpaceTime)) + scaledUpWeightedSumSpaceTime := big.Lsh(weightedSumSpaceTime, SectorQualityPrecision) + + return big.Div(big.Div(scaledUpWeightedSumSpaceTime, sectorSpaceTime), QualityBaseMultiplier) +} + +// Returns the power for a sector size and weight. +func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower { + quality := QualityForWeight(size, duration, dealWeight, verifiedWeight) + return big.Rsh(big.Mul(big.NewIntUnsigned(uint64(size)), quality), SectorQualityPrecision) +} + +// Returns the quality-adjusted power for a sector. +func QAPowerForSector(size abi.SectorSize, sector *SectorOnChainInfo) abi.StoragePower { + duration := sector.Expiration - sector.Activation + return QAPowerForWeight(size, duration, sector.DealWeight, sector.VerifiedDealWeight) +} + +// Deposit per sector required at pre-commitment, refunded after the commitment is proven (else burned). +func precommitDeposit(qaSectorPower abi.StoragePower, networkQAPower abi.StoragePower, networkTotalPledge, epochTargetReward, circulatingSupply abi.TokenAmount) abi.TokenAmount { + return InitialPledgeForPower(qaSectorPower, networkQAPower, networkTotalPledge, epochTargetReward, circulatingSupply) +} + +type BigFrac struct { + numerator big.Int + denominator big.Int +} + +var consensusFaultReporterInitialShare = BigFrac{ + // PARAM_FINISH + numerator: big.NewInt(1), + denominator: big.NewInt(1000), +} +var consensusFaultReporterShareGrowthRate = BigFrac{ + // PARAM_FINISH + numerator: big.NewInt(101251), + denominator: big.NewInt(100000), +} + +// Specification for a linear vesting schedule. +type VestSpec struct { + InitialDelay abi.ChainEpoch // Delay before any amount starts vesting. + VestPeriod abi.ChainEpoch // Period over which the total should vest, after the initial delay. + StepDuration abi.ChainEpoch // Duration between successive incremental vests (independent of vesting period). + Quantization abi.ChainEpoch // Maximum precision of vesting table (limits cardinality of table). +} + +var PledgeVestingSpec = VestSpec{ + InitialDelay: abi.ChainEpoch(7 * builtin.EpochsInDay), // 1 week for testnet, PARAM_FINISH + VestPeriod: abi.ChainEpoch(7 * builtin.EpochsInDay), // 1 week for testnet, PARAM_FINISH + StepDuration: abi.ChainEpoch(1 * builtin.EpochsInDay), // 1 day for testnet, PARAM_FINISH + Quantization: 12 * builtin.EpochsInHour, // 12 hours for testnet, PARAM_FINISH +} + +func RewardForConsensusSlashReport(elapsedEpoch abi.ChainEpoch, collateral abi.TokenAmount) abi.TokenAmount { + // PARAM_FINISH + // var growthRate = SLASHER_SHARE_GROWTH_RATE_NUM / SLASHER_SHARE_GROWTH_RATE_DENOM + // var multiplier = growthRate^elapsedEpoch + // var slasherProportion = min(INITIAL_SLASHER_SHARE * multiplier, 1.0) + // return collateral * slasherProportion + + // BigInt Operation + // NUM = SLASHER_SHARE_GROWTH_RATE_NUM^elapsedEpoch * INITIAL_SLASHER_SHARE_NUM * collateral + // DENOM = SLASHER_SHARE_GROWTH_RATE_DENOM^elapsedEpoch * INITIAL_SLASHER_SHARE_DENOM + // slasher_amount = min(NUM/DENOM, collateral) + maxReporterShareNum := big.NewInt(1) + maxReporterShareDen := big.NewInt(2) + + elapsed := big.NewInt(int64(elapsedEpoch)) + slasherShareNumerator := big.Exp(consensusFaultReporterShareGrowthRate.numerator, elapsed) + slasherShareDenominator := big.Exp(consensusFaultReporterShareGrowthRate.denominator, elapsed) + + num := big.Mul(big.Mul(slasherShareNumerator, consensusFaultReporterInitialShare.numerator), collateral) + denom := big.Mul(slasherShareDenominator, consensusFaultReporterInitialShare.denominator) + return big.Min(big.Div(num, denom), big.Div(big.Mul(collateral, maxReporterShareNum), maxReporterShareDen)) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/cbor_gen.go new file mode 100644 index 0000000000..d21de7229a --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/cbor_gen.go @@ -0,0 +1,1351 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package multisig + +import ( + "fmt" + "io" + + address "github.com/filecoin-project/go-address" + abi "github.com/filecoin-project/specs-actors/actors/abi" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{135}); err != nil { + return err + } + + // t.Signers ([]address.Address) (slice) + if len(t.Signers) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Signers was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Signers)))); err != nil { + return err + } + for _, v := range t.Signers { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.NumApprovalsThreshold (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NumApprovalsThreshold))); err != nil { + return err + } + + // t.NextTxnID (multisig.TxnID) (int64) + if t.NextTxnID >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NextTxnID))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.NextTxnID)-1)); err != nil { + return err + } + } + + // t.InitialBalance (big.Int) (struct) + if err := t.InitialBalance.MarshalCBOR(w); err != nil { + return err + } + + // t.StartEpoch (abi.ChainEpoch) (int64) + if t.StartEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.StartEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.StartEpoch)-1)); err != nil { + return err + } + } + + // t.UnlockDuration (abi.ChainEpoch) (int64) + if t.UnlockDuration >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.UnlockDuration))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.UnlockDuration)-1)); err != nil { + return err + } + } + + // t.PendingTxns (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.PendingTxns); err != nil { + return xerrors.Errorf("failed to write cid field t.PendingTxns: %w", err) + } + + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 7 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Signers ([]address.Address) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Signers: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Signers = make([]address.Address, extra) + } + + for i := 0; i < int(extra); i++ { + + var v address.Address + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Signers[i] = v + } + + // t.NumApprovalsThreshold (uint64) (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.NumApprovalsThreshold = uint64(extra) + + } + // t.NextTxnID (multisig.TxnID) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.NextTxnID = TxnID(extraI) + } + // t.InitialBalance (big.Int) (struct) + + { + + if err := t.InitialBalance.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.InitialBalance: %w", err) + } + + } + // t.StartEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.StartEpoch = abi.ChainEpoch(extraI) + } + // t.UnlockDuration (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.UnlockDuration = abi.ChainEpoch(extraI) + } + // t.PendingTxns (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.PendingTxns: %w", err) + } + + t.PendingTxns = c + + } + return nil +} + +func (t *Transaction) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{133}); err != nil { + return err + } + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + + // t.Value (big.Int) (struct) + if err := t.Value.MarshalCBOR(w); err != nil { + return err + } + + // t.Method (abi.MethodNum) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Method))); err != nil { + return err + } + + // t.Params ([]uint8) (slice) + if len(t.Params) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Params was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Params)))); err != nil { + return err + } + if _, err := w.Write(t.Params); err != nil { + return err + } + + // t.Approved ([]address.Address) (slice) + if len(t.Approved) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Approved was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Approved)))); err != nil { + return err + } + for _, v := range t.Approved { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *Transaction) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 5 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + // t.Value (big.Int) (struct) + + { + + if err := t.Value.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Value: %w", err) + } + + } + // t.Method (abi.MethodNum) (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.Method = abi.MethodNum(extra) + + } + // t.Params ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Params: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Params = make([]byte, extra) + if _, err := io.ReadFull(br, t.Params); err != nil { + return err + } + // t.Approved ([]address.Address) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Approved: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Approved = make([]address.Address, extra) + } + + for i := 0; i < int(extra); i++ { + + var v address.Address + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Approved[i] = v + } + + return nil +} + +func (t *ProposalHashData) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{133}); err != nil { + return err + } + + // t.Requester (address.Address) (struct) + if err := t.Requester.MarshalCBOR(w); err != nil { + return err + } + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + + // t.Value (big.Int) (struct) + if err := t.Value.MarshalCBOR(w); err != nil { + return err + } + + // t.Method (abi.MethodNum) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Method))); err != nil { + return err + } + + // t.Params ([]uint8) (slice) + if len(t.Params) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Params was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Params)))); err != nil { + return err + } + if _, err := w.Write(t.Params); err != nil { + return err + } + return nil +} + +func (t *ProposalHashData) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 5 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Requester (address.Address) (struct) + + { + + if err := t.Requester.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Requester: %w", err) + } + + } + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + // t.Value (big.Int) (struct) + + { + + if err := t.Value.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Value: %w", err) + } + + } + // t.Method (abi.MethodNum) (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.Method = abi.MethodNum(extra) + + } + // t.Params ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Params: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Params = make([]byte, extra) + if _, err := io.ReadFull(br, t.Params); err != nil { + return err + } + return nil +} + +func (t *ConstructorParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.Signers ([]address.Address) (slice) + if len(t.Signers) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Signers was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Signers)))); err != nil { + return err + } + for _, v := range t.Signers { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.NumApprovalsThreshold (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NumApprovalsThreshold))); err != nil { + return err + } + + // t.UnlockDuration (abi.ChainEpoch) (int64) + if t.UnlockDuration >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.UnlockDuration))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.UnlockDuration)-1)); err != nil { + return err + } + } + return nil +} + +func (t *ConstructorParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Signers ([]address.Address) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Signers: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Signers = make([]address.Address, extra) + } + + for i := 0; i < int(extra); i++ { + + var v address.Address + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Signers[i] = v + } + + // t.NumApprovalsThreshold (uint64) (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.NumApprovalsThreshold = uint64(extra) + + } + // t.UnlockDuration (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.UnlockDuration = abi.ChainEpoch(extraI) + } + return nil +} + +func (t *ProposeParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + + // t.Value (big.Int) (struct) + if err := t.Value.MarshalCBOR(w); err != nil { + return err + } + + // t.Method (abi.MethodNum) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Method))); err != nil { + return err + } + + // t.Params ([]uint8) (slice) + if len(t.Params) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Params was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Params)))); err != nil { + return err + } + if _, err := w.Write(t.Params); err != nil { + return err + } + return nil +} + +func (t *ProposeParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + // t.Value (big.Int) (struct) + + { + + if err := t.Value.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Value: %w", err) + } + + } + // t.Method (abi.MethodNum) (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.Method = abi.MethodNum(extra) + + } + // t.Params ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Params: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Params = make([]byte, extra) + if _, err := io.ReadFull(br, t.Params); err != nil { + return err + } + return nil +} + +func (t *AddSignerParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Signer (address.Address) (struct) + if err := t.Signer.MarshalCBOR(w); err != nil { + return err + } + + // t.Increase (bool) (bool) + if err := cbg.WriteBool(w, t.Increase); err != nil { + return err + } + return nil +} + +func (t *AddSignerParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Signer (address.Address) (struct) + + { + + if err := t.Signer.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Signer: %w", err) + } + + } + // t.Increase (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Increase = false + case 21: + t.Increase = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + return nil +} + +func (t *RemoveSignerParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Signer (address.Address) (struct) + if err := t.Signer.MarshalCBOR(w); err != nil { + return err + } + + // t.Decrease (bool) (bool) + if err := cbg.WriteBool(w, t.Decrease); err != nil { + return err + } + return nil +} + +func (t *RemoveSignerParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Signer (address.Address) (struct) + + { + + if err := t.Signer.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Signer: %w", err) + } + + } + // t.Decrease (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Decrease = false + case 21: + t.Decrease = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + return nil +} + +func (t *TxnIDParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.ID (multisig.TxnID) (int64) + if t.ID >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ID))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.ID)-1)); err != nil { + return err + } + } + + // t.ProposalHash ([]uint8) (slice) + if len(t.ProposalHash) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.ProposalHash was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.ProposalHash)))); err != nil { + return err + } + if _, err := w.Write(t.ProposalHash); err != nil { + return err + } + return nil +} + +func (t *TxnIDParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.ID (multisig.TxnID) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.ID = TxnID(extraI) + } + // t.ProposalHash ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.ProposalHash: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.ProposalHash = make([]byte, extra) + if _, err := io.ReadFull(br, t.ProposalHash); err != nil { + return err + } + return nil +} + +func (t *ChangeNumApprovalsThresholdParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.NewThreshold (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NewThreshold))); err != nil { + return err + } + + return nil +} + +func (t *ChangeNumApprovalsThresholdParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.NewThreshold (uint64) (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.NewThreshold = uint64(extra) + + } + return nil +} + +func (t *SwapSignerParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.From (address.Address) (struct) + if err := t.From.MarshalCBOR(w); err != nil { + return err + } + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SwapSignerParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.From (address.Address) (struct) + + { + + if err := t.From.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.From: %w", err) + } + + } + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + return nil +} + +func (t *ApproveReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.Applied (bool) (bool) + if err := cbg.WriteBool(w, t.Applied); err != nil { + return err + } + + // t.Code (exitcode.ExitCode) (int64) + if t.Code >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Code))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.Code)-1)); err != nil { + return err + } + } + + // t.Ret ([]uint8) (slice) + if len(t.Ret) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Ret was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Ret)))); err != nil { + return err + } + if _, err := w.Write(t.Ret); err != nil { + return err + } + return nil +} + +func (t *ApproveReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Applied (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Applied = false + case 21: + t.Applied = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Code (exitcode.ExitCode) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Code = exitcode.ExitCode(extraI) + } + // t.Ret ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Ret: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Ret = make([]byte, extra) + if _, err := io.ReadFull(br, t.Ret); err != nil { + return err + } + return nil +} + +func (t *ProposeReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.TxnID (multisig.TxnID) (int64) + if t.TxnID >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.TxnID))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.TxnID)-1)); err != nil { + return err + } + } + + // t.Applied (bool) (bool) + if err := cbg.WriteBool(w, t.Applied); err != nil { + return err + } + + // t.Code (exitcode.ExitCode) (int64) + if t.Code >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Code))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.Code)-1)); err != nil { + return err + } + } + + // t.Ret ([]uint8) (slice) + if len(t.Ret) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Ret was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Ret)))); err != nil { + return err + } + if _, err := w.Write(t.Ret); err != nil { + return err + } + return nil +} + +func (t *ProposeReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.TxnID (multisig.TxnID) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.TxnID = TxnID(extraI) + } + // t.Applied (bool) (bool) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Applied = false + case 21: + t.Applied = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Code (exitcode.ExitCode) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Code = exitcode.ExitCode(extraI) + } + // t.Ret ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Ret: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Ret = make([]byte, extra) + if _, err := io.ReadFull(br, t.Ret); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_actor.go new file mode 100644 index 0000000000..ce5167b3c5 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_actor.go @@ -0,0 +1,510 @@ +package multisig + +import ( + "bytes" + "encoding/binary" + "fmt" + addr "github.com/filecoin-project/go-address" + abi "github.com/filecoin-project/specs-actors/actors/abi" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type TxnID int64 + +func (t TxnID) Key() string { + // convert a TxnID to a HAMT key. + txnKey := make([]byte, binary.MaxVarintLen64) + n := binary.PutVarint(txnKey, int64(t)) + return string(txnKey[:n]) +} + +type Transaction struct { + To addr.Address + Value abi.TokenAmount + Method abi.MethodNum + Params []byte + + // This address at index 0 is the transaction proposer, order of this slice must be preserved. + Approved []addr.Address +} + +// Data for a BLAKE2B-256 to be attached to methods referencing proposals via TXIDs. +// Ensures the existence of a cryptographic reference to the original proposal. Useful +// for offline signers and for protection when reorgs change a multisig TXID. +// +// Requester - The requesting multisig wallet member. +// All other fields - From the "Transaction" struct. +type ProposalHashData struct { + Requester addr.Address + To addr.Address + Value abi.TokenAmount + Method abi.MethodNum + Params []byte +} + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.Propose, + 3: a.Approve, + 4: a.Cancel, + 5: a.AddSigner, + 6: a.RemoveSigner, + 7: a.SwapSigner, + 8: a.ChangeNumApprovalsThreshold, + } +} + +var _ abi.Invokee = Actor{} + +type ConstructorParams struct { + Signers []addr.Address + NumApprovalsThreshold uint64 + UnlockDuration abi.ChainEpoch +} + +func (a Actor) Constructor(rt vmr.Runtime, params *ConstructorParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.InitActorAddr) + + if len(params.Signers) < 1 { + rt.Abortf(exitcode.ErrIllegalArgument, "must have at least one signer") + } + + // do not allow duplicate signers + resolvedSigners := make(map[addr.Address]struct{}, len(params.Signers)) + for _, signer := range params.Signers { + resolved := resolve(rt, signer) + if _, ok := resolvedSigners[resolved]; ok { + rt.Abortf(exitcode.ErrIllegalArgument, "duplicate signer not allowed: %s", signer) + } + resolvedSigners[resolved] = struct{}{} + } + + if params.NumApprovalsThreshold > uint64(len(params.Signers)) { + rt.Abortf(exitcode.ErrIllegalArgument, "must not require more approvals than signers") + } + + if params.NumApprovalsThreshold < 1 { + rt.Abortf(exitcode.ErrIllegalArgument, "must require at least one approval") + } + + if params.UnlockDuration < 0 { + rt.Abortf(exitcode.ErrIllegalArgument, "negative unlock duration disallowed") + } + + pending, err := adt.MakeEmptyMap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to create empty map: %v", err) + } + + var st State + st.Signers = params.Signers + st.NumApprovalsThreshold = params.NumApprovalsThreshold + st.PendingTxns = pending + st.InitialBalance = abi.NewTokenAmount(0) + if params.UnlockDuration != 0 { + st.InitialBalance = rt.Message().ValueReceived() + st.UnlockDuration = params.UnlockDuration + st.StartEpoch = rt.CurrEpoch() + } + + rt.State().Create(&st) + return nil +} + +type ProposeParams struct { + To addr.Address + Value abi.TokenAmount + Method abi.MethodNum + Params []byte +} + +type ProposeReturn struct { + // TxnID is the ID of the proposed transaction + TxnID TxnID + // Applied indicates if the transaction was applied as opposed to proposed but not applied due to lack of approvals + Applied bool + // Code is the exitcode of the transaction, if Applied is false this field should be ignored. + Code exitcode.ExitCode + // Ret is the return vale of the transaction, if Applied is false this field should be ignored. + Ret []byte +} + +func (a Actor) Propose(rt vmr.Runtime, params *ProposeParams) *ProposeReturn { + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + callerAddr := rt.Message().Caller() + + var txnID TxnID + var st State + var txn *Transaction + rt.State().Transaction(&st, func() interface{} { + if !isSigner(rt, &st, callerAddr) { + rt.Abortf(exitcode.ErrForbidden, "%s is not a signer", callerAddr) + } + + txnID = st.NextTxnID + st.NextTxnID += 1 + txn = &Transaction{ + To: params.To, + Value: params.Value, + Method: params.Method, + Params: params.Params, + Approved: []addr.Address{}, + } + + if err := st.putPendingTransaction(adt.AsStore(rt), txnID, txn); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to put transaction for propose: %v", err) + } + return nil + }) + + applied, ret, code := a.approveTransaction(rt, txnID, txn) + + // Note: this transaction ID may not be stable across chain re-orgs. + // The proposal hash may be provided as a stability check when approving. + return &ProposeReturn{ + TxnID: txnID, + Applied: applied, + Code: code, + Ret: ret, + } +} + +type TxnIDParams struct { + ID TxnID + ProposalHash []byte +} + +type ApproveReturn struct { + // Applied indicates if the transaction was applied as opposed to proposed but not applied due to lack of approvals + Applied bool + // Code is the exitcode of the transaction, if Applied is false this field should be ignored. + Code exitcode.ExitCode + // Ret is the return vale of the transaction, if Applied is false this field should be ignored. + Ret []byte +} + +func (a Actor) Approve(rt vmr.Runtime, params *TxnIDParams) *ApproveReturn { + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + callerAddr := rt.Message().Caller() + var st State + var txn *Transaction + rt.State().Transaction(&st, func() interface{} { + if !isSigner(rt, &st, callerAddr) { + rt.Abortf(exitcode.ErrForbidden, "%s is not a signer", callerAddr) + } + txn = a.getTransaction(rt, st, params.ID, params.ProposalHash, true) + return nil + }) + + // if the transaction already has enough approvers, execute it without "processing" this approval. + approved,ret, code := executeTransactionIfApproved(rt, st, params.ID, txn) + if !approved { + // if the transaction hasn't already been approved, let's "process" this approval + // and see if we can execute the transaction + approved, ret, code = a.approveTransaction(rt, params.ID, txn) + } + + return &ApproveReturn{ + Applied: approved, + Code: code, + Ret: ret, + } +} + +func (a Actor) Cancel(rt vmr.Runtime, params *TxnIDParams) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + callerAddr := rt.Message().Caller() + + var st State + rt.State().Transaction(&st, func() interface{} { + if !isSigner(rt, &st, callerAddr) { + rt.Abortf(exitcode.ErrForbidden, "%s is not a signer", callerAddr) + } + + txn, err := st.getPendingTransaction(adt.AsStore(rt), params.ID) + if err != nil { + rt.Abortf(exitcode.ErrNotFound, "failed to get transaction for cancel: %v", err) + } + proposer := txn.Approved[0] + if proposer != callerAddr { + rt.Abortf(exitcode.ErrForbidden, "Cannot cancel another signers transaction") + } + + // confirm the hashes match + calculatedHash, err := ComputeProposalHash(&txn, rt.Syscalls().HashBlake2b) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to compute proposal hash: %v", err) + } + if params.ProposalHash != nil && !bytes.Equal(params.ProposalHash, calculatedHash[:]) { + rt.Abortf(exitcode.ErrIllegalState, "hash does not match proposal params") + } + + if err = st.deletePendingTransaction(adt.AsStore(rt), params.ID); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete transaction for cancel: %v", err) + } + return nil + }) + return nil +} + +type AddSignerParams struct { + Signer addr.Address + Increase bool +} + +func (a Actor) AddSigner(rt vmr.Runtime, params *AddSignerParams) *adt.EmptyValue { + // Can only be called by the multisig wallet itself. + rt.ValidateImmediateCallerIs(rt.Message().Receiver()) + + var st State + rt.State().Transaction(&st, func() interface{} { + if isSigner(rt, &st, params.Signer) { + rt.Abortf(exitcode.ErrIllegalArgument, "%s is already a signer", params.Signer) + } + st.Signers = append(st.Signers, params.Signer) + if params.Increase { + st.NumApprovalsThreshold = st.NumApprovalsThreshold + 1 + } + return nil + }) + return nil +} + +type RemoveSignerParams struct { + Signer addr.Address + Decrease bool +} + +func (a Actor) RemoveSigner(rt vmr.Runtime, params *RemoveSignerParams) *adt.EmptyValue { + // Can only be called by the multisig wallet itself. + rt.ValidateImmediateCallerIs(rt.Message().Receiver()) + + var st State + rt.State().Transaction(&st, func() interface{} { + if !isSigner(rt, &st, params.Signer) { + rt.Abortf(exitcode.ErrNotFound, "%s is not a signer", params.Signer) + } + + if len(st.Signers) == 1 { + rt.Abortf(exitcode.ErrForbidden, "cannot remove only signer") + } + + newSigners := make([]addr.Address, 0, len(st.Signers)) + for _, s := range st.Signers { + if s != params.Signer { + newSigners = append(newSigners, s) + } + } + + // if the number of signers is below the threshold after removing the given signer, + // we should decrease the threshold by 1. This means that decrease should NOT be set to false + // in such a scenario. + if !params.Decrease && uint64(len(st.Signers)-1) < st.NumApprovalsThreshold { + rt.Abortf(exitcode.ErrIllegalArgument, "can't reduce signers to %d below threshold %d with decrease=false", len(st.Signers)-1, st.NumApprovalsThreshold) + } + + if params.Decrease { + st.NumApprovalsThreshold = st.NumApprovalsThreshold - 1 + } + st.Signers = newSigners + return nil + }) + + return nil +} + +type SwapSignerParams struct { + From addr.Address + To addr.Address +} + +func (a Actor) SwapSigner(rt vmr.Runtime, params *SwapSignerParams) *adt.EmptyValue { + // Can only be called by the multisig wallet itself. + rt.ValidateImmediateCallerIs(rt.Message().Receiver()) + + var st State + rt.State().Transaction(&st, func() interface{} { + if !isSigner(rt, &st, params.From) { + rt.Abortf(exitcode.ErrNotFound, "%s is not a signer", params.From) + } + + if isSigner(rt, &st, params.To) { + rt.Abortf(exitcode.ErrIllegalArgument, "%s already a signer", params.To) + } + + newSigners := make([]addr.Address, 0, len(st.Signers)) + for _, s := range st.Signers { + if s != params.From { + newSigners = append(newSigners, s) + } + } + newSigners = append(newSigners, params.To) + st.Signers = newSigners + return nil + }) + + return nil +} + +type ChangeNumApprovalsThresholdParams struct { + NewThreshold uint64 +} + +func (a Actor) ChangeNumApprovalsThreshold(rt vmr.Runtime, params *ChangeNumApprovalsThresholdParams) *adt.EmptyValue { + // Can only be called by the multisig wallet itself. + rt.ValidateImmediateCallerIs(rt.Message().Receiver()) + + var st State + rt.State().Transaction(&st, func() interface{} { + if params.NewThreshold == 0 || params.NewThreshold > uint64(len(st.Signers)) { + rt.Abortf(exitcode.ErrIllegalArgument, "New threshold value not supported") + } + + st.NumApprovalsThreshold = params.NewThreshold + return nil + }) + return nil +} + +func (a Actor) approveTransaction(rt vmr.Runtime, txnID TxnID, txn *Transaction) (bool, []byte, exitcode.ExitCode) { + var st State + // abort duplicate approval + for _, previousApprover := range txn.Approved { + if previousApprover == rt.Message().Caller() { + rt.Abortf(exitcode.ErrForbidden, "%s already approved this message", previousApprover) + } + } + + // add the caller to the list of approvers + rt.State().Transaction(&st, func() interface{} { + // update approved on the transaction + txn.Approved = append(txn.Approved, rt.Message().Caller()) + if err := st.putPendingTransaction(adt.AsStore(rt), txnID, txn); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to put transaction for approval: %v", err) + } + return nil + }) + + return executeTransactionIfApproved(rt,st, txnID, txn) +} + +func (a Actor) getTransaction(rt vmr.Runtime, st State, txnID TxnID, proposalHash []byte, checkHash bool) *Transaction { + var txn Transaction + + // get transaction from the state trie + var err error + txn, err = st.getPendingTransaction(adt.AsStore(rt), txnID) + if err != nil { + rt.Abortf(exitcode.ErrNotFound, "failed to get transaction for approval: %v", err) + } + + // confirm the hashes match + if checkHash { + calculatedHash, err := ComputeProposalHash(&txn, rt.Syscalls().HashBlake2b) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to compute proposal hash: %v", err) + } + if proposalHash != nil && !bytes.Equal(proposalHash, calculatedHash[:]) { + rt.Abortf(exitcode.ErrIllegalArgument, "hash does not match proposal params") + } + } + + return &txn +} + +func executeTransactionIfApproved(rt vmr.Runtime, st State, txnID TxnID, txn *Transaction) (bool, []byte, exitcode.ExitCode) { + var out vmr.CBORBytes + var code exitcode.ExitCode + applied := false + + thresholdMet := uint64(len(txn.Approved)) >= st.NumApprovalsThreshold + if thresholdMet { + if err := st.assertAvailable(rt.CurrentBalance(), txn.Value, rt.CurrEpoch()); err != nil { + rt.Abortf(exitcode.ErrInsufficientFunds, "insufficient funds unlocked: %v", err) + } + + var ret vmr.SendReturn + // A sufficient number of approvals have arrived and sufficient funds have been unlocked: relay the message and delete from pending queue. + ret, code = rt.Send( + txn.To, + txn.Method, + vmr.CBORBytes(txn.Params), + txn.Value, + ) + applied = true + + // Pass the return value through uninterpreted with the expectation that serializing into a CBORBytes never fails + // since it just copies the bytes. + if err := ret.Into(&out); err != nil { + rt.Abortf(exitcode.ErrSerialization, "failed to deserialize result: %v", err) + } + + // This could be rearranged to happen inside the first state transaction, before the send(). + rt.State().Transaction(&st, func() interface{} { + if err := st.deletePendingTransaction(adt.AsStore(rt), txnID); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete transaction for cleanup: %v", err) + } + return nil + }) + } + + return applied, out, code +} + +func isSigner(rt vmr.Runtime, st *State, address addr.Address) bool { + candidateResolved := resolve(rt,address) + + for _, ap := range st.Signers { + signerResolved := resolve(rt, ap) + if signerResolved == candidateResolved { + return true + } + } + + return false +} + +func resolve(rt vmr.Runtime, address addr.Address) addr.Address { + resolved := address + if resolved.Protocol() != addr.ID { + idAddr, found := rt.ResolveAddress(resolved) + if found { + resolved = idAddr + } + } + return resolved +} + +// Computes a digest of a proposed transaction. This digest is used to confirm identity of the transaction +// associated with an ID, which might change under chain re-orgs. +func ComputeProposalHash(txn *Transaction, hash func([]byte) [32]byte) ([]byte, error) { + hashData := ProposalHashData{ + Requester: txn.Approved[0], + To: txn.To, + Value: txn.Value, + Method: txn.Method, + Params: txn.Params, + } + + data, err := hashData.Serialize() + if err != nil { + return nil, fmt.Errorf("failed to construct multisig approval hash: %w", err) + } + + hashResult := hash(data) + return hashResult[:], nil +} + +func (phd *ProposalHashData) Serialize() ([]byte, error) { + buf := new(bytes.Buffer) + if err := phd.MarshalCBOR(buf); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_state.go new file mode 100644 index 0000000000..6689d4958f --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_state.go @@ -0,0 +1,111 @@ +package multisig + +import ( + address "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + errors "github.com/pkg/errors" + xerrors "golang.org/x/xerrors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type State struct { + // Signers may be either public-key or actor ID-addresses. The ID address is canonical, but doesn't exist + // for a public key that has not yet received a message on chain. + // If any signer address is a public-key address, it will be resolved to an ID address and persisted + // in this state when the address is used. + Signers []address.Address + NumApprovalsThreshold uint64 + NextTxnID TxnID + + // Linear unlock + InitialBalance abi.TokenAmount + StartEpoch abi.ChainEpoch + UnlockDuration abi.ChainEpoch + + PendingTxns cid.Cid +} + +func (st *State) AmountLocked(elapsedEpoch abi.ChainEpoch) abi.TokenAmount { + if elapsedEpoch >= st.UnlockDuration { + return abi.NewTokenAmount(0) + } + + unitLocked := big.Div(st.InitialBalance, big.NewInt(int64(st.UnlockDuration))) + return big.Mul(unitLocked, big.Sub(big.NewInt(int64(st.UnlockDuration)), big.NewInt(int64(elapsedEpoch)))) +} + +// return nil if MultiSig maintains required locked balance after spending the amount, else return an error. +func (st *State) assertAvailable(currBalance abi.TokenAmount, amountToSpend abi.TokenAmount, currEpoch abi.ChainEpoch) error { + if amountToSpend.LessThan(big.Zero()) { + return errors.Errorf("amount to spend %s less than zero", amountToSpend.String()) + } + if currBalance.LessThan(amountToSpend) { + return errors.Errorf("current balance %s less than amount to spend %s", currBalance.String(), amountToSpend.String()) + } + + remainingBalance := big.Sub(currBalance, amountToSpend) + amountLocked := st.AmountLocked(currEpoch - st.StartEpoch) + if remainingBalance.LessThan(amountLocked) { + return errors.Errorf("actor balance if spent %s would be less than required locked amount %s", remainingBalance.String(), amountLocked.String()) + } + + return nil +} + +func (as *State) getPendingTransaction(s adt.Store, txnID TxnID) (Transaction, error) { + hm, err := adt.AsMap(s, as.PendingTxns) + if err != nil { + return Transaction{}, err + } + + var out Transaction + found, err := hm.Get(txnID, &out) + if err != nil { + return Transaction{}, errors.Wrapf(err, "failed to read transaction") + } + if !found { + return Transaction{}, errors.Errorf("failed to find transaction %v in HAMT %s", txnID, as.PendingTxns) + } + + return out, nil +} + +func (st *State) mutatePendingTransactions(s adt.Store, f func(pt *adt.Map) error) error { + hm, err := adt.AsMap(s, st.PendingTxns) + if err != nil { + return xerrors.Errorf("Failed to load pending txns map: %w", err) + } + + if err := f(hm); err != nil { + return err + } + + c, err := hm.Root() + if err != nil { + return xerrors.Errorf("failed to flush pending txns map: %w", err) + } + + st.PendingTxns = c + return nil +} + +func (as *State) putPendingTransaction(s adt.Store, txnID TxnID, txn *Transaction) error { + return as.mutatePendingTransactions(s, func(hm *adt.Map) error { + if err := hm.Put(txnID, txn); err != nil { + return errors.Wrapf(err, "failed to write transaction") + } + return nil + }) +} + +func (as *State) deletePendingTransaction(s adt.Store, txnID TxnID) error { + return as.mutatePendingTransactions(s, func(hm *adt.Map) error { + if err := hm.Delete(txnID); err != nil { + return errors.Wrapf(err, "failed to delete transaction") + } + return nil + }) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_test.go new file mode 100644 index 0000000000..faac0fa787 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/multisig/multisig_test.go @@ -0,0 +1,1547 @@ +package multisig_test + +import ( + "bytes" + "context" + "testing" + + addr "github.com/filecoin-project/go-address" + "github.com/minio/blake2b-simd" + assert "github.com/stretchr/testify/assert" + require "github.com/stretchr/testify/require" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + miner "github.com/filecoin-project/specs-actors/actors/builtin/miner" + multisig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + runtime "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" + mock "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, multisig.Actor{}) +} + +func TestConstruction(t *testing.T) { + actor := multisig.Actor{} + + receiver := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + charlie := tutil.NewIDAddr(t, 103) + + builder := mock.NewBuilder(context.Background(), receiver).WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + + t.Run("simple construction", func(t *testing.T) { + rt := builder.Build(t) + params := multisig.ConstructorParams{ + Signers: []addr.Address{anne, bob, charlie}, + NumApprovalsThreshold: 2, + UnlockDuration: 0, + } + + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + ret := rt.Call(actor.Constructor, ¶ms) + assert.Nil(t, ret) + rt.Verify() + + var st multisig.State + rt.GetState(&st) + assert.Equal(t, params.Signers, st.Signers) + assert.Equal(t, params.NumApprovalsThreshold, st.NumApprovalsThreshold) + assert.Equal(t, abi.NewTokenAmount(0), st.InitialBalance) + assert.Equal(t, abi.ChainEpoch(0), st.UnlockDuration) + assert.Equal(t, abi.ChainEpoch(0), st.StartEpoch) + txns, err := adt.AsMap(adt.AsStore(rt), st.PendingTxns) + assert.NoError(t, err) + keys, err := txns.CollectKeys() + require.NoError(t, err) + assert.Empty(t, keys) + }) + + t.Run("construction with vesting", func(t *testing.T) { + rt := builder.WithEpoch(1234).Build(t) + params := multisig.ConstructorParams{ + Signers: []addr.Address{anne, bob, charlie}, + NumApprovalsThreshold: 3, + UnlockDuration: 100, + } + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + ret := rt.Call(actor.Constructor, ¶ms) + assert.Nil(t, ret) + rt.Verify() + + var st multisig.State + rt.GetState(&st) + assert.Equal(t, params.Signers, st.Signers) + assert.Equal(t, params.NumApprovalsThreshold, st.NumApprovalsThreshold) + assert.Equal(t, abi.NewTokenAmount(0), st.InitialBalance) + assert.Equal(t, abi.ChainEpoch(100), st.UnlockDuration) + assert.Equal(t, abi.ChainEpoch(1234), st.StartEpoch) + // assert no transactions + }) + + t.Run("fail to construct multisig actor with 0 signers", func(t *testing.T) { + rt := builder.Build(t) + params := multisig.ConstructorParams{ + Signers: []addr.Address{}, + NumApprovalsThreshold: 1, + UnlockDuration: 1, + } + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.Constructor, ¶ms) + }) + rt.Verify() + + }) + + t.Run("fail to construct multisig with more approvals than signers", func(t *testing.T) { + rt := builder.Build(t) + params := multisig.ConstructorParams{ + Signers: []addr.Address{anne, bob, charlie}, + NumApprovalsThreshold: 4, + UnlockDuration: 1, + } + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.Constructor, ¶ms) + }) + rt.Verify() + }) + + t.Run("fail to construct multisig with duplicate signers(all ID addresses)", func(t *testing.T) { + rt := builder.Build(t) + params := multisig.ConstructorParams{ + Signers: []addr.Address{anne, bob, bob}, + NumApprovalsThreshold: 2, + UnlockDuration: 0, + } + + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.Constructor, ¶ms) + }) + rt.Verify() + }) + + t.Run("fail to construct multisig with duplicate signers(ID & non-ID addresses)", func(t *testing.T) { + bobNonId := tutil.NewBLSAddr(t,1) + rt := builder.Build(t) + params := multisig.ConstructorParams{ + Signers: []addr.Address{anne, bobNonId, bob}, + NumApprovalsThreshold: 2, + UnlockDuration: 0, + } + + rt.AddIDAddress(bobNonId, bob) + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.Constructor, ¶ms) + }) + rt.Verify() + }) +} + +func TestVesting(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + receiver := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + charlie := tutil.NewIDAddr(t, 103) + darlene := tutil.NewIDAddr(t, 103) + + const unlockDuration = 10 + var multisigInitialBalance = abi.NewTokenAmount(100) + var fakeParams = runtime.CBORBytes([]byte{1, 2, 3, 4}) + + builder := mock.NewBuilder(context.Background(), receiver). + WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID). + WithEpoch(0). + // balance 0: current balance of the actor. receive: 100 the amount the multisig actor will be initalized with -- InitialBalance + WithBalance(multisigInitialBalance, multisigInitialBalance). + WithHasher(blake2b.Sum256) + + t.Run("happy path full vesting", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, 2, unlockDuration, []addr.Address{anne, bob, charlie}...) + + // anne proposes that darlene receives `multisgiInitialBalance` FIL. + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.SetReceived(big.Zero()) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, darlene, multisigInitialBalance, builtin.MethodSend, fakeParams, nil) + rt.Verify() + + // Advance the epoch s.t. all funds are unlocked. + rt.SetEpoch(0 + unlockDuration) + // bob approves annes transaction + rt.SetCaller(bob, builtin.AccountActorCodeID) + // expect darlene to receive the transaction proposed by anne. + rt.ExpectSend(darlene, builtin.MethodSend, fakeParams, multisigInitialBalance, nil, exitcode.Ok) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: darlene, + Value: multisigInitialBalance, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + actor.approveOK(rt, 0, proposalHashData, nil) + }) + + t.Run("partial vesting propose to send half the actor balance when the epoch is hald the unlock duration", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, 2, 10, []addr.Address{anne, bob, charlie}...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.SetReceived(big.Zero()) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, darlene, big.Div(multisigInitialBalance, big.NewInt(2)), builtin.MethodSend, fakeParams, nil) + rt.Verify() + + // set the current balance of the multisig actor to its InitialBalance amount + rt.SetEpoch(0 + unlockDuration/2) + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectSend(darlene, builtin.MethodSend, fakeParams, big.Div(multisigInitialBalance, big.NewInt(2)), nil, exitcode.Ok) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: darlene, + Value: big.Div(multisigInitialBalance, big.NewInt(2)), + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + + actor.approveOK(rt, 0, proposalHashData, nil) + }) + + t.Run("propose and autoapprove transaction above locked amount fails", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, 1, unlockDuration, []addr.Address{anne, bob, charlie}...) + + rt.SetReceived(big.Zero()) + // this propose will fail since it would send more than the required locked balance and num approvals == 1 + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + _ = actor.propose(rt, darlene, abi.NewTokenAmount(100), builtin.MethodSend, fakeParams, nil) + }) + rt.Verify() + + // this will pass since sending below the locked amount is permitted + rt.SetEpoch(1) + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(darlene, builtin.MethodSend, fakeParams, abi.NewTokenAmount(10), nil, 0) + actor.proposeOK(rt, darlene, abi.NewTokenAmount(10), builtin.MethodSend, fakeParams, nil) + rt.Verify() + }) + + t.Run("fail to vest more than locked amount", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, 2, unlockDuration, []addr.Address{anne, bob, charlie}...) + + rt.SetReceived(big.Zero()) + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, darlene, big.Div(multisigInitialBalance, big.NewInt(2)), builtin.MethodSend, fakeParams, nil) + rt.Verify() + + // this propose will fail since it would send more than the required locked balance. + rt.SetEpoch(1) + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: darlene, + Value: big.Div(multisigInitialBalance, big.NewInt(2)), + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + _ = actor.approve(rt, 0, proposalHashData, nil) + }) + rt.Verify() + }) + +} + +func TestPropose(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + receiver := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + chuck := tutil.NewIDAddr(t, 103) + + const noUnlockDuration = int64(0) + var sendValue = abi.NewTokenAmount(10) + var fakeParams = runtime.CBORBytes([]byte{1, 2, 3, 4}) + var signers = []addr.Address{anne, bob} + + builder := mock.NewBuilder(context.Background(), receiver).WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + + t.Run("simple propose", func(t *testing.T) { + const numApprovals = uint64(2) + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, builtin.MethodSend, fakeParams, nil) + + // the transaction remains awaiting second approval + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + }) + + t.Run("propose with threshold met", func(t *testing.T) { + const numApprovals = uint64(1) + + rt := builder.WithBalance(abi.NewTokenAmount(20), abi.NewTokenAmount(0)).Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.ExpectSend(chuck, builtin.MethodSend, fakeParams, sendValue, nil, 0) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, builtin.MethodSend, fakeParams, nil) + + // the transaction has been sent and cleaned up + actor.assertTransactions(rt) + rt.Verify() + }) + + t.Run("propose with threshold and non-empty return value", func(t *testing.T) { + const numApprovals = uint64(1) + + rt := builder.WithBalance(abi.NewTokenAmount(20), abi.NewTokenAmount(0)).Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + proposeRet := miner.GetControlAddressesReturn{ + Owner: tutil.NewIDAddr(t, 1), + Worker: tutil.NewIDAddr(t, 2), + } + rt.ExpectSend(chuck, builtin.MethodsMiner.ControlAddresses, fakeParams, sendValue, &proposeRet, 0) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + + var out miner.GetControlAddressesReturn + actor.proposeOK(rt, chuck, sendValue, builtin.MethodsMiner.ControlAddresses, fakeParams, &out) + // assert ProposeReturn.Ret can be marshaled into the expected structure. + assert.Equal(t, proposeRet, out) + + // the transaction has been sent and cleaned up + actor.assertTransactions(rt) + rt.Verify() + + }) + + t.Run("fail propose with threshold met and insufficient balance", func(t *testing.T) { + const numApprovals = uint64(1) + rt := builder.WithBalance(abi.NewTokenAmount(0), abi.NewTokenAmount(0)).Build(t) + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { + _ = actor.propose(rt, chuck, sendValue, builtin.MethodSend, fakeParams, nil) + }) + rt.Verify() + + // proposal failed since it should have but failed to immediately execute. + actor.assertTransactions(rt) + }) + + t.Run("fail propose from non-signer", func(t *testing.T) { + // non-signer address + richard := tutil.NewIDAddr(t, 105) + const numApprovals = uint64(2) + + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(richard, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + _ = actor.propose(rt, chuck, sendValue, builtin.MethodSend, fakeParams, nil) + }) + rt.Verify() + + // the transaction is not persisted + actor.assertTransactions(rt) + }) +} + +func TestApprove(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + receiver := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + chuck := tutil.NewIDAddr(t, 103) + + const noUnlockDuration = int64(0) + const numApprovals = uint64(2) + const txnID = int64(0) + const fakeMethod = abi.MethodNum(42) + var sendValue = abi.NewTokenAmount(10) + var fakeParams = runtime.CBORBytes([]byte{1, 2, 3, 4}) + var signers = []addr.Address{anne, bob} + + builder := mock.NewBuilder(context.Background(), receiver). + WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID). + WithHasher(blake2b.Sum256) + + t.Run("simple propose and approval", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + + rt.SetBalance(sendValue) + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(chuck, fakeMethod, fakeParams, sendValue, nil, 0) + + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + + actor.approveOK(rt, txnID, proposalHashData, nil) + + // Transaction should be removed from actor state after send + actor.assertTransactions(rt) + }) + + t.Run("approve with non-empty return value", func(t *testing.T) { + const numApprovals = uint64(2) + + rt := builder.WithBalance(abi.NewTokenAmount(20), abi.NewTokenAmount(0)).Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, builtin.MethodsMiner.ControlAddresses, fakeParams, nil) + + approveRet := miner.GetControlAddressesReturn{ + Owner: tutil.NewIDAddr(t, 1), + Worker: tutil.NewIDAddr(t, 2), + } + + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodsMiner.ControlAddresses, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(chuck, builtin.MethodsMiner.ControlAddresses, fakeParams, sendValue, &approveRet, 0) + + var out miner.GetControlAddressesReturn + actor.approveOK(rt, txnID, proposalHashData, &out) + // assert approveRet.Ret can be marshaled into the expected structure. + assert.Equal(t, approveRet, out) + + // the transaction has been sent and cleaned up + actor.assertTransactions(rt) + }) + + t.Run("fail approval with bad proposal hash", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + + rt.SetBalance(sendValue) + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectSend(chuck, fakeMethod, fakeParams, sendValue, nil, 0) + + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{bob}, + }) + _ = actor.approve(rt, txnID, proposalHashData, nil) + }) + }) + + t.Run("fail approve transaction more than once", func(t *testing.T) { + const numApprovals = uint64(2) + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, builtin.MethodSend, fakeParams, nil) + rt.Verify() + + // anne is going to approve it twice and fail, poor anne. + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + _ = actor.approve(rt, txnID, proposalHashData, nil) + }) + rt.Verify() + + // Transaction still exists + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + }) + + t.Run("fail approve transaction that does not exist", func(t *testing.T) { + const dneTxnID = int64(1) + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, builtin.MethodSend, fakeParams, nil) + rt.Verify() + + // bob is going to approve a transaction that doesn't exist. + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrNotFound, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{bob}, + }) + _ = actor.approve(rt, dneTxnID, proposalHashData, nil) + }) + rt.Verify() + + // Transaction was not removed from store. + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + }) + + t.Run("fail to approve transaction by non-signer", func(t *testing.T) { + // non-signer address + richard := tutil.NewIDAddr(t, 105) + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, builtin.MethodSend, fakeParams, nil) + + // richard is going to approve a transaction they are not a signer for. + rt.SetCaller(richard, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{richard}, + }) + _ = actor.approve(rt, txnID, proposalHashData, nil) + }) + rt.Verify() + + // Transaction was not removed from store. + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: builtin.MethodSend, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + }) + + t.Run("proposed transaction is approved by proposer if number of approvers has already crossed threshold", func(t *testing.T) { + rt := builder.Build(t) + const newThreshold = 1 + signers := []addr.Address{anne, bob} + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + proposalHash := actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // reduce the threshold so the transaction is already approved + rt.SetCaller(receiver, builtin.MultisigActorCodeID) + rt.ExpectValidateCallerAddr(receiver) + actor.changeNumApprovalsThreshold(rt, newThreshold) + rt.Verify() + + // even if anne calls for an approval again(duplicate approval), transaction is executed because the threshold has been met. + rt.ExpectSend(chuck, fakeMethod, fakeParams, sendValue, nil, 0) + rt.SetBalance(sendValue) + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.approveOK(rt, txnID, proposalHash, nil) + + // Transaction should be removed from actor state after send + actor.assertTransactions(rt) + }) + + t.Run("approve transaction if number of approvers has already crossed threshold even if we attempt a duplicate approval", func(t *testing.T) { + rt := builder.Build(t) + const numApprovals = 3 + const newThreshold = 2 + signers := []addr.Address{anne, bob, chuck} + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + proposalHash := actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // bob approves the transaction (number of approvals is now two but threshold is three) + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + + actor.approveOK(rt, txnID, proposalHash, nil) + + // reduce the threshold so the transaction is already approved + rt.SetCaller(receiver, builtin.MultisigActorCodeID) + rt.ExpectValidateCallerAddr(receiver) + actor.changeNumApprovalsThreshold(rt, newThreshold) + rt.Verify() + + // even if bob calls for an approval again(duplicate approval), transaction is executed because the threshold has been met. + rt.ExpectSend(chuck, fakeMethod, fakeParams, sendValue, nil, 0) + rt.SetBalance(sendValue) + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.approveOK(rt, txnID, proposalHash, nil) + + // Transaction should be removed from actor state after send + actor.assertTransactions(rt) + }) + + t.Run("approve transaction if number of approvers has already crossed threshold and ensure non-signatory cannot approve a transaction", func(t *testing.T) { + rt := builder.Build(t) + const newThreshold = 1 + signers := []addr.Address{anne, bob} + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + proposalHash := actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // reduce the threshold so the transaction is already approved + rt.SetCaller(receiver, builtin.MultisigActorCodeID) + rt.ExpectValidateCallerAddr(receiver) + actor.changeNumApprovalsThreshold(rt, newThreshold) + rt.Verify() + + // alice cannot approve the transaction as alice is not a signatory + alice := tutil.NewIDAddr(t, 104) + rt.SetCaller(alice, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + _ = actor.approve(rt, txnID, proposalHash, nil) + }) + rt.Verify() + + // bob attempts to approve the transaction but it gets approved without + // processing his approval as it the threshold has been met. + rt.ExpectSend(chuck, fakeMethod, fakeParams, sendValue, nil, 0) + rt.SetBalance(sendValue) + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + + actor.approveOK(rt, txnID, proposalHash, nil) + + // Transaction should be removed from actor state after send + actor.assertTransactions(rt) + }) +} + +func TestCancel(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + richard := tutil.NewIDAddr(t, 104) + receiver := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + chuck := tutil.NewIDAddr(t, 103) + + const noUnlockDuration = int64(0) + const numApprovals = uint64(2) + const txnID = int64(0) + const fakeMethod = abi.MethodNum(42) + var fakeParams = []byte{1, 2, 3, 4, 5} + var sendValue = abi.NewTokenAmount(10) + var signers = []addr.Address{anne, bob} + + builder := mock.NewBuilder(context.Background(), receiver). + WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID). + WithHasher(blake2b.Sum256) + + t.Run("simple propose and cancel", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // anne cancels their transaction + rt.SetBalance(sendValue) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + actor.cancel(rt, txnID, proposalHashData) + rt.Verify() + + // Transaction should be removed from actor state after cancel + actor.assertTransactions(rt) + }) + + t.Run("fail cancel with bad proposal hash", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // anne cancels their transaction + rt.SetBalance(sendValue) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + + rt.ExpectAbort(exitcode.ErrIllegalState, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: bob, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{chuck}, + }) + actor.cancel(rt, txnID, proposalHashData) + }) + }) + + t.Run("signer fails to cancel transaction from another signer", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // bob (a signer) fails to cancel anne's transaction because bob didn't create it, nice try bob. + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + actor.cancel(rt, txnID, proposalHashData) + }) + rt.Verify() + + // Transaction should remain after invalid cancel + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + }) + + t.Run("fail to cancel transaction when not signer", func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // richard (not a signer) fails to cancel anne's transaction because richard isn't a signer, go away richard. + rt.SetCaller(richard, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + actor.cancel(rt, txnID, proposalHashData) + }) + rt.Verify() + + // Transaction should remain after invalid cancel + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + }) + + t.Run("fail to cancel a transaction that does not exist", func(t *testing.T) { + rt := builder.Build(t) + const dneTxnID = int64(1) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction ID: 0 + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + rt.Verify() + + // anne fails to cancel a transaction that does not exists ID: 1 (dneTxnID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrNotFound, func() { + proposalHashData := makeProposalHash(t, &multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + actor.cancel(rt, dneTxnID, proposalHashData) + }) + rt.Verify() + + // Transaction should remain after invalid cancel + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne}, + }) + }) + + t.Run("transaction can ONLY be cancelled by a proposer who is still the signer", func(t *testing.T) { + rt := builder.Build(t) + const numApprovals = 3 + signers := []addr.Address{anne, bob, chuck} + + txnId := int64(0) + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, signers...) + + // anne proposes a transaction ID: 0 + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + proposalHash := actor.proposeOK(rt, chuck, sendValue, fakeMethod, fakeParams, nil) + + // bob approves the transaction -> but he is the second approver and hence not the proposer + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.approveOK(rt, txnId, proposalHash, nil) + + // remove anne as a signer - tx creator + rt.SetCaller(receiver, builtin.MultisigActorCodeID) + rt.ExpectValidateCallerAddr(receiver) + actor.removeSigner(rt, anne, true) + + // anne fails to cancel a transaction - she is not a signer + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + actor.cancel(rt, txnID, proposalHash) + }) + + // bob fails to cancel the transaction -> he is not the proposer + rt.SetCaller(bob, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + rt.ExpectAbort(exitcode.ErrForbidden, func() { + actor.cancel(rt, txnID, proposalHash) + }) + + // Transaction should remain after invalid cancel + actor.assertTransactions(rt, multisig.Transaction{ + To: chuck, + Value: sendValue, + Method: fakeMethod, + Params: fakeParams, + Approved: []addr.Address{anne, bob}, + }) + + // add anne as a signer again + rt.SetCaller(receiver, builtin.MultisigActorCodeID) + rt.ExpectValidateCallerAddr(receiver) + actor.addSigner(rt, anne, true) + + // now anne can cancel the transaction + rt.SetCaller(anne, builtin.AccountActorCodeID) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + actor.cancel(rt, txnID, proposalHash) + actor.assertTransactions(rt) + }) +} + +type addSignerTestCase struct { + desc string + + idAddrsMapping map[addr.Address]addr.Address + initialSigners []addr.Address + initialApprovals uint64 + + addSigner addr.Address + increase bool + + expectSigners []addr.Address + expectApprovals uint64 + code exitcode.ExitCode +} + +func TestAddSigner(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + multisigWalletAdd := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + chuck := tutil.NewIDAddr(t, 103) + chuckNonId := tutil.NewBLSAddr(t,1) + + const noUnlockDuration = int64(0) + + testCases := []addSignerTestCase{ + { + desc: "happy path add signer", + + initialSigners: []addr.Address{anne, bob}, + initialApprovals: uint64(2), + + addSigner: chuck, + increase: false, + + expectSigners: []addr.Address{anne, bob, chuck}, + expectApprovals: uint64(2), + code: exitcode.Ok, + }, + { + desc: "add signer and increase threshold", + + initialSigners: []addr.Address{anne, bob}, + initialApprovals: uint64(2), + + addSigner: chuck, + increase: true, + + expectSigners: []addr.Address{anne, bob, chuck}, + expectApprovals: uint64(3), + code: exitcode.Ok, + }, + { + desc: "fail to add signer than already exists", + + initialSigners: []addr.Address{anne, bob, chuck}, + initialApprovals: uint64(3), + + addSigner: chuck, + increase: false, + + expectSigners: []addr.Address{anne, bob, chuck}, + expectApprovals: uint64(3), + code: exitcode.ErrIllegalArgument, + }, + { + desc: "fail to add signer with ID address that already exists(even though we ONLY have the non ID address as an approver)", + + idAddrsMapping: map[addr.Address]addr.Address{chuckNonId: chuck}, + initialSigners: []addr.Address{anne, bob, chuckNonId}, + initialApprovals: uint64(3), + + addSigner: chuck, + increase: false, + + expectSigners: []addr.Address{anne, bob, chuck}, + expectApprovals: uint64(3), + code: exitcode.ErrIllegalArgument, + }, + { + desc: "fail to add signer with non-ID address that already exists(even though we ONLY have the ID address as an approver)", + idAddrsMapping: map[addr.Address]addr.Address{chuckNonId: chuck}, + initialSigners: []addr.Address{anne, bob, chuck}, + initialApprovals: uint64(3), + + addSigner: chuckNonId, + increase: false, + + expectSigners: []addr.Address{anne, bob, chuck}, + expectApprovals: uint64(3), + code: exitcode.ErrIllegalArgument, + }, + } + + builder := mock.NewBuilder(context.Background(), multisigWalletAdd).WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, tc.initialApprovals, noUnlockDuration, tc.initialSigners...) + + rt.SetCaller(multisigWalletAdd, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(multisigWalletAdd) + for src,target := range tc.idAddrsMapping { + rt.AddIDAddress(src,target) + } + if tc.code != exitcode.Ok { + rt.ExpectAbort(tc.code, func() { + actor.addSigner(rt, tc.addSigner, tc.increase) + }) + } else { + actor.addSigner(rt, tc.addSigner, tc.increase) + var st multisig.State + rt.Readonly(&st) + assert.Equal(t, tc.expectSigners, st.Signers) + assert.Equal(t, tc.expectApprovals, st.NumApprovalsThreshold) + } + rt.Verify() + }) + } +} + +type removeSignerTestCase struct { + desc string + + initialSigners []addr.Address + initialApprovals uint64 + + removeSigner addr.Address + decrease bool + + expectSigners []addr.Address + expectApprovals uint64 + code exitcode.ExitCode +} + +func TestRemoveSigner(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + multisigWalletAdd := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + chuck := tutil.NewIDAddr(t, 103) + richard := tutil.NewIDAddr(t, 104) + + const noUnlockDuration = int64(0) + + testCases := []removeSignerTestCase{ + { + desc: "happy path remove signer", + + initialSigners: []addr.Address{anne, bob, chuck}, + initialApprovals: uint64(2), + + removeSigner: chuck, + decrease: false, + + expectSigners: []addr.Address{anne, bob}, + expectApprovals: uint64(2), + code: exitcode.Ok, + }, + { + desc: "remove signer and decrease threshold", + + initialSigners: []addr.Address{anne, bob, chuck}, + initialApprovals: uint64(2), + + removeSigner: chuck, + decrease: true, + + expectSigners: []addr.Address{anne, bob}, + expectApprovals: uint64(1), + code: exitcode.Ok, + }, + { + desc: "fail remove signer if decrease set to false and number of signers below threshold", + + initialSigners: []addr.Address{anne, bob, chuck}, + initialApprovals: uint64(3), + + removeSigner: chuck, + decrease: false, + + expectSigners: []addr.Address{anne, bob}, + expectApprovals: uint64(2), + code: exitcode.ErrIllegalArgument, + }, + { + desc: "remove signer from single singer list", + + initialSigners: []addr.Address{anne}, + initialApprovals: uint64(1), + + removeSigner: anne, + decrease: false, + + expectSigners: nil, + expectApprovals: uint64(1), + code: exitcode.ErrForbidden, + }, + { + desc: "fail to remove non-signer", + + initialSigners: []addr.Address{anne, bob, chuck}, + initialApprovals: uint64(2), + + removeSigner: richard, + decrease: false, + + expectSigners: []addr.Address{anne, bob, chuck}, + expectApprovals: uint64(2), + code: exitcode.ErrNotFound, + }, + } + + builder := mock.NewBuilder(context.Background(), multisigWalletAdd).WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, tc.initialApprovals, noUnlockDuration, tc.initialSigners...) + + rt.SetCaller(multisigWalletAdd, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(multisigWalletAdd) + if tc.code != exitcode.Ok { + rt.ExpectAbort(tc.code, func() { + actor.removeSigner(rt, tc.removeSigner, tc.decrease) + }) + } else { + actor.removeSigner(rt, tc.removeSigner, tc.decrease) + var st multisig.State + rt.Readonly(&st) + assert.Equal(t, tc.expectSigners, st.Signers) + assert.Equal(t, tc.expectApprovals, st.NumApprovalsThreshold) + } + rt.Verify() + }) + } +} + +type swapTestCase struct { + initialSigner []addr.Address + idAddrMappings map[addr.Address]addr.Address + desc string + to addr.Address + from addr.Address + expect []addr.Address + code exitcode.ExitCode +} + +func TestSwapSigners(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + multisigWalletAdd := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + bobNonId := tutil.NewBLSAddr(t,1) + chuck := tutil.NewIDAddr(t, 103) + darlene := tutil.NewIDAddr(t, 104) + + const noUnlockDuration = int64(0) + const numApprovals = uint64(1) + + testCases := []swapTestCase{ + { + desc: "happy path signer swap", + initialSigner : []addr.Address{anne, bob}, + to: chuck, + from: bob, + expect: []addr.Address{anne, chuck}, + code: exitcode.Ok, + }, + { + desc: "fail to swap when from signer not found", + initialSigner : []addr.Address{anne, bob}, + to: chuck, + from: darlene, + expect: []addr.Address{anne, chuck}, + code: exitcode.ErrNotFound, + }, + { + desc: "fail to swap when to signer already present", + initialSigner : []addr.Address{anne, bob}, + to: bob, + from: anne, + expect: []addr.Address{anne, chuck}, + code: exitcode.ErrIllegalArgument, + }, + { + desc: "fail to swap when to signer ID address already present(even though we have the non-ID address)", + initialSigner : []addr.Address{anne, bobNonId}, + idAddrMappings: map[addr.Address]addr.Address{bobNonId:bob}, + to: bob, + from: anne, + expect: []addr.Address{anne, chuck}, + code: exitcode.ErrIllegalArgument, + }, + { + desc: "fail to swap when to signer non-ID address already present(even though we have the ID address)", + initialSigner : []addr.Address{anne, bob}, + idAddrMappings: map[addr.Address]addr.Address{bobNonId:bob}, + to: bobNonId, + from: anne, + expect: []addr.Address{anne, chuck}, + code: exitcode.ErrIllegalArgument, + }, + } + + builder := mock.NewBuilder(context.Background(), multisigWalletAdd).WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, numApprovals, noUnlockDuration, tc.initialSigner...) + for src,target := range tc.idAddrMappings { + rt.AddIDAddress(src, target) + } + + rt.SetCaller(multisigWalletAdd, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(multisigWalletAdd) + if tc.code != exitcode.Ok { + rt.ExpectAbort(tc.code, func() { + actor.swapSigners(rt, tc.from, tc.to) + }) + } else { + actor.swapSigners(rt, tc.from, tc.to) + var st multisig.State + rt.Readonly(&st) + assert.Equal(t, tc.expect, st.Signers) + } + rt.Verify() + }) + } +} + +type thresholdTestCase struct { + desc string + initialThreshold uint64 + setThreshold uint64 + code exitcode.ExitCode +} + +func TestChangeThreshold(t *testing.T) { + actor := msActorHarness{multisig.Actor{}, t} + + multisigWalletAdd := tutil.NewIDAddr(t, 100) + anne := tutil.NewIDAddr(t, 101) + bob := tutil.NewIDAddr(t, 102) + chuck := tutil.NewIDAddr(t, 103) + + const noUnlockDuration = int64(0) + var initialSigner = []addr.Address{anne, bob, chuck} + + testCases := []thresholdTestCase{ + { + desc: "happy path decrease threshold", + initialThreshold: 2, + setThreshold: 1, + code: exitcode.Ok, + }, + { + desc: "happy path simple increase threshold", + initialThreshold: 2, + setThreshold: 3, + code: exitcode.Ok, + }, + { + desc: "fail to set threshold to zero", + initialThreshold: 2, + setThreshold: 0, + code: exitcode.ErrIllegalArgument, + }, + { + desc: "fail to set threshold above number of signers", + initialThreshold: 2, + setThreshold: uint64(len(initialSigner) + 1), + code: exitcode.ErrIllegalArgument, + }, + // TODO missing test case that needs definition: https://github.com/filecoin-project/specs-actors/issues/71 + // what happens when threshold is reduced below the number of approvers an existing transaction already ha + } + + builder := mock.NewBuilder(context.Background(), multisigWalletAdd).WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + rt := builder.Build(t) + + actor.constructAndVerify(rt, tc.initialThreshold, noUnlockDuration, initialSigner...) + + rt.SetCaller(multisigWalletAdd, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(multisigWalletAdd) + if tc.code != exitcode.Ok { + rt.ExpectAbort(tc.code, func() { + actor.changeNumApprovalsThreshold(rt, tc.setThreshold) + }) + } else { + actor.changeNumApprovalsThreshold(rt, tc.setThreshold) + var st multisig.State + rt.Readonly(&st) + assert.Equal(t, tc.setThreshold, st.NumApprovalsThreshold) + } + rt.Verify() + }) + } +} + +// +// Helper methods for calling multisig actor methods +// + +type msActorHarness struct { + a multisig.Actor + t testing.TB +} + +func (h *msActorHarness) constructAndVerify(rt *mock.Runtime, numApprovalsThresh uint64, unlockDuration int64, signers ...addr.Address) { + constructParams := multisig.ConstructorParams{ + Signers: signers, + NumApprovalsThreshold: numApprovalsThresh, + UnlockDuration: abi.ChainEpoch(unlockDuration), + } + + rt.ExpectValidateCallerAddr(builtin.InitActorAddr) + ret := rt.Call(h.a.Constructor, &constructParams) + assert.Nil(h.t, ret) + rt.Verify() +} + +func (h *msActorHarness) propose(rt *mock.Runtime, to addr.Address, value abi.TokenAmount, method abi.MethodNum, params []byte, out runtime.CBORUnmarshaler) exitcode.ExitCode { + proposeParams := &multisig.ProposeParams{ + To: to, + Value: value, + Method: method, + Params: params, + } + ret := rt.Call(h.a.Propose, proposeParams) + rt.Verify() + + proposeReturn, ok := ret.(*multisig.ProposeReturn) + if !ok { + h.t.Fatalf("unexpected type returned from call to Propose") + } + // if the transaction was applied and a return value is expected deserialize it to the out parameter + if proposeReturn.Applied { + if out != nil { + require.NoError(h.t, out.UnmarshalCBOR(bytes.NewReader(proposeReturn.Ret))) + } + } + return proposeReturn.Code +} + +// returns the proposal hash +func (h *msActorHarness) proposeOK(rt *mock.Runtime, to addr.Address, value abi.TokenAmount, method abi.MethodNum, params []byte, out runtime.CBORUnmarshaler) []byte { + code := h.propose(rt, to, value, method, params, out) + if code != exitcode.Ok { + h.t.Fatalf("unexpected exitcode %d from propose", code) + } + + proposalHashData, err := multisig.ComputeProposalHash(&multisig.Transaction{ + To: to, + Value: value, + Method: method, + Params: params, + Approved: []addr.Address{rt.Caller()}, + }, blake2b.Sum256) + require.NoError(h.t, err) + + return proposalHashData +} + +func (h *msActorHarness) approve(rt *mock.Runtime, txnID int64, proposalParams []byte, out runtime.CBORUnmarshaler) exitcode.ExitCode { + approveParams := &multisig.TxnIDParams{ID: multisig.TxnID(txnID), ProposalHash: proposalParams} + ret := rt.Call(h.a.Approve, approveParams) + rt.Verify() + approveReturn, ok := ret.(*multisig.ApproveReturn) + if !ok { + h.t.Fatalf("unexpected type returned from call to Approve") + } + // if the transaction was applied and a return value is expected deserialize it to the out parameter + if approveReturn.Applied { + if out != nil { + require.NoError(h.t, out.UnmarshalCBOR(bytes.NewReader(approveReturn.Ret))) + } + } + return approveReturn.Code +} + +func (h *msActorHarness) approveOK(rt *mock.Runtime, txnID int64, proposalParams []byte, out runtime.CBORUnmarshaler) { + code := h.approve(rt, txnID, proposalParams, out) + if code != exitcode.Ok { + h.t.Fatalf("unexpected exitcode %d from approve", code) + } +} + +func (h *msActorHarness) cancel(rt *mock.Runtime, txnID int64, proposalParams []byte) { + cancelParams := &multisig.TxnIDParams{ID: multisig.TxnID(txnID), ProposalHash: proposalParams} + rt.Call(h.a.Cancel, cancelParams) + rt.Verify() +} + +func (h *msActorHarness) addSigner(rt *mock.Runtime, signer addr.Address, increase bool) { + addSignerParams := &multisig.AddSignerParams{ + Signer: signer, + Increase: increase, + } + rt.Call(h.a.AddSigner, addSignerParams) + rt.Verify() +} + +func (h *msActorHarness) removeSigner(rt *mock.Runtime, signer addr.Address, decrease bool) { + rmSignerParams := &multisig.RemoveSignerParams{ + Signer: signer, + Decrease: decrease, + } + rt.Call(h.a.RemoveSigner, rmSignerParams) + rt.Verify() +} + +func (h *msActorHarness) swapSigners(rt *mock.Runtime, oldSigner, newSigner addr.Address) { + swpParams := &multisig.SwapSignerParams{ + From: oldSigner, + To: newSigner, + } + rt.Call(h.a.SwapSigner, swpParams) +} + +func (h *msActorHarness) changeNumApprovalsThreshold(rt *mock.Runtime, newThreshold uint64) { + thrshParams := &multisig.ChangeNumApprovalsThresholdParams{NewThreshold: newThreshold} + rt.Call(h.a.ChangeNumApprovalsThreshold, thrshParams) +} + +func (h *msActorHarness) assertTransactions(rt *mock.Runtime, expected ...multisig.Transaction) { + var st multisig.State + rt.GetState(&st) + + txns, err := adt.AsMap(adt.AsStore(rt), st.PendingTxns) + assert.NoError(h.t, err) + keys, err := txns.CollectKeys() + assert.NoError(h.t, err) + + require.Equal(h.t, len(expected), len(keys)) + for i, k := range keys { + var actual multisig.Transaction + found, err_ := txns.Get(asKey(k), &actual) + require.NoError(h.t, err_) + assert.True(h.t, found) + assert.Equal(h.t, expected[i], actual) + } +} + +func makeProposalHash(t *testing.T, txn *multisig.Transaction) []byte { + proposalHashData, err := multisig.ComputeProposalHash(txn, blake2b.Sum256) + require.NoError(t, err) + return proposalHashData +} + +type key string + +func (s key) Key() string { + return string(s) +} + +func asKey(in string) adt.Keyer { + return key(in) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/network.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/network.go new file mode 100644 index 0000000000..12567d1da5 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/network.go @@ -0,0 +1,30 @@ +package builtin + +import "fmt" + +// The duration of a chain epoch. +// This is used for deriving epoch-denominated periods that are more naturally expressed in clock time. +// TODO: In lieu of a real configuration mechanism for this value, we'd like to make it a var so that implementations +// can override it at runtime. Doing so requires changing all the static references to it in this repo to go through +// late-binding function calls, or they'll see the "wrong" value. +// https://github.com/filecoin-project/specs-actors/issues/353 +const EpochDurationSeconds = 25 +const SecondsInHour = 3600 +const SecondsInDay = 86400 +const SecondsInYear = 31556925 +const EpochsInHour = SecondsInHour / EpochDurationSeconds +const EpochsInDay = SecondsInDay / EpochDurationSeconds +const EpochsInYear = SecondsInYear / EpochDurationSeconds + +// The expected number of block producers in each epoch. +var ExpectedLeadersPerEpoch = int64(5) + +func init() { + //noinspection GoBoolExpressions + if SecondsInHour%EpochDurationSeconds != 0 { + // This even division is an assumption that other code might unwittingly make. + // Don't rely on it on purpose, though. + // While we're pretty sure everything will still work fine, we're safer maintaining this invariant anyway. + panic(fmt.Sprintf("epoch duration %d does not evenly divide one hour (%d)", EpochDurationSeconds, SecondsInHour)) + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/cbor_gen.go new file mode 100644 index 0000000000..719debdf52 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/cbor_gen.go @@ -0,0 +1,1007 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package paych + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + crypto "github.com/filecoin-project/specs-actors/actors/crypto" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{134}); err != nil { + return err + } + + // t.From (address.Address) (struct) + if err := t.From.MarshalCBOR(w); err != nil { + return err + } + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + + // t.ToSend (big.Int) (struct) + if err := t.ToSend.MarshalCBOR(w); err != nil { + return err + } + + // t.SettlingAt (abi.ChainEpoch) (int64) + if t.SettlingAt >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SettlingAt))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SettlingAt)-1)); err != nil { + return err + } + } + + // t.MinSettleHeight (abi.ChainEpoch) (int64) + if t.MinSettleHeight >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.MinSettleHeight))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.MinSettleHeight)-1)); err != nil { + return err + } + } + + // t.LaneStates ([]*paych.LaneState) (slice) + if len(t.LaneStates) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.LaneStates was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.LaneStates)))); err != nil { + return err + } + for _, v := range t.LaneStates { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 6 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.From (address.Address) (struct) + + { + + if err := t.From.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.From: %w", err) + } + + } + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + // t.ToSend (big.Int) (struct) + + { + + if err := t.ToSend.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ToSend: %w", err) + } + + } + // t.SettlingAt (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SettlingAt = abi.ChainEpoch(extraI) + } + // t.MinSettleHeight (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.MinSettleHeight = abi.ChainEpoch(extraI) + } + // t.LaneStates ([]*paych.LaneState) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.LaneStates: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.LaneStates = make([]*LaneState, extra) + } + + for i := 0; i < int(extra); i++ { + + var v LaneState + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.LaneStates[i] = &v + } + + return nil +} + +func (t *LaneState) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.ID (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.ID))); err != nil { + return err + } + + // t.Redeemed (big.Int) (struct) + if err := t.Redeemed.MarshalCBOR(w); err != nil { + return err + } + + // t.Nonce (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Nonce))); err != nil { + return err + } + + return nil +} + +func (t *LaneState) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.ID (uint64) (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.ID = uint64(extra) + + } + // t.Redeemed (big.Int) (struct) + + { + + if err := t.Redeemed.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Redeemed: %w", err) + } + + } + // t.Nonce (uint64) (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.Nonce = uint64(extra) + + } + return nil +} + +func (t *Merge) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Lane (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Lane))); err != nil { + return err + } + + // t.Nonce (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Nonce))); err != nil { + return err + } + + return nil +} + +func (t *Merge) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Lane (uint64) (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.Lane = uint64(extra) + + } + // t.Nonce (uint64) (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.Nonce = uint64(extra) + + } + return nil +} + +func (t *ConstructorParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.From (address.Address) (struct) + if err := t.From.MarshalCBOR(w); err != nil { + return err + } + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *ConstructorParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.From (address.Address) (struct) + + { + + if err := t.From.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.From: %w", err) + } + + } + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + return nil +} + +func (t *UpdateChannelStateParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.Sv (paych.SignedVoucher) (struct) + if err := t.Sv.MarshalCBOR(w); err != nil { + return err + } + + // t.Secret ([]uint8) (slice) + if len(t.Secret) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Secret was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Secret)))); err != nil { + return err + } + if _, err := w.Write(t.Secret); err != nil { + return err + } + + // t.Proof ([]uint8) (slice) + if len(t.Proof) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Proof was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Proof)))); err != nil { + return err + } + if _, err := w.Write(t.Proof); err != nil { + return err + } + return nil +} + +func (t *UpdateChannelStateParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Sv (paych.SignedVoucher) (struct) + + { + + if err := t.Sv.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Sv: %w", err) + } + + } + // t.Secret ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Secret: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Secret = make([]byte, extra) + if _, err := io.ReadFull(br, t.Secret); err != nil { + return err + } + // t.Proof ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Proof: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Proof = make([]byte, extra) + if _, err := io.ReadFull(br, t.Proof); err != nil { + return err + } + return nil +} + +func (t *SignedVoucher) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{138}); err != nil { + return err + } + + // t.TimeLockMin (abi.ChainEpoch) (int64) + if t.TimeLockMin >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.TimeLockMin))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.TimeLockMin)-1)); err != nil { + return err + } + } + + // t.TimeLockMax (abi.ChainEpoch) (int64) + if t.TimeLockMax >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.TimeLockMax))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.TimeLockMax)-1)); err != nil { + return err + } + } + + // t.SecretPreimage ([]uint8) (slice) + if len(t.SecretPreimage) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.SecretPreimage was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.SecretPreimage)))); err != nil { + return err + } + if _, err := w.Write(t.SecretPreimage); err != nil { + return err + } + + // t.Extra (paych.ModVerifyParams) (struct) + if err := t.Extra.MarshalCBOR(w); err != nil { + return err + } + + // t.Lane (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Lane))); err != nil { + return err + } + + // t.Nonce (uint64) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Nonce))); err != nil { + return err + } + + // t.Amount (big.Int) (struct) + if err := t.Amount.MarshalCBOR(w); err != nil { + return err + } + + // t.MinSettleHeight (abi.ChainEpoch) (int64) + if t.MinSettleHeight >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.MinSettleHeight))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.MinSettleHeight)-1)); err != nil { + return err + } + } + + // t.Merges ([]paych.Merge) (slice) + if len(t.Merges) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Merges was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Merges)))); err != nil { + return err + } + for _, v := range t.Merges { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + + // t.Signature (crypto.Signature) (struct) + if err := t.Signature.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SignedVoucher) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 10 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.TimeLockMin (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.TimeLockMin = abi.ChainEpoch(extraI) + } + // t.TimeLockMax (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.TimeLockMax = abi.ChainEpoch(extraI) + } + // t.SecretPreimage ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.SecretPreimage: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.SecretPreimage = make([]byte, extra) + if _, err := io.ReadFull(br, t.SecretPreimage); err != nil { + return err + } + // t.Extra (paych.ModVerifyParams) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Extra = new(ModVerifyParams) + if err := t.Extra.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Extra pointer: %w", err) + } + } + + } + // t.Lane (uint64) (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.Lane = uint64(extra) + + } + // t.Nonce (uint64) (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.Nonce = uint64(extra) + + } + // t.Amount (big.Int) (struct) + + { + + if err := t.Amount.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Amount: %w", err) + } + + } + // t.MinSettleHeight (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.MinSettleHeight = abi.ChainEpoch(extraI) + } + // t.Merges ([]paych.Merge) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Merges: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Merges = make([]Merge, extra) + } + + for i := 0; i < int(extra); i++ { + + var v Merge + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Merges[i] = v + } + + // t.Signature (crypto.Signature) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Signature = new(crypto.Signature) + if err := t.Signature.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Signature pointer: %w", err) + } + } + + } + return nil +} + +func (t *ModVerifyParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.Actor (address.Address) (struct) + if err := t.Actor.MarshalCBOR(w); err != nil { + return err + } + + // t.Method (abi.MethodNum) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Method))); err != nil { + return err + } + + // t.Data ([]uint8) (slice) + if len(t.Data) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Data was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Data)))); err != nil { + return err + } + if _, err := w.Write(t.Data); err != nil { + return err + } + return nil +} + +func (t *ModVerifyParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Actor (address.Address) (struct) + + { + + if err := t.Actor.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Actor: %w", err) + } + + } + // t.Method (abi.MethodNum) (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.Method = abi.MethodNum(extra) + + } + // t.Data ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Data: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Data = make([]byte, extra) + if _, err := io.ReadFull(br, t.Data); err != nil { + return err + } + return nil +} + +func (t *PaymentVerifyParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Extra ([]uint8) (slice) + if len(t.Extra) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Extra was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Extra)))); err != nil { + return err + } + if _, err := w.Write(t.Extra); err != nil { + return err + } + + // t.Proof ([]uint8) (slice) + if len(t.Proof) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Proof was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Proof)))); err != nil { + return err + } + if _, err := w.Write(t.Proof); err != nil { + return err + } + return nil +} + +func (t *PaymentVerifyParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Extra ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Extra: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Extra = make([]byte, extra) + if _, err := io.ReadFull(br, t.Extra); err != nil { + return err + } + // t.Proof ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Proof: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Proof = make([]byte, extra) + if _, err := io.ReadFull(br, t.Proof); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_actor.go new file mode 100644 index 0000000000..8e2b55c98d --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_actor.go @@ -0,0 +1,340 @@ +package paych + +import ( + "bytes" + "fmt" + "sort" + + addr "github.com/filecoin-project/go-address" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + crypto "github.com/filecoin-project/specs-actors/actors/crypto" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +// Maximum number of lanes in a channel. +const LaneLimit = 256 + +const SettleDelay = abi.ChainEpoch(1) // placeholder PARAM_FINISH + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.UpdateChannelState, + 3: a.Settle, + 4: a.Collect, + } +} + +var _ abi.Invokee = Actor{} + +type ConstructorParams struct { + From addr.Address // Payer + To addr.Address // Payee +} + +// Constructor creates a payment channel actor. See State for meaning of params. +func (pca *Actor) Constructor(rt vmr.Runtime, params *ConstructorParams) *adt.EmptyValue { + // Only InitActor can create a payment channel actor. It creates the actor on + // behalf of the payer/payee. + rt.ValidateImmediateCallerType(builtin.InitActorCodeID) + + // check that both parties are capable of signing vouchers + to, err := pca.resolveAccount(rt, params.To) + if err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, err.Error()) + } + from, err := pca.resolveAccount(rt, params.From) + if err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, err.Error()) + } + + st := ConstructState(from, to) + rt.State().Create(st) + + return nil +} + +// Resolves an address to a canonical ID address and requires it to address an account actor. +// The account actor constructor checks that the embedded address is associated with an appropriate key. +// An alternative (more expensive) would be to send a message to the actor to fetch its key. +func (pca *Actor) resolveAccount(rt vmr.Runtime, raw addr.Address) (addr.Address, error) { + resolved, ok := rt.ResolveAddress(raw) + if !ok { + return addr.Undef, fmt.Errorf("failed to resolve address %v", raw) + } + + codeCID, ok := rt.GetActorCodeCID(resolved) + if !ok { + return addr.Undef, fmt.Errorf("no code for address %v", resolved) + } + if codeCID != builtin.AccountActorCodeID { + return addr.Undef, fmt.Errorf("actor %v must be an account (%v), was %v", raw, builtin.AccountActorCodeID, codeCID) + } + return resolved, nil +} + +//////////////////////////////////////////////////////////////////////////////// +// Payment Channel state operations +//////////////////////////////////////////////////////////////////////////////// + +type UpdateChannelStateParams struct { + Sv SignedVoucher + Secret []byte + Proof []byte +} + +// A voucher is sent by `From` to `To` off-chain in order to enable +// `To` to redeem payments on-chain in the future +type SignedVoucher struct { + // TimeLockMin sets a min epoch before which the voucher cannot be redeemed + TimeLockMin abi.ChainEpoch + // TimeLockMax sets a max epoch beyond which the voucher cannot be redeemed + // TimeLockMax set to 0 means no timeout + TimeLockMax abi.ChainEpoch + // (optional) The SecretPreImage is used by `To` to validate + SecretPreimage []byte + // (optional) Extra can be specified by `From` to add a verification method to the voucher + Extra *ModVerifyParams + // Specifies which lane the Voucher merges into (will be created if does not exist) + Lane uint64 + // Nonce is set by `From` to prevent redemption of stale vouchers on a lane + Nonce uint64 + // Amount voucher can be redeemed for + Amount big.Int + // (optional) MinSettleHeight can extend channel MinSettleHeight if needed + MinSettleHeight abi.ChainEpoch + + // (optional) Set of lanes to be merged into `Lane` + Merges []Merge + + // Sender's signature over the voucher + Signature *crypto.Signature +} + +// Modular Verification method +type ModVerifyParams struct { + Actor addr.Address + Method abi.MethodNum + Data []byte +} + +type PaymentVerifyParams struct { + Extra []byte + Proof []byte +} + +func (pca Actor) UpdateChannelState(rt vmr.Runtime, params *UpdateChannelStateParams) *adt.EmptyValue { + var st State + rt.State().Readonly(&st) + + // both parties must sign voucher: one who submits it, the other explicitly signs it + rt.ValidateImmediateCallerIs(st.From, st.To) + var signer addr.Address + if rt.Message().Caller() == st.From { + signer = st.To + } else { + signer = st.From + } + sv := params.Sv + + if sv.Signature == nil { + rt.Abortf(exitcode.ErrIllegalArgument, "voucher has no signature") + } + + vb, nerr := sv.SigningBytes() + if nerr != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "failed to serialize signedvoucher") + } + + if err := rt.Syscalls().VerifySignature(*sv.Signature, signer, vb); err != nil { + rt.Abortf(exitcode.ErrIllegalArgument, "voucher signature invalid: %s", err) + } + + if rt.CurrEpoch() < sv.TimeLockMin { + rt.Abortf(exitcode.ErrIllegalArgument, "cannot use this voucher yet!") + } + + if sv.TimeLockMax != 0 && rt.CurrEpoch() > sv.TimeLockMax { + rt.Abortf(exitcode.ErrIllegalArgument, "this voucher has expired!") + } + + if len(sv.SecretPreimage) > 0 { + hashedSecret := rt.Syscalls().HashBlake2b(params.Secret) + if !bytes.Equal(hashedSecret[:], sv.SecretPreimage) { + rt.Abortf(exitcode.ErrIllegalArgument, "incorrect secret!") + } + } + + if sv.Extra != nil { + + _, code := rt.Send( + sv.Extra.Actor, + sv.Extra.Method, + &PaymentVerifyParams{ + sv.Extra.Data, + params.Proof, + }, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "spend voucher verification failed") + } + + rt.State().Transaction(&st, func() interface{} { + // Find the voucher lane, create and insert it in sorted order if necessary. + laneIdx, ls := findLane(st.LaneStates, sv.Lane) + if ls == nil { + if len(st.LaneStates) >= LaneLimit { + rt.Abortf(exitcode.ErrIllegalArgument, "lane limit exceeded") + } + ls = &LaneState{ + ID: sv.Lane, + Redeemed: big.Zero(), + Nonce: 0, + } + st.LaneStates = append(st.LaneStates[:laneIdx], append([]*LaneState{ls}, st.LaneStates[laneIdx:]...)...) + + } + + if ls.Nonce > sv.Nonce { + rt.Abortf(exitcode.ErrIllegalArgument, "voucher has an outdated nonce, cannot redeem") + } + + // The next section actually calculates the payment amounts to update the payment channel state + // 1. (optional) sum already redeemed value of all merging lanes + redeemedFromOthers := big.Zero() + for _, merge := range sv.Merges { + if merge.Lane == sv.Lane { + rt.Abortf(exitcode.ErrIllegalArgument, "voucher cannot merge lanes into its own lane") + } + + _, otherls := findLane(st.LaneStates, merge.Lane) + if otherls != nil { + if otherls.Nonce >= merge.Nonce { + rt.Abortf(exitcode.ErrIllegalArgument, "merged lane in voucher has outdated nonce, cannot redeem") + } + + redeemedFromOthers = big.Add(redeemedFromOthers, otherls.Redeemed) + otherls.Nonce = merge.Nonce + } else { + rt.Abortf(exitcode.ErrIllegalArgument, "voucher specifies invalid merge lane %v", merge.Lane) + } + } + + // 2. To prevent double counting, remove already redeemed amounts (from + // voucher or other lanes) from the voucher amount + ls.Nonce = sv.Nonce + balanceDelta := big.Sub(sv.Amount, big.Add(redeemedFromOthers, ls.Redeemed)) + // 3. set new redeemed value for merged-into lane + ls.Redeemed = sv.Amount + + newSendBalance := big.Add(st.ToSend, balanceDelta) + + // 4. check operation validity + if newSendBalance.LessThan(big.Zero()) { + rt.Abortf(exitcode.ErrIllegalState, "voucher would leave channel balance negative") + } + if newSendBalance.GreaterThan(rt.CurrentBalance()) { + rt.Abortf(exitcode.ErrIllegalState, "not enough funds in channel to cover voucher") + } + + // 5. add new redemption ToSend + st.ToSend = newSendBalance + + // update channel settlingAt and MinSettleHeight if delayed by voucher + if sv.MinSettleHeight != 0 { + if st.SettlingAt != 0 && st.SettlingAt < sv.MinSettleHeight { + st.SettlingAt = sv.MinSettleHeight + } + if st.MinSettleHeight < sv.MinSettleHeight { + st.MinSettleHeight = sv.MinSettleHeight + } + } + return nil + }) + return nil +} + +func (pca Actor) Settle(rt vmr.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + var st State + rt.State().Transaction(&st, func() interface{} { + + rt.ValidateImmediateCallerIs(st.From, st.To) + + if st.SettlingAt != 0 { + rt.Abortf(exitcode.ErrIllegalState, "channel already settling") + } + + st.SettlingAt = rt.CurrEpoch() + SettleDelay + if st.SettlingAt < st.MinSettleHeight { + st.SettlingAt = st.MinSettleHeight + } + + return nil + }) + return nil +} + +func (pca Actor) Collect(rt vmr.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + var st State + rt.State().Readonly(&st) + rt.ValidateImmediateCallerIs(st.From, st.To) + + if st.SettlingAt == 0 || rt.CurrEpoch() < st.SettlingAt { + rt.Abortf(exitcode.ErrForbidden, "payment channel not settling or settled") + } + + // send remaining balance to "From" + _, codeFrom := rt.Send( + st.From, + builtin.MethodSend, + nil, + big.Sub(rt.CurrentBalance(), st.ToSend), + ) + builtin.RequireSuccess(rt, codeFrom, "Failed to send balance to `From`") + + // send ToSend to "To" + _, codeTo := rt.Send( + st.To, + builtin.MethodSend, + nil, + st.ToSend, + ) + builtin.RequireSuccess(rt, codeTo, "Failed to send funds to `To`") + + rt.State().Transaction(&st, func() interface{} { + st.ToSend = big.Zero() + return nil + }) + return nil +} + +func (t *SignedVoucher) SigningBytes() ([]byte, error) { + osv := *t + osv.Signature = nil + + buf := new(bytes.Buffer) + if err := osv.MarshalCBOR(buf); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// Returns the insertion index for a lane ID, with the matching lane state if found, or nil. +func findLane(lanes []*LaneState, ID uint64) (int, *LaneState) { + insertionIdx := sort.Search(len(lanes), func(i int) bool { + return lanes[i].ID >= ID + }) + if insertionIdx == len(lanes) || lanes[insertionIdx].ID != uint64(insertionIdx) { + // Not found + return insertionIdx, nil + } + return insertionIdx, lanes[insertionIdx] +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_state.go new file mode 100644 index 0000000000..75b3982270 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_state.go @@ -0,0 +1,54 @@ +package paych + +import ( + addr "github.com/filecoin-project/go-address" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" +) + +// A given payment channel actor is established by From +// to enable off-chain microtransactions to To to be reconciled +// and tallied on chain. +type State struct { + // Channel owner, who has funded the actor + From addr.Address + // Recipient of payouts from channel + To addr.Address + + // Amount successfully redeemed through the payment channel, paid out on `Collect()` + ToSend abi.TokenAmount + + // Height at which the channel can be `Collected` + SettlingAt abi.ChainEpoch + // Height before which the channel `ToSend` cannot be collected + MinSettleHeight abi.ChainEpoch + + // Collections of lane states for the channel, maintained in ID order. + LaneStates []*LaneState +} + +// The Lane state tracks the latest (highest) voucher nonce used to merge the lane +// as well as the amount it has already redeemed. +type LaneState struct { + ID uint64 // Unique to this channel + Redeemed big.Int + Nonce uint64 +} + +// Specifies which `Lane`s to be merged with what `Nonce` on channelUpdate +type Merge struct { + Lane uint64 + Nonce uint64 +} + +func ConstructState(from addr.Address, to addr.Address) *State { + return &State{ + From: from, + To: to, + ToSend: big.Zero(), + SettlingAt: 0, + MinSettleHeight: 0, + LaneStates: []*LaneState{}, + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_test.go new file mode 100644 index 0000000000..a0739885fa --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/paych/paych_test.go @@ -0,0 +1,817 @@ +package paych_test + +import ( + "context" + "fmt" + "math" + "reflect" + "testing" + + addr "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + . "github.com/filecoin-project/specs-actors/actors/builtin/paych" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, Actor{}) +} + +func TestPaymentChannelActor_Constructor(t *testing.T) { + ctx := context.Background() + paychAddr := tutil.NewIDAddr(t, 100) + payerAddr := tutil.NewIDAddr(t, 101) + payeeAddr := tutil.NewIDAddr(t, 102) + callerAddr := tutil.NewIDAddr(t, 102) + + actor := pcActorHarness{Actor{}, t, paychAddr, payerAddr, payeeAddr} + + t.Run("can create a payment channel actor", func(t *testing.T) { + builder := mock.NewBuilder(ctx, paychAddr). + WithCaller(callerAddr, builtin.InitActorCodeID). + WithActorType(payerAddr, builtin.AccountActorCodeID). + WithActorType(payeeAddr, builtin.AccountActorCodeID) + rt := builder.Build(t) + actor.constructAndVerify(t, rt, payerAddr, payeeAddr) + }) + + testCases := []struct { + desc string + paymentChannelAddr addr.Address + callerCode cid.Cid + newActorCode cid.Cid + payerCode cid.Cid + expExitCode exitcode.ExitCode + }{ + {"fails if target (to) is not account actor", + paychAddr, + builtin.InitActorCodeID, + builtin.MultisigActorCodeID, + builtin.AccountActorCodeID, + exitcode.ErrIllegalArgument, + }, {"fails if sender (from) is not account actor", + paychAddr, + builtin.InitActorCodeID, + builtin.MultisigActorCodeID, + builtin.AccountActorCodeID, + exitcode.ErrIllegalArgument, + }, {"fails if addr is not ID type", + tutil.NewSECP256K1Addr(t, "beach blanket babylon"), + builtin.InitActorCodeID, + builtin.AccountActorCodeID, + builtin.AccountActorCodeID, + exitcode.ErrIllegalArgument, + }, + } + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + builder := mock.NewBuilder(ctx, paychAddr). + WithCaller(callerAddr, tc.callerCode). + WithActorType(tc.paymentChannelAddr, tc.newActorCode). + WithActorType(payerAddr, tc.payerCode) + rt := builder.Build(t) + rt.ExpectValidateCallerType(builtin.InitActorCodeID) + rt.ExpectAbort(tc.expExitCode, func() { + rt.Call(actor.Constructor, &ConstructorParams{To: tc.paymentChannelAddr}) + }) + }) + } + + t.Run("fails if actor does not exist with: no code for address", func(t *testing.T) { + builder := mock.NewBuilder(ctx, paychAddr). + WithCaller(callerAddr, builtin.InitActorCodeID). + WithActorType(payerAddr, builtin.AccountActorCodeID) + rt := builder.Build(t) + rt.ExpectValidateCallerType(builtin.InitActorCodeID) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.Constructor, &ConstructorParams{To: paychAddr}) + }) + }) +} + +func TestPaymentChannelActor_CreateLane(t *testing.T) { + ctx := context.Background() + initActorAddr := tutil.NewIDAddr(t, 100) + paychAddr := tutil.NewIDAddr(t, 101) + payerAddr := tutil.NewIDAddr(t, 102) + payeeAddr := tutil.NewIDAddr(t, 103) + payChBalance := abi.NewTokenAmount(9) + + actor := pcActorHarness{Actor{}, t, paychAddr, payerAddr, payeeAddr} + sig := &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("doesn't matter")} + + testCases := []struct { + desc string + targetCode cid.Cid + + balance int64 + received int64 + epoch int64 + + tlmin int64 + tlmax int64 + lane uint64 + nonce uint64 + amt int64 + + secretPreimage []byte + sig *crypto.Signature + verifySig bool + expExitCode exitcode.ExitCode + }{ + {desc: "succeeds", targetCode: builtin.AccountActorCodeID, + amt: 1, epoch: 1, tlmin: 1, tlmax: 0, + sig: sig, verifySig: true, + expExitCode: exitcode.Ok}, + {desc: "fails if balance too low", targetCode: builtin.AccountActorCodeID, + amt: 10, epoch: 1, tlmin: 1, tlmax: 0, + sig: sig, verifySig: true, + expExitCode: exitcode.ErrIllegalState}, + {desc: "fails if new send balance is negative", targetCode: builtin.AccountActorCodeID, + amt: -1, epoch: 1, tlmin: 1, tlmax: 0, + sig: sig, verifySig: true, + expExitCode: exitcode.ErrIllegalState}, + {desc: "fails if signature not valid", targetCode: builtin.AccountActorCodeID, + amt: 1, epoch: 1, tlmin: 1, tlmax: 0, + sig: nil, verifySig: true, + expExitCode: exitcode.ErrIllegalArgument}, + {desc: "fails if too early for voucher", targetCode: builtin.AccountActorCodeID, + amt: 1, epoch: 1, tlmin: 10, tlmax: 0, + sig: sig, verifySig: true, + expExitCode: exitcode.ErrIllegalArgument}, + {desc: "fails if beyond TimeLockMax", targetCode: builtin.AccountActorCodeID, + amt: 1, epoch: 10, tlmin: 1, tlmax: 5, + sig: sig, verifySig: true, + expExitCode: exitcode.ErrIllegalArgument}, + {desc: "fails if signature not verified", targetCode: builtin.AccountActorCodeID, + amt: 1, epoch: 1, tlmin: 1, tlmax: 0, + sig: sig, verifySig: false, + expExitCode: exitcode.ErrIllegalArgument}, + {desc: "fails if SigningBytes fails", targetCode: builtin.AccountActorCodeID, + amt: 1, epoch: 1, tlmin: 1, tlmax: 0, + sig: sig, verifySig: true, + secretPreimage: make([]byte, 2<<21), + expExitCode: exitcode.ErrIllegalArgument}, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + hasher := func(data []byte) [32]byte { return [32]byte{} } + + builder := mock.NewBuilder(ctx, paychAddr). + WithBalance(payChBalance, abi.NewTokenAmount(tc.received)). + WithEpoch(abi.ChainEpoch(tc.epoch)). + WithCaller(initActorAddr, builtin.InitActorCodeID). + WithActorType(payeeAddr, builtin.AccountActorCodeID). + WithActorType(payerAddr, builtin.AccountActorCodeID). + WithHasher(hasher) + + rt := builder.Build(t) + actor.constructAndVerify(t, rt, payerAddr, payeeAddr) + + sv := SignedVoucher{ + TimeLockMin: abi.ChainEpoch(tc.tlmin), + TimeLockMax: abi.ChainEpoch(tc.tlmax), + Lane: tc.lane, + Nonce: tc.nonce, + Amount: big.NewInt(tc.amt), + Signature: tc.sig, + SecretPreimage: tc.secretPreimage, + } + ucp := &UpdateChannelStateParams{Sv: sv} + + rt.SetCaller(payeeAddr, tc.targetCode) + rt.ExpectValidateCallerAddr(payerAddr, payeeAddr) + if tc.sig != nil && tc.secretPreimage == nil { + var result error + if !tc.verifySig { + result = fmt.Errorf("bad signature") + } + rt.ExpectVerifySignature(*sv.Signature, payerAddr, voucherBytes(t, &sv), result) + } + + if tc.expExitCode == exitcode.Ok { + rt.Call(actor.UpdateChannelState, ucp) + var st State + rt.GetState(&st) + assert.Len(t, st.LaneStates, 1) + ls := st.LaneStates[0] + assert.Equal(t, sv.Amount, ls.Redeemed) + assert.Equal(t, sv.Nonce, ls.Nonce) + assert.Equal(t, sv.Lane, ls.ID) + } else { + rt.ExpectAbort(tc.expExitCode, func() { + rt.Call(actor.UpdateChannelState, ucp) + }) + // verify state unchanged; no lane was created + verifyInitialState(t, rt, payerAddr, payeeAddr) + } + rt.Verify() + }) + } +} + +func TestActor_UpdateChannelStateRedeem(t *testing.T) { + ctx := context.Background() + newVoucherAmt := big.NewInt(9) + + t.Run("redeeming voucher updates correctly with one lane", func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, ctx, 1) + var st1 State + rt.GetState(&st1) + + ucp := &UpdateChannelStateParams{Sv: *sv} + ucp.Sv.Amount = newVoucherAmt + + // Sending to same lane updates the lane with "new" state + rt.SetCaller(actor.payee, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, actor.payer, voucherBytes(t, &ucp.Sv), nil) + ret := rt.Call(actor.UpdateChannelState, ucp) + require.Nil(t, ret) + rt.Verify() + + expLs := LaneState{ + ID: 0, + Redeemed: newVoucherAmt, + Nonce: 1, + } + expState := State{ + From: st1.From, + To: st1.To, + ToSend: newVoucherAmt, + SettlingAt: st1.SettlingAt, + MinSettleHeight: st1.MinSettleHeight, + LaneStates: []*LaneState{&expLs}, + } + verifyState(t, rt, 1, expState) + }) + + t.Run("redeems voucher for correct lane", func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, ctx, 3) + var st1, st2 State + rt.GetState(&st1) + + initialAmt := st1.ToSend + + ucp := &UpdateChannelStateParams{Sv: *sv} + ucp.Sv.Amount = newVoucherAmt + ucp.Sv.Lane = 1 + lsToUpdate := st1.LaneStates[ucp.Sv.Lane] + ucp.Sv.Nonce = lsToUpdate.Nonce + 1 + + // Sending to same lane updates the lane with "new" state + rt.SetCaller(actor.payee, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, actor.payer, voucherBytes(t, &ucp.Sv), nil) + ret := rt.Call(actor.UpdateChannelState, ucp) + require.Nil(t, ret) + rt.Verify() + + rt.GetState(&st2) + lUpdated := st2.LaneStates[ucp.Sv.Lane] + + bDelta := big.Sub(ucp.Sv.Amount, lsToUpdate.Redeemed) + expToSend := big.Add(initialAmt, bDelta) + assert.Equal(t, expToSend, st2.ToSend) + assert.Equal(t, ucp.Sv.Amount, lUpdated.Redeemed) + assert.Equal(t, ucp.Sv.Nonce, lUpdated.Nonce) + }) +} + +func TestActor_UpdateChannelStateMergeSuccess(t *testing.T) { + // Check that a lane merge correctly updates lane states + numLanes := 3 + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), numLanes) + + var st1 State + rt.GetState(&st1) + rt.SetCaller(st1.From, builtin.AccountActorCodeID) + + mergeTo := st1.LaneStates[0] + mergeFrom := st1.LaneStates[1] + + // Note sv.Amount = 4 + sv.Lane = mergeTo.ID + mergeNonce := mergeTo.Nonce + 10 + + merges := []Merge{{Lane: mergeFrom.ID, Nonce: mergeNonce}} + sv.Merges = merges + + ucp := &UpdateChannelStateParams{Sv: *sv} + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, actor.payee, voucherBytes(t, &ucp.Sv), nil) + ret := rt.Call(actor.UpdateChannelState, ucp) + require.Nil(t, ret) + rt.Verify() + + expMergeTo := LaneState{ID: mergeTo.ID, Redeemed: sv.Amount, Nonce: sv.Nonce} + expMergeFrom := LaneState{ID: mergeFrom.ID, Redeemed: mergeFrom.Redeemed, Nonce: mergeNonce} + + // calculate ToSend amount + redeemed := big.Add(mergeFrom.Redeemed, mergeTo.Redeemed) + expDelta := big.Sub(sv.Amount, redeemed) + expSendAmt := big.Add(st1.ToSend, expDelta) + + // last lane should be unchanged + expState := st1 + expState.ToSend = expSendAmt + expState.LaneStates = []*LaneState{&expMergeTo, &expMergeFrom, st1.LaneStates[2]} + verifyState(t, rt, numLanes, expState) +} + +func TestActor_UpdateChannelStateMergeFailure(t *testing.T) { + testCases := []struct { + name string + balance int64 + lane, voucherNonce, mergeNonce uint64 + expExitCode exitcode.ExitCode + }{ + { + name: "fails: merged lane in voucher has outdated nonce, cannot redeem", + lane: 1, voucherNonce: 10, mergeNonce: 1, + expExitCode: exitcode.ErrIllegalArgument, + }, + { + name: "fails: voucher has an outdated nonce, cannot redeem", + lane: 1, voucherNonce: 0, mergeNonce: 10, + expExitCode: exitcode.ErrIllegalArgument, + }, + { + name: "fails: not enough funds in channel to cover voucher", + lane: 1, balance: 1, voucherNonce: 10, mergeNonce: 10, + expExitCode: exitcode.ErrIllegalState, + }, + { + name: "fails: voucher cannot merge lanes into its own lane", + lane: 0, voucherNonce: 10, mergeNonce: 10, + expExitCode: exitcode.ErrIllegalArgument, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), 2) + if tc.balance > 0 { + rt.SetBalance(abi.NewTokenAmount(tc.balance)) + } + + var st1 State + rt.GetState(&st1) + mergeTo := st1.LaneStates[0] + mergeFrom := st1.LaneStates[tc.lane] + + sv.Lane = mergeTo.ID + sv.Nonce = tc.voucherNonce + merges := []Merge{{Lane: mergeFrom.ID, Nonce: tc.mergeNonce}} + sv.Merges = merges + ucp := &UpdateChannelStateParams{Sv: *sv} + + rt.SetCaller(st1.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, actor.payee, voucherBytes(t, &ucp.Sv), nil) + rt.ExpectAbort(tc.expExitCode, func() { + rt.Call(actor.UpdateChannelState, ucp) + }) + rt.Verify() + + }) + } + t.Run("When lane doesn't exist, fails with: voucher specifies invalid merge lane 999", func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), 2) + + var st1 State + rt.GetState(&st1) + mergeTo := st1.LaneStates[0] + mergeFrom := LaneState{ID: 999, Nonce: 2} + + sv.Lane = mergeTo.ID + sv.Nonce = 10 + merges := []Merge{{Lane: mergeFrom.ID, Nonce: sv.Nonce}} + sv.Merges = merges + ucp := &UpdateChannelStateParams{Sv: *sv} + + rt.SetCaller(st1.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, actor.payee, voucherBytes(t, &ucp.Sv), nil) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.UpdateChannelState, ucp) + }) + rt.Verify() + }) + + t.Run("Too many lanes, fails with: lane limit exceeded", func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), LaneLimit) + + var st1 State + rt.GetState(&st1) + sv.Lane++ + sv.Nonce++ + sv.Amount = abi.NewTokenAmount(100) + ucp := &UpdateChannelStateParams{Sv: *sv} + rt.SetCaller(st1.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, actor.payee, voucherBytes(t, &ucp.Sv), nil) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.UpdateChannelState, ucp) + }) + rt.Verify() + }) +} + +func TestActor_UpdateChannelStateExtra(t *testing.T) { + mnum := builtin.MethodsPaych.UpdateChannelState + fakeParams := runtime.CBORBytes([]byte{1, 2, 3, 4}) + expSendParams := &PaymentVerifyParams{fakeParams, nil} + otherAddr := tutil.NewIDAddr(t, 104) + ex := &ModVerifyParams{ + Actor: otherAddr, + Method: mnum, + Data: fakeParams, + } + + t.Run("Succeeds if extra call succeeds", func(t *testing.T) { + rt, actor1, sv1 := requireCreateChannelWithLanes(t, context.Background(), 1) + var st1 State + rt.GetState(&st1) + rt.SetCaller(st1.From, builtin.AccountActorCodeID) + + ucp := &UpdateChannelStateParams{Sv: *sv1} + ucp.Sv.Extra = ex + + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, st1.To, voucherBytes(t, &ucp.Sv), nil) + rt.ExpectSend(otherAddr, mnum, expSendParams, big.Zero(), nil, exitcode.Ok) + rt.Call(actor1.UpdateChannelState, ucp) + rt.Verify() + }) + t.Run("If Extra call fails, fails with: spend voucher verification failed", func(t *testing.T) { + rt, actor1, sv1 := requireCreateChannelWithLanes(t, context.Background(), 1) + var st1 State + rt.GetState(&st1) + rt.SetCaller(st1.From, builtin.AccountActorCodeID) + + ucp := &UpdateChannelStateParams{Sv: *sv1} + ucp.Sv.Extra = ex + + rt.ExpectValidateCallerAddr(st1.From, st1.To) + rt.ExpectSend(otherAddr, mnum, expSendParams, big.Zero(), nil, exitcode.ErrPlaceholder) + rt.ExpectVerifySignature(*ucp.Sv.Signature, st1.To, voucherBytes(t, &ucp.Sv), nil) + rt.ExpectAbort(exitcode.ErrPlaceholder, func() { + rt.Call(actor1.UpdateChannelState, ucp) + }) + rt.Verify() + }) +} + +func TestActor_UpdateChannelStateSettling(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), 1) + + ep := abi.ChainEpoch(10) + rt.SetEpoch(ep) + var st State + rt.GetState(&st) + + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.Call(actor.Settle, nil) + + expSettlingAt := ep + SettleDelay + rt.GetState(&st) + require.Equal(t, expSettlingAt, st.SettlingAt) + require.Equal(t, abi.ChainEpoch(0), st.MinSettleHeight) + + ucp := &UpdateChannelStateParams{Sv: *sv} + + testCases := []struct { + name string + minSettleHeight, expSettlingAt, expMinSettleHeight abi.ChainEpoch + //expExitCode exitcode.ExitCode + }{ + {name: "No change", + minSettleHeight: 0, expMinSettleHeight: st.MinSettleHeight, + expSettlingAt: st.SettlingAt}, + {name: "Updates MinSettleHeight only", + minSettleHeight: abi.ChainEpoch(2), expMinSettleHeight: abi.ChainEpoch(2), + expSettlingAt: st.SettlingAt}, + {name: "Updates both SettlingAt and MinSettleHeight", + minSettleHeight: abi.ChainEpoch(12), expMinSettleHeight: abi.ChainEpoch(12), + expSettlingAt: abi.ChainEpoch(12)}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var newSt State + ucp.Sv.MinSettleHeight = tc.minSettleHeight + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, st.To, voucherBytes(t, &ucp.Sv), nil) + rt.Call(actor.UpdateChannelState, ucp) + rt.GetState(&newSt) + assert.Equal(t, tc.expSettlingAt, newSt.SettlingAt) + assert.Equal(t, tc.expMinSettleHeight, newSt.MinSettleHeight) + }) + } +} + +func TestActor_UpdateChannelStateSecretPreimage(t *testing.T) { + t.Run("Succeeds with correct secret", func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), 1) + var st State + rt.GetState(&st) + + rt.SetHasher(func(data []byte) [32]byte { + aux := []byte("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") + var res [32]byte + copy(res[:], aux) + copy(res[:], data) + return res + }) + ucp := &UpdateChannelStateParams{ + Sv: *sv, + Secret: []byte("Profesr"), + Proof: nil, + } + ucp.Sv.SecretPreimage = []byte("ProfesrXXXXXXXXXXXXXXXXXXXXXXXXX") + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, st.To, voucherBytes(t, &ucp.Sv), nil) + rt.Call(actor.UpdateChannelState, ucp) + rt.Verify() + }) + + t.Run("If bad secret preimage, fails with: incorrect secret!", func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), 1) + var st State + rt.GetState(&st) + ucp := &UpdateChannelStateParams{ + Sv: *sv, + Secret: []byte("Profesr"), + Proof: nil, + } + ucp.Sv.SecretPreimage = append([]byte("Magneto"), make([]byte, 25)...) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, st.To, voucherBytes(t, &ucp.Sv), nil) + rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { + rt.Call(actor.UpdateChannelState, ucp) + }) + rt.Verify() + }) +} + +func TestActor_Settle(t *testing.T) { + ep := abi.ChainEpoch(10) + + t.Run("Settle adjusts SettlingAt", func(t *testing.T) { + rt, actor, _ := requireCreateChannelWithLanes(t, context.Background(), 1) + rt.SetEpoch(ep) + var st State + rt.GetState(&st) + + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.Call(actor.Settle, nil) + + expSettlingAt := ep + SettleDelay + rt.GetState(&st) + assert.Equal(t, expSettlingAt, st.SettlingAt) + assert.Equal(t, abi.ChainEpoch(0), st.MinSettleHeight) + }) + + t.Run("settle fails if called twice: channel already settling", func(t *testing.T) { + rt, actor, _ := requireCreateChannelWithLanes(t, context.Background(), 1) + rt.SetEpoch(ep) + var st State + rt.GetState(&st) + + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.Call(actor.Settle, nil) + + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.ExpectAbort(exitcode.ErrIllegalState, func() { + rt.Call(actor.Settle, nil) + }) + }) + + t.Run("Settle changes SettleHeight again if MinSettleHeight is less", func(t *testing.T) { + rt, actor, sv := requireCreateChannelWithLanes(t, context.Background(), 1) + rt.SetEpoch(ep) + var st State + rt.GetState(&st) + + // UpdateChannelState to increase MinSettleHeight only + ucp := &UpdateChannelStateParams{Sv: *sv} + ucp.Sv.MinSettleHeight = (ep + SettleDelay) + 1 + + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.ExpectVerifySignature(*ucp.Sv.Signature, st.To, voucherBytes(t, &ucp.Sv), nil) + rt.Call(actor.UpdateChannelState, ucp) + + var newSt State + rt.GetState(&newSt) + // SettlingAt should remain the same. + require.Equal(t, abi.ChainEpoch(0), newSt.SettlingAt) + require.Equal(t, ucp.Sv.MinSettleHeight, newSt.MinSettleHeight) + + // Settle. + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.Call(actor.Settle, nil) + + // SettlingAt should = MinSettleHeight, not epoch + SettleDelay. + rt.GetState(&newSt) + assert.Equal(t, ucp.Sv.MinSettleHeight, newSt.SettlingAt) + }) +} + +func TestActor_Collect(t *testing.T) { + t.Run("Happy path", func(t *testing.T) { + rt, actor, _ := requireCreateChannelWithLanes(t, context.Background(), 1) + rt.SetEpoch(10) + var st State + rt.GetState(&st) + + // Settle. + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.Call(actor.Settle, nil) + + rt.GetState(&st) + require.Equal(t, abi.ChainEpoch(11), st.SettlingAt) + rt.ExpectValidateCallerAddr(st.From, st.To) + + // "wait" for SettlingAt epoch + rt.SetEpoch(12) + + bal := rt.Balance() + sentToFrom := big.Sub(bal, st.ToSend) + rt.ExpectSend(st.From, builtin.MethodSend, nil, sentToFrom, nil, exitcode.Ok) + rt.ExpectSend(st.To, builtin.MethodSend, nil, st.ToSend, nil, exitcode.Ok) + + // Collect. + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + res := rt.Call(actor.Collect, nil) + assert.Nil(t, res) + + var newSt State + rt.GetState(&newSt) + assert.Equal(t, big.Zero(), newSt.ToSend) + }) + + testCases := []struct { + name string + expSendToCode, expSendFromCode, expCollectExit exitcode.ExitCode + dontSettle bool + }{ + {name: "fails if not settling with: payment channel not settling or settled", dontSettle: true, expCollectExit: exitcode.ErrForbidden}, + {name: "fails if Failed to send balance to `From`", expSendFromCode: exitcode.ErrPlaceholder, expCollectExit: exitcode.ErrPlaceholder}, + {name: "fails if Failed to send funds to `To`", expSendToCode: exitcode.ErrPlaceholder, expCollectExit: exitcode.ErrPlaceholder}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + rt, actor, _ := requireCreateChannelWithLanes(t, context.Background(), 1) + rt.SetEpoch(10) + var st State + rt.GetState(&st) + + if !tc.dontSettle { + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.Call(actor.Settle, nil) + rt.GetState(&st) + require.Equal(t, abi.ChainEpoch(11), st.SettlingAt) + } + + // "wait" for SettlingAt epoch + rt.SetEpoch(12) + + sentToFrom := big.Sub(rt.Balance(), st.ToSend) + rt.ExpectSend(st.From, builtin.MethodSend, nil, sentToFrom, nil, tc.expSendFromCode) + rt.ExpectSend(st.To, builtin.MethodSend, nil, st.ToSend, nil, tc.expSendToCode) + + // Collect. + rt.SetCaller(st.From, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(st.From, st.To) + rt.ExpectAbort(tc.expCollectExit, func() { + rt.Call(actor.Collect, nil) + }) + }) + } +} + +type pcActorHarness struct { + Actor + t testing.TB + + addr addr.Address + payer addr.Address + payee addr.Address +} + +type laneParams struct { + epochNum int64 + from, to addr.Address + amt big.Int + lane, nonce uint64 +} + +func requireCreateChannelWithLanes(t *testing.T, ctx context.Context, numLanes int) (*mock.Runtime, *pcActorHarness, *SignedVoucher) { + paychAddr := tutil.NewIDAddr(t, 100) + payerAddr := tutil.NewIDAddr(t, 102) + payeeAddr := tutil.NewIDAddr(t, 103) + balance := abi.NewTokenAmount(100000) + received := abi.NewTokenAmount(0) + + curEpoch := 2 + hasher := func(data []byte) [32]byte { return [32]byte{} } + + builder := mock.NewBuilder(ctx, paychAddr). + WithBalance(balance, received). + WithEpoch(abi.ChainEpoch(curEpoch)). + WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID). + WithActorType(payerAddr, builtin.AccountActorCodeID). + WithActorType(payeeAddr, builtin.AccountActorCodeID). + WithHasher(hasher) + + actor := pcActorHarness{Actor{}, t, paychAddr, payerAddr, payeeAddr} + + rt := builder.Build(t) + actor.constructAndVerify(t, rt, payerAddr, payeeAddr) + + var lastSv *SignedVoucher + for i := 0; i < numLanes; i++ { + amt := big.NewInt(int64(i + 1)) + lastSv = requireAddNewLane(t, rt, &actor, laneParams{ + epochNum: int64(curEpoch), + from: payerAddr, + to: payeeAddr, + amt: amt, + lane: uint64(i), + nonce: uint64(i + 1), + }) + } + return rt, &actor, lastSv +} + +func requireAddNewLane(t *testing.T, rt *mock.Runtime, actor *pcActorHarness, params laneParams) *SignedVoucher { + sig := &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte{0, 1, 2, 3, 4, 5, 6, 7}} + tl := abi.ChainEpoch(params.epochNum) + sv := SignedVoucher{TimeLockMin: tl, TimeLockMax: math.MaxInt64, Lane: params.lane, Nonce: params.nonce, Amount: params.amt, Signature: sig} + ucp := &UpdateChannelStateParams{Sv: sv} + + rt.SetCaller(params.from, builtin.AccountActorCodeID) + rt.ExpectValidateCallerAddr(params.from, params.to) + rt.ExpectVerifySignature(*sv.Signature, actor.payee, voucherBytes(t, &sv), nil) + ret := rt.Call(actor.UpdateChannelState, ucp) + require.Nil(t, ret) + rt.Verify() + return &sv +} + +func (h *pcActorHarness) constructAndVerify(t *testing.T, rt *mock.Runtime, sender, receiver addr.Address) { + params := &ConstructorParams{To: receiver, From: sender} + + rt.ExpectValidateCallerType(builtin.InitActorCodeID) + ret := rt.Call(h.Actor.Constructor, params) + assert.Nil(h.t, ret) + rt.Verify() + verifyInitialState(t, rt, sender, receiver) +} + +func verifyInitialState(t *testing.T, rt *mock.Runtime, sender, receiver addr.Address) { + var st State + rt.GetState(&st) + expectedState := State{From: sender, To: receiver, ToSend: abi.NewTokenAmount(0)} + verifyState(t, rt, -1, expectedState) +} + +func verifyState(t *testing.T, rt *mock.Runtime, expLanes int, expectedState State) { + var st State + rt.GetState(&st) + assert.Equal(t, expectedState.To, st.To) + assert.Equal(t, expectedState.From, st.From) + assert.Equal(t, expectedState.MinSettleHeight, st.MinSettleHeight) + assert.Equal(t, expectedState.SettlingAt, st.SettlingAt) + assert.Equal(t, expectedState.ToSend, st.ToSend) + if expLanes >= 0 { + require.Len(t, st.LaneStates, expLanes) + assert.True(t, reflect.DeepEqual(expectedState.LaneStates, st.LaneStates)) + } else { + assert.Len(t, st.LaneStates, 0) + } +} + +func voucherBytes(t *testing.T, sv *SignedVoucher) []byte { + bytes, err := sv.SigningBytes() + require.NoError(t, err) + return bytes +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/cbor_gen.go new file mode 100644 index 0000000000..b0b1a2b6ae --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/cbor_gen.go @@ -0,0 +1,1159 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package power + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{137}); err != nil { + return err + } + + // t.TotalRawBytePower (big.Int) (struct) + if err := t.TotalRawBytePower.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalQualityAdjPower (big.Int) (struct) + if err := t.TotalQualityAdjPower.MarshalCBOR(w); err != nil { + return err + } + + // t.TotalPledgeCollateral (big.Int) (struct) + if err := t.TotalPledgeCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.MinerCount (int64) (int64) + if t.MinerCount >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.MinerCount))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.MinerCount)-1)); err != nil { + return err + } + } + + // t.CronEventQueue (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.CronEventQueue); err != nil { + return xerrors.Errorf("failed to write cid field t.CronEventQueue: %w", err) + } + + // t.LastEpochTick (abi.ChainEpoch) (int64) + if t.LastEpochTick >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.LastEpochTick))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.LastEpochTick)-1)); err != nil { + return err + } + } + + // t.Claims (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.Claims); err != nil { + return xerrors.Errorf("failed to write cid field t.Claims: %w", err) + } + + // t.NumMinersMeetingMinPower (int64) (int64) + if t.NumMinersMeetingMinPower >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.NumMinersMeetingMinPower))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.NumMinersMeetingMinPower)-1)); err != nil { + return err + } + } + + // t.ProofValidationBatch (cid.Cid) (struct) + + if t.ProofValidationBatch == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCid(w, *t.ProofValidationBatch); err != nil { + return xerrors.Errorf("failed to write cid field t.ProofValidationBatch: %w", err) + } + } + + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 9 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.TotalRawBytePower (big.Int) (struct) + + { + + if err := t.TotalRawBytePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalRawBytePower: %w", err) + } + + } + // t.TotalQualityAdjPower (big.Int) (struct) + + { + + if err := t.TotalQualityAdjPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalQualityAdjPower: %w", err) + } + + } + // t.TotalPledgeCollateral (big.Int) (struct) + + { + + if err := t.TotalPledgeCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.TotalPledgeCollateral: %w", err) + } + + } + // t.MinerCount (int64) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.MinerCount = int64(extraI) + } + // t.CronEventQueue (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.CronEventQueue: %w", err) + } + + t.CronEventQueue = c + + } + // t.LastEpochTick (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.LastEpochTick = abi.ChainEpoch(extraI) + } + // t.Claims (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Claims: %w", err) + } + + t.Claims = c + + } + // t.NumMinersMeetingMinPower (int64) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.NumMinersMeetingMinPower = int64(extraI) + } + // t.ProofValidationBatch (cid.Cid) (struct) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.ProofValidationBatch: %w", err) + } + + t.ProofValidationBatch = &c + } + + } + return nil +} + +func (t *Claim) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.RawBytePower (big.Int) (struct) + if err := t.RawBytePower.MarshalCBOR(w); err != nil { + return err + } + + // t.QualityAdjPower (big.Int) (struct) + if err := t.QualityAdjPower.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *Claim) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.RawBytePower (big.Int) (struct) + + { + + if err := t.RawBytePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RawBytePower: %w", err) + } + + } + // t.QualityAdjPower (big.Int) (struct) + + { + + if err := t.QualityAdjPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.QualityAdjPower: %w", err) + } + + } + return nil +} + +func (t *CronEvent) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.MinerAddr (address.Address) (struct) + if err := t.MinerAddr.MarshalCBOR(w); err != nil { + return err + } + + // t.CallbackPayload ([]uint8) (slice) + if len(t.CallbackPayload) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.CallbackPayload was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.CallbackPayload)))); err != nil { + return err + } + if _, err := w.Write(t.CallbackPayload); err != nil { + return err + } + return nil +} + +func (t *CronEvent) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.MinerAddr (address.Address) (struct) + + { + + if err := t.MinerAddr.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.MinerAddr: %w", err) + } + + } + // t.CallbackPayload ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.CallbackPayload: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.CallbackPayload = make([]byte, extra) + if _, err := io.ReadFull(br, t.CallbackPayload); err != nil { + return err + } + return nil +} + +func (t *CreateMinerParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{133}); err != nil { + return err + } + + // t.Owner (address.Address) (struct) + if err := t.Owner.MarshalCBOR(w); err != nil { + return err + } + + // t.Worker (address.Address) (struct) + if err := t.Worker.MarshalCBOR(w); err != nil { + return err + } + + // t.SealProofType (abi.RegisteredSealProof) (int64) + if t.SealProofType >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealProofType))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealProofType)-1)); err != nil { + return err + } + } + + // t.Peer ([]uint8) (slice) + if len(t.Peer) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Peer was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Peer)))); err != nil { + return err + } + if _, err := w.Write(t.Peer); err != nil { + return err + } + + // t.Multiaddrs ([][]uint8) (slice) + if len(t.Multiaddrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Multiaddrs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Multiaddrs)))); err != nil { + return err + } + for _, v := range t.Multiaddrs { + if len(v) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field v was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(v)))); err != nil { + return err + } + if _, err := w.Write(v); err != nil { + return err + } + } + return nil +} + +func (t *CreateMinerParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 5 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Owner (address.Address) (struct) + + { + + if err := t.Owner.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Owner: %w", err) + } + + } + // t.Worker (address.Address) (struct) + + { + + if err := t.Worker.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Worker: %w", err) + } + + } + // t.SealProofType (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProofType = abi.RegisteredSealProof(extraI) + } + // t.Peer ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Peer: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Peer = make([]byte, extra) + if _, err := io.ReadFull(br, t.Peer); err != nil { + return err + } + // t.Multiaddrs ([][]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Multiaddrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Multiaddrs = make([][]uint8, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Multiaddrs[i]: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Multiaddrs[i] = make([]byte, extra) + if _, err := io.ReadFull(br, t.Multiaddrs[i]); err != nil { + return err + } + } + } + + return nil +} + +func (t *EnrollCronEventParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.EventEpoch (abi.ChainEpoch) (int64) + if t.EventEpoch >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.EventEpoch))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.EventEpoch)-1)); err != nil { + return err + } + } + + // t.Payload ([]uint8) (slice) + if len(t.Payload) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Payload was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Payload)))); err != nil { + return err + } + if _, err := w.Write(t.Payload); err != nil { + return err + } + return nil +} + +func (t *EnrollCronEventParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.EventEpoch (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.EventEpoch = abi.ChainEpoch(extraI) + } + // t.Payload ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Payload: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Payload = make([]byte, extra) + if _, err := io.ReadFull(br, t.Payload); err != nil { + return err + } + return nil +} + +func (t *UpdateClaimedPowerParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.RawByteDelta (big.Int) (struct) + if err := t.RawByteDelta.MarshalCBOR(w); err != nil { + return err + } + + // t.QualityAdjustedDelta (big.Int) (struct) + if err := t.QualityAdjustedDelta.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *UpdateClaimedPowerParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.RawByteDelta (big.Int) (struct) + + { + + if err := t.RawByteDelta.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RawByteDelta: %w", err) + } + + } + // t.QualityAdjustedDelta (big.Int) (struct) + + { + + if err := t.QualityAdjustedDelta.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.QualityAdjustedDelta: %w", err) + } + + } + return nil +} + +func (t *CreateMinerReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.IDAddress (address.Address) (struct) + if err := t.IDAddress.MarshalCBOR(w); err != nil { + return err + } + + // t.RobustAddress (address.Address) (struct) + if err := t.RobustAddress.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *CreateMinerReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.IDAddress (address.Address) (struct) + + { + + if err := t.IDAddress.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.IDAddress: %w", err) + } + + } + // t.RobustAddress (address.Address) (struct) + + { + + if err := t.RobustAddress.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RobustAddress: %w", err) + } + + } + return nil +} + +func (t *CurrentTotalPowerReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.RawBytePower (big.Int) (struct) + if err := t.RawBytePower.MarshalCBOR(w); err != nil { + return err + } + + // t.QualityAdjPower (big.Int) (struct) + if err := t.QualityAdjPower.MarshalCBOR(w); err != nil { + return err + } + + // t.PledgeCollateral (big.Int) (struct) + if err := t.PledgeCollateral.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *CurrentTotalPowerReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.RawBytePower (big.Int) (struct) + + { + + if err := t.RawBytePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RawBytePower: %w", err) + } + + } + // t.QualityAdjPower (big.Int) (struct) + + { + + if err := t.QualityAdjPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.QualityAdjPower: %w", err) + } + + } + // t.PledgeCollateral (big.Int) (struct) + + { + + if err := t.PledgeCollateral.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.PledgeCollateral: %w", err) + } + + } + return nil +} + +func (t *MinerConstructorParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{133}); err != nil { + return err + } + + // t.OwnerAddr (address.Address) (struct) + if err := t.OwnerAddr.MarshalCBOR(w); err != nil { + return err + } + + // t.WorkerAddr (address.Address) (struct) + if err := t.WorkerAddr.MarshalCBOR(w); err != nil { + return err + } + + // t.SealProofType (abi.RegisteredSealProof) (int64) + if t.SealProofType >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SealProofType))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.SealProofType)-1)); err != nil { + return err + } + } + + // t.PeerId ([]uint8) (slice) + if len(t.PeerId) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.PeerId was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.PeerId)))); err != nil { + return err + } + if _, err := w.Write(t.PeerId); err != nil { + return err + } + + // t.Multiaddrs ([][]uint8) (slice) + if len(t.Multiaddrs) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Multiaddrs was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Multiaddrs)))); err != nil { + return err + } + for _, v := range t.Multiaddrs { + if len(v) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field v was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(v)))); err != nil { + return err + } + if _, err := w.Write(v); err != nil { + return err + } + } + return nil +} + +func (t *MinerConstructorParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 5 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.OwnerAddr (address.Address) (struct) + + { + + if err := t.OwnerAddr.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.OwnerAddr: %w", err) + } + + } + // t.WorkerAddr (address.Address) (struct) + + { + + if err := t.WorkerAddr.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.WorkerAddr: %w", err) + } + + } + // t.SealProofType (abi.RegisteredSealProof) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.SealProofType = abi.RegisteredSealProof(extraI) + } + // t.PeerId ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.PeerId: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.PeerId = make([]byte, extra) + if _, err := io.ReadFull(br, t.PeerId); err != nil { + return err + } + // t.Multiaddrs ([][]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Multiaddrs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Multiaddrs = make([][]uint8, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Multiaddrs[i]: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Multiaddrs[i] = make([]byte, extra) + if _, err := io.ReadFull(br, t.Multiaddrs[i]); err != nil { + return err + } + } + } + + return nil +} + +func (t *SectorStorageWeightDesc) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.SectorSize (abi.SectorSize) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.SectorSize))); err != nil { + return err + } + + // t.Duration (abi.ChainEpoch) (int64) + if t.Duration >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Duration))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.Duration)-1)); err != nil { + return err + } + } + + // t.DealWeight (big.Int) (struct) + if err := t.DealWeight.MarshalCBOR(w); err != nil { + return err + } + + // t.VerifiedDealWeight (big.Int) (struct) + if err := t.VerifiedDealWeight.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SectorStorageWeightDesc) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.SectorSize (abi.SectorSize) (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.SectorSize = abi.SectorSize(extra) + + } + // t.Duration (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Duration = abi.ChainEpoch(extraI) + } + // t.DealWeight (big.Int) (struct) + + { + + if err := t.DealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.DealWeight: %w", err) + } + + } + // t.VerifiedDealWeight (big.Int) (struct) + + { + + if err := t.VerifiedDealWeight.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.VerifiedDealWeight: %w", err) + } + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/policy.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/policy.go new file mode 100644 index 0000000000..6b937ee62e --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/policy.go @@ -0,0 +1,11 @@ +package power + +import ( + abi "github.com/filecoin-project/specs-actors/actors/abi" +) + +// Minimum number of registered miners for the minimum miner size limit to effectively limit consensus power. +const ConsensusMinerMinMiners = 3 + +// Minimum power of an individual miner to meet the threshold for leader election. +var ConsensusMinerMinPower = abi.NewStoragePower(1 << 40) // PARAM_FINISH diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_actor.go new file mode 100644 index 0000000000..5b87e3aa71 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_actor.go @@ -0,0 +1,485 @@ +package power + +import ( + "bytes" + + "github.com/filecoin-project/go-address" + addr "github.com/filecoin-project/go-address" + errors "github.com/pkg/errors" + xerrors "golang.org/x/xerrors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + initact "github.com/filecoin-project/specs-actors/actors/builtin/init" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + . "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Runtime = vmr.Runtime + +type SectorTermination int64 + +const ( + SectorTerminationExpired SectorTermination = iota // Implicit termination after all deals expire + SectorTerminationManual // Unscheduled explicit termination by the miner + SectorTerminationFaulty // Implicit termination due to unrecovered fault +) + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.CreateMiner, + 3: a.UpdateClaimedPower, + 4: a.EnrollCronEvent, + 5: a.OnEpochTickEnd, + 6: a.UpdatePledgeTotal, + 7: a.OnConsensusFault, + 8: a.SubmitPoRepForBulkVerify, + 9: a.CurrentTotalPower, + } +} + +var _ abi.Invokee = Actor{} + +// Storage miner actor constructor params are defined here so the power actor can send them to the init actor +// to instantiate miners. +type MinerConstructorParams struct { + OwnerAddr addr.Address + WorkerAddr addr.Address + SealProofType abi.RegisteredSealProof + PeerId abi.PeerID + Multiaddrs []abi.Multiaddrs +} + +type SectorStorageWeightDesc struct { + SectorSize abi.SectorSize + Duration abi.ChainEpoch + DealWeight abi.DealWeight + VerifiedDealWeight abi.DealWeight +} + +//////////////////////////////////////////////////////////////////////////////// +// Actor methods +//////////////////////////////////////////////////////////////////////////////// + +func (a Actor) Constructor(rt Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + + emptyMap, err := adt.MakeEmptyMap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to create storage power state: %v", err) + } + emptyMMapCid, err := adt.MakeEmptyMultimap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to get empty multimap cid") + } + + st := ConstructState(emptyMap, emptyMMapCid) + rt.State().Create(st) + return nil +} + +type CreateMinerParams struct { + Owner addr.Address + Worker addr.Address + SealProofType abi.RegisteredSealProof + Peer abi.PeerID + Multiaddrs []abi.Multiaddrs +} + +type CreateMinerReturn struct { + IDAddress addr.Address // The canonical ID-based address for the actor. + RobustAddress addr.Address // A more expensive but re-org-safe address for the newly created actor. +} + +func (a Actor) CreateMiner(rt Runtime, params *CreateMinerParams) *CreateMinerReturn { + rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...) + + ctorParams := MinerConstructorParams{ + OwnerAddr: params.Owner, + WorkerAddr: params.Worker, + SealProofType: params.SealProofType, + PeerId: params.Peer, + Multiaddrs: params.Multiaddrs, + } + ctorParamBuf := new(bytes.Buffer) + err := ctorParams.MarshalCBOR(ctorParamBuf) + if err != nil { + rt.Abortf(exitcode.ErrPlaceholder, "failed to serialize miner constructor params %v: %v", ctorParams, err) + } + ret, code := rt.Send( + builtin.InitActorAddr, + builtin.MethodsInit.Exec, + &initact.ExecParams{ + CodeCID: builtin.StorageMinerActorCodeID, + ConstructorParams: ctorParamBuf.Bytes(), + }, + rt.Message().ValueReceived(), // Pass on any value to the new actor. + ) + builtin.RequireSuccess(rt, code, "failed to init new actor") + var addresses initact.ExecReturn + err = ret.Into(&addresses) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "unmarshaling exec return value: %v", err) + } + + var st State + rt.State().Transaction(&st, func() interface{} { + store := adt.AsStore(rt) + err = st.setClaim(store, addresses.IDAddress, &Claim{abi.NewStoragePower(0), abi.NewStoragePower(0)}) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to put power in claimed table while creating miner: %v", err) + } + st.MinerCount += 1 + return nil + }) + return &CreateMinerReturn{ + IDAddress: addresses.IDAddress, + RobustAddress: addresses.RobustAddress, + } +} + +type UpdateClaimedPowerParams struct { + RawByteDelta abi.StoragePower + QualityAdjustedDelta abi.StoragePower +} + +// Adds or removes claimed power for the calling actor. +// May only be invoked by a miner actor. +func (a Actor) UpdateClaimedPower(rt Runtime, params *UpdateClaimedPowerParams) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + minerAddr := rt.Message().Caller() + var st State + rt.State().Transaction(&st, func() interface{} { + err := st.AddToClaim(adt.AsStore(rt), minerAddr, params.RawByteDelta, params.QualityAdjustedDelta) + builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update power raw %s, qa %s", params.RawByteDelta, params.QualityAdjustedDelta) + return nil + }) + return nil +} + +type EnrollCronEventParams struct { + EventEpoch abi.ChainEpoch + Payload []byte +} + +func (a Actor) EnrollCronEvent(rt Runtime, params *EnrollCronEventParams) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + minerAddr := rt.Message().Caller() + minerEvent := CronEvent{ + MinerAddr: minerAddr, + CallbackPayload: params.Payload, + } + + var st State + rt.State().Transaction(&st, func() interface{} { + err := st.appendCronEvent(adt.AsStore(rt), params.EventEpoch, &minerEvent) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to enroll cron event: %v", err) + } + return nil + }) + return nil +} + +// Called by Cron. +func (a Actor) OnEpochTickEnd(rt Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.CronActorAddr) + + if err := a.processDeferredCronEvents(rt); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to process deferred cron events: %v", err) + } + + if err := a.processBatchProofVerifies(rt); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to process batch proof verification: %s", err) + } + + var st State + rt.State().Readonly(&st) + + // update network KPI in RewardActor + _, code := rt.Send( + builtin.RewardActorAddr, + builtin.MethodsReward.UpdateNetworkKPI, + &st.TotalRawBytePower, + abi.NewTokenAmount(0), + ) + builtin.RequireSuccess(rt, code, "failed to update network KPI with Reward Actor") + + return nil +} + +func (a Actor) UpdatePledgeTotal(rt Runtime, pledgeDelta *abi.TokenAmount) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + var st State + rt.State().Transaction(&st, func() interface{} { + st.addPledgeTotal(*pledgeDelta) + return nil + }) + return nil +} + +func (a Actor) OnConsensusFault(rt Runtime, pledgeAmount *abi.TokenAmount) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + minerAddr := rt.Message().Caller() + + var st State + rt.State().Transaction(&st, func() interface{} { + claim, powerOk, err := st.GetClaim(adt.AsStore(rt), minerAddr) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to read claimed power for fault: %v", err) + } + if !powerOk { + rt.Abortf(exitcode.ErrIllegalArgument, "miner %v not registered (already slashed?)", minerAddr) + } + Assert(claim.RawBytePower.GreaterThanEqual(big.Zero())) + Assert(claim.QualityAdjPower.GreaterThanEqual(big.Zero())) + + st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, claim.QualityAdjPower) + st.TotalRawBytePower = big.Sub(st.TotalRawBytePower, claim.RawBytePower) + + st.addPledgeTotal(pledgeAmount.Neg()) + return nil + }) + + err := a.deleteMinerActor(rt, minerAddr) + AssertNoError(err) + + return nil +} + +// GasOnSubmitVerifySeal is amount of gas charged for SubmitPoRepForBulkVerify +// This number is empirically determined +const GasOnSubmitVerifySeal = 132166313 + +func (a Actor) SubmitPoRepForBulkVerify(rt Runtime, sealInfo *abi.SealVerifyInfo) *adt.EmptyValue { + rt.ValidateImmediateCallerType(builtin.StorageMinerActorCodeID) + + minerAddr := rt.Message().Caller() + + rt.ChargeGas("OnSubmitVerifySeal", GasOnSubmitVerifySeal, 0) + var st State + rt.State().Transaction(&st, func() interface{} { + store := adt.AsStore(rt) + var mmap *adt.Multimap + if st.ProofValidationBatch == nil { + mmap = adt.MakeEmptyMultimap(store) + } else { + var err error + mmap, err = adt.AsMultimap(adt.AsStore(rt), *st.ProofValidationBatch) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to load proof batching set: %s", err) + } + } + + if err := mmap.Add(adt.AddrKey(minerAddr), sealInfo); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to insert proof into set: %s", err) + } + + mmrc, err := mmap.Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to flush proofs batch map: %s", err) + } + st.ProofValidationBatch = &mmrc + return nil + }) + + return nil +} + +type CurrentTotalPowerReturn struct { + RawBytePower abi.StoragePower + QualityAdjPower abi.StoragePower + PledgeCollateral abi.TokenAmount +} + +// Returns the total power and pledge recorded by the power actor. +// TODO hold these values constant during an epoch for stable calculations, https://github.com/filecoin-project/specs-actors/issues/495 +func (a Actor) CurrentTotalPower(rt Runtime, _ *adt.EmptyValue) *CurrentTotalPowerReturn { + rt.ValidateImmediateCallerAcceptAny() + var st State + rt.State().Readonly(&st) + return &CurrentTotalPowerReturn{ + RawBytePower: st.TotalRawBytePower, + QualityAdjPower: st.TotalQualityAdjPower, + PledgeCollateral: st.TotalPledgeCollateral, + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Method utility functions +//////////////////////////////////////////////////////////////////////////////// + +func (a Actor) processBatchProofVerifies(rt Runtime) error { + var st State + + var miners []address.Address + verifies := make(map[address.Address][]abi.SealVerifyInfo) + + rt.State().Transaction(&st, func() interface{} { + store := adt.AsStore(rt) + if st.ProofValidationBatch == nil { + return nil + } + mmap, err := adt.AsMultimap(store, *st.ProofValidationBatch) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to load proofs validation batch: %s", err) + } + + err = mmap.ForAll(func(k string, arr *adt.Array) error { + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return xerrors.Errorf("failed to parse address key: %w", err) + } + + miners = append(miners, a) + + var infos []abi.SealVerifyInfo + var svi abi.SealVerifyInfo + err = arr.ForEach(&svi, func(i int64) error { + infos = append(infos, svi) + return nil + }) + if err != nil { + return xerrors.Errorf("failed to iterate over proof verify array for miner %s: %w", a, err) + } + verifies[a] = infos + return nil + }) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to iterate proof batch: %s", err) + } + + st.ProofValidationBatch = nil + + return nil + }) + + res, err := rt.Syscalls().BatchVerifySeals(verifies) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to batch verify: %s", err) + } + + for _, m := range miners { + vres, ok := res[m] + if !ok { + rt.Abortf(exitcode.ErrNotFound, "batch verify seals syscall implemented incorrectly") + } + + verifs := verifies[m] + + seen := map[abi.SectorNumber]struct{}{} + var successful []abi.SectorNumber + for i, r := range vres { + if r { + snum := verifs[i].SectorID.Number + + if _, exists := seen[snum]; exists { + // filter-out duplicates + continue + } + + seen[snum] = struct{}{} + successful = append(successful, snum) + } + } + + // The exit code is explicitly ignored + _, _ = rt.Send( + m, + builtin.MethodsMiner.ConfirmSectorProofsValid, + &builtin.ConfirmSectorProofsParams{Sectors: successful}, + abi.NewTokenAmount(0), + ) + } + + return nil +} + +func (a Actor) processDeferredCronEvents(rt Runtime) error { + rtEpoch := rt.CurrEpoch() + + var cronEvents []CronEvent + var st State + rt.State().Transaction(&st, func() interface{} { + store := adt.AsStore(rt) + + for epoch := st.LastEpochTick + 1; epoch <= rtEpoch; epoch++ { + epochEvents, err := st.loadCronEvents(store, epoch) + if err != nil { + return errors.Wrapf(err, "failed to load cron events at %v", epoch) + } + + cronEvents = append(cronEvents, epochEvents...) + + if len(epochEvents) > 0 { + err = st.clearCronEvents(store, epoch) + if err != nil { + return errors.Wrapf(err, "failed to clear cron events at %v", epoch) + } + } + } + + st.LastEpochTick = rtEpoch + return nil + }) + failedMinerCrons := make([]addr.Address, 0) + for _, event := range cronEvents { + _, code := rt.Send( + event.MinerAddr, + builtin.MethodsMiner.OnDeferredCronEvent, + vmr.CBORBytes(event.CallbackPayload), + abi.NewTokenAmount(0), + ) + // If a callback fails, this actor continues to invoke other callbacks + // and persists state removing the failed event from the event queue. It won't be tried again. + // Failures are unexpected here but will result in removal of miner power + // A log message would really help here. + if code != exitcode.Ok { + rt.Log(vmr.WARN, "OnDeferredCronEvent failed for miner %s: exitcode %d", event.MinerAddr, code) + failedMinerCrons = append(failedMinerCrons, event.MinerAddr) + } + } + rt.State().Transaction(&st, func() interface{} { + store := adt.AsStore(rt) + // Remove power and leave miner frozen + for _, minerAddr := range failedMinerCrons { + claim, found, err := st.GetClaim(store, minerAddr) + if err != nil { + rt.Log(vmr.ERROR, "failed to get claim for miner %s after failing OnDeferredCronEvent: %s", minerAddr, err) + continue + } + if !found { + rt.Log(vmr.WARN, "miner OnDeferredCronEvent failed for miner %s with no power", minerAddr) + continue + } + + // zero out miner power + err = st.AddToClaim(store, minerAddr, claim.RawBytePower.Neg(), claim.QualityAdjPower.Neg()) + if err != nil { + rt.Log(vmr.WARN, "failed to remove (%d, %d) power for miner %s after to failed cron", claim.RawBytePower, claim.QualityAdjPower, minerAddr) + continue + } + } + return nil + }) + return nil +} + +func (a Actor) deleteMinerActor(rt Runtime, miner addr.Address) error { + var st State + err := rt.State().Transaction(&st, func() interface{} { + if err := st.deleteClaim(adt.AsStore(rt), miner); err != nil { + return errors.Wrapf(err, "failed to delete %v from claimed power table", miner) + } + + st.MinerCount -= 1 + return nil + }).(error) + return err +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_state.go new file mode 100644 index 0000000000..2063797819 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_state.go @@ -0,0 +1,272 @@ +package power + +import ( + "reflect" + "sort" + + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + errors "github.com/pkg/errors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + . "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type State struct { + TotalRawBytePower abi.StoragePower + TotalQualityAdjPower abi.StoragePower + TotalPledgeCollateral abi.TokenAmount + MinerCount int64 + + // A queue of events to be triggered by cron, indexed by epoch. + CronEventQueue cid.Cid // Multimap, (HAMT[ChainEpoch]AMT[CronEvent] + + // Last chain epoch OnEpochTickEnd was called on + LastEpochTick abi.ChainEpoch + + // Claimed power for each miner. + Claims cid.Cid // Map, HAMT[address]Claim + + // Number of miners having proven the minimum consensus power. + NumMinersMeetingMinPower int64 + + ProofValidationBatch *cid.Cid +} + +type Claim struct { + // Sum of raw byte power for a miner's sectors. + RawBytePower abi.StoragePower + + // Sum of quality adjusted power for a miner's sectors. + QualityAdjPower abi.StoragePower +} + +type CronEvent struct { + MinerAddr addr.Address + CallbackPayload []byte +} + +type AddrKey = adt.AddrKey + +func ConstructState(emptyMapCid, emptyMMapCid cid.Cid) *State { + return &State{ + TotalRawBytePower: abi.NewStoragePower(0), + TotalQualityAdjPower: abi.NewStoragePower(0), + TotalPledgeCollateral: abi.NewTokenAmount(0), + LastEpochTick: -1, + CronEventQueue: emptyMapCid, + Claims: emptyMapCid, + NumMinersMeetingMinPower: 0, + } +} + +// Note: this method is currently (Feb 2020) unreferenced in the actor code, but expected to be used to validate +// Election PoSt winners outside the chain state. We may remove it. +// See https://github.com/filecoin-project/specs-actors/issues/266 +func (st *State) minerNominalPowerMeetsConsensusMinimum(s adt.Store, miner addr.Address) (bool, error) { //nolint:deadcode,unused + claim, ok, err := st.GetClaim(s, miner) + if err != nil { + return false, err + } + if !ok { + return false, errors.Errorf("no claim for actor %v", miner) + } + + minerNominalPower := claim.QualityAdjPower + + // if miner is larger than min power requirement, we're set + if minerNominalPower.GreaterThanEqual(ConsensusMinerMinPower) { + return true, nil + } + + // otherwise, if another miner meets min power requirement, return false + if st.NumMinersMeetingMinPower > 0 { + return false, nil + } + + // else if none do, check whether in MIN_MINER_SIZE_TARG miners + if st.MinerCount <= ConsensusMinerMinMiners { + // miner should pass + return true, nil + } + + m, err := adt.AsMap(s, st.Claims) + if err != nil { + return false, err + } + + var minerSizes []abi.StoragePower + var claimed Claim + if err = m.ForEach(&claimed, func(k string) error { + nominalPower := claimed.QualityAdjPower + minerSizes = append(minerSizes, nominalPower) + return nil + }); err != nil { + return false, errors.Wrap(err, "failed to iterate power table") + } + + // get size of MIN_MINER_SIZE_TARGth largest miner + sort.Slice(minerSizes, func(i, j int) bool { return i > j }) + return minerNominalPower.GreaterThanEqual(minerSizes[ConsensusMinerMinMiners-1]), nil +} + +// Parameters may be negative to subtract. +func (st *State) AddToClaim(s adt.Store, miner addr.Address, power abi.StoragePower, qapower abi.StoragePower) error { + oldClaim, ok, err := st.GetClaim(s, miner) + if err != nil { + return err + } + if !ok { + return errors.Errorf("no claim for actor %v", miner) + } + + newClaim := Claim{ + RawBytePower: big.Add(oldClaim.RawBytePower, power), + QualityAdjPower: big.Add(oldClaim.QualityAdjPower, qapower), + } + + prevBelow := oldClaim.QualityAdjPower.LessThan(ConsensusMinerMinPower) + stillBelow := newClaim.QualityAdjPower.LessThan(ConsensusMinerMinPower) + + if prevBelow && !stillBelow { + // just passed min miner size + st.NumMinersMeetingMinPower++ + st.TotalQualityAdjPower = big.Add(st.TotalQualityAdjPower, newClaim.QualityAdjPower) + st.TotalRawBytePower = big.Add(st.TotalRawBytePower, newClaim.RawBytePower) + } else if !prevBelow && stillBelow { + // just went below min miner size + st.NumMinersMeetingMinPower-- + st.TotalQualityAdjPower = big.Sub(st.TotalQualityAdjPower, oldClaim.QualityAdjPower) + st.TotalRawBytePower = big.Sub(st.TotalRawBytePower, oldClaim.RawBytePower) + } else if !prevBelow && !stillBelow { + // Was above the threshold, still above + st.TotalQualityAdjPower = big.Add(st.TotalQualityAdjPower, qapower) + st.TotalRawBytePower = big.Add(st.TotalRawBytePower, power) + } + + AssertMsg(newClaim.RawBytePower.GreaterThanEqual(big.Zero()), "negative claimed raw byte power: %v", newClaim.RawBytePower) + AssertMsg(newClaim.QualityAdjPower.GreaterThanEqual(big.Zero()), "negative claimed quality adjusted power: %v", newClaim.QualityAdjPower) + AssertMsg(st.NumMinersMeetingMinPower >= 0, "negative number of miners larger than min: %v", st.NumMinersMeetingMinPower) + return st.setClaim(s, miner, &newClaim) +} + +func (st *State) GetClaim(s adt.Store, a addr.Address) (*Claim, bool, error) { + hm, err := adt.AsMap(s, st.Claims) + if err != nil { + return nil, false, err + } + + var out Claim + found, err := hm.Get(AddrKey(a), &out) + if err != nil { + return nil, false, errors.Wrapf(err, "failed to get claim for address %v from store %s", a, st.Claims) + } + if !found { + return nil, false, nil + } + return &out, true, nil +} + +func (st *State) addPledgeTotal(amount abi.TokenAmount) { + st.TotalPledgeCollateral = big.Add(st.TotalPledgeCollateral, amount) + Assert(st.TotalPledgeCollateral.GreaterThanEqual(big.Zero())) +} + +func (st *State) appendCronEvent(store adt.Store, epoch abi.ChainEpoch, event *CronEvent) error { + mmap, err := adt.AsMultimap(store, st.CronEventQueue) + if err != nil { + return err + } + + err = mmap.Add(epochKey(epoch), event) + if err != nil { + return errors.Wrapf(err, "failed to store cron event at epoch %v for miner %v", epoch, event) + } + st.CronEventQueue, err = mmap.Root() + if err != nil { + return err + } + return nil +} + +func (st *State) loadCronEvents(store adt.Store, epoch abi.ChainEpoch) ([]CronEvent, error) { + mmap, err := adt.AsMultimap(store, st.CronEventQueue) + if err != nil { + return nil, err + } + + var events []CronEvent + var ev CronEvent + err = mmap.ForEach(epochKey(epoch), &ev, func(i int64) error { + events = append(events, ev) + return nil + }) + return events, err +} + +func (st *State) clearCronEvents(store adt.Store, epoch abi.ChainEpoch) error { + mmap, err := adt.AsMultimap(store, st.CronEventQueue) + if err != nil { + return err + } + + err = mmap.RemoveAll(epochKey(epoch)) + if err != nil { + return errors.Wrapf(err, "failed to clear cron events") + } + st.CronEventQueue, err = mmap.Root() + if err != nil { + return err + } + return nil +} + +func (st *State) setClaim(s adt.Store, a addr.Address, claim *Claim) error { + Assert(claim.RawBytePower.GreaterThanEqual(big.Zero())) + Assert(claim.QualityAdjPower.GreaterThanEqual(big.Zero())) + + hm, err := adt.AsMap(s, st.Claims) + if err != nil { + return err + } + + if err = hm.Put(AddrKey(a), claim); err != nil { + return errors.Wrapf(err, "failed to put claim with address %s power %v in store %s", a, claim, st.Claims) + } + + st.Claims, err = hm.Root() + if err != nil { + return err + } + return nil +} + +func (st *State) deleteClaim(s adt.Store, a addr.Address) error { + hm, err := adt.AsMap(s, st.Claims) + if err != nil { + return err + } + + if err = hm.Delete(AddrKey(a)); err != nil { + return errors.Wrapf(err, "failed to delete claim at address %s from store %s", a, st.Claims) + } + st.Claims, err = hm.Root() + if err != nil { + return err + } + return nil +} + +func epochKey(e abi.ChainEpoch) adt.Keyer { + return adt.IntKey(int64(e)) +} + +func init() { + // Check that ChainEpoch is indeed a signed integer to confirm that epochKey is making the right interpretation. + var e abi.ChainEpoch + if reflect.TypeOf(e).Kind() != reflect.Int64 { + panic("incorrect chain epoch encoding") + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_test.go new file mode 100644 index 0000000000..f440a7f35e --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/power/power_test.go @@ -0,0 +1,382 @@ +package power_test + +import ( + "bytes" + "context" + "strconv" + "testing" + + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + assert "github.com/stretchr/testify/assert" + require "github.com/stretchr/testify/require" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + initact "github.com/filecoin-project/specs-actors/actors/builtin/init" + power "github.com/filecoin-project/specs-actors/actors/builtin/power" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" + mock "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, power.Actor{}) +} + +func TestConstruction(t *testing.T) { + actor := newHarness(t) + owner := tutil.NewIDAddr(t, 101) + miner := tutil.NewIDAddr(t, 103) + actr := tutil.NewActorAddr(t, "actor") + + builder := mock.NewBuilder(context.Background(), builtin.StoragePowerActorAddr).WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + t.Run("simple construction", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + }) + + t.Run("create miner", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + actor.createMiner(rt, owner, owner, miner, actr, abi.PeerID("miner"), []abi.Multiaddrs{{1}}, abi.RegisteredSealProof_StackedDrg2KiBV1, abi.NewTokenAmount(10)) + + var st power.State + rt.GetState(&st) + assert.Equal(t, int64(1), st.MinerCount) + assert.Equal(t, abi.NewStoragePower(0), st.TotalQualityAdjPower) + assert.Equal(t, abi.NewStoragePower(0), st.TotalRawBytePower) + assert.Equal(t, int64(0), st.NumMinersMeetingMinPower) + + claim, err := adt.AsMap(adt.AsStore(rt), st.Claims) + assert.NoError(t, err) + keys, err := claim.CollectKeys() + require.NoError(t, err) + assert.Equal(t, 1, len(keys)) + var actualClaim power.Claim + found, err_ := claim.Get(asKey(keys[0]), &actualClaim) + require.NoError(t, err_) + assert.True(t, found) + assert.Equal(t, power.Claim{big.Zero(), big.Zero()}, actualClaim) // miner has not proven anything + + verifyEmptyMap(t, rt, st.CronEventQueue) + }) +} + +func TestPowerAndPledgeAccounting(t *testing.T) { + actor := newHarness(t) + owner := tutil.NewIDAddr(t, 101) + miner1 := tutil.NewIDAddr(t, 111) + miner2 := tutil.NewIDAddr(t, 112) + + // These tests use the min power for consensus to check the accounting above that value. + // TODO: tests for crossing the consensus minimum boundary after settling the behaviour. + // See https://github.com/filecoin-project/specs-actors/issues/266 + powerUnit := power.ConsensusMinerMinPower + + mul := func(a big.Int, b int64) big.Int { + return big.Mul(a, big.NewInt(b)) + } + + builder := mock.NewBuilder(context.Background(), builtin.StoragePowerActorAddr). + WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + t.Run("power & pledge accounted", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + actor.createMinerBasic(rt, owner, owner, miner1) + actor.createMinerBasic(rt, owner, owner, miner2) + + ret := actor.currentPowerTotal(rt) + assert.Equal(t, big.Zero(), ret.RawBytePower) + assert.Equal(t, big.Zero(), ret.QualityAdjPower) + assert.Equal(t, big.Zero(), ret.PledgeCollateral) + + // Add power for miner1 + actor.updateClaimedPower(rt, miner1, powerUnit, mul(powerUnit, 2)) + ret = actor.currentPowerTotal(rt) + assert.Equal(t, powerUnit, ret.RawBytePower) + assert.Equal(t, mul(powerUnit, 2), ret.QualityAdjPower) + assert.Equal(t, big.Zero(), ret.PledgeCollateral) + + // Add power and pledge for miner2 + actor.updateClaimedPower(rt, miner2, powerUnit, powerUnit) + actor.updatePledgeTotal(rt, miner1, abi.NewTokenAmount(1e6)) + ret = actor.currentPowerTotal(rt) + assert.Equal(t, mul(powerUnit, 2), ret.RawBytePower) + assert.Equal(t, mul(powerUnit, 3), ret.QualityAdjPower) + assert.Equal(t, abi.NewTokenAmount(1e6), ret.PledgeCollateral) + + rt.Verify() + + // Verify claims in state. + var st power.State + rt.GetState(&st) + claim1, found, err := st.GetClaim(rt.AdtStore(), miner1) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, powerUnit, claim1.RawBytePower) + require.Equal(t, mul(powerUnit, 2), claim1.QualityAdjPower) + + claim2, found, err := st.GetClaim(rt.AdtStore(), miner2) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, powerUnit, claim2.RawBytePower) + require.Equal(t, powerUnit, claim2.QualityAdjPower) + + // Subtract power and some pledge for miner2 + actor.updateClaimedPower(rt, miner2, powerUnit.Neg(), powerUnit.Neg()) + actor.updatePledgeTotal(rt, miner2, abi.NewTokenAmount(1e5).Neg()) + ret = actor.currentPowerTotal(rt) + assert.Equal(t, mul(powerUnit, 1), ret.RawBytePower) + assert.Equal(t, mul(powerUnit, 2), ret.QualityAdjPower) + assert.Equal(t, abi.NewTokenAmount(9e5), ret.PledgeCollateral) + + rt.GetState(&st) + claim2, found, err = st.GetClaim(rt.AdtStore(), miner2) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, big.Zero(), claim2.RawBytePower) + require.Equal(t, big.Zero(), claim2.QualityAdjPower) + }) +} + +func TestCron(t *testing.T) { + actor := newHarness(t) + miner1 := tutil.NewIDAddr(t, 101) + miner2 := tutil.NewIDAddr(t, 102) + owner := tutil.NewIDAddr(t, 103) + + builder := mock.NewBuilder(context.Background(), builtin.StoragePowerActorAddr).WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + t.Run("calls reward actor", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + expectedPower := big.NewInt(0) + rt.SetEpoch(1) + rt.ExpectValidateCallerAddr(builtin.CronActorAddr) + rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.UpdateNetworkKPI, &expectedPower, abi.NewTokenAmount(0), nil, 0) + rt.SetCaller(builtin.CronActorAddr, builtin.CronActorCodeID) + rt.Call(actor.Actor.OnEpochTickEnd, nil) + rt.Verify() + }) + + t.Run("event scheduled in null round called next round", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + // 0 - genesis + // 1 - block - registers events + // 2 - null - has event + // 3 - null + // 4 - block - has event + + rt.SetEpoch(1) + actor.enrollCronEvent(rt, miner1, 2, []byte{0x1, 0x3}) + actor.enrollCronEvent(rt, miner2, 4, []byte{0x2, 0x3}) + + expectedRawBytePower := big.NewInt(0) + rt.SetEpoch(4) + rt.ExpectValidateCallerAddr(builtin.CronActorAddr) + rt.ExpectSend(miner1, builtin.MethodsMiner.OnDeferredCronEvent, vmr.CBORBytes([]byte{0x1, 0x3}), big.Zero(), nil, exitcode.Ok) + rt.ExpectSend(miner2, builtin.MethodsMiner.OnDeferredCronEvent, vmr.CBORBytes([]byte{0x2, 0x3}), big.Zero(), nil, exitcode.Ok) + rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.UpdateNetworkKPI, &expectedRawBytePower, big.Zero(), nil, exitcode.Ok) + rt.SetCaller(builtin.CronActorAddr, builtin.CronActorCodeID) + rt.Call(actor.Actor.OnEpochTickEnd, nil) + rt.Verify() + }) + + t.Run("handles failed call", func(t *testing.T) { + rt := builder.Build(t) + actor.constructAndVerify(rt) + + rt.SetEpoch(1) + actor.enrollCronEvent(rt, miner1, 2, []byte{}) + actor.enrollCronEvent(rt, miner2, 2, []byte{}) + + actor.createMinerBasic(rt, owner, owner, miner1) + actor.createMinerBasic(rt, owner, owner, miner2) + + rawPow := power.ConsensusMinerMinPower + qaPow := rawPow + actor.updateClaimedPower(rt, miner1, rawPow, qaPow) + startPow := actor.currentPowerTotal(rt) + assert.Equal(t, rawPow, startPow.RawBytePower) + assert.Equal(t, qaPow, startPow.QualityAdjPower) + + expectedPower := big.NewInt(0) + rt.SetEpoch(2) + rt.ExpectValidateCallerAddr(builtin.CronActorAddr) + // First send fails + rt.ExpectSend(miner1, builtin.MethodsMiner.OnDeferredCronEvent, vmr.CBORBytes([]byte{}), big.Zero(), nil, exitcode.ErrIllegalState) + // Subsequent one still invoked + rt.ExpectSend(miner2, builtin.MethodsMiner.OnDeferredCronEvent, vmr.CBORBytes([]byte{}), big.Zero(), nil, exitcode.Ok) + // Reward actor still invoked + rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.UpdateNetworkKPI, &expectedPower, big.Zero(), nil, exitcode.Ok) + rt.SetCaller(builtin.CronActorAddr, builtin.CronActorCodeID) + rt.Call(actor.Actor.OnEpochTickEnd, nil) + rt.Verify() + + // expect cron failure was logged + rt.ExpectLogsContain("OnDeferredCronEvent failed for miner") + + newPow := actor.currentPowerTotal(rt) + assert.Equal(t, abi.NewStoragePower(0), newPow.RawBytePower) + assert.Equal(t, abi.NewStoragePower(0), newPow.QualityAdjPower) + + // Next epoch, only the reward actor is invoked + rt.SetEpoch(3) + rt.ExpectValidateCallerAddr(builtin.CronActorAddr) + rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.UpdateNetworkKPI, &expectedPower, big.Zero(), nil, exitcode.Ok) + rt.SetCaller(builtin.CronActorAddr, builtin.CronActorCodeID) + rt.Call(actor.Actor.OnEpochTickEnd, nil) + rt.Verify() + }) +} + +// +// Misc. Utility Functions +// + +type key string + +func asKey(in string) adt.Keyer { + return key(in) +} + +func verifyEmptyMap(t testing.TB, rt *mock.Runtime, cid cid.Cid) { + mapChecked, err := adt.AsMap(adt.AsStore(rt), cid) + assert.NoError(t, err) + keys, err := mapChecked.CollectKeys() + require.NoError(t, err) + assert.Empty(t, keys) +} + +type spActorHarness struct { + power.Actor + t *testing.T + minerSeq int +} + +func newHarness(t *testing.T) *spActorHarness { + return &spActorHarness{ + Actor: power.Actor{}, + t: t, + } +} + +func (h *spActorHarness) constructAndVerify(rt *mock.Runtime) { + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + ret := rt.Call(h.Actor.Constructor, nil) + assert.Nil(h.t, ret) + rt.Verify() + + var st power.State + rt.GetState(&st) + assert.Equal(h.t, abi.NewStoragePower(0), st.TotalRawBytePower) + assert.Equal(h.t, abi.NewStoragePower(0), st.TotalQualityAdjPower) + assert.Equal(h.t, abi.NewTokenAmount(0), st.TotalPledgeCollateral) + assert.Equal(h.t, abi.ChainEpoch(-1), st.LastEpochTick) + assert.Equal(h.t, int64(0), st.MinerCount) + assert.Equal(h.t, int64(0), st.NumMinersMeetingMinPower) + + verifyEmptyMap(h.t, rt, st.Claims) + verifyEmptyMap(h.t, rt, st.CronEventQueue) +} + +func (h *spActorHarness) createMiner(rt *mock.Runtime, owner, worker, miner, robust addr.Address, peer abi.PeerID, + multiaddrs []abi.Multiaddrs, sealProofType abi.RegisteredSealProof, value abi.TokenAmount) { + createMinerParams := &power.CreateMinerParams{ + Owner: owner, + Worker: worker, + SealProofType: sealProofType, + Peer: peer, + Multiaddrs: multiaddrs, + } + + // owner send CreateMiner to Actor + rt.SetCaller(owner, builtin.AccountActorCodeID) + rt.SetReceived(value) + rt.SetBalance(value) + rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) + + createMinerRet := &power.CreateMinerReturn{ + IDAddress: miner, // miner actor id address + RobustAddress: robust, // should be long miner actor address + } + + msgParams := &initact.ExecParams{ + CodeCID: builtin.StorageMinerActorCodeID, + ConstructorParams: initCreateMinerBytes(h.t, owner, worker, peer, multiaddrs, sealProofType), + } + rt.ExpectSend(builtin.InitActorAddr, builtin.MethodsInit.Exec, msgParams, value, createMinerRet, 0) + rt.Call(h.Actor.CreateMiner, createMinerParams) + rt.Verify() +} + +func (h *spActorHarness) createMinerBasic(rt *mock.Runtime, owner, worker, miner addr.Address) { + label := strconv.Itoa(h.minerSeq) + actrAddr := tutil.NewActorAddr(h.t, label) + h.minerSeq += 1 + h.createMiner(rt, owner, worker, miner, actrAddr, abi.PeerID(label), nil, abi.RegisteredSealProof_StackedDrg2KiBV1, big.Zero()) +} + +func (h *spActorHarness) updateClaimedPower(rt *mock.Runtime, miner addr.Address, rawDelta, qaDelta abi.StoragePower) { + params := power.UpdateClaimedPowerParams{ + RawByteDelta: rawDelta, + QualityAdjustedDelta: qaDelta, + } + rt.SetCaller(miner, builtin.StorageMinerActorCodeID) + rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) + rt.Call(h.UpdateClaimedPower, ¶ms) + rt.Verify() +} + +func (h *spActorHarness) updatePledgeTotal(rt *mock.Runtime, miner addr.Address, delta abi.TokenAmount) { + rt.SetCaller(miner, builtin.StorageMinerActorCodeID) + rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) + rt.Call(h.UpdatePledgeTotal, &delta) + rt.Verify() +} + +func (h *spActorHarness) currentPowerTotal(rt *mock.Runtime) *power.CurrentTotalPowerReturn { + rt.ExpectValidateCallerAny() + ret := rt.Call(h.CurrentTotalPower, nil).(*power.CurrentTotalPowerReturn) + rt.Verify() + return ret +} + +func (h *spActorHarness) enrollCronEvent(rt *mock.Runtime, miner addr.Address, epoch abi.ChainEpoch, payload []byte) { + rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) + rt.SetCaller(miner, builtin.StorageMinerActorCodeID) + rt.Call(h.Actor.EnrollCronEvent, &power.EnrollCronEventParams{ + EventEpoch: epoch, + Payload: payload, + }) + rt.Verify() +} + +func initCreateMinerBytes(t testing.TB, owner, worker addr.Address, peer abi.PeerID, multiaddrs []abi.Multiaddrs, sealProofType abi.RegisteredSealProof) []byte { + params := &power.MinerConstructorParams{ + OwnerAddr: owner, + WorkerAddr: worker, + SealProofType: sealProofType, + PeerId: peer, + Multiaddrs: multiaddrs, + } + + buf := new(bytes.Buffer) + require.NoError(t, params.MarshalCBOR(buf)) + return buf.Bytes() +} + +func (s key) Key() string { + return string(s) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/cbor_gen.go new file mode 100644 index 0000000000..f352db9b41 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/cbor_gen.go @@ -0,0 +1,298 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package reward + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{137}); err != nil { + return err + } + + // t.BaselinePower (big.Int) (struct) + if err := t.BaselinePower.MarshalCBOR(w); err != nil { + return err + } + + // t.RealizedPower (big.Int) (struct) + if err := t.RealizedPower.MarshalCBOR(w); err != nil { + return err + } + + // t.CumsumBaseline (big.Int) (struct) + if err := t.CumsumBaseline.MarshalCBOR(w); err != nil { + return err + } + + // t.CumsumRealized (big.Int) (struct) + if err := t.CumsumRealized.MarshalCBOR(w); err != nil { + return err + } + + // t.EffectiveNetworkTime (big.Int) (struct) + if err := t.EffectiveNetworkTime.MarshalCBOR(w); err != nil { + return err + } + + // t.SimpleSupply (big.Int) (struct) + if err := t.SimpleSupply.MarshalCBOR(w); err != nil { + return err + } + + // t.BaselineSupply (big.Int) (struct) + if err := t.BaselineSupply.MarshalCBOR(w); err != nil { + return err + } + + // t.ThisEpochReward (big.Int) (struct) + if err := t.ThisEpochReward.MarshalCBOR(w); err != nil { + return err + } + + // t.RewardEpochsPaid (abi.ChainEpoch) (int64) + if t.RewardEpochsPaid >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.RewardEpochsPaid))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.RewardEpochsPaid)-1)); err != nil { + return err + } + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 9 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.BaselinePower (big.Int) (struct) + + { + + if err := t.BaselinePower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.BaselinePower: %w", err) + } + + } + // t.RealizedPower (big.Int) (struct) + + { + + if err := t.RealizedPower.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RealizedPower: %w", err) + } + + } + // t.CumsumBaseline (big.Int) (struct) + + { + + if err := t.CumsumBaseline.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.CumsumBaseline: %w", err) + } + + } + // t.CumsumRealized (big.Int) (struct) + + { + + if err := t.CumsumRealized.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.CumsumRealized: %w", err) + } + + } + // t.EffectiveNetworkTime (big.Int) (struct) + + { + + if err := t.EffectiveNetworkTime.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.EffectiveNetworkTime: %w", err) + } + + } + // t.SimpleSupply (big.Int) (struct) + + { + + if err := t.SimpleSupply.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.SimpleSupply: %w", err) + } + + } + // t.BaselineSupply (big.Int) (struct) + + { + + if err := t.BaselineSupply.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.BaselineSupply: %w", err) + } + + } + // t.ThisEpochReward (big.Int) (struct) + + { + + if err := t.ThisEpochReward.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.ThisEpochReward: %w", err) + } + + } + // t.RewardEpochsPaid (abi.ChainEpoch) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.RewardEpochsPaid = abi.ChainEpoch(extraI) + } + return nil +} + +func (t *AwardBlockRewardParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.Miner (address.Address) (struct) + if err := t.Miner.MarshalCBOR(w); err != nil { + return err + } + + // t.Penalty (big.Int) (struct) + if err := t.Penalty.MarshalCBOR(w); err != nil { + return err + } + + // t.GasReward (big.Int) (struct) + if err := t.GasReward.MarshalCBOR(w); err != nil { + return err + } + + // t.WinCount (int64) (int64) + if t.WinCount >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.WinCount))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.WinCount)-1)); err != nil { + return err + } + } + return nil +} + +func (t *AwardBlockRewardParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Miner (address.Address) (struct) + + { + + if err := t.Miner.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Miner: %w", err) + } + + } + // t.Penalty (big.Int) (struct) + + { + + if err := t.Penalty.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Penalty: %w", err) + } + + } + // t.GasReward (big.Int) (struct) + + { + + if err := t.GasReward.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.GasReward: %w", err) + } + + } + // t.WinCount (int64) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.WinCount = int64(extraI) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_actor.go new file mode 100644 index 0000000000..93562801eb --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_actor.go @@ -0,0 +1,114 @@ +package reward + +import ( + "github.com/filecoin-project/go-address" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + . "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.AwardBlockReward, + 3: a.ThisEpochReward, + 4: a.UpdateNetworkKPI, + } +} + +var _ abi.Invokee = Actor{} + +func (a Actor) Constructor(rt vmr.Runtime, currRealizedPower *abi.StoragePower) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + + st := ConstructState(currRealizedPower) + rt.State().Create(st) + return nil +} + +type AwardBlockRewardParams struct { + Miner address.Address + Penalty abi.TokenAmount // penalty for including bad messages in a block + GasReward abi.TokenAmount // gas reward from all gas fees in a block + WinCount int64 +} + +// Awards a reward to a block producer. +// This method is called only by the system actor, implicitly, as the last message in the evaluation of a block. +// The system actor thus computes the parameters and attached value. +// +// The reward includes two components: +// - the epoch block reward, computed and paid from the reward actor's balance, +// - the block gas reward, expected to be transferred to the reward actor with this invocation. +// +// The reward is reduced before the residual is credited to the block producer, by: +// - a penalty amount, provided as a parameter, which is burnt, +func (a Actor) AwardBlockReward(rt vmr.Runtime, params *AwardBlockRewardParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + AssertMsg(rt.CurrentBalance().GreaterThanEqual(params.GasReward), + "actor current balance %v insufficient to pay gas reward %v", rt.CurrentBalance(), params.GasReward) + + minerAddr, ok := rt.ResolveAddress(params.Miner) + if !ok { + rt.Abortf(exitcode.ErrIllegalState, "failed to resolve given owner address") + } + + priorBalance := rt.CurrentBalance() + + penalty := abi.NewTokenAmount(0) + var st State + rt.State().Readonly(&st) + blockReward := big.Div(st.ThisEpochReward, big.NewInt(builtin.ExpectedLeadersPerEpoch)) + blockReward = big.Mul(blockReward, big.NewInt(params.WinCount)) + totalReward := big.Add(blockReward, params.GasReward) + + // Cap the penalty at the total reward value. + penalty = big.Min(params.Penalty, totalReward) + + // Reduce the payable reward by the penalty. + rewardPayable := big.Sub(totalReward, penalty) + + AssertMsg(big.Add(rewardPayable, penalty).LessThanEqual(priorBalance), + "reward payable %v + penalty %v exceeds balance %v", rewardPayable, penalty, priorBalance) + + _, code := rt.Send(minerAddr, builtin.MethodsMiner.AddLockedFund, &rewardPayable, rewardPayable) + builtin.RequireSuccess(rt, code, "failed to send reward to miner: %s", minerAddr) + + // Burn the penalty amount. + _, code = rt.Send(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, penalty) + builtin.RequireSuccess(rt, code, "failed to send penalty to burnt funds actor") + + return nil +} + +func (a Actor) ThisEpochReward(rt vmr.Runtime, _ *adt.EmptyValue) *abi.TokenAmount { + rt.ValidateImmediateCallerAcceptAny() + + var st State + rt.State().Readonly(&st) + return &st.ThisEpochReward +} + +// Called at the end of each epoch by the power actor (in turn by its cron hook). +// This is only invoked for non-empty tipsets. The impact of this is that block rewards are paid out over +// a schedule defined by non-empty tipsets, not by elapsed time/epochs. +// This is not necessarily what we want, and may change. +func (a Actor) UpdateNetworkKPI(rt vmr.Runtime, currRealizedPower *abi.StoragePower) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.StoragePowerActorAddr) + + var st State + rt.State().Transaction(&st, func() interface{} { + // By the time this is called, the rewards for this epoch have been paid to miners. + st.RewardEpochsPaid++ + st.updateToNextEpochReward(currRealizedPower) + return nil + }) + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state.go new file mode 100644 index 0000000000..7d3fa50787 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state.go @@ -0,0 +1,307 @@ +package reward + +import ( + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +// Fractional representation of NetworkTime with an implicit denominator of (2^MintingInputFixedPoint). +type NetworkTime = big.Int + +// A quantity of space * time (in byte-epochs) representing power committed to the network for some duration. +type Spacetime = big.Int + +type State struct { + BaselinePower abi.StoragePower + RealizedPower abi.StoragePower + CumsumBaseline Spacetime + CumsumRealized Spacetime + EffectiveNetworkTime NetworkTime + + SimpleSupply abi.TokenAmount // current supply + BaselineSupply abi.TokenAmount // current supply + + // The reward to be paid in total to block producers, if exactly the expected number of them produce a block. + // The actual reward total paid out depends on the number of winners in any round. + // This is computed at the end of the previous epoch, and should really be called ThisEpochReward. + ThisEpochReward abi.TokenAmount + + // The count of epochs for which a reward has been paid. + // This should equal the number of non-empty tipsets after the genesis, aka "chain height". + RewardEpochsPaid abi.ChainEpoch +} + +type AddrKey = adt.AddrKey + +// These numbers are placeholders, but should be in units of attoFIL, 10^-18 FIL +var SimpleTotal = big.Mul(big.NewInt(100e6), big.NewInt(1e18)) // 100M for testnet, PARAM_FINISH +var BaselineTotal = big.Mul(big.NewInt(900e6), big.NewInt(1e18)) // 900M for testnet, PARAM_FINISH + +func ConstructState(currRealizedPower *abi.StoragePower) *State { + st := &State{ + BaselinePower: big.Zero(), + RealizedPower: big.Zero(), + CumsumBaseline: big.Zero(), + CumsumRealized: big.Zero(), + EffectiveNetworkTime: big.Zero(), + + SimpleSupply: big.Zero(), + BaselineSupply: big.Zero(), + ThisEpochReward: big.Zero(), + RewardEpochsPaid: 0, + } + st.updateToNextEpochReward(currRealizedPower) + + return st +} + +// Takes in a current realized power for a reward epoch and computes +// and updates reward state to track reward for the next epoch +func (st *State) updateToNextEpochReward(currRealizedPower *abi.StoragePower) { + st.RealizedPower = *currRealizedPower + + st.BaselinePower = st.newBaselinePower() + st.CumsumBaseline = big.Add(st.CumsumBaseline, st.BaselinePower) + + // Cap realized power in computing CumsumRealized so that progress is only relative to the current epoch. + cappedRealizedPower := big.Min(st.BaselinePower, st.RealizedPower) + st.CumsumRealized = big.Add(st.CumsumRealized, cappedRealizedPower) + + st.EffectiveNetworkTime = st.getEffectiveNetworkTime() + + st.computePerEpochReward() +} + +// Updates the simple/baseline supply state and last epoch reward with computation for for a single epoch. +func (st *State) computePerEpochReward() abi.TokenAmount { + // TODO: PARAM_FINISH + clockTime := st.RewardEpochsPaid + networkTime := st.EffectiveNetworkTime + newSimpleSupply := mintingFunction(SimpleTotal, big.Lsh(big.NewInt(int64(clockTime)), MintingInputFixedPoint)) + newBaselineSupply := mintingFunction(BaselineTotal, networkTime) + + newSimpleMinted := big.Max(big.Sub(newSimpleSupply, st.SimpleSupply), big.Zero()) + newBaselineMinted := big.Max(big.Sub(newBaselineSupply, st.BaselineSupply), big.Zero()) + + // TODO: this isn't actually counting emitted reward, but expected reward (which will generally over-estimate). + // It's difficult to extract this from the minting function in its current form. + // https://github.com/filecoin-project/specs-actors/issues/317 + st.SimpleSupply = newSimpleSupply + st.BaselineSupply = newBaselineSupply + + perEpochReward := big.Add(newSimpleMinted, newBaselineMinted) + st.ThisEpochReward = perEpochReward + + return perEpochReward +} + +const baselinePower = 1 << 50 // 1PiB for testnet, PARAM_FINISH +func (st *State) newBaselinePower() abi.StoragePower { + // TODO: this is not the final baseline function or value, PARAM_FINISH + return big.NewInt(baselinePower) +} + +func (st *State) getEffectiveNetworkTime() NetworkTime { + // TODO: this function depends on the final baseline + // EffectiveNetworkTime is a fractional input with an implicit denominator of (2^MintingInputFixedPoint). + // realizedCumsum is thus left shifted by MintingInputFixedPoint before converted into a FixedPoint fraction + // through division (which is an inverse function for the integral of the baseline). + return big.Div(big.Lsh(st.CumsumRealized, MintingInputFixedPoint), big.NewInt(baselinePower)) +} + +// Minting Function: Taylor series expansion +// +// Intent +// The intent of the following code is to compute the desired fraction of +// coins that should have been minted at a given epoch according to the +// simple exponential decay supply. This function is used both directly, +// to compute simple minting, and indirectly, to compute baseline minting +// by providing a synthetic "effective network time" instead of an actual +// epoch number. The prose specification of the simple exponential decay is +// that the unminted supply should decay exponentially with a half-life of +// 6 years. The formalization of the minted fraction at epoch t is thus: +// +// ( t ) +// ( ------------------------ ) +// ( 1 )^( [# of epochs in 6 years] ) +// f(t) = 1 - ( - ) +// ( 2 ) +// Challenges +// +// 1. Since we cannot rely on floating-point computations in this setting, we +// have resorted to using an ad-hoc fixed-point standard. Experimental +// testing with the relevant scales of inputs and with a desired "atto" +// level of output precision yielded a recommendation of a 97-bit fractional +// part, which was stored in the constant "MintingOutputFixedPoint". +// Fractional input is only necessary when considering "effective network +// time"; there, the desired precision is determined by the minimum +// plausible ratio between realized network power and network baseline, +// which is set in "MintingInputFixedPoint". +// +// !IMPORTANT!: the time input to this function should be a factor of +// 2^MintingInputFixedPoint greater than the semantically intended value, and +// the return value from this function is a factor of 2^MintingOutputFixedPoint +// greater. The semantics of the output value will always be a fraction +// between 0 and 1, but will be represented as an integer between 0 and +// 2^FixedPoint. The expectation is that callers will multiply the result by +// some number, and THEN right-shift the result of the multiplication by +// FixedPoint bits, thus implementing fixed-point multiplication by the +// returned fraction. Analogously, if callers intend to pass in an integer +// "t", it should be left-shifted by MintingInputFixedPoint before being +// passed; if it is fractional, its fractional part should be +// MintingInputFixedPoint bits long. +// +// 2. Since we do not have a math library in this setting, we cannot directly +// implement the intended closed form using stock implementations of +// elementary functions like exp and ln. Not even powf is available. +// Instead, we have manipulated the function into a form with a tractable +// Taylor expansion, and then implemented the fixed-point Taylor expansion +// in an efficient way. +// +// Mathematical Derivation +// +// Note that the function f above is analytically equivalent to: +// +// ( ( 1 ) 1 ) +// ( ln( - ) * ------------------------ * t ) +// ( ( 2 ) [# of epochs in 6 years] ) +// f(t) = 1 - e +// +// We define λ = -ln(1/2)/[# of epochs in 6 years] +// = -ln(1/2)*([Seconds per epoch] / (6 * [Seconds per year])) +// such that +// -λt +// f(t) = 1 - e +// +// Now, we substitute for the exponential its well-known Taylor series at 0: +// +// infinity n +// \```` (-λt) +// f(t) = 1 - > ------ +// /,,,, n! +// n = 0 +// +// Simplifying, and truncating to the empirically necessary precision: +// +// 24 n +// \```` (-1)(-λt) +// f(t) = > ---------- +// /,,,, n! +// n = 1 +// +// This is the final mathematical form of what is computed below. What remains +// is to explain how the series calculation is carried out in fixed-point. +// +// Algorithm +// +// The key observation is that each successive term can be represented as a +// rational number, and derived from the previous term by simple +// multiplications on the numerator and denominator. In particular: +// * the numerator is the previous numerator multiplied by (-λt) +// * the denominator is the previous denominator multiplied by n +// We also need to represent λ itself as a rational, so the denominator of +// the series term is actually multiplied by both n and the denominator of +// lambda. +// +// When we have the numerator and denominator for a given term set up, we +// compute their fixed-point fraction by left-shifting the numerator before +// performing integer division. +// +// Finally, at the end of each loop, we remove unnecessary bits of precision +// from both the numerator and denominator accumulators to control the +// computational complexity of the bigint multiplications. + +// Fixed-point precision (in bits) used for minting function's input "t" +const MintingInputFixedPoint = 30 + +// Fixed-point precision (in bits) used internally and for output +const MintingOutputFixedPoint = 97 + +// The following are the numerator and denominator of -ln(1/2)=ln(2), +// represented as a rational with sufficient precision. They are parsed from +// strings because literals cannot be this long; they are stored as separate +// variables only because the string parsing function has multiple returns. +var LnTwoNum, _ = big.FromString("6931471805599453094172321215") +var LnTwoDen, _ = big.FromString("10000000000000000000000000000") + +// We multiply the fraction ([Seconds per epoch] / (6 * [Seconds per year])) +// into the rational representation of -ln(1/2) which was just loaded, to +// produce the final, constant, rational representation of λ. +var LambdaNum = big.Mul(big.NewInt(builtin.EpochDurationSeconds), LnTwoNum) +var LambdaDen = big.Mul(big.NewInt(6*builtin.SecondsInYear), LnTwoDen) + +// This function implements f(t) as described in the large comment block above, +// with the important caveat that its return value must not be interpreted +// semantically as an integer, but rather as a fixed-point number with +// FixedPoint bits of fractional part. +func taylorSeriesExpansion(lambdaNum big.Int, lambdaDen big.Int, t big.Int) big.Int { + // `numeratorBase` is the numerator of the rational representation of (-λt). + numeratorBase := big.Mul(lambdaNum.Neg(), t) + // The denominator of (-λt) is the denominator of λ times the denominator of t, + // which is a fixed 2^MintingInputFixedPoint. Multiplying by this is a left shift. + denominatorBase := big.Lsh(lambdaDen, MintingInputFixedPoint) + + // `numerator` is the accumulator for numerators of the series terms. The + // first term is simply (-1)(-λt). To include that factor of (-1), which + // appears in every term, we introduce this negation into the numerator of + // the first term. (All terms will be negated by this, because each term is + // derived from the last by multiplying into it.) + numerator := numeratorBase.Neg() + // `denominator` is the accumulator for denominators of the series terms. + denominator := denominatorBase + + // `ret` is an _additive_ accumulator for partial sums of the series, and + // carries a _fixed-point_ representation rather than a rational + // representation. This just means it has an implicit denominator of + // 2^(FixedPoint). + ret := big.Zero() + + // The first term computed has order 1; the final term has order 24. + for n := int64(1); n < int64(25); n++ { + + // Multiplying the denominator by `n` on every loop accounts for the + // `n!` (factorial) in the denominator of the series. + denominator = big.Mul(denominator, big.NewInt(n)) + + // Left-shift and divide to convert rational into fixed-point. + term := big.Div(big.Lsh(numerator, MintingOutputFixedPoint), denominator) + + // Accumulate the fixed-point result into the return accumulator. + ret = big.Add(ret, term) + + // Multiply the rational representation of (-λt) into the term accumulators + // for the next iteration. Doing this here in the loop allows us to save a + // couple bigint operations by initializing numerator and denominator + // directly instead of multiplying by 1. + numerator = big.Mul(numerator, numeratorBase) + denominator = big.Mul(denominator, denominatorBase) + + // If the denominator has grown beyond the necessary precision, then we can + // truncate it by right-shifting. As long as we right-shift the numerator + // by the same number of bits, all we have done is lose unnecessary + // precision that would slow down the next iteration's multiplies. + denominatorLen := big.BitLen(denominator) + unnecessaryBits := denominatorLen - MintingOutputFixedPoint + + numerator = big.Rsh(numerator, unnecessaryBits) + denominator = big.Rsh(denominator, unnecessaryBits) + + } + + return ret +} + +// Minting Function Wrapper +// +// Intent +// The necessary calling conventions for the function above are unwieldy: +// the common case is to supply the canonical Lambda, multiply by some other +// number, and right-shift down by MintingOutputFixedPoint. This convenience +// wrapper implements those conventions. However, it does NOT implement +// left-shifting the input by the MintingInputFixedPoint, because baseline +// minting will actually supply a fractional input. +func mintingFunction(factor big.Int, t big.Int) big.Int { + return big.Rsh(big.Mul(factor, taylorSeriesExpansion(LambdaNum, LambdaDen, t)), MintingOutputFixedPoint) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state_test.go new file mode 100644 index 0000000000..008dadd9ca --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_state_test.go @@ -0,0 +1,67 @@ +package reward + +import ( + "testing" + + "github.com/filecoin-project/specs-actors/actors/abi/big" +) + +// Minting function test vectors +// +// Intent +// Check that for the first 7 years, the current minting function +// approximation is exact to the desired precision, namely 1 attoFIL out of 1 +// gigaFIL. +// +// Approach +// The desired precision is, in particular lg(1e9/1e-18) ≈ 90 bits. +// An offline calculation with arbitrary-precision arithmetic was used to +// establish ground truth about the first 90 bits of the minting function, +// f(t):=1-exp(t*ln(1/2)*SecondsPerEpoch/(6*SecondsPerYear)), for epoch +// numbers corresponding to the endpoints of the first 7 years with +// SecondsPerEpoch set to 30. These numbers were written below as strings, +// because they contain more digits than literals support. + +var mintingTestVectorPrecision = uint(90) + +var mintingTestVectors = []struct { + in int64 + out string +}{ + {1051897, "135060784589637453410950129"}, + {2103794, "255386271058940593613485187"}, + {3155691, "362584098600550296025821387"}, + {4207588, "458086510989070493849325308"}, + {5259485, "543169492437427724953202180"}, + {6311382, "618969815707708523300124489"}, + {7363279, "686500230252085183344830372"}, +} + +const SecondsInYear = 31556925 +const TestEpochDurationSeconds = 30 + +var TestLambdaNum = big.Mul(big.NewInt(TestEpochDurationSeconds), LnTwoNum) +var TestLambdaDen = big.Mul(big.NewInt(6*SecondsInYear), LnTwoDen) + +func TestMintingFunction(t *testing.T) { + for _, vector := range mintingTestVectors { + // In order to supply an integer as an input to the minting function, we + // first left-shift zeroes into the fractional part of its fixed-point + // representation. + ts_input := big.Lsh(big.NewInt(vector.in), MintingInputFixedPoint) + + ts_output := taylorSeriesExpansion(TestLambdaNum, TestLambdaDen, ts_input) + + // ts_output will always range between 0 and 2^FixedPoint. If we + // right-shifted by FixedPoint, without first multiplying by something, we + // would discard _all_ the bits and get 0. Instead, we want to discard only + // those bits in the FixedPoint representation that we don't also want to + // require to exactly match the test vectors. + ts_truncated_fractional_part := big.Rsh(ts_output, MintingOutputFixedPoint-mintingTestVectorPrecision) + + expected_truncated_fractional_part, _ := big.FromString(vector.out) + if !(ts_truncated_fractional_part.Equals(expected_truncated_fractional_part)) { + t.Errorf("minting function: on input %q, computed %q, expected %q", ts_input, ts_truncated_fractional_part, expected_truncated_fractional_part) + } + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_test.go new file mode 100644 index 0000000000..48546a5bce --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/reward/reward_test.go @@ -0,0 +1,91 @@ +package reward_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/reward" + "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, reward.Actor{}) +} + +func TestConstructor(t *testing.T) { + actor := rewardHarness{reward.Actor{}, t} + + t.Run("construct with 0 power", func(t *testing.T) { + rt := mock.NewBuilder(context.Background(), builtin.RewardActorAddr). + WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID). + Build(t) + startRealizedPower := abi.NewStoragePower(0) + actor.constructAndVerify(rt, &startRealizedPower) + }) + t.Run("construct with some power", func(t *testing.T) { + rt := mock.NewBuilder(context.Background(), builtin.RewardActorAddr). + WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID). + Build(t) + startRealizedPower := abi.NewStoragePower(1 << 25) + actor.constructAndVerify(rt, &startRealizedPower) + st := getState(rt) + assert.Equal(t, abi.ChainEpoch(0), st.RewardEpochsPaid) // constructor shouldn't bump count of rewards + assert.Equal(t, startRealizedPower, st.RealizedPower) + assert.Equal(t, startRealizedPower, st.CumsumRealized) + + // Note this check is sensative to the value of startRealizedPower and the minting function + // so it is somewhat brittle. Values of startRealizedPower below 1<<20 mint no coins + assert.NotEqual(t, big.Zero(), st.ThisEpochReward) + }) +} + +func TestAwardBlockReward(t *testing.T) { + actor := rewardHarness{reward.Actor{}, t} + builder := mock.NewBuilder(context.Background(), builtin.RewardActorAddr). + WithCaller(builtin.SystemActorAddr, builtin.SystemActorCodeID) + + t.Run("assertion failure when current balance is less than gas reward", func(t *testing.T) { + rt := builder.Build(t) + startRealizedPower := abi.NewStoragePower(0) + actor.constructAndVerify(rt, &startRealizedPower) + miner := tutil.NewIDAddr(t, 1000) + + gasreward := abi.NewTokenAmount(10) + rt.SetBalance(abi.NewTokenAmount(0)) + + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + rt.ExpectAssertionFailure("actor current balance 0 insufficient to pay gas reward 10", func() { + rt.Call(actor.AwardBlockReward, &reward.AwardBlockRewardParams{ + Miner: miner, + Penalty: big.Zero(), + GasReward: gasreward, + }) + }) + rt.Verify() + }) +} + +type rewardHarness struct { + reward.Actor + t testing.TB +} + +func (h *rewardHarness) constructAndVerify(rt *mock.Runtime, currRawPower *abi.StoragePower) { + rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) + ret := rt.Call(h.Constructor, currRawPower) + assert.Nil(h.t, ret) + rt.Verify() + +} + +func getState(rt *mock.Runtime) *reward.State { + var st reward.State + rt.GetState(&st) + return &st +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/shared.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/shared.go new file mode 100644 index 0000000000..e2d95e22d2 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/shared.go @@ -0,0 +1,55 @@ +package builtin + +import ( + addr "github.com/filecoin-project/go-address" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + runtime "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + autil "github.com/filecoin-project/specs-actors/actors/util" +) + +///// Code shared by multiple built-in actors. ///// + +// Aborts with an ErrIllegalArgument if predicate is not true. +func RequireParam(rt runtime.Runtime, predicate bool, msg string, args ...interface{}) { + if !predicate { + rt.Abortf(exitcode.ErrIllegalArgument, msg, args...) + } +} + +// Propagates a failed send by aborting the current method with the same exit code. +func RequireSuccess(rt runtime.Runtime, e exitcode.ExitCode, msg string, args ...interface{}) { + if !e.IsSuccess() { + rt.Abortf(e, msg, args...) + } +} + +// Aborts with a formatted message if err is not nil. +// The provided message will be suffixed by ": %s" and the provided args suffixed by the err. +func RequireNoErr(rt runtime.Runtime, err error, code exitcode.ExitCode, msg string, args ...interface{}) { + if err != nil { + newMsg := msg + ": %s" + newArgs := append(args, err) + rt.Abortf(code, newMsg, newArgs...) + } +} + +func RequestMinerControlAddrs(rt runtime.Runtime, minerAddr addr.Address) (ownerAddr addr.Address, workerAddr addr.Address) { + ret, code := rt.Send(minerAddr, MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0)) + RequireSuccess(rt, code, "failed fetching control addresses") + var addrs MinerAddrs + autil.AssertNoError(ret.Into(&addrs)) + + return addrs.Owner, addrs.Worker +} + +// This type duplicates the Miner.ControlAddresses return type, to work around a circular dependency between actors. +type MinerAddrs struct { + Owner addr.Address + Worker addr.Address +} + +type ConfirmSectorProofsParams struct { + Sectors []abi.SectorNumber +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/singletons.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/singletons.go new file mode 100644 index 0000000000..8fb55fbcf7 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/singletons.go @@ -0,0 +1,40 @@ +package builtin + +import ( + addr "github.com/filecoin-project/go-address" + autil "github.com/filecoin-project/specs-actors/actors/util" + "github.com/ipfs/go-cid" +) + +// Addresses for singleton system actors. +var ( + // Distinguished AccountActor that is the source of system implicit messages. + SystemActorAddr = mustMakeAddress(0) + InitActorAddr = mustMakeAddress(1) + RewardActorAddr = mustMakeAddress(2) + CronActorAddr = mustMakeAddress(3) + StoragePowerActorAddr = mustMakeAddress(4) + StorageMarketActorAddr = mustMakeAddress(5) + VerifiedRegistryActorAddr = mustMakeAddress(6) + // Distinguished AccountActor that is the destination of all burnt funds. + BurntFundsActorAddr = mustMakeAddress(99) +) + +const FirstNonSingletonActorId = 100 + +func mustMakeAddress(id uint64) addr.Address { + address, err := addr.NewIDAddress(id) + autil.AssertNoError(err) + return address +} + +// IsSingletonActor returns true if the code belongs to a singleton actor. +func IsSingletonActor(code cid.Cid) bool { + return code.Equals(SystemActorCodeID) || + code.Equals(InitActorCodeID) || + code.Equals(RewardActorCodeID) || + code.Equals(CronActorCodeID) || + code.Equals(StoragePowerActorCodeID) || + code.Equals(StorageMarketActorCodeID) || + code.Equals(VerifiedRegistryActorCodeID) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/cbor_gen.go new file mode 100644 index 0000000000..512e4bbf37 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/cbor_gen.go @@ -0,0 +1,42 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package system + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{128}); err != nil { + return err + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 0 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_actor.go new file mode 100644 index 0000000000..65adba7517 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_actor.go @@ -0,0 +1,27 @@ +package system + +import ( + abi "github.com/filecoin-project/specs-actors/actors/abi" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + runtime "github.com/filecoin-project/specs-actors/actors/runtime" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + } +} + +var _ abi.Invokee = Actor{} + +func (a Actor) Constructor(rt runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + + rt.State().Create(&State{}) + return nil +} + +type State struct{} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_test.go new file mode 100644 index 0000000000..4a7dfb8a3c --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/system/system_test.go @@ -0,0 +1,12 @@ +package system_test + +import ( + "testing" + + "github.com/filecoin-project/specs-actors/actors/builtin/system" + "github.com/filecoin-project/specs-actors/support/mock" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, system.Actor{}) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/cbor_gen.go new file mode 100644 index 0000000000..c96423fb46 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/cbor_gen.go @@ -0,0 +1,321 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package verifreg + +import ( + "fmt" + "io" + + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.RootKey (address.Address) (struct) + if err := t.RootKey.MarshalCBOR(w); err != nil { + return err + } + + // t.Verifiers (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.Verifiers); err != nil { + return xerrors.Errorf("failed to write cid field t.Verifiers: %w", err) + } + + // t.VerifiedClients (cid.Cid) (struct) + + if err := cbg.WriteCid(w, t.VerifiedClients); err != nil { + return xerrors.Errorf("failed to write cid field t.VerifiedClients: %w", err) + } + + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.RootKey (address.Address) (struct) + + { + + if err := t.RootKey.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.RootKey: %w", err) + } + + } + // t.Verifiers (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Verifiers: %w", err) + } + + t.Verifiers = c + + } + // t.VerifiedClients (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.VerifiedClients: %w", err) + } + + t.VerifiedClients = c + + } + return nil +} + +func (t *AddVerifierParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + + // t.Allowance (big.Int) (struct) + if err := t.Allowance.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *AddVerifierParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + // t.Allowance (big.Int) (struct) + + { + + if err := t.Allowance.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Allowance: %w", err) + } + + } + return nil +} + +func (t *AddVerifiedClientParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + + // t.Allowance (big.Int) (struct) + if err := t.Allowance.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *AddVerifiedClientParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + // t.Allowance (big.Int) (struct) + + { + + if err := t.Allowance.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Allowance: %w", err) + } + + } + return nil +} + +func (t *UseBytesParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + + // t.DealSize (big.Int) (struct) + if err := t.DealSize.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *UseBytesParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + // t.DealSize (big.Int) (struct) + + { + + if err := t.DealSize.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.DealSize: %w", err) + } + + } + return nil +} + +func (t *RestoreBytesParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + + // t.DealSize (big.Int) (struct) + if err := t.DealSize.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *RestoreBytesParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + // t.DealSize (big.Int) (struct) + + { + + if err := t.DealSize.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.DealSize: %w", err) + } + + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_actor.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_actor.go new file mode 100644 index 0000000000..6d5316bfc1 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_actor.go @@ -0,0 +1,219 @@ +package verifreg + +import ( + addr "github.com/filecoin-project/go-address" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + . "github.com/filecoin-project/specs-actors/actors/util" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.AddVerifier, + 3: a.RemoveVerifier, + 4: a.AddVerifiedClient, + 5: a.UseBytes, + 6: a.RestoreBytes, + } +} + +var _ abi.Invokee = Actor{} + +//////////////////////////////////////////////////////////////////////////////// +// Actor methods +//////////////////////////////////////////////////////////////////////////////// + +func (a Actor) Constructor(rt vmr.Runtime, rootKey *addr.Address) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.SystemActorAddr) + + emptyMap, err := adt.MakeEmptyMap(adt.AsStore(rt)).Root() + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to create verified registry state: %v", err) + } + + st := ConstructState(emptyMap, *rootKey) + rt.State().Create(st) + return nil +} + +type AddVerifierParams struct { + Address addr.Address + Allowance DataCap +} + +func (a Actor) AddVerifier(rt vmr.Runtime, params *AddVerifierParams) *adt.EmptyValue { + var st State + rt.State().Readonly(&st) + rt.ValidateImmediateCallerIs(st.RootKey) + + rt.State().Transaction(&st, func() interface{} { + err := st.PutVerifier(adt.AsStore(rt), params.Address, params.Allowance) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to add verifier: %v", err) + } + return nil + }) + + return nil +} + +func (a Actor) RemoveVerifier(rt vmr.Runtime, verifierAddr *addr.Address) *adt.EmptyValue { + var st State + rt.State().Readonly(&st) + rt.ValidateImmediateCallerIs(st.RootKey) + + rt.State().Transaction(&st, func() interface{} { + err := st.DeleteVerifier(adt.AsStore(rt), *verifierAddr) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to delete verifier: %v", err) + } + return nil + }) + + return nil +} + +type AddVerifiedClientParams struct { + Address addr.Address + Allowance DataCap +} + +func (a Actor) AddVerifiedClient(rt vmr.Runtime, params *AddVerifiedClientParams) *adt.EmptyValue { + if params.Allowance.LessThanEqual(MinVerifiedDealSize) { + rt.Abortf(exitcode.ErrIllegalArgument, "Allowance %d below MinVerifiedDealSize for add verified client %v", params.Allowance, params.Address) + } + rt.ValidateImmediateCallerAcceptAny() + + var st State + rt.State().Transaction(&st, func() interface{} { + // Validate caller is one of the verifiers. + verifierAddr := rt.Message().Caller() + verifierCap, found, err := st.GetVerifier(adt.AsStore(rt), verifierAddr) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to get Verifier for %v", err) + } else if !found { + rt.Abortf(exitcode.ErrNotFound, "Invalid verifier %v", verifierAddr) + } + + // Compute new verifier cap and update. + if verifierCap.LessThan(params.Allowance) { + rt.Abortf(exitcode.ErrIllegalArgument, "Add more DataCap (%d) for VerifiedClient than allocated %d", params.Allowance, verifierCap) + } + newVerifierCap := big.Sub(*verifierCap, params.Allowance) + + if err := st.PutVerifier(adt.AsStore(rt), verifierAddr, newVerifierCap); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to update new verifier cap (%d) for %v", newVerifierCap, verifierAddr) + } + + // Write-once entry and does not get changed for simplicity. + // If parties neeed more allowance, they can get another VerifiedClient account. + // This is a one-time, upfront allocation. + // Returns error if VerifiedClient already exists. + _, found, err = st.GetVerifiedClient(adt.AsStore(rt), params.Address) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to load verified client state for %v", params.Address) + } else if found { + rt.Abortf(exitcode.ErrIllegalArgument, "Verified client already exists: %v", params.Address) + } + + if err := st.PutVerifiedClient(adt.AsStore(rt), params.Address, params.Allowance); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to add verified client %v with cap %d", params.Address, params.Allowance) + } + return nil + }) + + return nil +} + +type UseBytesParams struct { + Address addr.Address // Address of verified client. + DealSize abi.StoragePower // Number of bytes to use. +} + +// Called by StorageMarketActor during PublishStorageDeals. +// Do not allow partially verified deals (DealSize must be greater than equal to allowed cap). +// Delete VerifiedClient if remaining DataCap is smaller than minimum VerifiedDealSize. +func (a Actor) UseBytes(rt vmr.Runtime, params *UseBytesParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.StorageMarketActorAddr) + + if params.DealSize.LessThan(MinVerifiedDealSize) { + rt.Abortf(exitcode.ErrIllegalArgument, "VerifiedDealSize: %d below minimum in UseBytes", params.DealSize) + } + + var st State + rt.State().Transaction(&st, func() interface{} { + vcCap, found, err := st.GetVerifiedClient(adt.AsStore(rt), params.Address) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to get verified client state for %v", params.Address) + } else if !found { + rt.Abortf(exitcode.ErrIllegalArgument, "Invalid address for verified client %v", params.Address) + } + Assert(vcCap.GreaterThanEqual(big.Zero())) + + if params.DealSize.GreaterThan(vcCap) { + rt.Abortf(exitcode.ErrIllegalArgument, "DealSize %d exceeds allowable cap: %d for VerifiedClient %v", params.DealSize, vcCap, params.Address) + } + + newVcCap := big.Sub(vcCap, params.DealSize) + if newVcCap.LessThan(MinVerifiedDealSize) { + // Delete entry if remaining DataCap is less than MinVerifiedDealSize. + // Will be restored later if the deal did not get activated with a ProvenSector. + err = st.DeleteVerifiedClient(adt.AsStore(rt), params.Address) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to delete verified client %v with cap %d when %d bytes are used.", params.Address, vcCap, params.DealSize) + } + } else { + err = st.PutVerifiedClient(adt.AsStore(rt), params.Address, newVcCap) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to update verified client %v when %d bytes are used.", params.Address, params.DealSize) + } + } + + return nil + }) + + return nil +} + +type RestoreBytesParams struct { + Address addr.Address + DealSize abi.StoragePower +} + +// Called by HandleInitTimeoutDeals from StorageMarketActor when a VerifiedDeal fails to init. +// Restore allowable cap for the client, creating new entry if the client has been deleted. +func (a Actor) RestoreBytes(rt vmr.Runtime, params *RestoreBytesParams) *adt.EmptyValue { + rt.ValidateImmediateCallerIs(builtin.StorageMarketActorAddr) + + if params.DealSize.LessThan(MinVerifiedDealSize) { + rt.Abortf(exitcode.ErrIllegalArgument, "Below minimum VerifiedDealSize requested in RestoreBytes: %d", params.DealSize) + } + + var st State + rt.State().Transaction(&st, func() interface{} { + vcCap, found, err := st.GetVerifiedClient(adt.AsStore(rt), params.Address) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to get verified client state for %v", params.Address) + } + + if !found { + vcCap = big.Zero() + } + + newVcCap := big.Add(vcCap, params.DealSize) + if err := st.PutVerifiedClient(adt.AsStore(rt), params.Address, newVcCap); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "Failed to restore verified client state for %v", params.Address) + } + return nil + }) + + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_state.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_state.go new file mode 100644 index 0000000000..64909b0ad8 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_state.go @@ -0,0 +1,132 @@ +package verifreg + +import ( + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + errors "github.com/pkg/errors" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + big "github.com/filecoin-project/specs-actors/actors/abi/big" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +// DataCap is an integer number of bytes. +// We can introduce policy changes and replace this in the future. +type DataCap = abi.StoragePower +type AddrKey = adt.AddrKey + +type State struct { + // Root key holder multisig. + // Authorize and remove verifiers. + RootKey addr.Address + + // Verifiers authorize VerifiedClients. + // Verifiers delegate their DataCap. + Verifiers cid.Cid // HAMT[addr.Address]DataCap + + // VerifiedClients can add VerifiedClientData, up to DataCap. + VerifiedClients cid.Cid // HAMT[addr.Address]DataCap +} + +var MinVerifiedDealSize abi.StoragePower = big.NewInt(1 << 20) // PARAM_FINISH + +// rootKeyAddress comes from genesis. +func ConstructState(emptyMapCid cid.Cid, rootKeyAddress addr.Address) *State { + return &State{ + RootKey: rootKeyAddress, + Verifiers: emptyMapCid, + VerifiedClients: emptyMapCid, + } +} + +func (st *State) PutVerifier(store adt.Store, verifierAddr addr.Address, verifierCap DataCap) error { + verifiers, err := adt.AsMap(store, st.Verifiers) + if err != nil { + return err + } + + if err := verifiers.Put(AddrKey(verifierAddr), &verifierCap); err != nil { + return errors.Wrapf(err, "failed to put verifier %v with a cap of %v", verifierAddr, verifierCap) + } + st.Verifiers, err = verifiers.Root() + if err != nil { + return errors.Wrapf(err, "failed to flush Verifiers in PutVerifier") + } + return nil +} + +func (st *State) GetVerifier(store adt.Store, address addr.Address) (*DataCap, bool, error) { + verifiers, err := adt.AsMap(store, st.Verifiers) + if err != nil { + return nil, false, err + } + + var allowance DataCap + found, err := verifiers.Get(AddrKey(address), &allowance) + if err != nil { + return nil, false, errors.Wrapf(err, "failed to load verifier for address %v", address) + } + return &allowance, found, nil +} + +func (st *State) DeleteVerifier(store adt.Store, address addr.Address) error { + verifiers, err := adt.AsMap(store, st.Verifiers) + if err != nil { + return err + } + + if err := verifiers.Delete(AddrKey(address)); err != nil { + return errors.Wrapf(err, "failed to delete verifier for address %v", address) + } + st.Verifiers, err = verifiers.Root() + if err != nil { + return errors.Wrapf(err, "failed to flush Verifiers in DeleteVerifier") + } + return nil +} + +func (st *State) PutVerifiedClient(store adt.Store, vcAddress addr.Address, vcCap DataCap) error { + vc, err := adt.AsMap(store, st.VerifiedClients) + if err != nil { + return err + } + + if err := vc.Put(AddrKey(vcAddress), &vcCap); err != nil { + return err + } + st.VerifiedClients, err = vc.Root() + if err != nil { + return errors.Wrapf(err, "failed to flush VerifiedClients in PutVerifiedClient") + } + return nil +} + +func (st *State) GetVerifiedClient(store adt.Store, vcAddress addr.Address) (DataCap, bool, error) { + vc, err := adt.AsMap(store, st.VerifiedClients) + if err != nil { + return big.Zero(), false, err + } + + var allowance DataCap + found, err := vc.Get(AddrKey(vcAddress), &allowance) + if err != nil { + return big.Zero(), false, errors.Wrapf(err, "failed to load verified client for address %v", vcAddress) + } + return allowance, found, nil +} + +func (st *State) DeleteVerifiedClient(store adt.Store, vcAddress addr.Address) error { + vc, err := adt.AsMap(store, st.VerifiedClients) + if err != nil { + return err + } + + if err := vc.Delete(AddrKey(vcAddress)); err != nil { + return errors.Wrapf(err, "failed to delete verified client for address %v", vcAddress) + } + st.VerifiedClients, err = vc.Root() + if err != nil { + return errors.Wrapf(err, "failed to flush VerifiedClients in DeleteVerifiedClient") + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_test.go new file mode 100644 index 0000000000..8c02f6f90a --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/builtin/verifreg/verified_registry_test.go @@ -0,0 +1,12 @@ +package verifreg_test + +import ( + "testing" + + "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + "github.com/filecoin-project/specs-actors/support/mock" +) + +func TestExports(t *testing.T) { + mock.CheckActorExports(t, verifreg.Actor{}) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/crypto/randomness.go b/vendor/github.com/filecoin-project/specs-actors/actors/crypto/randomness.go new file mode 100644 index 0000000000..aa04ef3536 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/crypto/randomness.go @@ -0,0 +1,14 @@ +package crypto + +// Specifies a domain for randomness generation. +type DomainSeparationTag int + +const ( + DomainSeparationTag_TicketProduction DomainSeparationTag = 1 + iota + DomainSeparationTag_ElectionProofProduction + DomainSeparationTag_WinningPoStChallengeSeed + DomainSeparationTag_WindowedPoStChallengeSeed + DomainSeparationTag_SealRandomness + DomainSeparationTag_InteractiveSealChallengeSeed + DomainSeparationTag_WindowedPoStDeadlineAssignment +) diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/crypto/signature.go b/vendor/github.com/filecoin-project/specs-actors/actors/crypto/signature.go new file mode 100644 index 0000000000..e2bf0be973 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/crypto/signature.go @@ -0,0 +1,119 @@ +package crypto + +import ( + "bytes" + "fmt" + "io" + "math" + + cbg "github.com/whyrusleeping/cbor-gen" +) + +type SigType byte + +const ( + SigTypeUnknown = SigType(math.MaxUint8) + + SigTypeSecp256k1 = SigType(iota) + SigTypeBLS +) + +func (t SigType) Name() (string, error) { + switch t { + case SigTypeUnknown: + return "unknown", nil + case SigTypeSecp256k1: + return "secp256k1", nil + case SigTypeBLS: + return "bls", nil + default: + return "", fmt.Errorf("invalid signature type: %d", t) + } +} + +const SignatureMaxLength = 200 + +type Signature struct { + Type SigType + Data []byte +} + +func (s *Signature) Equals(o *Signature) bool { + if s == nil || o == nil { + return s == o + } + return s.Type == o.Type && bytes.Equal(s.Data, o.Data) +} + +func (s *Signature) MarshalCBOR(w io.Writer) error { + if s == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + header := cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(s.Data)+1)) + if _, err := w.Write(header); err != nil { + return err + } + if _, err := w.Write([]byte{byte(s.Type)}); err != nil { + return err + } + if _, err := w.Write(s.Data); err != nil { + return err + } + return nil +} + +func (s *Signature) UnmarshalCBOR(br io.Reader) error { + maj, l, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + + if maj != cbg.MajByteString { + return fmt.Errorf("cbor input for signature was not a byte string") + } + if l > SignatureMaxLength { + return fmt.Errorf("cbor byte array for signature was too long") + } + buf := make([]byte, l) + if _, err = io.ReadFull(br, buf); err != nil { + return err + } + switch SigType(buf[0]) { + default: + return fmt.Errorf("invalid signature type in cbor input: %d", buf[0]) + case SigTypeSecp256k1: + s.Type = SigTypeSecp256k1 + case SigTypeBLS: + s.Type = SigTypeBLS + } + s.Data = buf[1:] + return nil +} + +func (s *Signature) MarshalBinary() ([]byte, error) { + bs := make([]byte, len(s.Data)+1) + bs[0] = byte(s.Type) + copy(bs[1:], s.Data) + return bs, nil +} + +func (s *Signature) UnmarshalBinary(bs []byte) error { + if len(bs) == 0 { + return fmt.Errorf("invalid signature bytes of length 0") + } + switch SigType(bs[0]) { + default: + // Do not error during unmarshal but leave a standard value. + // unmarshal(marshal(zero valued sig)) is valuable for test + // and type needs to be checked by caller anyway. + s.Type = SigTypeUnknown + case SigTypeSecp256k1: + s.Type = SigTypeSecp256k1 + case SigTypeBLS: + s.Type = SigTypeBLS + } + s.Data = bs[1:] + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/puppet/cbor_gen.go b/vendor/github.com/filecoin-project/specs-actors/actors/puppet/cbor_gen.go new file mode 100644 index 0000000000..5aaeb73d1b --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/puppet/cbor_gen.go @@ -0,0 +1,287 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package puppet + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.OptFailToMarshalCBOR ([]*puppet.FailToMarshalCBOR) (slice) + if len(t.OptFailToMarshalCBOR) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.OptFailToMarshalCBOR was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.OptFailToMarshalCBOR)))); err != nil { + return err + } + for _, v := range t.OptFailToMarshalCBOR { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.OptFailToMarshalCBOR ([]*puppet.FailToMarshalCBOR) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.OptFailToMarshalCBOR: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.OptFailToMarshalCBOR = make([]*FailToMarshalCBOR, extra) + } + + for i := 0; i < int(extra); i++ { + + var v FailToMarshalCBOR + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.OptFailToMarshalCBOR[i] = &v + } + + return nil +} + +func (t *SendParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + + // t.Value (big.Int) (struct) + if err := t.Value.MarshalCBOR(w); err != nil { + return err + } + + // t.Method (abi.MethodNum) (uint64) + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Method))); err != nil { + return err + } + + // t.Params ([]uint8) (slice) + if len(t.Params) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Params was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Params)))); err != nil { + return err + } + if _, err := w.Write(t.Params); err != nil { + return err + } + return nil +} + +func (t *SendParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + // t.Value (big.Int) (struct) + + { + + if err := t.Value.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Value: %w", err) + } + + } + // t.Method (abi.MethodNum) (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.Method = abi.MethodNum(extra) + + } + // t.Params ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Params: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Params = make([]byte, extra) + if _, err := io.ReadFull(br, t.Params); err != nil { + return err + } + return nil +} + +func (t *SendReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.Return (runtime.CBORBytes) (slice) + if len(t.Return) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Return was too long") + } + + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Return)))); err != nil { + return err + } + if _, err := w.Write(t.Return); err != nil { + return err + } + + // t.Code (exitcode.ExitCode) (int64) + if t.Code >= 0 { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Code))); err != nil { + return err + } + } else { + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajNegativeInt, uint64(-t.Code)-1)); err != nil { + return err + } + } + return nil +} + +func (t *SendReturn) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Return (runtime.CBORBytes) (slice) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Return: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.Return = make([]byte, extra) + if _, err := io.ReadFull(br, t.Return); err != nil { + return err + } + // t.Code (exitcode.ExitCode) (int64) + { + maj, extra, err := cbg.CborReadHeader(br) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Code = exitcode.ExitCode(extraI) + } + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet.go b/vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet.go new file mode 100644 index 0000000000..ffddaae1e9 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet.go @@ -0,0 +1,156 @@ +package puppet + +import ( + "fmt" + "io" + + addr "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + builtin "github.com/filecoin-project/specs-actors/actors/builtin" + runtime "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + adt "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +// The Puppet Actor exists to aid testing the runtime and environment in which it's embedded. It provides direct access +// to the runtime methods, including sending arbitrary messages to other actors, without any preconditions or invariants +// to get in the way. +type Actor struct{} + +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + 2: a.Send, + 3: a.SendMarshalCBORFailure, + 4: a.ReturnMarshalCBORFailure, + 5: a.RuntimeTransactionMarshalCBORFailure, + } +} + +var _ abi.Invokee = Actor{} + +func (a Actor) Constructor(rt runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + + rt.State().Create(&State{}) + return nil +} + +type SendParams struct { + To addr.Address + Value abi.TokenAmount + Method abi.MethodNum + Params []byte +} + +type SendReturn struct { + Return runtime.CBORBytes + Code exitcode.ExitCode +} + +func (a Actor) Send(rt runtime.Runtime, params *SendParams) *SendReturn { + rt.ValidateImmediateCallerAcceptAny() + ret, code := rt.Send( + params.To, + params.Method, + runtime.CBORBytes(params.Params), + params.Value, + ) + out, err := handleSendReturn(ret) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unmarshal send return: %v", err) + } + return &SendReturn{ + Return: out, + Code: code, + } +} + +func (a Actor) SendMarshalCBORFailure(rt runtime.Runtime, params *SendParams) *SendReturn { + rt.ValidateImmediateCallerAcceptAny() + ret, code := rt.Send( + params.To, + params.Method, + &FailToMarshalCBOR{}, + params.Value, + ) + out, err := handleSendReturn(ret) + if err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unmarshal send return: %v", err) + } + return &SendReturn{ + Return: out, + Code: code, + } +} + +func (a Actor) ReturnMarshalCBORFailure(rt runtime.Runtime, _ *adt.EmptyValue) *FailToMarshalCBOR { + rt.ValidateImmediateCallerAcceptAny() + return &FailToMarshalCBOR{} +} + +func (a Actor) RuntimeTransactionMarshalCBORFailure(rt runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + + var st State + + rt.State().Transaction(&st, func() interface{} { + st.OptFailToMarshalCBOR = []*FailToMarshalCBOR{{}} + return nil + }) + + return nil +} + +func handleSendReturn(ret runtime.SendReturn) (runtime.CBORBytes, error) { + if ret != nil { + var out runtime.CBORBytes + if err := ret.Into(&out); err != nil { + return nil, err + } + return out, nil + } + // nothing was returned + return nil, nil +} + +type FailToMarshalCBOR struct{} + +func (t *FailToMarshalCBOR) UnmarshalCBOR(io.Reader) error { + return fmt.Errorf("failed to unmarshal cbor") +} + +func (t *FailToMarshalCBOR) MarshalCBOR(w io.Writer) error { + return fmt.Errorf("failed to marshal cbor") +} + +type State struct { + // OptFailToMarshalCBOR is to be used as an Option or Maybe, with T + // specialized to *FailToMarshalCBOR. If the slice contains no values, the + // State struct will encode as CBOR without issue. If the slice contains + // more than zero values, the CBOR encoding will fail. + OptFailToMarshalCBOR []*FailToMarshalCBOR +} + +func init() { + builder := cid.V1Builder{Codec: cid.Raw, MhType: mh.IDENTITY} + c, err := builder.Sum([]byte("fil/1/puppet")) + if err != nil { + panic(err) + } + PuppetActorCodeID = c +} + +// The actor code ID & Methods +var PuppetActorCodeID cid.Cid + +var MethodsPuppet = struct { + Constructor abi.MethodNum + Send abi.MethodNum + SendMarshalCBORFailure abi.MethodNum + ReturnMarshalCBORFailure abi.MethodNum + RuntimeTransactionMarshalCBORFailure abi.MethodNum +}{builtin.MethodConstructor, 2, 3, 4, 5} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet_test.go new file mode 100644 index 0000000000..5cc6df1790 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/puppet/puppet_test.go @@ -0,0 +1,72 @@ +package puppet_test + +import ( + "context" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/puppet" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSend(t *testing.T) { + + receiver := tutil.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + t.Run("Simple Send", func(t *testing.T) { + rt := builder.Build(t) + a := newHarness(t) + a.constructAndVerify(rt) + + toAddr := tutil.NewIDAddr(t, 101) + amount := abi.NewTokenAmount(100) + params := []byte{1, 2, 3, 4, 5} + methodNum := abi.MethodNum(1) + sendParams := &puppet.SendParams{ + To: toAddr, + Value: amount, + Method: methodNum, + Params: params, + } + + rt.SetBalance(amount) + expRet := runtime.CBORBytes([]byte{6, 7, 8, 9, 10}) + rt.ExpectSend(toAddr, 1, runtime.CBORBytes(params), amount, expRet, exitcode.Ok) + ret := a.puppetSend(rt, sendParams) + + assert.Equal(t, expRet, ret.Return) + + }) +} + +type actorHarness struct { + a puppet.Actor + t testing.TB +} + +func newHarness(t testing.TB) *actorHarness { + return &actorHarness{ + a: puppet.Actor{}, + t: t, + } +} + +func (h *actorHarness) constructAndVerify(rt *mock.Runtime) { + rt.ExpectValidateCallerAny() + ret := rt.Call(h.a.Constructor, nil) + assert.Nil(h.t, ret) + rt.Verify() +} + +func (h *actorHarness) puppetSend(rt *mock.Runtime, params *puppet.SendParams) *puppet.SendReturn { + rt.ExpectValidateCallerAny() + ret := rt.Call(h.a.Send, params) + assert.NotNil(h.t, ret) + out := ret.(*puppet.SendReturn) + rt.Verify() + return out +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/common.go b/vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/common.go new file mode 100644 index 0000000000..841929bda0 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/common.go @@ -0,0 +1,21 @@ +package exitcode + +// Common error codes that may be shared by different actors. +// Actors may also define their own codes, including redefining these values. + +const ( + // Indicates a method parameter is invalid. + ErrIllegalArgument = FirstActorErrorCode + iota + // Indicates a requested resource does not exist. + ErrNotFound + // Indicates an action is disallowed. + ErrForbidden + // Indicates a balance of funds is insufficient. + ErrInsufficientFunds + // Indicates an actor's internal state is invalid. + ErrIllegalState + // Indicates de/serialization failure within actor code. + ErrSerialization + // An error code intended to be replaced by different code structure or a more descriptive error. + ErrPlaceholder = ExitCode(1000) +) diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/reserved.go b/vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/reserved.go new file mode 100644 index 0000000000..acf6197f37 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/runtime/exitcode/reserved.go @@ -0,0 +1,119 @@ +package exitcode + +import ( + "fmt" + "strconv" +) + +type ExitCode int64 + +func (x ExitCode) IsSuccess() bool { + return x == Ok +} + +func (x ExitCode) IsError() bool { + return !x.IsSuccess() +} + +// Whether an exit code indicates a message send failure. +// A send failure means that the caller's CallSeqNum is not incremented and the caller has not paid +// gas fees for the message (because the caller doesn't exist or can't afford it). +// A receipt with send failure does not indicate that the message (or another one carrying the same CallSeqNum) +// could not apply in the future, against a different state. +func (x ExitCode) IsSendFailure() bool { + return x == SysErrSenderInvalid || x == SysErrSenderStateInvalid +} + +// A non-canonical string representation for human inspection. +func (x ExitCode) String() string { + name, ok := names[x] + if ok { + return fmt.Sprintf("%s(%d)", name, x) + } + return strconv.FormatInt(int64(x), 10) +} + +// Implement error to trigger Go compiler checking of exit code return values. +func (x ExitCode) Error() string { + return x.String() +} + +// The system error codes are reserved for use by the runtime. +// No actor may use one explicitly. Correspondingly, no runtime invocation should abort with an exit +// code outside this list. +// We could move these definitions out of this package and into the runtime spec. +const ( + Ok = ExitCode(0) + + // Indicates that the actor identified as the sender of a message is not valid as a message sender: + // - not present in the state tree + // - not an account actor (for top-level messages) + // - code CID is not found or invalid + // (not found in the state tree, not an account, has no code). + SysErrSenderInvalid = ExitCode(1) + + // Indicates that the sender of a message is not in a state to send the message: + // - invocation out of sequence (mismatched CallSeqNum) + // - insufficient funds to cover execution + SysErrSenderStateInvalid = ExitCode(2) + + // Indicates failure to find a method in an actor. + SysErrInvalidMethod = ExitCode(3) + + // Indicates non-decodeable or syntactically invalid parameters for a method. + SysErrInvalidParameters = ExitCode(4) + + // Indicates that the receiver of a message is not valid (and cannot be implicitly created). + SysErrInvalidReceiver = ExitCode(5) + + // Indicates that a message sender has insufficient balance for the value being sent. + // Note that this is distinct from SysErrSenderStateInvalid when a top-level sender can't cover + // value transfer + gas. This code is only expected to come from inter-actor sends. + SysErrInsufficientFunds = ExitCode(6) + + // Indicates message execution (including subcalls) used more gas than the specified limit. + SysErrOutOfGas = ExitCode(7) + + // Indicates message execution is forbidden for the caller by runtime caller validation. + SysErrForbidden = ExitCode(8) + + // Indicates actor code performed a disallowed operation. Disallowed operations include: + // - mutating state outside of a state acquisition block + // - failing to invoke caller validation + // - aborting with a reserved exit code (including success or a system error). + SysErrorIllegalActor = ExitCode(9) + + // Indicates an invalid argument passed to a runtime method. + SysErrorIllegalArgument = ExitCode(10) + + // Indicates an object failed to de/serialize for storage. + SysErrSerialization = ExitCode(11) + + SysErrorReserved3 = ExitCode(12) + SysErrorReserved4 = ExitCode(13) + SysErrorReserved5 = ExitCode(14) + SysErrorReserved6 = ExitCode(15) +) + +// The initial range of exit codes is reserved for system errors. +// Actors may define codes starting with this one. +const FirstActorErrorCode = ExitCode(16) + +var names = map[ExitCode]string{ + Ok: "Ok", + SysErrSenderInvalid: "SysErrSenderInvalid", + SysErrSenderStateInvalid: "SysErrSenderStateInvalid", + SysErrInvalidMethod: "SysErrInvalidMethod", + SysErrInvalidParameters: "SysErrInvalidParameters", + SysErrInvalidReceiver: "SysErrInvalidReceiver", + SysErrInsufficientFunds: "SysErrInsufficientFunds", + SysErrOutOfGas: "SysErrOutOfGas", + SysErrForbidden: "SysErrForbidden", + SysErrorIllegalActor: "SysErrorIllegalActor", + SysErrorIllegalArgument: "SysErrorIllegalArgument", + SysErrSerialization: "SysErrSerialization", + SysErrorReserved3: "SysErrorReserved3", + SysErrorReserved4: "SysErrorReserved4", + SysErrorReserved5: "SysErrorReserved5", + SysErrorReserved6: "SysErrorReserved6", +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/runtime/runtime.go b/vendor/github.com/filecoin-project/specs-actors/actors/runtime/runtime.go new file mode 100644 index 0000000000..051125e161 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/runtime/runtime.go @@ -0,0 +1,271 @@ +package runtime + +import ( + "bytes" + "context" + "io" + + "github.com/filecoin-project/go-address" + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + + abi "github.com/filecoin-project/specs-actors/actors/abi" + crypto "github.com/filecoin-project/specs-actors/actors/crypto" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" +) + +// Specifies importance of message, LogLevel numbering is consistent with the uber-go/zap package. +type LogLevel int + +const ( + // DebugLevel logs are typically voluminous, and are usually disabled in + // production. + DEBUG LogLevel = iota - 1 + // InfoLevel is the default logging priority. + INFO + // WarnLevel logs are more important than Info, but don't need individual + // human review. + WARN + // ErrorLevel logs are high-priority. If an application is running smoothly, + // it shouldn't generate any error-level logs. + ERROR +) + +// Runtime is the VM's internal runtime object. +// this is everything that is accessible to actors, beyond parameters. +type Runtime interface { + // Information related to the current message being executed. + Message() Message + + // The current chain epoch number. The genesis block has epoch zero. + CurrEpoch() abi.ChainEpoch + + // Validates the caller against some predicate. + // Exported actor methods must invoke at least one caller validation before returning. + ValidateImmediateCallerAcceptAny() + ValidateImmediateCallerIs(addrs ...addr.Address) + ValidateImmediateCallerType(types ...cid.Cid) + + // The balance of the receiver. + CurrentBalance() abi.TokenAmount + + // Resolves an address of any protocol to an ID address (via the Init actor's table). + // This allows resolution of externally-provided SECP, BLS, or actor addresses to the canonical form. + // If the argument is an ID address it is returned directly. + ResolveAddress(address addr.Address) (addr.Address, bool) + + // Look up the code ID at an actor address. + GetActorCodeCID(addr addr.Address) (ret cid.Cid, ok bool) + + // Randomness returns a (pseudo)random byte array drawing from a + // random beacon at a given epoch and incorporating reequisite entropy + GetRandomness(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness + + // Provides a handle for the actor's state object. + State() StateHandle + + Store() Store + + // Sends a message to another actor, returning the exit code and return value envelope. + // If the invoked method does not return successfully, its state changes (and that of any messages it sent in turn) + // will be rolled back. + // The result is never a bare nil, but may be (a wrapper of) adt.Empty. + Send(toAddr addr.Address, methodNum abi.MethodNum, params CBORMarshaler, value abi.TokenAmount) (SendReturn, exitcode.ExitCode) + + // Halts execution upon an error from which the receiver cannot recover. The caller will receive the exitcode and + // an empty return value. State changes made within this call will be rolled back. + // This method does not return. + // The message and args are for diagnostic purposes and do not persist on chain. They should be suitable for + // passing to fmt.Errorf(msg, args...). + Abortf(errExitCode exitcode.ExitCode, msg string, args ...interface{}) + + // Computes an address for a new actor. The returned address is intended to uniquely refer to + // the actor even in the event of a chain re-org (whereas an ID-address might refer to a + // different actor after messages are re-ordered). + // Always an ActorExec address. + NewActorAddress() addr.Address + + // Creates an actor with code `codeID` and address `address`, with empty state. May only be called by Init actor. + CreateActor(codeId cid.Cid, address addr.Address) + + // Deletes the executing actor from the state tree, transferring any balance to beneficiary. + // Aborts if the beneficiary does not exist. + // May only be called by the actor itself. + DeleteActor(beneficiary addr.Address) + + // Provides the system call interface. + Syscalls() Syscalls + + // Returns the total token supply in circulation at the beginning of the current epoch. + // The circulating supply is the sum of: + // - rewards emitted by the reward actor, + // - funds vested from lock-ups in the genesis state, + // less the sum of: + // - funds burnt, + // - pledge collateral locked in storage miner actors (recorded in the storage power actor) + // - deal collateral locked by the storage market actor + TotalFilCircSupply() abi.TokenAmount + + // Provides a Go context for use by HAMT, etc. + // The VM is intended to provide an idealised machine abstraction, with infinite storage etc, so this context + // should not be used by actor code directly. + Context() context.Context + + // Starts a new tracing span. The span must be End()ed explicitly, typically with a deferred invocation. + StartSpan(name string) TraceSpan + + // ChargeGas charges specified amount of `gas` for execution. + // `name` provides information about gas charging point + // `virtual` sets virtual amount of gas to charge, this amount is not counted + // toward execution cost. This functionality is used for observing global changes + // in total gas charged if amount of gas charged was to be changed. + ChargeGas(name string, gas int64, virtual int64) + + // Note events that may make debugging easier + Log(level LogLevel, msg string, args ...interface{}) +} + +// Store defines the storage module exposed to actors. +type Store interface { + // Retrieves and deserializes an object from the store into `o`. Returns whether successful. + Get(c cid.Cid, o CBORUnmarshaler) bool + // Serializes and stores an object, returning its CID. + Put(x CBORMarshaler) cid.Cid +} + +// Message contains information available to the actor about the executing message. +type Message interface { + // The address of the immediate calling actor. Always an ID-address. + Caller() addr.Address + + // The address of the actor receiving the message. Always an ID-address. + Receiver() addr.Address + + // The value attached to the message being processed, implicitly added to CurrentBalance() before method invocation. + ValueReceived() abi.TokenAmount +} + +// Pure functions implemented as primitives by the runtime. +type Syscalls interface { + // Verifies that a signature is valid for an address and plaintext. + VerifySignature(signature crypto.Signature, signer addr.Address, plaintext []byte) error + // Hashes input data using blake2b with 256 bit output. + HashBlake2b(data []byte) [32]byte + // Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes. + ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) + // Verifies a sector seal proof. + VerifySeal(vi abi.SealVerifyInfo) error + + BatchVerifySeals(vis map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) + + // Verifies a proof of spacetime. + VerifyPoSt(vi abi.WindowPoStVerifyInfo) error + // Verifies that two block headers provide proof of a consensus fault: + // - both headers mined by the same actor + // - headers are different + // - first header is of the same or lower epoch as the second + // - the headers provide evidence of a fault (see the spec for the different fault types). + // The parameters are all serialized block headers. The third "extra" parameter is consulted only for + // the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the + // blocks in an ancestor of h2. + // Returns nil and an error if the headers don't prove a fault. + VerifyConsensusFault(h1, h2, extra []byte) (*ConsensusFault, error) +} + +// The return type from a message send from one actor to another. This abstracts over the internal representation of +// the return, in particular whether it has been serialized to bytes or just passed through. +// Production code is expected to de/serialize, but test and other code may pass the value straight through. +type SendReturn interface { + Into(CBORUnmarshaler) error +} + +// Provides (minimal) tracing facilities to actor code. +type TraceSpan interface { + // Ends the span + End() +} + +// StateHandle provides mutable, exclusive access to actor state. +type StateHandle interface { + // Create initializes the state object. + // This is only valid in a constructor function and when the state has not yet been initialized. + Create(obj CBORMarshaler) + + // Readonly loads a readonly copy of the state into the argument. + // + // Any modification to the state is illegal and will result in an abort. + Readonly(obj CBORUnmarshaler) + + // Transaction loads a mutable version of the state into the `obj` argument and protects + // the execution from side effects (including message send). + // + // The second argument is a function which allows the caller to mutate the state. + // The return value from that function will be returned from the call to Transaction(). + // + // If the state is modified after this function returns, execution will abort. + // + // The gas cost of this method is that of a Store.Put of the mutated state object. + // + // Note: the Go signature is not ideal due to lack of type system power. + // + // # Usage + // ```go + // var state SomeState + // ret := rt.State().Transaction(&state, func() (interface{}) { + // // make some changes + // st.ImLoaded = True + // return st.Thing, nil + // }) + // // state.ImLoaded = False // BAD!! state is readonly outside the lambda, it will panic + // ``` + Transaction(obj CBORer, f func() interface{}) interface{} +} + +// Result of checking two headers for a consensus fault. +type ConsensusFault struct { + // Address of the miner at fault (always an ID address). + Target addr.Address + // Epoch of the fault, which is the higher epoch of the two blocks causing it. + Epoch abi.ChainEpoch + // Type of fault. + Type ConsensusFaultType +} + +type ConsensusFaultType int64 + +const ( + //ConsensusFaultNone ConsensusFaultType = 0 + ConsensusFaultDoubleForkMining ConsensusFaultType = 1 + ConsensusFaultParentGrinding ConsensusFaultType = 2 + ConsensusFaultTimeOffsetMining ConsensusFaultType = 3 +) + +// These interfaces are intended to match those from whyrusleeping/cbor-gen, such that code generated from that +// system is automatically usable here (but not mandatory). +type CBORMarshaler interface { + MarshalCBOR(w io.Writer) error +} + +type CBORUnmarshaler interface { + UnmarshalCBOR(r io.Reader) error +} + +type CBORer interface { + CBORMarshaler + CBORUnmarshaler +} + +// Wraps already-serialized bytes as CBOR-marshalable. +type CBORBytes []byte + +func (b CBORBytes) MarshalCBOR(w io.Writer) error { + _, err := w.Write(b) + return err +} + +func (b *CBORBytes) UnmarshalCBOR(r io.Reader) error { + var c bytes.Buffer + _, err := c.ReadFrom(r) + *b = c.Bytes() + return err +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/adt_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/adt_test.go new file mode 100644 index 0000000000..8abc1205e0 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/adt_test.go @@ -0,0 +1,24 @@ +package adt_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/specs-actors/actors/util/adt" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestAddrKey(t *testing.T) { + id_address_1 := tutil.NewIDAddr(t, 101) + id_address_2 := tutil.NewIDAddr(t, 102) + actor_address_1 := tutil.NewActorAddr(t, "actor1") + actor_address_2 := tutil.NewActorAddr(t, "222") + + t.Run("address to key string conversion", func(t *testing.T) { + assert.Equal(t, "\x00\x65", adt.AddrKey(id_address_1).Key()) + assert.Equal(t, "\x00\x66", adt.AddrKey(id_address_2).Key()) + assert.Equal(t, "\x02\x58\xbe\x4f\xd7\x75\xa0\xc8\xcd\x9a\xed\x86\x4e\x73\xab\xb1\x86\x46\x5f\xef\xe1", adt.AddrKey(actor_address_1).Key()) + assert.Equal(t, "\x02\xaa\xd0\xb2\x98\xa9\xde\xab\xbb\xb6\u007f\x80\x5f\x66\xaa\x68\x8c\xdd\x89\xad\xf5", adt.AddrKey(actor_address_2).Key()) + }) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array.go new file mode 100644 index 0000000000..35d8d621cf --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array.go @@ -0,0 +1,108 @@ +package adt + +import ( + "bytes" + + amt "github.com/filecoin-project/go-amt-ipld/v2" + cid "github.com/ipfs/go-cid" + errors "github.com/pkg/errors" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + runtime "github.com/filecoin-project/specs-actors/actors/runtime" +) + +// Array stores a sparse sequence of values in an AMT. +type Array struct { + root *amt.Root + store Store +} + +// AsArray interprets a store as an AMT-based array with root `r`. +func AsArray(s Store, r cid.Cid) (*Array, error) { + root, err := amt.LoadAMT(s.Context(), s, r) + if err != nil { + return nil, xerrors.Errorf("failed to root: %w", err) + } + + return &Array{ + root: root, + store: s, + }, nil +} + +// Creates a new map backed by an empty HAMT and flushes it to the store. +func MakeEmptyArray(s Store) *Array { + root := amt.NewAMT(s) + return &Array{ + root: root, + store: s, + } +} + +// Returns the root CID of the underlying AMT. +func (a *Array) Root() (cid.Cid, error) { + return a.root.Flush(a.store.Context()) +} + +// Appends a value to the end of the array. Assumes continuous array. +// If the array isn't continuous use Set and a separate counter +func (a *Array) AppendContinuous(value runtime.CBORMarshaler) error { + if err := a.root.Set(a.store.Context(), a.root.Count, value); err != nil { + return errors.Wrapf(err, "array append failed to set index %v value %v in root %v, ", a.root.Count, value, a.root) + } + return nil +} + +func (a *Array) Set(i uint64, value runtime.CBORMarshaler) error { + if err := a.root.Set(a.store.Context(), i, value); err != nil { + return xerrors.Errorf("array set failed to set index %v in root %v: %w", i, a.root, err) + } + return nil +} + +func (a *Array) Delete(i uint64) error { + if err := a.root.Delete(a.store.Context(), i); err != nil { + return xerrors.Errorf("array delete failed to delete index %v in root %v: %w", i, a.root, err) + } + return nil +} + +func (a *Array) BatchDelete(ix []uint64) error { + if err := a.root.BatchDelete(a.store.Context(), ix); err != nil { + return xerrors.Errorf("array delete failed to batchdelete: %w", err) + } + return nil +} + +// Iterates all entries in the array, deserializing each value in turn into `out` and then calling a function. +// Iteration halts if the function returns an error. +// If the output parameter is nil, deserialization is skipped. +func (a *Array) ForEach(out runtime.CBORUnmarshaler, fn func(i int64) error) error { + return a.root.ForEach(a.store.Context(), func(k uint64, val *cbg.Deferred) error { + if out != nil { + // Why doesn't amt.ForEach() just return the value as bytes? + if err := out.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil { + return err + } + } + return fn(int64(k)) + }) +} + +func (a *Array) Length() uint64 { + return a.root.Count +} + +// Get retrieves array element into the 'out' unmarshaler, returning a boolean +// indicating whether the element was found in the array +func (a *Array) Get(k uint64, out runtime.CBORUnmarshaler) (bool, error) { + + if err := a.root.Get(a.store.Context(), k, out); err == nil { + return true, nil + } else if _, nf := err.(*amt.ErrNotFound); nf { + return false, nil + } else { + return false, err + } +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array_test.go new file mode 100644 index 0000000000..e402889c00 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/array_test.go @@ -0,0 +1,22 @@ +package adt_test + +import ( + "context" + "testing" + + "github.com/filecoin-project/go-address" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/support/mock" +) + +func TestArrayNotFound(t *testing.T) { + rt := mock.NewBuilder(context.Background(), address.Undef).Build(t) + store := adt.AsStore(rt) + arr := adt.MakeEmptyArray(store) + + found, err := arr.Get(7, nil) + require.NoError(t, err) + require.False(t, found) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable.go new file mode 100644 index 0000000000..d36c37414e --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable.go @@ -0,0 +1,144 @@ +package adt + +import ( + "errors" + "fmt" + + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" +) + +// A specialization of a map of addresses to token amounts. +type BalanceTable Map + +// Interprets a store as balance table with root `r`. +func AsBalanceTable(s Store, r cid.Cid) (*BalanceTable, error) { + m, err := AsMap(s, r) + if err != nil { + return nil, err + } + + return &BalanceTable{ + root: m.root, + store: s, + }, nil +} + +// Returns the root cid of underlying HAMT. +func (t *BalanceTable) Root() (cid.Cid, error) { + return (*Map)(t).Root() +} + +// Gets the balance for a key. The entry must have been previously initialized. +func (t *BalanceTable) Get(key addr.Address) (abi.TokenAmount, error) { + var value abi.TokenAmount + found, err := (*Map)(t).Get(AddrKey(key), &value) + if err != nil { + return big.Zero(), err // The errors from Map carry good information, no need to wrap here. + } + if !found { + return big.Zero(), ErrNotFound{t.lastCid, key} + } + return value, nil +} + +// Has checks if the balance for a key exists +func (t *BalanceTable) Has(key addr.Address) (bool, error) { + var value abi.TokenAmount + return (*Map)(t).Get(AddrKey(key), &value) +} + +// Sets the balance for an address, overwriting any previous balance. +func (t *BalanceTable) Set(key addr.Address, value abi.TokenAmount) error { + return (*Map)(t).Put(AddrKey(key), &value) +} + +// Adds an amount to a balance. The entry must have been previously initialized. +func (t *BalanceTable) Add(key addr.Address, value abi.TokenAmount) error { + prev, err := t.Get(key) + if err != nil { + return err + } + sum := big.Add(prev, value) + return (*Map)(t).Put(AddrKey(key), &sum) +} + +// Adds an amount to a balance. Create entry if not exists +func (t *BalanceTable) AddCreate(key addr.Address, value abi.TokenAmount) error { + var prev abi.TokenAmount + found, err := (*Map)(t).Get(AddrKey(key), &prev) + if err != nil { + return err + } + if found { + value = big.Add(prev, value) + } + + return (*Map)(t).Put(AddrKey(key), &value) +} + +// Subtracts up to the specified amount from a balance, without reducing the balance below some minimum. +// Returns the amount subtracted (always positive or zero). +func (t *BalanceTable) SubtractWithMinimum(key addr.Address, req abi.TokenAmount, floor abi.TokenAmount) (abi.TokenAmount, error) { + prev, err := t.Get(key) + if err != nil { + return big.Zero(), err + } + available := big.Max(big.Zero(), big.Sub(prev, floor)) + sub := big.Min(available, req) + if sub.Sign() > 0 { + err = t.Add(key, sub.Neg()) + if err != nil { + return big.Zero(), err + } + } + return sub, nil +} + +func (t *BalanceTable) MustSubtract(key addr.Address, req abi.TokenAmount) error { + subst, err := t.SubtractWithMinimum(key, req, big.Zero()) + if err != nil { + return err + } + if !subst.Equals(req) { + return errors.New("couldn't subtract the requested amount") + } + return nil +} + +// Removes an entry from the table, returning the prior value. The entry must have been previously initialized. +func (t *BalanceTable) Remove(key addr.Address) (abi.TokenAmount, error) { + prev, err := t.Get(key) + if err != nil { + return big.Zero(), err + } + err = (*Map)(t).Delete(AddrKey(key)) + if err != nil { + return big.Zero(), err + } + return prev, nil +} + +// Returns the total balance held by this BalanceTable +func (t *BalanceTable) Total() (abi.TokenAmount, error) { + total := big.Zero() + var cur abi.TokenAmount + err := (*Map)(t).ForEach(&cur, func(key string) error { + total = big.Add(total, cur) + return nil + }) + return total, err +} + +// Error type returned when an expected key is absent. +type ErrNotFound struct { + Root cid.Cid + Key interface{} +} + +func (e ErrNotFound) Error() string { + return fmt.Sprintf("no key %v in map root %v", e.Key, e.Root) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable_test.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable_test.go new file mode 100644 index 0000000000..27826262ab --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/balancetable_test.go @@ -0,0 +1,80 @@ +package adt_test + +import ( + "context" + "testing" + + "github.com/filecoin-project/go-address" + "github.com/stretchr/testify/assert" + + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/support/mock" + tutil "github.com/filecoin-project/specs-actors/support/testing" +) + +func TestBalanceTable(t *testing.T) { + t.Run("AddCreate adds or creates", func(t *testing.T) { + addr := tutil.NewIDAddr(t, 100) + rt := mock.NewBuilder(context.Background(), address.Undef).Build(t) + store := adt.AsStore(rt) + emptyMap := adt.MakeEmptyMap(store) + + bt, err := adt.AsBalanceTable(store, tutil.MustRoot(t, emptyMap)) + assert.NoError(t, err) + + has, err := bt.Has(addr) + assert.NoError(t, err) + assert.False(t, has) + + err = bt.AddCreate(addr, abi.NewTokenAmount(10)) + assert.NoError(t, err) + + amount, err := bt.Get(addr) + assert.NoError(t, err) + assert.Equal(t, abi.NewTokenAmount(10), amount) + + err = bt.AddCreate(addr, abi.NewTokenAmount(20)) + assert.NoError(t, err) + + amount, err = bt.Get(addr) + assert.NoError(t, err) + assert.Equal(t, abi.NewTokenAmount(30), amount) + }) + + t.Run("Total returns total amount tracked", func(t *testing.T) { + addr1 := tutil.NewIDAddr(t, 100) + addr2 := tutil.NewIDAddr(t, 101) + + rt := mock.NewBuilder(context.Background(), address.Undef).Build(t) + store := adt.AsStore(rt) + emptyMap := adt.MakeEmptyMap(store) + + bt, err := adt.AsBalanceTable(store, tutil.MustRoot(t, emptyMap)) + assert.NoError(t, err) + total, err := bt.Total() + assert.NoError(t, err) + assert.Equal(t, big.Zero(), total) + + testCases := []struct { + amount int64 + addr address.Address + total int64 + }{ + {10, addr1, 10}, + {20, addr1, 30}, + {40, addr2, 70}, + {50, addr2, 120}, + } + + for _, tc := range testCases { + err = bt.AddCreate(tc.addr, abi.NewTokenAmount(tc.amount)) + assert.NoError(t, err) + + total, err = bt.Total() + assert.NoError(t, err) + assert.Equal(t, abi.NewTokenAmount(tc.total), total) + } + }) +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/empty.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/empty.go new file mode 100644 index 0000000000..d91a029ad5 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/empty.go @@ -0,0 +1,38 @@ +package adt + +import ( + "fmt" + "io" + + runtime "github.com/filecoin-project/specs-actors/actors/runtime" +) + +// The empty value represents absence of a value. It is used for parameter and return types for actor methods +// that don't take/return any data. This saves a byte in serialization of messages and receipts: the serialized +// form is an empty byte slice, rather than a byte slice containing a single byte CBOR encoding of nil/empty/etc. +// +// The only expected use of this is as the type of a nil reference. Don't instantiate this type. +// +// This is primarily necessary due to Go's lack of a void type and our interface-based serialization scheme. +type EmptyValue struct{} + +// A typed nil pointer to EmptyValue. +var Empty *EmptyValue = nil + +var _ runtime.CBORMarshaler = (*EmptyValue)(nil) +var _ runtime.CBORUnmarshaler = (*EmptyValue)(nil) + +func (v *EmptyValue) MarshalCBOR(_ io.Writer) error { + // An attempt to serialize a non-nil value indicates a caller mis-using this type. + if v != nil { + return fmt.Errorf("cannot marshal empty value, try nil instead") + } + // Allow nil to write zero bytes as a convenience so callers don't need to nil-check all values before + // attempting serialization. + return nil +} + +func (v *EmptyValue) UnmarshalCBOR(_ io.Reader) error { + // Read zero bytes. + return nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/map.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/map.go new file mode 100644 index 0000000000..31dcdb9321 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/map.go @@ -0,0 +1,118 @@ +package adt + +import ( + "bytes" + + cid "github.com/ipfs/go-cid" + hamt "github.com/ipfs/go-hamt-ipld" + errors "github.com/pkg/errors" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + runtime "github.com/filecoin-project/specs-actors/actors/runtime" +) + +// Branching factor of the HAMT. +// This value has been empirically chosen, but the optimal value for maps with different mutation profiles +// may differ, in which case we can expose it for configuration. +const hamtBitwidth = 5 + +// Map stores key-value pairs in a HAMT. +type Map struct { + lastCid cid.Cid + root *hamt.Node + store Store +} + +// AsMap interprets a store as a HAMT-based map with root `r`. +func AsMap(s Store, r cid.Cid) (*Map, error) { + nd, err := hamt.LoadNode(s.Context(), s, r, hamt.UseTreeBitWidth(hamtBitwidth)) + if err != nil { + return nil, xerrors.Errorf("failed to load hamt node: %w", err) + } + + return &Map{ + lastCid: r, + root: nd, + store: s, + }, nil +} + +// Creates a new map backed by an empty HAMT and flushes it to the store. +func MakeEmptyMap(s Store) *Map { + nd := hamt.NewNode(s, hamt.UseTreeBitWidth(hamtBitwidth)) + return &Map{ + lastCid: cid.Undef, + root: nd, + store: s, + } +} + +// Returns the root cid of underlying HAMT. +func (m *Map) Root() (cid.Cid, error) { + if err := m.root.Flush(m.store.Context()); err != nil { + return cid.Undef, xerrors.Errorf("failed to flush map root: %w", err) + } + + c, err := m.store.Put(m.store.Context(), m.root) + if err != nil { + return cid.Undef, xerrors.Errorf("writing map root object: %w", err) + } + m.lastCid = c + + return c, nil +} + +// Put adds value `v` with key `k` to the hamt store. +func (m *Map) Put(k Keyer, v runtime.CBORMarshaler) error { + if err := m.root.Set(m.store.Context(), k.Key(), v); err != nil { + return errors.Wrapf(err, "map put failed set in node %v with key %v value %v", m.lastCid, k.Key(), v) + } + return nil +} + +// Get puts the value at `k` into `out`. +func (m *Map) Get(k Keyer, out runtime.CBORUnmarshaler) (bool, error) { + if err := m.root.Find(m.store.Context(), k.Key(), out); err != nil { + if err == hamt.ErrNotFound { + return false, nil + } + return false, errors.Wrapf(err, "map get failed find in node %v with key %v", m.lastCid, k.Key()) + } + return true, nil +} + +// Delete removes the value at `k` from the hamt store. +func (m *Map) Delete(k Keyer) error { + if err := m.root.Delete(m.store.Context(), k.Key()); err != nil { + return errors.Wrapf(err, "map delete failed in node %v key %v", m.root, k.Key()) + } + + return nil +} + +// Iterates all entries in the map, deserializing each value in turn into `out` and then +// calling a function with the corresponding key. +// Iteration halts if the function returns an error. +// If the output parameter is nil, deserialization is skipped. +func (m *Map) ForEach(out runtime.CBORUnmarshaler, fn func(key string) error) error { + return m.root.ForEach(m.store.Context(), func(k string, val interface{}) error { + if out != nil { + // Why doesn't hamt.ForEach() just return the value as bytes? + err := out.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)) + if err != nil { + return err + } + } + return fn(k) + }) +} + +// Collects all the keys from the map into a slice of strings. +func (m *Map) CollectKeys() (out []string, err error) { + err = m.ForEach(nil, func(key string) error { + out = append(out, key) + return nil + }) + return +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/multimap.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/multimap.go new file mode 100644 index 0000000000..9fa9e9472d --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/multimap.go @@ -0,0 +1,123 @@ +package adt + +import ( + cid "github.com/ipfs/go-cid" + errors "github.com/pkg/errors" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + runtime "github.com/filecoin-project/specs-actors/actors/runtime" +) + +// Multimap stores multiple values per key in a HAMT of AMTs. +// The order of insertion of values for each key is retained. +type Multimap struct { + mp *Map +} + +// Interprets a store as a HAMT-based map of AMTs with root `r`. +func AsMultimap(s Store, r cid.Cid) (*Multimap, error) { + m, err := AsMap(s, r) + if err != nil { + return nil, err + } + + return &Multimap{m}, nil +} + +// Creates a new map backed by an empty HAMT and flushes it to the store. +func MakeEmptyMultimap(s Store) *Multimap { + m := MakeEmptyMap(s) + return &Multimap{m} +} + +// Returns the root cid of the underlying HAMT. +func (mm *Multimap) Root() (cid.Cid, error) { + return mm.mp.Root() +} + +// Adds a value for a key. +func (mm *Multimap) Add(key Keyer, value runtime.CBORMarshaler) error { + // Load the array under key, or initialize a new empty one if not found. + array, found, err := mm.Get(key) + if err != nil { + return err + } + if !found { + array = MakeEmptyArray(mm.mp.store) + } + + // Append to the array. + if err = array.AppendContinuous(value); err != nil { + return errors.Wrapf(err, "failed to add multimap key %v value %v", key, value) + } + + c, err := array.Root() + if err != nil { + return xerrors.Errorf("failed to flush child array: %w", err) + } + + // Store the new array root under key. + newArrayRoot := cbg.CborCid(c) + err = mm.mp.Put(key, &newArrayRoot) + if err != nil { + return errors.Wrapf(err, "failed to store multimap values") + } + return nil +} + +// Removes all values for a key. +func (mm *Multimap) RemoveAll(key Keyer) error { + err := mm.mp.Delete(key) + if err != nil { + return errors.Wrapf(err, "failed to delete multimap key %v root %v", key, mm.mp.root) + } + return nil +} + +// Iterates all entries for a key in the order they were inserted, deserializing each value in turn into `out` and then +// calling a function. +// Iteration halts if the function returns an error. +// If the output parameter is nil, deserialization is skipped. +func (mm *Multimap) ForEach(key Keyer, out runtime.CBORUnmarshaler, fn func(i int64) error) error { + array, found, err := mm.Get(key) + if err != nil { + return err + } + if found { + return array.ForEach(out, fn) + } + return nil +} + +func (mm *Multimap) ForAll(fn func(k string, arr *Array) error) error { + var arrRoot cbg.CborCid + if err := mm.mp.ForEach(&arrRoot, func(k string) error { + arr, err := AsArray(mm.mp.store, cid.Cid(arrRoot)) + if err != nil { + return err + } + + return fn(k, arr) + }); err != nil { + return err + } + + return nil +} + +func (mm *Multimap) Get(key Keyer) (*Array, bool, error) { + var arrayRoot cbg.CborCid + found, err := mm.mp.Get(key, &arrayRoot) + if err != nil { + return nil, false, errors.Wrapf(err, "failed to load multimap key %v", key) + } + var array *Array + if found { + array, err = AsArray(mm.mp.store, cid.Cid(arrayRoot)) + if err != nil { + return nil, false, xerrors.Errorf("failed to load value %v as an array: %w", key, err) + } + } + return array, found, nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/set.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/set.go new file mode 100644 index 0000000000..21e486d9e8 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/set.go @@ -0,0 +1,59 @@ +package adt + +import ( + cid "github.com/ipfs/go-cid" +) + +// Set interprets a Map as a set, storing keys (with empty values) in a HAMT. +type Set struct { + m *Map +} + +// AsSet interprets a store as a HAMT-based set with root `r`. +func AsSet(s Store, r cid.Cid) (*Set, error) { + m, err := AsMap(s, r) + if err != nil { + return nil, err + } + + return &Set{ + m: m, + }, nil +} + +// NewSet creates a new HAMT with root `r` and store `s`. +func MakeEmptySet(s Store) *Set { + m := MakeEmptyMap(s) + return &Set{m} +} + +// Root return the root cid of HAMT. +func (h *Set) Root() (cid.Cid, error) { + return h.m.Root() +} + +// Put adds `k` to the set. +func (h *Set) Put(k Keyer) error { + return h.m.Put(k, nil) +} + +// Has returns true iff `k` is in the set. +func (h *Set) Has(k Keyer) (bool, error) { + return h.m.Get(k, nil) +} + +// Delete removes `k` from the set. +func (h *Set) Delete(k Keyer) error { + return h.m.Delete(k) +} + +// ForEach iterates over all values in the set, calling the callback for each value. +// Returning error from the callback stops the iteration. +func (h *Set) ForEach(cb func(k string) error) error { + return h.m.ForEach(nil, cb) +} + +// Collects all the keys from the set into a slice of strings. +func (h *Set) CollectKeys() (out []string, err error) { + return h.m.CollectKeys() +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/store.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/store.go new file mode 100644 index 0000000000..16bbe38786 --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/adt/store.go @@ -0,0 +1,138 @@ +package adt + +import ( + "context" + "encoding/binary" + + addr "github.com/filecoin-project/go-address" + cid "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/pkg/errors" + + vmr "github.com/filecoin-project/specs-actors/actors/runtime" + exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" +) + +// Store defines an interface required to back the ADTs in this package. +type Store interface { + Context() context.Context + cbor.IpldStore +} + +// Adapts a vanilla IPLD store as an ADT store. +func WrapStore(ctx context.Context, store cbor.IpldStore) Store { + return &wstore{ + ctx: ctx, + IpldStore: store, + } +} + +type wstore struct { + ctx context.Context + cbor.IpldStore +} + +var _ Store = &wstore{} + +func (s *wstore) Context() context.Context { + return s.ctx +} + +// Adapter for a Runtime as an ADT Store. + +// Adapts a Runtime as an ADT store. +func AsStore(rt vmr.Runtime) Store { + return rtStore{rt} +} + +type rtStore struct { + vmr.Runtime +} + +var _ Store = &rtStore{} + +func (r rtStore) Context() context.Context { + return r.Runtime.Context() +} + +func (r rtStore) Get(_ context.Context, c cid.Cid, out interface{}) error { + // The Go context is (un/fortunately?) dropped here. + // See https://github.com/filecoin-project/specs-actors/issues/140 + if !r.Store().Get(c, out.(vmr.CBORUnmarshaler)) { + r.Abortf(exitcode.ErrNotFound, "not found") + } + return nil +} + +func (r rtStore) Put(_ context.Context, v interface{}) (cid.Cid, error) { + // The Go context is (un/fortunately?) dropped here. + // See https://github.com/filecoin-project/specs-actors/issues/140 + return r.Store().Put(v.(vmr.CBORMarshaler)), nil +} + +// Keyer defines an interface required to put values in mapping. +type Keyer interface { + Key() string +} + +// Adapts an address as a mapping key. +type AddrKey addr.Address + +func (k AddrKey) Key() string { + return string(addr.Address(k).Bytes()) +} + +type CidKey cid.Cid + +func (k CidKey) Key() string { + return cid.Cid(k).KeyString() +} + +// Adapts an int64 as a mapping key. +type intKey struct { + int64 +} + +//noinspection GoExportedFuncWithUnexportedType +func IntKey(k int64) intKey { + return intKey{k} +} + +func (k intKey) Key() string { + buf := make([]byte, 10) + n := binary.PutVarint(buf, k.int64) + return string(buf[:n]) +} + +//noinspection GoUnusedExportedFunction +func ParseIntKey(k string) (int64, error) { + i, n := binary.Varint([]byte(k)) + if n != len(k) { + return 0, errors.New("failed to decode varint key") + } + return i, nil +} + +// Adapts a uint64 as a mapping key. +type uintKey struct { + uint64 +} + +//noinspection GoExportedFuncWithUnexportedType +func UIntKey(k uint64) uintKey { + return uintKey{k} +} + +func (k uintKey) Key() string { + buf := make([]byte, 10) + n := binary.PutUvarint(buf, k.uint64) + return string(buf[:n]) +} + +func ParseUIntKey(k string) (uint64, error) { + i, n := binary.Uvarint([]byte(k)) + if n != len(k) { + return 0, errors.New("failed to decode varint key") + } + return i, nil +} diff --git a/vendor/github.com/filecoin-project/specs-actors/actors/util/assert.go b/vendor/github.com/filecoin-project/specs-actors/actors/util/assert.go new file mode 100644 index 0000000000..a903f2b70d --- /dev/null +++ b/vendor/github.com/filecoin-project/specs-actors/actors/util/assert.go @@ -0,0 +1,25 @@ +package util + +import "fmt" + +// Indicates a condition that should never happen. If encountered, execution will halt and the +// resulting state is undefined. +func AssertMsg(b bool, format string, a ...interface{}) { + if !b { + panic(fmt.Sprintf(format, a...)) + } +} + +func Assert(b bool) { + AssertMsg(b, "assertion failed") +} + +func AssertNoError(e error) { + if e != nil { + panic(e.Error()) + } +} + +// Indicating behavior not yet specified, and may require other spec changes. +func TODO(...interface{}) { +} diff --git a/vendor/github.com/filecoin-project/specs-actors/gen/command-line-arguments b/vendor/github.com/filecoin-project/specs-actors/gen/command-line-arguments new file mode 100755 index 0000000000000000000000000000000000000000..790671f84690f2c0f8e7fe03d2da0149f2af1eb2 GIT binary patch literal 15310924 zcmeFa33!uL`Zt_H15v>zC`d(+pjC?tv?^mOR#GhR1X8VvS``ElDkwsQghfGHlL9eD ztKy97$T*8Q>WmA6;M&qcSyVO^6c^l245PRVtJ?4PyU+7vDMe@g@B4k<`(D@dx|*El zEcdzhbD!loS-T4;=}qo8s8@V$BZd288+mKAs1a>mn6Tl zlBr)v5Y8-gFlNliAr&JtD(d$6f6K^pSkJ)C;lw|``8Q@vV8X0`PV47Z@Z1i8ckc@$ zbS1aLk)5i}hwAjlF=M7p9e;J;YCEqrev6t%2t4yo`BDYXf{$Il_4k-D(`Vl>ZtCPQ z(*wbA1#Qqfd5*w4f(+;1hThrv*7uk(Q=lVSRjLBh4uI#e@bg+g@GSOe zgCSla`vKp8Hx+P_s@xjCv1e*}w@0-!@%)Q?8#5*eN_uGx&s+bj@UQA+jRc;51>U&n z(=+hR(d>aeViP*OI)q5^c*vyMY7v*JqA~cg?GYH1Feo?N{)#^kwqYYuKPQe&Mq>3Vt8< z(SvgM(DnZwylGcYxpu{jlwh!`kTia8&o;zZ3rZ2d7W#KY7x) z{^Ms)9*<}KF~1Q1f(tXOzhqt1zj*faz=Rw64ep0_lg8-^Y&Q}A2ei|b`}-%2n|AfI z+5LyoP0XA+?fU8c&zm}J!qBO~DHs?gO`XzD90*JLUpishbmUC$U(%`$;Ip5x|5-m5 zPq-#HZBk%%+dbH&fcf9Q|8n5J9QZE>{>y>?IR{!i!=`#rTM@526N=UsovO=GV14Zn6~VEXveFB?4NnqdE%PAfCdpLneqyn04O z!H|j96ixF@=s#rEB@@mp2^I_+FlEy48&4a0{m`kGA9tvy<#qe-5;O97$z>&%mW;gE z4DE26k^SnBC!G#oWR<${$~lf^p~Q?1j81o%(Tm;D5jpb_JAT{nN-iM>YIfX@UP>Zw4+;M>aElr3^{-xk16nQUz!%wN#s+-w?9GmX zO$GJpxy$D`*lldUkH~tFkq&YnPUiM_4!I1fkUKA#dp2_!J|VX%nR_vF889OE3gr4D zE&j-^Wi9wKYg>$PH%yMr+FeGt6BChFs#p;D$3%Wbo#TL_8O<>x9~JCUeF!u%WRZS4 zQa{~~T7Id8vf2vW?7U>gSY-HP1BTC-?eNFuKI4x~SY5EKG;%||(c9}Vn}<9D%p4`r zbAIoS{H#`0%yHD#8?~1r&^05Y7nsqx&!`uW3CQJyTw8C(MsG0g?12geyW*Tqhqw77 z`;G9oAkiNUE+S2}pWy+pHxRZNX?~USP0htMzQ|T}z17VttQMWSLHO_t9@J$hfub-| zU5K&``XWupHDQA1AS*ItF`m>}Quj;MAK%fk#THN!Yet7GGipZw zczBHwz5+zVhvES$S1O%9174fRRr@XjnIJxV5{k{x+yxFJJOurLj@6{2U>jJ!4Ad0t z@<%>V8(BR%cQx7d2PlZpa6b~^ZAR_OcE`pVhI%ANfKZi$Z!5 zayAHt?US5vec*aCDo6?TT+>vCX*foB5uSXJm1$x$qyG@~ioB;jx^#{M&ASPsqyM0i zsi%<#Uzcb=hlHVg(nH{4N-Y|!R)3ea!SnQUoe6Mtl4XSduBqAZDy_(j zUDBi$pd>n^sbzI&Pdj7YZ;@Tu&-NCTb-tD+A-*eW`HGs1I}QUPp}9@)T{qNI`oXE- z5#;GeRD#5SQyq?)XtL~8a0uGUTP^THT36X>=~o9$Ouz{Hjg1@ z3h6y{KdXo4Zg2$p!Me{snm)kw>RG5NR%FJC&-mNT4mDFl-JlAQh))F`TF7cV3t)Gm zTchy+LHb%&QYx3olVw8w$XCmy&Jg56p2woM?K$kN5bD_xeSk%!k-czTkB+1@eyRGP zCM|9yo>N2*Sq9s`za-Ss-Uzq<5ey8qvaBC5=KL<%@h|Mm{tnjp}`X0Gq`8 zYo9OQ0XgeqpN*T$;ZpzA~WUNZ`h+R|u-_O~}`Yxc2Tt$6!r*&;LI!jpFTW%uK$ zpx&%$;&{a|ceEbP>+JDNkB_%JX2%DrH#*}0dp)w+7+`IS$!vdas{Q8|>Gr4mdV3k~ zn^FIO@&4;S*!Xa~HkMxORyXf~E[D6-<7oV2l8@VS(+Rk;stKI*)FP{F(w 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%0DH0ux3zs?8ar@m9d$mYJz%av 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%0Dn%H&_K6_(V;N38OfPKljiXK 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∾u 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 Jm%s^Rn9Q8EzE6s|ZNv^{QANXx& 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

    230`oUUKFfZ7WF?kk+A2)Z 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 z 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�VlH~OxprQL_1?G=1KyN4!s+d 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

    ^L6wt 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å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 z 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≻rQAEblDLt%R(E8V6jA$5(gz|Oop3!j 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

    jegzjQ@Jyd_`}#SO^zf;6jR5W*_zDQ}Sk0$vmt; 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�I>y$9p4r#2{BQV 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

    BTz!?ElKy%BjV+JusiDV4Zz3R+IwVn1QzeMdZ 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

    KE|e* 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

    si!1D2P!m#B+pR3jAv6GDK!rVLh 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� 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

    7UojniAb+{##v_JYsY@` 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%0AU7t6fE#fVsdU9d z8n#_`4=m@WmFIXJL3$9!iLxZ^FO3mzP;s#hjS$_>9cg%BV5wgpI;wxN#741zWvE1egE|vtxQEk;`l2z zr+`U=VUx8kO3TH{*8Az#A>&B44 zmz@s+j}kkqS=`<5Yu>?cxdOlO1dh=+DGIGezNMrnB8rm1Ak-9vkVQVHK5%{4a$e0b zSl88syZwPp!M{#~AF=wc)JOtEN%K&@K1WG=_J7wt8tb0Mjd&ZBvAJF`4H;v{* zQfQQW*!*iHan08(BFg^~hw}LLb4dRz(jQE&`Ttb1SuXh>s}{lkn(NbvTMsds1-+WH zLS5=K0_`-S2KhlJMpo%Y;_E;1{`D3%V*lRmdg%Un;Yg`%qmQtE@L#4^B#t+6_BTvP zVPvRQ(=rdsMbn@xdP=s*Qg40U26x)8!>_qKi9FbzG3%WuPkDd=#FYN&gGs$7o`1z( zlCWr!y`U*agSJ-axJJ+r>>568H{2K;et*)vdBQC--mjcG+a+61wJ#UuOEe%)dM8N$$|&#v3eE|EPgBPq26(_N8Enp~WwRF(&})GM%2#NHu=|b>;IKlS z+#_|X!uRQeGPCXaW!qq&gVK#Lq$dZ}s7FuX z>P`CJfVLp=V#;!_ERQdTWsYg;x`c8hzon-d%xq;syLZ1FUp|}VPfk%j9|(GdwWGJW zD+Z^@Q4MPLxxigpoDEOH-$N{r$S;5ftg3ldlU>cj>2)`t^@DW`#i4`(8BTaqtv&~YaMjgKbkDKvJltC?CcqVO z0LS39>+`sPMW?|12)@LWtj<$;Rwu96<`)jV>+dhOKjJ-N>R+KmmW-&2JW)L)k4v4a#oEZ{$SgtHc8Wt_ZD{rPN4bGr(ikb%_*$ z24h|iOZtm+5~tf<3dP}V#I|M@u%asm$vpkh3Q0zB%8?yq^dNy*J&bw1%NkJ`Yvyj( zV+ctOVeEiDF_$I<$!c0EDM;Afs2bCE-_OD}IVMLLUoyudJRIck+hcJ4_KKQ8_{1G7 z2TH8g9WWphkISOR#GT=4R)xFc%VFChds&6x#J&YK{Y9M;h=$k&rS;oXbcp0un!eCGEf#6!v5S^J%&ktNP)Oc-t~vSwl7GT{1wz!-!t1s;j%rvk}cYJ z6xwfvz!<9_x*PDBdLA?1+&?3LGdF=Cl;~y)2KlUk1e7f3gOSuBH!; zfrzI~_*c@m1ttlL8lI%3HdS*6l8|EckUAV$FIC?05fay}VCxU`5%+Diuyvai{4`Vc zPlZ~cE>^Ffs0-$kMLcX7uJ=S?mg>R00;6nW7Md`hyL1)K&w+cjR=6d+PC`GT?{(%S zeZw(48L|b4TY?^OXZMu;vHUdP542P&k zon7*2-~e{H#=#u}Se^6&+7XM`qioP6t@<%J9VEm&#@JXtuC Dj94N{6RYv+#4l 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

    Gp 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

    X+Q z8(&f7QPjPR2{Kygw;;!`wJh9oH*w0aA_wtA4$=2z_6cyxOgxd1L+}d3JH4`>-bA!> z@H}%ADxP>%uOzf1o(QzVYLjL~!6^#T6Bj0)sKWSk(j?A-z}mmlIeYCw4CuDwi8v*Q z`VMr>trM6(f^h(`qfEe|#48Lo6;6Z>(BZ^NUS;!T6|ed_m%r>9h&<&OCppqXN!NXy zVY)2H-mDB^kg-n0-fR^Y0glL0IxHlz3XW?LmLyrroNq2b&xV)?VFJBwU^RaIL1Osf z>>9eG8zWouhKsuR2E9_=i*K`l-F%-R5*go8>#7fBE>TPAzD~tU+dv0C8m_Q$xGuWG z*w`={*!Vgw5EJn6l|MdAy!1}KMn5ppf|_l1ZTg>+SroKC6oI}lK8|xL{Gh(h>F&}( z7x^*tBRC!8hm zbV;P=)1`XbW@fSMJa2yo4`h249sp|OYv+SB*_^7jn?EHFWOJ(8aQ;WN-82)WM;5HX zo>jHu{AQha02^3G7Q8ia*J9anF2;)4YuW{GKHwWk^L-(tPbs(k@L&4Kf+*jx)~Mv7 zSt`$wwS8p4Kln!WY#xGdiq+=x0l2inkg6gCyzPagsv?qt z6&e2P1cwhkbYI75Q{O>=SIGV|R|WiTs8z6O+G1)RWvG~Cy{RVb)v)eZIH#flr1m@P zQA&;nJ`B|O$Y%=)&XpM2K85qu$|OuBAO`RYf%bJ?&}Da6#D>p7cLrn3C_xhB>*xOc zVS@AjoW5~ZYy%rW#&Bj@7b<&7m)>D~O!*n`@lP#D67cc0KR%4Una9^^ptn!oWchTB z`o3HZ_W2_)ur>YK4-;3}nWrg`;^ z*T0yj)hYGO8_Rvrkfd)6LHtpd)+z_V1GWk2oTzewvzf)0j)ig`&9;D4YNzZhAf;pb znW%F9;IDFS z^jA4tdEl>dxKGnx7>Imsa2uPt!TaCD6W4_(Pej3COO^Nu@3al##Hk5hiRZr$>~d5wjUt{y6g@k zWb^4j$R;Id6XffUt$*xiePsvyC0~c!0Fn>z@yQsQxK^#)XS* z>mT|%Ws#oWCMuu**ZrMj<&(ceA;znGj*BZFI6Mfq(#(r#A8~lTep-E)QuQqQ iv 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

    vNwj`rZ{vYHC4*@k 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%0ADEYEb2PKE%^QZVM^XqLzFsm4p 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 %<`=;%OQiB6tc9?#zL4 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

  1. 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�y^^=^rP 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 z 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
      7@ujrp#K5f{#zH;K-Zt61pU=oc=;#X zS%J=)&ODUoA}k!h-(xQh57w&*--Zkw)&y#MGt={`FC z^i7fP;FXd%|Ka+zQJDOI6#vorvN(UXLcj=&m%Wnf-@#ie;C!C^$2>5;D~x}6`O|v- zTVP)6y%--Uv_B~aF8_W7FLeERg;4)eDV$$E@X0nz{x}#vasNr{`EB(k?=N8dV_3gR z=F`~!;8u8L4vgrG5Umn^XJqMG&MyUU^ zoLr~DeYIU|3x^Tb&dx*{!#`z z+h1MZ+Mx;`ck-(;eNiXOe*Hc<^U`>H{2&jyj6Q$6G2fY&=i>aHXDgOt@+Gstd*J++ zU)G$&czLWduWrTd_u%_`12O(`O8j%!KdtAt%X&6@j`4Fv|4HNd<&t$<(f;RXytDpF zYrOqj@4Xz2U%!jxPlGSmE8u5L|2IPat>nPhuj+?{a+31g8JXP?i&YS z@})D*yb^?$f8v{%Tqr-p*?#uB`21(+>~84(^$9bad3iNHetCPRRz*yHuLaJ$wHH2r z7&rD3I)1fwa^{sNoUh-l0lNRHb~$HWJ&!*>nBAfkI{zxQU9f*AobQ{i^Hr?;8{D1c z%WLuWTRikIy8fKysUSa%=U2xX{J9>JzdylQzNtPwe;U8_$R~`K3Oe&@W!(Qq-g{91 z<9~+t-}O?k@gwAs=W&-`@1LKG#;-v_|Ht#lbBb!3O_ z3MT)7Fn&tw`PVnqKL3O9vjzW`Cgbs|bHpT_gEeQqc7V*DOq{GHbGlUmC? z(EfXxFn*J!y3vcX$Unf7&37AJcmNaizh+Oql$2 zg8pf(-qpZ%j910-LmnJ%H-0@3 z=erx@PYZln>+g+AFF23!c7ac8{ryyl)x9x(r4T>UT7U1;cX&38zafktl{D7hf7!qI z7mSbdaQ1(m$A#OCU(dd}gUa_j=FBS(@&5bS#8qhf`LtBvd*ku%&g!1SG5ueQ>z9y6 zgzK$)mn7}CE+2=zKl;ZG_WmY2GvA(He}_|if0FYrOYM$kyvzI3PoA;&mxr+TkC*6g zjHboAjoZ`{0y!)!w zTQL4&CT71G?$YUKTE2UodT|)v<{Z<1CX>I{nHS67xazcu*!%DIy0G{EXEFO7apuMH zZ+MV>9VY+yM5h02S6;N^An)2`8SnD`^yaxt|2fQe;W>oJasLgRvr@(6pJ>kZf6sN7 z6oD7Zf9!_WXRQ3+ZD#KuGhQ9(Tz-*%w&X@A##dv!{a^4ach*b7_&GP2{pPdw)1Q{# zy~B_*7=Qj9Yd`;j@7Q|I42&=JJ8M4(FV=&6aC#oB{!VOS_FKT}Z>zKZqW=VJIMJQ) zF7ZcV=RYV7GfDQv&b(;<$vXqgnEr*^F#VUX_EVhZpIr3Wi}6>r^Bts5J z`QLq(f5^VvUD{q#_f*kt+<)6l^DWAFm-qL(Tw?r6R{sNN{#11Odl;`)X8yN|wSVFK z7g7Jx8P9ydc+ZT?|5h9GZV%o6z{>CG&*~rH#rn&iF=#Dj{|4uo{s=GXf4h*kcK(Tr z{iLcaeynkqCL5H0{eltb`7O^`{I#uhmuyv>{YN}MVU$N)9(I007V-R&MJ)fXoGH8X z?k~FjKJ;$;7PH?#c5a7#z20|gci{e`Yop&&`}d^v++%irjz^que#05&ck%{TUew>M z?%G}0`72i$Z$fy{{$J3@CMxqo(q7v;Cl>vb2a zfBQmK|C`*U0J|=c+fOXNd2RjYSos^hVEkrdKBC;>J{aGX@pgn4%O6>x;6Tj(+wErl zv&C3`RI~a&Ve-c_`8I?X?YAH%$3)D2q3rxX+coC@J#=5=_7n9lv@qXmO#e8>%h!$h zr5iRa#p?gUaArTdyA%N~%;k&qH~jdF1g!jF5zKx!U3pRe=Z6&*JApW4>gEI(0E#)#CSKR(^x?&qfsRX@l{9v-&qZVf`XbdtG5JmEvikeSU79VFU-Tcp#IGTk{d-(s`Xjtp{=-|m z+F^aPR#z(S^eA6yUG{!AGvneA*R1e{}I)T>7T)s=W&ed5p(eNY9`-h{v68I zKjbW~yePj{P@fB!{hE(v<q(B7x_tT8t%dPT9?`QA*Y8l*{;_Z_ZxoY_u1U#t9JgKi~p=*`CDzCDWw%T zuD>n%2W|bz<^0LKOVdf#K^dhe;rzjrJL-2RnalbPtG@+Ntp195NJoVJN8}HG7kmV3 zKQ<=chVZ=HT>qYjZ{}nAyR1Jx(){;34@oWOY(J6r%U!A@#t-Vo;_tuUpCrB1;;)PR z9+9m7Ebbv~I6}+M-FN#r#=Fda{j~GfOQcwf*PrPBwj3{?VgA3F)xQbhQ|_o+uvSvD z)0qADYW{=pqW!#ot~iS6@8bVQ7;i^-G5&O~S33-gA5XRUZ^;yGdHF^8Q!g~r+K-F> zrVnN1CwP9J6NkDKVtftp{6!_2`EO}g`J(=#vsJB&>7R6p`EMBy$$na|F|NPJ?`rux zH{)IA&r8A>U)DqNjB)0<-rWCRJx=Jt^mp;UooxImm-CS10nWTAKcwBUC7AwxOn*D$ z)tk<|D8KQ9U5haJ8$y`<%6mvQgZ1YdgU+7D_;qajZ)3b&;6?rK-v9OoOn*0R{8Pb| zm!#VNIsb?wEh{&Cn%Dn)|9ErX;CSY?2A}_Yf0k{^Vvc48&=Z)rWbsLrJ*u(U!cqgV z93H8@;~6-J8zjbrl;P=cSnirs>2LKUJUp!)Xpkz;3C~i3q(EsE5XgU5x&h<= ze>Z5`$~76$|D-|NHtqj^8U%Js(*`V$O9z%CT+8DkbvPLM`+NG)|)q~=rYS!&s~apsU@FMwOPglgVqQwrhoC%lcpE&iP&)o)qX zzoCmK!7Yf4Q4P$F)KO_Cje=V^1sE1X>g(yd9T6kBw{ZR`l`XWKmU_wmW2R~aZ4$A) znBO~6eaA+Hrb>Or!cO<_?kSlH9XZ15;@Q8FlW1xF#1l}m(j~BL=!pr9f?2A%6vu#j zxKtS!n1^#ms>%eG8Zx17q9wxLY>9{sO|}NygD1^`ELvz1=rnUf*G0|2LRo@2fhFYP z#c+I4Q`T~B#>TURVeD60B(GRaixK!eEHY32rDbYm;hW_L)icGh-1Z3(khWM$7AM>z zI*}#CWTD?*&*^FA>Ev0qNm;9YCYL3f*Kd`aYhKI1?&*lftr9J9iI#w1OGJX?qvr*4 zw1ZUN^Tc2--%CV^5OdH7ISnnUM>l8 zy;vvZ9jJ9w%=7dF>AdBGCN6H4lGU7t5&g<;p#7>YOGKLDt8kN4sbqPI+46F#FSY!# z`T(GErBrRfp-OUbSmmYJ$jhV|8d8eG)MSaqopZ;sCfg@C%8@FuawV2|(A+omk1m-E z>!s9issyx_Fu`A=&GF%mESSk|oBRdy`BXP?IBS~@;I7dQAJx5+xo$vwY#ht5-4$G4 z`%%jz&KeiHNqyZfP|*0oumyLU4;h5N5-+tf?Ak_ze|YI!eola z!EIa&!=06lQ=?+Ty<5bFhwB3;FYU*MeV8guW0;M@<5_aiWNm~1$$zXLVGil#2()!W zv@C*Y#7K837i4#5DMBGOMo4(b`+Q+~lC3uJju^$SUA=oOTbHvRu$gzJ{0=R#<|91aooyuzOAG_Q?;)8A<+mQD9e`@`=`~Ts$MSDL!SAbyuov^Qm z?+fSW8ylG0<=4~lL_Kgzm(Jz>z60S;Vc#)-f7ay&245_W9sL;9AM#4^ea&ji|7M>I zTh)thZf-96H#@4E-MT}6Z$WAGFYjM9n_eQgX8!r!|$q#!h;qDXZKY;^ zyI}wGV1NEzlmh3gi@fvQ*iXX!rPgP9V)qaEo2~!*u*wqZ*M%1ZL-zMCDLmKyw6crYJ zwq?-2m<`t);Ro8ae@KQWvC`5PFBDN;foV0v8|<5JF4>BF$AgqDDldDJLSL z6hjjb#6>}nW~hRIo^%8uAkswm?Q_q}B{w(s-rf6sKlvli-Cp)}lX>QuXP$Y=3j0YR z{^vNfU+N#|{h$V4(bV@!zUcbe4|Rn7M3MG&0_NSR|Fq)IC+)XM|4R70+vnV-nu31(*yj+V4t&0`*)dqYX5fmtKfS&HE-vQ&(nav3i!&`=KQvh z|A3Sq<4-F-{ru6NCnAM?x=8=>hiRW4AwTKA=>1ebt;mI||1?e#^&3v=_eK!=wBo~b zwC`Jb%s72V@RJGuK@j^H@4J(Kag*5p#H_#07koG2hyM%ynZ&o;7%t;Cy`J%n`FhgU z&yNZHdx-vTf`7p0h8Xbt8hSs$rN<`_r{wO`>?5yzg8$J6O8=bY4=F!B*U88R?H~Y1 zE@1ovrMqe^v47SVUm?FZ@b#nSLKgGK$YGDKldsGBpjS7cpERPMe}m|U-cN9fLh5&T z*QHg2e^9>m?;n-w=K6zLf&RgYPd~rEVRi~9e~u5OWHf%G_shS^@LN`!@51o34V8s` z#-H$)KiTwe;zxshyG9p#`ltHYd8X8Cp`WNz{`_UYr~RYu{np^W=;zr_bm_$DC!gux zT&Di1|DpE>d=uIye6Y9e)#DlM6a9aj7X%Y^)?BtOs&_y+g~4dPoXKK*>>l<{wJ`Y#OrjkaHU zKgx+^dwc<9>7xG~6Z+9f|62?D7t;S)@gt#qVfkz6w^s}OM1uXKLHlYCd_4D1gZ^s< zk&nLB%gQV9P?qc4uCw5)U_WY%?0>g^V6N>l?Z^1MS0?Wr9i;tR@e9ho_I>TB6|33_ z{iG8Azb=UXpY6Moe^HlQeyPvCxx)X)6aQZh>Q{qvWegZU<|X&jxAgPl_0?EmKPvG* zHG|j>y`S>UWt)CKi{4EBKSdOziR-~yJXCjTPNNAb;%OzJQF z&kEqH%jEos*47^10R5*x*+(z_VMhMkmn8qw*JXlETQ2>Z{=7YYL-G$jjF`Dww69d+ ze_ZDLf?C`3pV0p*o$T?c{uXRmQi;=lQ`7&rOg^_oNo${N4glz}G;hT?du`buMXo1eEzZ(UnBMtQ)EC7A-|j0k8&RVFt=>KS`q30t@sMzSG$nn)ju7- z&vnT}ktZ|sk45eAv0kxS%IE4_He>x_{^7^L@-OK8ix6&r zO4~-9{mcdV>G<7>Pe0!>x!&`_zq!f!mLZ~lG3BTI3%#F+>+^4T{pF3f{@~;ojX_Ek z^p52_S}E`PKppgd7xbTE#{X))!1%vl5H4P(pMQPhznR|lMcVIV;ok(GKY?8Mp1jpFB1Nfo_|>SIcUFRe$z^R704Ke%{k%`&qws>|5hKFU+rVskNENAf${0H_T*Q+ zcPR?$C;sLn@A_ekPq2QML;gVt2m7(fj|4szc`9%3A^dY1S>JdA+OP3~>|YFRJUiJs242LYUck;@ZCf|$^x^05&GFH^KbZkJE!u0+B zbpFDMPv!si^~Fs&`Foi95kDHt4;uCC=?Cow%dI);i|3~Vw6DRy$LH4Tkl(YCzp@ld zQK5XY_$%>zC!hV_1OM3({F^dT`cDPsH?8;>pP>9b2G#NI-@)}oX}~`P{R=)f#As?y zKPWfyx0cQ<;s>An$iMopl$7o-vyvaVSkJq+4ps%9`sWYL@rzs7KUrU7#i#mzK4;fF zUOu$nN1z|&vDtoweWpPF4)dp0e3T!{KZerKI$L!^SE`LnqEH0 zkMW7i^v`M|Q~s?oeo$b2qh0yIJe4UUE>95rRKnl*mDzqxzP1DMGdB4&K8*UP{5UQ? zT!Hy3$PeTCOe^_GdPd3n#k}q!KcatQILN#5+Oc>{I-?+<8z`V z$#PM}?xltP6|%mrnCU;o57qyEd0Wum2goP0h8C+T>|Z16V?AJ>)c)!H1ZTcg{Vsj- z&xL=z?Thfgg!r8D>HU5%^NpKanA2#EcYguhA9oYvr~aW3xu3qJpNCIbHC@QB5cv<7 z{zq*b=pX3)l%GZ}0eSmOWW;2{&>Pa1^$!jpWdHN zlCP$a3%j~!|4I0tRFa?kBuIYJik|{}EL~Z)i02y?&>_EC2=eohVE;yh%vpRaKuV0!u z^(Ubp4~ZXM5&2KkKJmH52J9~@iZ=!+=aB1<4t)Pe$nPTh`8kMwtoRQJKe@{rV}yOG z#J@cb;(zG<1g99}!iDME-tp>(ZWFbGs{}>-$3evvl z{XQ_fNG2Dme)8%Np?^2g|K%Y1x8kd$0~-B#r0(@UMF0N*pY|_S{6|E7*X_Ud2>ob; zUkvn5{SUpL;1r{|ypjxM-SSgXMg69M{kw+A{K+Zv>{7RB|HdjA|7)%IG zDgMx+W`eI0|EXj9CGp#1!lQ4m5`Jvs>E87fk%XTdg#RA}lJ`%^`yxFu|1I?IBKofw zME~@Df=f@_LI8K7#GR@_KT#mR?vna1B=R#t|7qZ#bIbTjA@&!*AMbzV*_stg3j1`O z?CiZ0+gHQqJ3*)IaLSh3muNxx=`>-jYx1XH}=6-uX?s zKJAX_-(05rbbpg2pU59sF8Wta{!-@ruiNA+mt_7{YiYB7iT>|2oE$CmPuCynkYCcF z|HbuDPURn&D|Zqn|GU7a{fi}^=>Ox7Ql5(TOZ8vZY`-3%AMihDr&jz_@IP1)$*B-X(+lv!LuV_l@@iKOF3TKCG{6Wy-HMHSM3|m#p~v$Tv=W z^E>bQ&v4>DqfEZ|q58Mt)6e&G-f>CjKa%**r>6aTe~A9+{qR@5VuA0Ke6i(~!v{tG zo=W=nLKmb0>G<7>kLRnv@=;~L_#W9a)^G9v>E8_SZ(3K`t~A)+U7W~A-_p-Nn_Y6L z&`&ba&t%BIxj&Ti?+VPX(fcXi4R*5-%Ciq!{wL&D!G4y4{R}kg*TvY66`y`y;Io1n zCx4!WAQ`D&dOwxFA;^u_r)O#E-Jcat`mbtGzcjwG;#VdKzVja~^qy~Eko_qiga6UU z_@WSz59P!%1wLN|<>Pg?dkFnUg8o;4{zsYmcQg7gfuJDea&kTGK#KSLE|tXRt%BIU z6@Mv7kZmvUQ4a6;h49s1+;uiX$Z*vp_#oetJIb*3K}W++h!AFlA~ANY4bKMPFz^aws#|6nD*4uWHOyXPUX{;Gfu z{OquP!z0EQ&9eloAF$%9z{j%UKPle*5y?dVYejy^$l4AoK55@{{3<@=e9_|A_Ggou8U!+NWFShwM+c;#2w8 z9DCV2KTGwK4E>7^dP0sSwnPuNAJga#8QP9SXS@5;%D-~rxYxg>5Pqt#{}!hHW5NH_ab`bQ50}5p;a#7P`2n1N-vQeHe&nLQR>h9@?%y#$e)K;sGd^*d@*8`l|Ir&elOOrR_m}hL$Ef{`hxI@D z50a}lvB!4<7|Tsl%X`-^rGoq}@IRH!{Eu7c|KGme9$Rm2kFNnA%ZP|uL$z1Yb4*W$*14{ai2*abM3ctJNcK!Pg3s+?60TygBpB=3a@}#I@u~lr`Jn!nLjTl1^aJ^6{=|w;KVSaFzwJ2tTq^oUQ+^ts)BB|s(|=R>=YPKC z7$^S?U#-pt@y>#{}u16$@gL#dh?THeAgZL zG(TX)r}p`2o8=LleO`q18}7}pKcZV`?Q6C1=AVMEZ0+oAP}qNcY4(pEvwn@Oa($Nu z>mRJ-SBQeXZacA=;K!5oElLg9erfwsXay2|k0`{~<; zME(Yi=8O~ds}uQ0Jts9`;QBE*pQpb3wYwEQ zn_BQ6_`XTLXmerh8$$o#gg+C{5P9zT$rZMZzn(OVn=~IltnvY5y)$|DK94 zzJ~J+EcwJhKizz_sNmE2ubTf#`*FP~`8tf>t@yg)|Ff{?w*$QL6Z=mx?cZ(6Pwn4| zub3`f{5*h${$=-%{uTNU2mheL{?mh|{yipN`B3@?y|qpK1NQ;c^RfjGKNWlx_#Vhl zZZQ47+A1(UQN7ark6*yYzt~lDt#|!7J%6&P8Q+Q@V+F|H&Yt|b_pbC`Wp6Yp>KP z{)_hSYWl70EBg7;zE4+){+I6We#5L^m#H7x|I+&dz69GBe9*wv>1xLIh5mnsnICWq z{geLJif@oFeA4?#8R36CBtLcm{SVpyYsL5ZANZcl4I1tC_AkW0ZAL!vZ&rNV*Ny*1 z=2>}~3;jfr{_%jRACIXYx<02Y-Wa5uOY|T8MyFcBej^lvc8RJr{(F zm&cI+I`gn2twjC0NqjXvNdA8W(JykbRLSQT!pn&Ltp(DE{Tzn&OXKJA2ntf3BG+H3 z^6MTUzfR<@4Em?>rxibi$iM%Ce1k>(rjYt=5u|>t_`ebPC--?YNywi<%vHSS@5K}S|0?=Np?|Xfj>-q>@D*tHcwxxy;@@n+b{ZuB@01= zDKbBx!TvQXz6%u(<-t;oatb~@AL)~x(0F3{X>wb>& zKL^eBm`4pNfO zpDE#1Mg8g|{<&uQfA0^eUn@TP1^o7hhhwgK?T7GBfq$m+oAiFX zp5)(FnEj*6w81kKRsXNnrZ)T zQ~%Wd>HWyTQX~4g8Mo>up&y0h&wmP{A1l5JUxa1L$VcA(3-e=-VSH3FMJj^kpR=N% zK}zIe`QD!1-tz}2KMeSK6s(Vh{IC^YBj4M8`9~*&{&9XB<4+alM-1|OKr4O@!e71P z_`AY>==zo&E~y_4&KJ_*`6*8MZ@ppM;`r_$<2x%p>K*@$bt8M96#fDAkNU|KB>uPJ zha(uuJ3s83DD0EYpI(Iih33z#_!@ArjH-Q0u77~|vkSzZTg3Vq(Y{Fh@034ozT#b9 zhxXGC_{oqTqxmF3j06)P$Hk51M&#m~r_!kUm{;1{+ zh5cjv>>4chcbo*i(G2GIF}@=GD^W-K{yzAiMcBq4g@218@n;c;AEYS)YlY1Ebu;#3$tMjgcFwxW8TEtyClc2W!1w~!hgk8OllbVRF3*?;^qcv4 zVxOKM@nOASdV%W=$mgq;9jfl_-${H}71}RtU-W*0Q|R+m_v#IIiuzT_`0jp?_{xgk zkbL31`R4qZS-HWFeA_07{Pcc;Q*iu;rG6`6jj(?W#=p6tf4qVIhpc}f zkAI^00KVr@yf_~l~Z#{)kW%4g^9^X}il`H>XR|0;~H zVBLvQ(4KxMzh#dPz2~Pf`g~w~YsKFOTrA&s=RMheA%2U8^;c0~ z|LRwAeX`cko_)$w<>5=r;>f#=+KT>>K7V{5_%|9qTggxD=ZDnSdU5viGVp19V#TNS z^J%g0{+#`cH~B78|1^HK;?vKMEVwyS_@cY1%irsXTTK5^sv#Au=a zC=#D!J|O!qx_-cl-;{je_j&Fn2>nNq{;L@9>G}{WzEacw3%Zvme?j<%<*l<50@q+%IK=hOCzl+a`_N$Qji>6>dwEbG~um0=*)ob(38RU(hN&Ah5_C@^2Q8qeA~UzIy=cGb6x1(EO?v0QA2=KVP=~Tz4Tq%`a7l{+-V6(EI)A<~!)X zaGka1!sr`9evGeNVE^aL{$2d&GhlxxoKLHHul|o;Ip8xWUmRuJ_v#1iM+N)o0rgAw z2U+q}$xnfW*mt`9`30?v<+{D37N{0@HY z!=Z6!g?>`V_;F+q|8K=ldx~UPZv5}R8bUv5r2TG$`B~*h8Mhg*KaSq-Pg9hZeiCB2bzyJ%m@q<@bEK8>HP`1JEf z*H&~C_8Cd+XIT*Yr1ukbC{+H;!>V@S@+q(%W0$O7 z4ffa2{1lbH4Y~04Yu`^2`iUa?S!3!)?T{tFf71I2PKksISYEmre?{mA^V{WMe0me| zGc^B0%$wqUeEi_qtiO!#wqIiZ)6DZLT&DbbbJ+g^`5&kJKASgt&-Xz2v3;e1{@pVr zUkjJ**D1f^$SmITwJ5)Iko<`izZfb8%8NNO4;B8C&R;YX<403JG=E~ncL5j6-~Q;n zQq->o`Y#XpjWm(p5cWgz8+Q49;CtR^e0hrCM*)8~*v~d$pB)3^b1Obw|F-yXg7^9I zbp6|p;2)@ev*Odwzj|rF9?`z&`n@&~f71Su-VbW<71*xu!nN-QdiOU``x%G+nZzen z{PGBf^1mb7@`(18M)Ct~g5(FR`0WY*=WQo13j5TF|LGSbKj4)Aca3+~2>nz3u^|4R z%16Xi6w{z@DDEV4?lu`@R;@MX8eN{pUR(e!%gq`JXHR_z>)gPn^&3TjLcvfNp-t#|*C0`}t?F30aV{*#|;&H8&^XgOqjqNo{A>`QqcepEisP4E5- zlzq+AdK}r|oJ^MhJtHN6? zME%Bte@KS>=Q^`~J&b>NF$fng=O7C(+Wz(Uk?_xH|eh=5D)k=|q(EK6!_Ys?3 z68|uH=&vt&$4A6IvrK}2v=7WL=acQrl287iP+?R5rv1?MGb!f&5%HtP!T18^m&xtv za^owodwly=;qN;MKF*J0{jU5P{?So#!L(k~p8N)}uaS!qdJ4XW_~+|?NWRe-?8hdb z{(p^L{P2{}KV4tCZ-La0LH3u?`%w>As`vuRdLy@=5%SaZZ?Vw-((#cMpMJis!|7Kz z`TrX%1)%w7dOs0Y(cuD?dn0GHN;>7R8t|IIERzjyE8>3<4- z8kt|46b<#e66zQBXIb$L1VdSUVxKU8v8N^q|K=v^8w;6y@k7UtR(#caSNgBdW%(YUjZ7 zovip;I@RiT)u11D$eHmKebPKKfx)uY#pzsEWP=% z(2siBe|&Kp0%1Bo8;v&xDLX^AjUT^$dd5+~k0ksYS9tq}ZU=7Hf!x6`+5C{UZkKA0fwE`NPe3?a7szv;J%^{6EeA zG!2q}u;M2JAIs>k7hME|6HOJ?%=H`0C=Li?rdi{4MF zQ>jlb?E7}zr(XX<;`6~l{J#}{6ydM#*ztzwe>GzNYR|Ix%()y{RY%;)2Lkv{d=rh}rw_qCEr;@FdG`7@96zOlzx?iBBk&@KH;m`Uh*1{Q~pb>=f2JHJCpi#AAskyJJiqqZZ{@!{9;@D_2W7mn*0%|`b>_m z4)N#X^R=Dor`213eZuh%68&qi{?I8uwfW{=9KU`;B7axeKl+|?g$7Sbw0kU<-55WB z<97?jcUZs2{wQ6P<99gXFTVokuR7Jwx&5=n`I!OjH-Yf=5c!!;+&RPXUn2J7UL2Z# ztA4pu2aaFc_n;f8C*O0@#=v-q)GNNldd2eIhvi~9e)4<%`bWNTR_0TXM@!^l`Eqg- z@%)Pb{dXqv<2ir2L-}1_)MNega%!LO966`<^Y_#en>qP65dEP1PW6-Lm3ypx7F$a6 z56{_fD*xC;8^rp70R6W-@6Xq#!E-_!w%;>3iwx!X^}h4x8$IPZN~iMQeLF>r-vi{2 zBl`EO3ax#OJ6b}lZw%m%qW1G$X#Gp}DGx?-{F#LBd(MeN{Wo1wosECy&hXd2ay>Nt z7t|B`bMmL9%6JnOG~+sSr|oyzGaXp_jQE=8{EXyH2<@9OtB-J{KtuZP?AIAR~SF@BF8V18^@-y9$Z^tp5a6JJ+xl&J=QCh z<;(V9`S*zYTEEcR@A*e>vG(~786PS0L(|W)lext6qXX<;|H10*Z(PmsJ%sOj4vfS2XKup#vpD``;(suY zZs^$U48r~bd;**SeUeiIU38PA8-zB)7* zoXGL7lJT9(6`K9L`s{?iIR0Xyf8RWn!}y_O`-4q6e)vp({UhIL|I)a@tE~RNCGn4s zkNaWJVUiO4CYC+V=HJB0|CHE2=CPdGr=GmIC&w>B;%B2{X!cV%SGx@yzYp=BTBp$X ziyE|y;P|7ik@^jh|JqJN%wGrihb2e+`Rc~d{By+0^Mg75Zo=0(ho+x|<`?>M{Nrc* zzbo=FdIR074-)2%^9F|L-Q{vhs*HaR=?0buT8Ov&&`|jrW)rv~}Q@+#qWbUS- zZ2eZcA>~HCRtC<|bQoV<58tA2@*iC4&o@Hk7wVL)EypkanZJHq-^%<3j>CKkCofR% zSU&fWQGnwQh5R|T0_0;!u)ep*#j^D?VXXY_d6JBLb*JZ*N>qL&Y!P8l;cOI{62TTWXE6OL;d-l1JZt+ z>SyLl5eo^Xk@;4`ZW2GGbI^~xx zuwLwc53rviM~QyGZ#wp$51((s@gqq6BG;+>%TN8ZpX2|z)L(uhBDDBn_S4td_{vS& z?=I;doXWp#`acB_8m_)CcWxOd9_*Qxw@^zMZ@erHm@$am^L z^IXpKBFA@S_OD;hvsd+(Un?Wy z5~uqA`#_G;9DgL}Uw(_Z)^sBHADBlaV*B2r+*sCJ(Swbz=IH+MgZ^r0@kv+Z{oI`V z3b9Ymhcf?wrB7h;0_Dc?QM2RUa{Ttxet_@PK5uJE4UXTkkAMBTSA-`2wu5_;IewpHWznlC9RK_gfBQkXo$9|&{sxsf{y?IC zl-sHObTuj_ar_2EKgh?@r*QHD^^RrnFCN|G_z#GFkn2=G>r0Jb{o9Qy{`RAM4g1U- zj_;=Y*Mim0ETSJ=|AQq_i|;M!1mLU$`ZJ2-k0<^?X&hSr zGOETk);_->{!PCu{ioCTxoz@i4LJFCU+}MA*G%bujIQJX3qH-u7pQkEFXxY$%JD0| z@6R{d$@mKM#02Ymi(D*Etgkhff{A{}9%_mU#YJfc_hi z@u|CUX!U#U>UV7ao}JjIt9NMe)zGoC25|D{{m5sZx-e9ux?H#9xhco-UgKqcq1|Iy zR8MHf@lznbVcNegFnW#9_;q^&msE9^^LerlapOsL%FexsP^u2 zocxc|`Cb&(uaYLmVRrfdF1aI~j~39r+I-~iA8_5IQ~z1C)$eYOADM3dUQv;+K9c>g zUHK;sUeTZ9Zzk~@@^K#9F8}!aN56CYg@kX^llFsgs9pa2>1nM0%yZ1=AG|07p09_c zUH-)EN7?n&28mD5KAqZswZlVabNV?&`MCbpVSHGzosyN~FD3pT&#}flkX`-Ujw$#G z$8Su=*T{ETzg?z%^Eb!eN#alBt8L_dZ@cm@x&CoQjz5mXKgh?@F27y;U^ag;jKn9% zb?P6o+=yi3lcS{n_3Xs-dCIBr;+xHe5d_yv9bl&_LU=xzkl=b9j<>!cJ(X5$*%_C>kj!> zc7M#y?=%d;$8{Wb+t=o_U)l97-v;q-IzDec$QNMTfaR$1ud(@op5WhPEtv5S*guv* z@B#73u+jfc;PgKU`~&4Xwa>MOatd0(gbt6Ur7&U5mAMDw@6ck2H?sF#Vg&pssnM6Of+Ij!U~ zc{uss2mk4_ACTWEKk~cslR17o(Z4oM#)tTS*lk}6;%aZ_`11|_`qjG2xZiWk+4yVO zfSxNke$p#E->H5E)Q)?LXO|udaEX z?SCI;QD5`(Q>W6$zfwP~LYx21 z`@*`Goc?vveo^mE?SFEf`V~0-DiZ%7AIl)>59q(jwfN>C$5%Q@{bT+R_cuB9pNrnD zvXkS_qT>tLpM`mPyYlyXbc>CzcGCD9_)hhoV|JF0IQfs${vG&E`}gS;%}f=Oe^^f9 z6AkxI;qx|vC(D?IR7oOqx zDI`CjJd%8;`HjmdU$gU%li)#cX#XzYJ8fUH22RMv$-f-@Kl1e@(r-HDZ>Z6hT_5!^ zmA_zU{4dJ<)R~k27R~=`4lRE;qSx?=9KR^(f0aU^t|UHIlx!fI?Eqk+7$LH$N!t;549el)$gT`bAQh9SCRNi%NN@EvD3#^f57oS z>g%t6Stk0D|B3s@o%+u?SuV2kYyBX8@aYHr4)nuz zAr*ry0+Q;8M-Oq=%zI4gex@S24#g6`b++Xih{!+J= zr*iytANce2KVg53L;F9xaVu+|>J-VBzs>pglW-2ML;rm0ruX@+0rRJ+AV1|h%}=(B zoc$`NpWcOJ{sH?(eY=dWJh`3CUySIq`$vvnI1kTP_sM#&YyXwbB`0wF(KLTmLHd7n znzQ-en4b=@?e{L^Pf$NvkhW1O|$(kep0@3xejtpAy? zfakk!J6j((;YqIJocw$K@?U>~@;i;MzAQa8Gskxm|BrGzo!|UC=bdjk{&J#!qmHzH zr}1ZpU$!K3e4UKnQ7`&lXZ|^?%uZJRAISU;@^KxFUHkcO!W4FX{3yxaBH!u!GKTPRbgU!FKC+i1LeryMJ^}n!bZPx!E?#Sy0 zzsD~BYU|EpIQ{n{;}_%_1DyGX)yJm|;P`1IKj!1_?d@p(JAdc7J*r$-g1rQ`}kpB);^KE1dlK$@mxfPV>*Zr=4T% zb3U0rLcUY~yn0)k`<(n~LHvW_aQ(pbzy4x}PIeszMg_PeKG zJGT9;aXS8;RV!};PXAX(|A>4n?bh!nZ@rg^HKMU<@g#mgzSH`hJu{qLU)`0=zaZaf|1#yBO{{-z|1qzB{2sgY z`*Jg#&Cky|!1L8;XYonC1B=-8ArHWQ&^~=~!}A#I%D;BrCtJDp^;UxUeBnu16w22Q z%YNQ2Klij#?E0%OO}_ZS{0zp;PVMvGis9`3$Ky2r92;7GqspY({W<-#qw_DwhtjTo zKD{uA%`g2$umr}p{H4>{TS$0nrzQqRf!o>RW- ztxS74{Uj3qiF|yXie3GG{mQ0_96$TB{_R&88QT2I&AU0-{YOJc`$9g}gI)Q1KiBgK zC;tM{KWZ<_`b9n2<-d1#Nmh>k;7_R^^q*Q&nIChyesxsL+J+pzG|4}>ewX&|)P9Qn zcsrism%QX(zv}05T;a5T&tLiso4-AH&Y$mY9vc5)*w%%d{DW!!0rDnJ<)1jc6nlQu zL25srgqHuT)Lwg@lfMjUU-}23`Tt(;4Px^rnVb6SAM++o?I(Zy`5m16CCU60@}1^S zy1n1@Cyu|H#GlA@D*wz1h1mSex5R%UA4|LbA$H`7W1Rf+w@UrX-{!Nt;rwAN?eh1` z=$4=3Hzf6oc_mGA*8kow(BU-4cftGu_V37dx<4`Y-8T6+zH-ptK9TQqezs)(KOb}a z$Hab+?{t6qn0s@>IR0@mzCgay{o}g_oMQW5PZ0U>945Q=)9C78c7M?NVDiIrc4b+d*`H`ykGwGcEqey(^<2#%mnbT^1EXOZ$%s>Bte5d`(=*jbEar{DL z{t@{`ci9iv)&H=L>)HOX@*KW>;W`n!{AUOED#OX2O7crS`5oqO&!)8foa6sO;zQ&s zW1P(oW?9vN%@1rM@fGr&`sXf>S6$)cZ$jpOk&mTa{ny#r_W;M&gZO8s`zt@G`ZAke z`uVtj|K*drhO_?Vm7hvv;pDFm_HTZRE_8u>-#HLL6omUCu>5DU#?Ehc0Q(Q%!#Ny5 z@B!^7eIVrT`xy(;^dzi#Q!^;-#Pl< zBes7ZnI2zxMa6dI-rU2H{m&azirs(LjI19v;=wOKp5Cs0@}AFLiqp?yvcJ{XDCKr~ zzFCpl#U60{$q+wd{=~Q{^S4gVpM3t?Uj}mgD6&2o{f^W8*pgD;7v=Z``pK4s@+05r z`1ioU?muw+Ze;y4^0BmAza6*#F`MJRMaI9#b?QHdj=RA=Urz)7fcinMQ~hh1`n|)+ zzZBXpg-`bi=7uL0Mo{(BXB z^oZmCP3#l-zW*bLf-vuiWsk$3vFoqWh<)lPzeD{rJv5jdA1x;9XK>x5Q~m6^|78zO zKl{n~RLIx-Y9Wf4&CeA}oW5ACP}8*S73_ zPCqTl`UlUT(AHP{dY~VBKE_;_f5i6XN|EatoyHGyK3|@LlYc#|ub_M!M+VbRG57%O zKYIP;++jI#6xCX6@Qyog_Ib@)<}ja6?VfDz0S0^b6qWmd!-Ik0I^`b=tGAxx&pMn* z@%%sF_Z$65c8))4a3)2a^8a7{w|+dspSV7MV#gn&wc@uSGtR zX#p$!M?pO_gtGRRGsO9*1+ab_^_BIT@^_g0iwiQ}X0(%ed9)|EJ)m&P_W)mc{{Mz= zTmln9+cVnFDX^bHccuMM`K6Z# zFdN?mH@un!<%10m=49mW=qK%Sd=S1|HS5C#yhwv9r=Tpj<6OOr{Pz7N|7;L`_5h;) z1r6R}IVbY3LmBz~KtJOb$oA^nukcXL`=a0Vr>4I{E|!D3RTT55zV?g!+?OTas3y5u zi2Rp_HLSw%_x&gN_*_ZlQE2janOZQG<1cF``MBOn3z1*9-s>ViAE2Lg^`s{=!eBh{ zZ)ozji7v_3@0p(9DLaGyL*zH~csg?OF9iK7wd8(QJw*P#U*<=0{BqHtpD$!y*a(py z{?Q$=zbrui2Mb8P>ygyI_Bb^C52&Gt`KbW@1JJ+zg5>HU@>h-d{3^%41oCSIU_Z)# zp~;{4hfC~_2$28oCGZdbf__5eXUV**5Xb)s>|a|i>sJqv|6$kNg*kpK+9&K+FrI{_ zpPeV(o6qqh3xfT?^JKKAq4DqkyIkxa4A6ga4bXot!Z#{3l@l#$;$;A@bvYN)q{#0R0Sw{t?&v z>sdmR|LnR`to^&&f&Cni?bisAU$|~gzxV|E-<|0HYeD~#H8lC-Dn2jrGXeU^3jSHi z+SgmrT8RA1i#|BU@ynH$`cZ33`SlR_+po2L$nkaX5AJ@T{}B1Ji-29`SH1cdWig2*Y4@c@gFUcF)==uPRSjb{CR5J-oWu+1p85LO8=&X z$e;4zNiqK((0)_E{`KEvKHhN1#}UE%TV8sQIa4MdAM-P)6a>#LvC>V9ne4OP_KH3{DWC{ z+~oK#O_BzN=S3MI@&^>mna1%qKzyY)1p9d=H2r)Vvr(K+7@+^|(7tdzvK}J;`pFN) z`iB7ij;&HZm=D$q*^{5fr-`4|dzSMLcLoC=)*~A>`I@{Lgs-|qT6B_kjGXOUXxP_UIyC-_)bp;4 z`aynW)Xyr(HA3WnnyW}Pj(_h1$mG2a^HF6&lYi3p&z9x*JrtRV)D}p-=8%u}<5_>= zt&DuMpZ+P*e(>CUO?4(e^5^b2=jZ>CzXJOgeC|cr(D?C9jpLmB4PF*DP1G-JVhJr)+)35LL%E(9g=L28aCiP-Ck6bLj?sE4I$M1YlHW0lk=m(y!P5W<9gRh{UpUT!X2iL!6 zh5pgA7W%Im_T;Dhq|;}9;P_|Jzrnf5hE2W>{|S~|t{)TYTYUOQ{}~POEuK59)U+qR z27D}5Z(4CUBOmRjF~$!A!M{a@#$T}Lgm^xJPk!Xr?kXj~{Zcs2p!!8Qu~hK|l=Vh# zKf|@(SRB8=ejuY(X!37fku07c5g>mO@O}H4U|*$`{5r^u<=%*%e&Zvo-y)OD^$DHK z7zp+o;dAw@_!{uB%)VOn>wmHRwp}9~m3xb{f1{2w{UCqSd!HW7s2}7{f&S6h3hk?I zX#Dk^z7ppH`1FtbAEAG7?S%L+M85jd(>RX*Rf_aKu2j%Zi2Tnhk8Q*8KS2EeUxDY3 zJFVZo$-fok_}UXGzvsA=Uw6m{Gg5{wjr=YnAKP!93edm9xl~32XZ4HxML%!hW5XV$;ij{6%P8r{dSs7z5#I?h^I{WHBy|f<+IOC5PzP+{LCH5 zKilN1AU_tx8W%ml`M1g-zXInX88-RUz77wYvw`cseuMZQ&s|a)+tWYgKb(7PAjdz2 z<0Ft?v&j!f#Xz|tSIHTfGiUbcAMNuF@Kq1AUz>alxLA%Gk+Vd``bGb97wdOE#6L~! z>4(}+t=eIWGxFDf{S1cqN}ng!4;VK2I>?XZ?oa3X<%iM!tC;?!Lve>WcZn=rmwD)pl@w4ztVf@$!+OKP-P2sBPd_O4c=&=|J?4t_&%XNI59_1C7Mr$X#wWO574xjL{iB@0%H~sFQ#t?O zhWwiX`v#Sc_T<;d7oGcjmf!ji^bfmJq@fuHC0FZgkFOH`XR{&`K~0#-wzEO*RL85`I=WcMX8`&Q8V(< zf1U>YD# z4jUUcq;l0UgGWa6iW?oBkQf_1YE(=@b=7-mEMDp{DtfSaEoscl5k1Ge91~YXtvq-gt0@C)QM_4b?k_^r1+$SCTfCOHQr>#M0Agi8y?ej%+Q!7 zYNCmW867_=Iw>Y1G0FVhL^Z$nW!1b#HTM!^dog;{*chcne8QNdF@whrYg}&dYe_MQ z)oWEB6Q5K)E_!rKvvJ}ts(b&SPC0dC;+VL`<>a+7qelpK(re`u<@u`pYt zQm2^LdL>2=k5R|hi)<9pHvK{qbw=%%v)-(3X!Boir*sF`|pqcF%<9 zxWr*&5=OT(YofZE5HoC)DM3Wf*WzQUs8!{kwi-KP)XX8(v-Y3TRe} zsl=FsVbMck)QOX^a`?;Dy&{=4_k7jS(eV+3#}0WpCaJ&V4e;V7M8^*qlMoZpHg1Sn zaS5%*#0?uU+=P+q_%(uL-X35BL(KXfl^8K(M0{*aLXWX#1@-LQqgI_JYRvffF42jm zygg!uB*Y}C{RarUY3MbAuF-L05*01o2*yR5|7cS6+UZshC;o(3fxMP(1wL~MBssRH z_Fx6RHjrLdUXx9KE2^%#Dw-5jahK>Ju_NNl>h!i2MQP6}Do(AMFxE7?(J>LD6XT=f zny7K{!diW;DK^6&#KuI&3)|#TW5y<_$ZFl{h3>wl9b-1iVR6!2Onug`3o->q#hdjP zo0JqE5g(I~I3h90Gy_vIvmGRjh#MQzI#z93V@PatoQhRHIYT3EnO=XxMvRXcTBo+t zX6&m#imG4NDN0c~$QqPQ%BK=vqjJ>#fHfrHwfLkl5pBkdjvf)$BgS-g(Mco5#Py6e z+hp|M5fQCp&FgLB#|(+Bj`m%}`+?~YhmIK?7n7JMfL7Ckg6qDPYHR-}H+rf)a zdRpwd047Y@bm0-Efs3-buxPJu^)F2+@k0LrRpVmJf2aG42+N{m6^&nMlWzFnxN22T zhk)1C<1s^-f45G$pH7s2L_9TK&FHJc%z7UaH#CvqW$@OC@{cGFuBP)a7-LF|oA9HK zKlVLm#!uO4{G>F@tmu`)6t%6`L7z#%xUWy7Ij%dFRWa21igu|UVtgh39e&SSzh!P_ z@{6UA_-w{?bN}T3;3t=@uXq?fa`6j4sPSfVlb@N&uP!pQ)l|Y)MxfZflFF}!y-|(hKWJq>UxeY$ zX(jC^yjx8r`8{j?g=zarnEU|y+|=IW*9lWxgLwON?I@?XH=409`JwVpzBldy$4@o+ zhRN51@RKhVQjC3t2wmvX|7X?IzDii8OgUV{{%2)1$5(a3lv77|{imGFr$iph=MOXA z(fxyy<`sWCENj+mI^oyeZk`!hFHDKA=C2>rzc#vv5*bw_fKTEXQ&T>Wm|mPyeX zB46?Ohi}`O$oJ(gM7O(e03X{Se$N|OU#V~M1N=kxH%f{(OAyrGfLw zc%CTH5OT3>^UDsAKMjz7SY>}c&Lh*3-~-MV$lh*uUXK6i7@qITcLsS*D9VlH`ZZs@ z!SUA;{iEFKHJGp1Df1bY^1t$gJs+p}5P$jcTu=NSyY*YC|1$RcyIVwlpI)F|gPntc zdcjircp6*3wPyOuk9kfk?ed>2YA)871lZ5OrT%;k@-V*t!)EV^{z0 zcKA-rZw2UoKGZMe<2fgG`Q`2p6Z6vn{G(O;_=)U^Q2$DG z&=2nCwpqWoJNEjGM6O84CezqC1hUMO8=QQ6cO_`0rG!8&%b`PUBH8OhIVSjzj!sr8jhc1p430u zC!R}3ODlfaynE_!{OMVwW+)%$i|~7__{9fI$i?wHzAyEI^=oXC^VDefcKt(-(VI_k z{7Lad|Kq{`;CxGvbJWppd}ZOUzvcLULHvOF!E^6uX{DbVe>M{9V*>0)`OIH_n}fYX-V(_@y}n?bLkv^ zv;{xdIet`rZeuelC~Uw$G`se zkNd=pwsJj`UH{W4{)c`Xzr|6W@BUS;7q-j4S@T|Rj^7^q1Nu+oVriEj)jQz=#~&4h zZ&dr=&sn4GYg2g3c^p3$^n?CW`5yc;^pAGimutmbv41SU{-?tJ9OUaqLgSZfaP$(# ze~-wo{{rz9jEn5bA6u~DT8_W)n!o+K8%w)))${Kst=d;o+LvWGejNA*)DQBV#74x6)BS^&kL!o< z{BgVd7jo7V=N|>w=SFIuh2(e|_siPlC%P-ga{Ny4d{&HaaeX%0rCq*WxLszBe~a`l zn4d9LO8d0UUluWnUos+4ywYh3vIB{iyq; z{?R`pU)>4&jckrzUflcaB#z$$&Q~@0y7&i>PfPDVm*E#}U$1^zP38Cx$oPwL(GO)n zdtXxi%J&QA=lJ8&<@er4`N|*sIn|V(cJ{rV9RGAF-b(&)CGNBFZLe2|{{eeP zu3h;v$Bt+78|SJ1kq_sc*yUf!Hm?w;pXSAg{UD!|R{H7jceXT+|LCm0el$2|z^Q(^ z++8l#M+U?v<1 zZ~o%igti+v{#M8zQu!5#L+#p6-Ejlwa{QUc{O!jle^)8DUH+Lp8`<$!xm?-2rWYXp zVwv}`%in$NomH-GCwL@K`m`_YN`0r|0VMuDarzr$lGKgRz7{2m>e~?azpIesbdZ>WFdyPzH0)xX-jy4e32V4qdr_m6*+>EPc!fVjt||3BV5D;q!0gZ>NU zSC2`*L+ioH{!4WKXecLthXT?*&EL9U;5kCR@dcb`V8vgy{Ie4r|0&52Xg#2QAwIXO z|09)+&K$pWCja(@d=2c#F8^TO&&2-NfchPKTedIsKSo|T-qqn8C%gQQTIWB=@fX4P zn)03Y@9kdvZVAVq1oQi7KPbQJvOF)xuKZU!_Gk0Msf+#X-^ah=jKAZ(4ea`;1Ml#B zeYrFLcJi}##QBB+^}B@lPn2K%(pmhxAlH_e9DmhyfB%fhxi=r zANkl1*o`07#cpKtKa-$-Q9pRj68cZO`k8X)6lEUfAds-zAHq2z4G1jar}ifrGG&EYprFwQcpR{ z4>yf@_7KNkS-^jMtuBN9cOT?Eu_Owj2gD~f<$sd4rZ~rcpTt)vzmn!mKT{TzWAhu;3j5o?2IpvD`%-Mmf8%s_cK+Ax zdp?|8v5xDL(J#1f!?}AF_51#gkE(I{$+^qlzhT~4f#)sY_YizQ{vkPc%G(@&E{uQC z{(XEnXTz@j%-ZxjyFTy;$qyqR=V|Ton+|S$fRn#z46h%j{nx+C&u{1WC#&*&-~VBA zeD}q(Yx;5g$RPEL&*`?SpT{{|5gfmv@A-4mK2dI``dMDOL^+PX51wC${s;M3+O^MY zQArxdkIEwTAB=BTKbQArD#r2Mlm9m#*O^+iujpS-KH&J(j`MtXd01y*(|#@=8YIq- z3y43f`kw#iU%%+z?CR(Ayo#*<&s9yzFTJR_egoFcARpgb>F51|qjPZbSNV$9k5l_! zQ2d>B9KR>nKl-;&_b=S(+l(DQwk7&UK9+Xv-{?}ICMUn^fYcAluj4s{6`YNae$1A? zJ;(2o;IDt=V`+E&#`Qn{V&xxY!N+xoR`yf1(HCs|;3E1*xqT(%39R_f)Tw%g)6W#* zpK)H+ssCKJu*GGL{}#;;LtKt=y508M{P4SMeyPI8{`Q0NW4pD>uhu?!DJTC&mv}yY zk6ru!=5{r9{53I;fBc4Ae4ZYbR`olq+^QX%{5^?(Mn0By4_KE$Yk2@0bh&KC|FBcUN=kEvfFIhkEuU{<|@^233M|LOfWY<4e1U|~| z<2xL`Kfalrjo%Iu{UG0`C!6|NpciK6N7_^UfZoyn*sb5wZ$I3`=|2VhzfV6{uleNo z$S!~1FMqK4pTDVofbUd4H*bB%&abJz`S&jx@((%7k6pbzhRqKbA^9I%m*&(zkH0i! z0H^;6Fn^8xuUbyVZ7z78m|gwXDPFh|$1i`~zkT63lemA!uK!tiU?rPBj4b8zpStjo z7|-H4ium5jf972^VjCy_AH+W+5A#3x-irTO^{6!*e;@QOX#dE=(yo4nROrq2Ux|?a z$NI&%R;dB&&~3&KgAN@%%gO%^>3@-r`-1Gsf8VtvFUP;^dw#jJBjjUTWtU&F&0{wH z`3CaC0s5)tEdG2@E&pCl{yWrv!n~=|{Sg~`ZfEnK$4UD_{Wx78{;>bc?Ec)aIsWYz z`A+>$pb(Z?4`a!>JSO1ll=Va|? zZngi-$99}Sbni1WpGy!=k%|LrT={>Aa@2GI}l?b^?8wQ{rh+rLSCi1mvl_VZTyDbaK{ zn}4_q{Ug;s^06IT@gx38oyO@W-!NYP$hYesj+cJO=Kl-j^~L{Q5q(@-pEeZcBgsEN z+t-;ch$y&}i24*ff=Upy~a8)UD4 z$$Il?7LLCV^4r+IE018@j{1j^s6U|nPHa_@^`9My{#`EF?|SY@xp5tk7601eX>W1z zClbB}``$6W)h9_mXT`sKY8IRS_dtAt`uB}{A^(H#t@zujFYCg|zm&-DZ@`qdof-@bgh zk)5B~1Nx_Y^%rOPpYn4%vio@Ye)v^@FpGx$D zeAEyAA6EV|`Rgg{`8g`oFZyR6|FE<5ljSSkV&l)EC;j!WBbSs`@+Tw~8O!PCMbdte z?<;MNughO-#pd5;LPS%~qB01Z(+Q=M8_B z<3Ctvo*(-^_$hCyO1uqz*Jh`$a{9>=n@Q1{o9930%jT#5p{Cmq=VPbT@1&&F>4a+b zmGpezx+QKd;m!wMGt@l)S@6w$02%9dU~Y3R?3Zkc_Nbhadb^yDi!W&XR?QnB&fm^M z?Pt$vbK{E^rfAbd51DR15#7!6b-y>y_rBXkaaC=BSYL^JEVu9JS;OQ9%)g)f#ni)G zVVm+Nd9>^=@%b?Bf^xmG4-7Ami`OswkMp0kHerhUQ-AsKeDCl5ocDzK*ZN97=Mx-WQ28JJwXF>&|J6mN zema}-f9`KS2x#>X~cn8$PF~ z4W2`cuSC7zg&7xX)iUJ|I3K>H$=CXZDO;QPpTCX%Gpbt&#VAw)F}{-Wi|yNXh2u~B z$n?+s!j$B}{(Nj-`t;&TTL0ocF1|qhV|k^wTjUQ5rNa5%xB9&1ZBklo(?74r(UGD= z1=(+hTr5$3EU!+kDaP;hG;)4;nJ4D_$k{B4XD{r_g?-V=ewjbdQ7k-@jF6BlOXOmi zcU;Ooj{gsgFN~k$c-MFe=bJg?ugEi8te**xzwcb>Z+z$Ot&(xSegNdpk*wH}|8V;h zk-rMy58E#JzV#ICU|ey~nSOeonJV_D1n}qVmV9?V=_h^b#SS@>KZ|GBGaO&jfnQSQ z-Ecf@AU{(dTlzU#`e!lz3XuQSSbsi_=k&w>A8&609!2r||2F{=K*XS^90~&{1Vjko zR1QawaEK5tMMT*U5{QH(Bmn^h7DVL`2p$}Yy5fBYQ4m2KZv~a$!670mDkz6W5e2;d z)!Y5v%}%O!H{Z|m`J5YD(hj6|NR$w-tbX9-vQ%3+bfs< zmmAzWl;hW#s^a(R^;$%cDqm4rx%js}I*N_I<4VOB)Acx{-lxpb{6tYK&{mf}!*E`~ z-o5qMBrg7iJr&<^t=r<=QMvs5HFWB89KX1_F5eY;J_W{wKU4fFi7R8OKUa_22#8uLFK!X-x6&d-5Z>{#b?jpReQhU#6b} zwpVd`zfiV*jl?Rklm$17yjWi!u^+-7#ZRnJ8dLjl z_`&vae7FMtX?^};KZ;=culY4%Z2x!Px8KL{H|zGz#=QRoRe!u+Rj&TL-F{FC$M5*8 z&cEh+2dnFVy|;4whrYS%Dvtl|4dHyD-}@C`YkqP`O#Pp}3wE;kAE?V0`9b}0z)viR zseZP7yAgZ+@}hnsKYCo!yRUNjnb>*2^;~}X>H35C9lZ~!{Y~ZgJL=B8mE(V_^N)T5 z#+}7}#jg=#|E=w~CUSr73ibbA7vKAhy3RP2Hbklkc;OD2Q)v%_IdSxzud#|9ew@9 zd9KTJS z|1Rg^KeM{JxAXp{^HNRsKYvjCuJw!KYO5*`_AmN{u+8_hkn?{k)c*(d^*6}Z*B1x; z8i_ISOS~`1=gSrNRpY|r_uix8_8!#ncP*|OOZ>gRyi7j7sKEE4{@{5y`k#jszgmp# z=RL1|_cX_!r_W!Hi!Xju{8;<9C#L7i_xmcuU)(_D$I*Px7FCZN@N2|&|Fx>9D|>zH zsp}8;-uqNP!uyksKSut2-{#!T#Xn7-U*O~VWgo6we*Rs$Fp=Z?bomC~E5P%vBZ?na zB`K!s0YA|f6ThIwjq?4G3jB`8RQr$j37lti{*S8oV{P9G zZgIME{Iz;~0DRAB-TyyUIsWBW9PY~TtwZ7QqkkoSt{nf4S8ib2=iRRO?Ye55!>J_y zyS!iJ`i&Lx|NhJ2@q7N#{m)-27yqdtFBEb7`MbjT_F7fGc3I{4pB-;gm*by#K{y}% zbMdR@S6LZT|G(BJt#0G^YhCe+uIfJ30Y5o0E|&Y#zfVs??8ZeBi06o7wx*mX9jF=Po_|pvRZICv^NYz7$LU^Utn_7jp66y-D%K zR^2bTTJ=-xKNLUK@rMb`+ppyK6ZQBT^6uz;#l)XFe!BmSrT?&E|5kSVp@lxbz_)EZ z{#;4EcmIkGT>Odaborv+JW!8Qo~&H_Nypbb$npL9`iS^(e`KGk9REP}B~>|o6O5ne z_&p!#=XIwm$3Oe)c(#8s4fl`WpRLC^D#_12l(mbCe+JGk^b4En_W!TS#lPgpH_%ptO~E6R*K>~ zmE?CDQe!{I|JRit%xCxhTe!;^a$dBhPz3%FNmE+f|aiv_}phA9{ zx$+}^R^=;%YUgDCEtdA@@w@(I?;m&T_7m}oIMt3i;MY&95)1#qiR0MocGcIJs+Hrne5j|* z@!$MKjcLSK^QsLw{xsSjSqkDu|G}=V`P4s* zrT%>NPD8eTK8T+GmghU^s(&ToH9yAs|5ef)c6@bZqME;l_{D5}|656Zqh(9K@E ztKJRx_HxDdCR8r|-loStQGam%B5GHTzu}+9mvHlf|C(-p&Z=De zug$E|ii^L|=_ ztsMW=ug+=2@r8>Yd>{Jk%9U^Tx2}xi_GXFHYTCmcz*nd86aYM+DaZk(gz zkFo!AW~+MFaQqM5<$I@|7hX^Et>T#4|LY$;#MaN>H&zjza_1NFB+ji|{-+MMQ7f!{de@f><;)bw*S6bE!pSSHD3?!p9J6AIZwwQBj0oJ!Bj4O>Qx7>Utay*m#C($ zFZTJ0AM5zT$v2w*$?*^A@&(@;ult|%HNSpYOyeg@ratvL$6u}6XYhm1QNgd4788Hz zG50e#XQBe8)|-1aZJz0Pv&3C&Y$U| z$4|ibJge`28)<%w&wpDiImXVvnydRi;M;nAX{VC>4ZDs%%H?MXo}cRaiT;E4g386; zr1fZaeokY3eg)%4KlDP)kMa5Jmy^HC;^KEOKLqEO9zPU~HDAP5KVQ7X4Kd}{XX18?B?19AO&Rh?JhJC)@3PXFR4$IsIJ|KR)R zx_)|_RWANV2hL#QpP|Q>99Q|;%@se^=d;hIR6oYWf31E#=zCQ^7r}XOk>Xo5`0*K4 z>jIaiz(0>%^XV*_-(J<@nqQrmOz(G$ruP@dhR+XQ*o)qqp!Y{g->xf4dz=*l>7U&E zn+gw@BMr%Aug_FzAOK46JKPT^OJmk zcTrO7vJgoBg!e8`k8bt#$ff#I;r*ccpV0X8%@z45Uu$c3QCwUxem6hi_YI3V{+8u* zq&a4O{>R-#+Op{Ul^<`pljGn1NSyFQ;CnvlE)tpiyW_v*n9SYr|(8|8=VWz6gA0e|O=m zsK|Hcr|%OJ3%LAD?iDAz`SgC!C9?Gly?=-LQ`(~wz2DRcX$V?3zgp`2XE^?43n)L6 zsr|erynP1WJ zFGvvcUGbxQOKzwsoMbmm1lOOz@jQCZ-mi&Y;reBDr1rDW%+J5ErV!^w=RckKUPIzn zc)#-OHz@uo31Vd+ej$+8AL*60NaFT*_wVheas1kkQT?=P{?Gi|e)?U$zgZ#vdBk^a zs_{Sbi|*Ta1IKqH-}AroA8fX=3CEv%bDXd<{&#-a?Waz2{O^CG^K0Dy&cFA-6#4#U zh5UDDOzp$;%GV!v|Ka$C)T3Pgp*poceulr~hDfzjwk6?Ww`!8dUEi1Qru@u6{Gs+O zc>aD_UF7@K9LR8D_@_qC|Isq8N|gp_uIu|b^nRt)Aat~8xIYd5dWBE!^Q(BrJF@;) zxW3fLruJbrU0*&7Z=ZM2Lmlf2dOx}mwQpCRAC>=deEK|&|1kBRy$t`43G{w3@ypJm zwlfC)73=Dp%know!W=W- zA%5xFihQ(#@N?b0_9)_4=wGGoq5BtxkLy=SYHd++ydoc5*ugC}w<}nSVds-Tz$s%b3kv|Fg!cRDb3s2!Cn#`^(p5QT?I&J7;z);lDA- zmHmp>uk+rz>sv1WZ+55l;f@61T_4UzemuW-5#DuOqVi8|9XOriKXVPW&vzvVYlh^9 zu3xo_)%pMx!1@=+JO2N-`&NHK{0i6K+OJdnpHKIvl=t%d1b2b~(iY`~U%xYO)_Gj} zlXpAizkV&@ckvS`C31a(kPK>_H6=GAsj#RZJ9m5=EAXL}m6V-Zlv$9Ko{?$YIA6-R{cTQWR!;W#2}Ny(W)@D#DQaVl&CAPaCB&fC#F~;(WZi1z z3Z~>1Wlzd%J84Q$=Cp2BRzYTF=y${N({l%A7Z!E1#!e}mUh((VOnSFlMVOIC zAx$f4+gsT-7D8^Fn_1L$c<;0;$Bip!W0n6z0plZmD;LKhk-->KttoV@`9%fYtOE6A zI-b0oshRYPjG}3l%PsvfFE>m5;kevF!e(WUmr)K;QA$|nj%_S5DkBsT`JyjPZJU*o zmtNFAH!F|g!tdyaQsu7$hZFcK{Dx9Flns;qDmRUCZMB|IRFvOV{*#iClbxAcM9~EP zPdBS5rTqULUXY$!n4ecrBm*@-3(J2&;f56zWTsD|ykr(;Sb=g6)B`H3ym8a5>^v&@ z^l_O55;{yBefqefw!@0@3NqVR>0`6o4$I7-4}+#m8k<=l%VJV?Zf1f0ZCXKQ@4QKq zvWo`i_MVWQoh$Q#jH&7-sa!D?X3xm9S_exlH#2kGjLd?(K>h1x<>nP;Pz{xpv71E) z)jC-J3aPHCSc6oqf)*B~m#ekoRqf2p8^-=xmUD*`NmYXLA9iojswP!x)adLUKeB0k z6DhtSYW%T&JJq+q_2KJDbp7hD_E1!0^)I-vvlhP5iQ|i|sv+?VR?kJPKH=AKw3Ck2 zSxAL|3w!VB!qpuA&Lb**Cknr~X=fo70xs;(q+1{2_~+32DN>yOMg$zG_(Sb*F#zh% zg8$;zu-ASyKab;&tfCv*EIpnX$WMsBg@zuzzgHKYgPj5j2jIe%P3!q3$G2$wQHqtO z@}IaoydQ%6r(JZhkO~18c4J<pnVO_S1YcPE~qQKu!GTZl7^B z$M622;(K-cmLYzpUJ|Vnk_3G4{uA+gmv8CF@#pI^#y+Lyy?(eOJU_ws|860QNg?3E zo>~8+DjYxgBUQf6K$Rb{CA^=|_)J<~Wij-cNw4zp z=g)2_q(Trk>_;oQ|H<*^>yCiOuj;>vU%H^BkO~18wqSiuD#w5PQ5C;mmv5S>e49}D zl0v|RO&#CoV~)R#`cG1P@#^`3$HgB=_0#`xHDQ;w45*3!^U~Cr9Dnt3#kWVRermpp z|LzI;|N9e!=c(j?n)o%}h@Z#tSJ3@uK!&UGb@OrldiHgsc?unYuTcN@yxHqbj(=i{ z&VPc+kDHJBUs|KRkP1QGVdqa3M>+l%$-4gA>ilx^Z>DvwoU-b||82*Bn)uGVInz15 zf3D{1{Pc6xf8@tEw4IO&LENy95B-ggf2q#@OclS0pE#E_t>EH6N#hq%dxcUz` ze~Z7O>n|w;T-bgCEf2>Zt@}UzDE#ETEre7ExUebh`)}v?uk_RTAF9qT&zSK1BYw~3 zW2e6N9D{Czzk6#_2oWg~VSIE@mt-g^5guY+D{X|)L&0Xg@6m2Ft|&5jz7Pe=Ii|IcJ<$o|B{_`gj5K) zu(wa&HihG-Y*OE_hN<$+chyhSe|yq-LMjAY*bINddX9hjcoo0>uf9II_=vyw7?m$6 z1YFn;lXhOn@tucN`T82_>$`!USe4dkB!z$ryU%L)Hpfrzq2l+|yFTE^ogc*SJ5ou`|H@xzi|@JkUq$?3^}q7* z*L^K7h2y8{`FYm&t~2R;U*eKeYcuO{OH_(n({LzVgCCZf2%HEaqxeO z|HAg?|G@F5exci+|B-)Q+-+?CbEwY0KdgR+>JQdIEuDUzkP1P)fvxv@>0Mm>Ii)Io z=RegxKkZtl6!kMXD_%&2fD3!RC}i8uYO6JWrkdA0(lw6@*I#jn1`4EV0T*^oucK`L zZTTIFZ#Po?L;H{L@rP+0)HuAoriqXW0T=e*^u`;x{H*y^^Jl33t(%`Dhxi9jUgi^9 zsuplz*KGSSo#V^(wF9Ep9gMWjwp?o)0xs;R$;Ut9_;P)1DOlIg#Fy)AOND?7+dX^q zA&xKC*OuZ$i+_P7&uxvjN?D2Oq#-LOj@I%1sb@e<{0Dlx$KJopJy%_S zo%0pn_d$63SxUF;&O0=|eOI%9n)sv7dSMiopCmp0Z#UriX#bO!HWN}I$P27Eb{|{+ zZOwNK{HLk?m*ew^3z`Mg#P8=MmT>X6*Uv}nY(4%kFFZfi5IVOXN)Tx)X`cd82;zo) zqV@QjIDUPvuAg73`ssD?asQR*vxHO#xUjd(kGq`XXX^fgcfP(qO$?9!=kZkkx6?fE z@B0MQ#6Nv{&l4Pf-`l$W==Wy4)5H1g9w+_})kJciJ^?lH@1JmW634H#R`dI){-K+X z_Qy)j|k4 zaAC(R=zJr`@2}f8J4e+|>%;K;|M)iLe=GH$f1-J|q!4gnKdjP=jo-Ra#qYg<=TD&a z!P-lmpx=otRSUSVkET7wjz5g^srv8L>kGT%2j73XyO0V27xtm8b9!+3xloS}i-oHG zyZP@pG(Y?R?W6G@&C@1@fD3zDN@_gEm-{zJ@#y*!X&(o#)VepWjjO#VFN(PEHN4 zpSZqQ^O^~%5X24pK&y>caQqqD72mJ(G@-6KJ8;d3IP|kUGkwHIezk3 zRsVehRr}-SkFvZ@EO}$9qiGPrs}EM}F+8&4g44@&a4^ zvo=dP{@hy>-_uydZ{j=EnhB{8aA7yUHix~xcD~g0vq@yWNFcUUE#Sg#==Co9{QauI zDt<@Te^dN+4ayHG1YFqlZ{@zq<>yhIAMXw7{4(*Ag_}Z`1uRDFj^DUB|Aujf;QHL+TrTogc^b{3R~0 zim=a#7p3)j2Gqol?^l+|@mJFOAyVu)D*q;a{<%GcR0!gRy*A~}Z#n+BNs8}_!cRP} zr;rK(7q<1mp3^w~1~qIY#N5d7mk?Vj1YFq6*)JXE_@$jx{GKTMwDWrksSt2szwdea zW{&^O?~3oVQRlBa|2V($-|Zo!LcoR1e6C?_j_=p;J5l2I)bA;zLcoPR7nd4vZhWdgx3g1U;sSt2sKm4)riyXhT=KG`Y?S?&tR0z1R zmu&o(z5nW}`S!fX`SBB5Dg<2Ewh4Ez<6|#9q`u*c!uK}nDWpQcg|!>5dy>mf?OFO8 zcSMfgx}c|!3IP}PC4cI<9RE4AKcm(4(Ov)VTtxG?&!v6V8WW!s0xs;p;*IS5hmlX| z^EXQTq6x93Y5^Cv-SM-kaq&;p?VIyL`TT^&uS7>`|LOkAM{KDOaADu}r`O>4TXcS$ zDDfv+)P9mez=dtL-nW6{Z`Sq4y0d)zq3ai}FD1m53IP{($2Cdp^T!omsc(3r@Y9-7 z`$-A`7xwvsPoC!De^T@PQTS!VmI?tE_U`N7Pv!WpYQB9}nWr{z=d76<1)5= z5S{h)F$zDqc~2n~0xs+yN55gmCqL5VE9OUzzm(WgA>hL9cxlv^Tz=&Kd{VHlPNaSM z%Bkw2?E2;bHSv?S&Sv|!ZF}qfb2R>S z#3zLyZrGX&;@J6ln(vRo_YZF_q(Z=jEp5MwogekRZr{Aa)cw0VKmM-N{_mvwmj)LF)WqLY z_QO6d{v6%@+Y8I*Kh!=Sj8{a9_);N=8@AWSL%!ztUd{J~@hi5UrK2tqQX$~Nwr#(M z9eb?JGY0GW-&Eay6)z8;e~$jM zUD}Z5S2qN{!u;eD_da_i$CvweO7ZFZN7~0z?&S$VUSR8N*i@I}PiUvw2k%%_|I_^Z z{5_{HJwqaefD60ryt^;w`1ADqE0L-AB?Ksce~RZj{^#i&BZYtq+i^-t8;+lrqVr#@ z%GbnC-bnKkNFm_Do-y&BjR-h0^4Aid6ap^nxc%=|Vfo3retxZ=FN_V( z51#J?*5RSGav!4tMdhodRm&S6e-Voj<%& zm#;NJ)laXB|H?cyeque-Nl1ktZrG#mY+&d2)`(Z}`*r@^eAIujgV<8FfD60kthVg< z-c@>h&oRUge(B4dgj5K)u(dv`wT!DjLbnfMzG~m{UF`$-Wy?AVsSt2s_av{ zRe#)koL~9P+X$%;aADs&obeLJm+MbS!Tw=xKF%+>4wY00xUkRL7qjz!l6;Eqy-D5w zDt@{C$tfED{Fg4mE&&&|!OahS$HjluK*e{OsruvQZ@h=zuMc|T5fl=4Fg0T*`goP_=y|Km;S8}^v;`3d!}P`*~-rL>NVnZIcA zc$?!d)b+Yg&=O&T7UOr`~QLU#pp}6-XAW~I%9IJF$lP@xBcFk z9sjAiTYba1O1=MO;#;X*g;WT*u$!iSp2+3r>(6!l>87v0uInT6U)#r9!}k{os!Yzi{z)nxo^_xoYa0T*`s`OmQR(;2Ap?~B5> z-tI1>LcoQsw`T_1f0OI?N%0xZU(|oOj-ONrxUiSqvE*eg|8o7lfav}IO!=4V_ytru z02lVv>t4Q=@$CvB(Nx}YqZa(UdT*pr;1YFpY zcmBxMpK-c=(#wYdM{Yjy@4QIsu#rN*g>CdK%@3HuAW<41nvI)qXo;KH8u-idWw{4e4BU8=6{iXZAf6lj3=maal7 z1YFnwc3pOSl~z3ue8oGNZ-0>g(&Ed6R0z1R+m`tXx%kU;{qZy}AAiN`d*Z`%evv}J zh26Ws{}jh>{DrQcPn54eq5ND$uVh(As|l-su8*V;aAEDfJ(_ZSx&EURuV39iy2}^& zk?TN8g@6ltGOpU~9N#lr@$EnO_H#GgABj~oezJ+qFH#7&u%7N!*yppQ)il3nd44EA ze|`sIxCIyX^3@+a#Kj+2zmmS{kCGp`j-^xxxUdt&XYBZcT)$F^{cYs@%XKWJLcoRH znBF#li(jr^Da99sFW0e@3IP}PjTRH%;rMsx>x;OEum9*j2HszFgl^iYE#`u+Ar~^$7tN_N<%+?Dgy4ELDG;Tln_# zmAzEA9;Wr>Hc|hU6ap^nLc^ zX&qO&mMg@~U!M5qQjRazZ(I)z zXd!NXjV=9;a(ub|tQ7luRlX*^T!%KW7Oi&R<}avPhn?T`@=nEfZd2!%n~(E1e?<); z6@s5&->>?@Brg74n-t$OvphdkzCZP*+#QQvz8id<)^PlrZdQEpkh(sqb#z15mmC^@ z_V27NN*2-_J5mVZhTXgWI6FT4`DV?Zui|&F(|e*noqJb@o-3I6={du5xcGbjrug1R z%f}ze&kNH*47Z3Ic13=Jxg7r=9ltkS^>5wr|97^!e+j3D)|Ujo-~FEI9ABwOto*I}{?T7gD*Gu{F{TMy|qA!}U=kHB->Gt7yK0jHv(D@Yu|I~%O*!Io4 zTk)NteECiYb*aJee&#bSKNB?Hb4vH$T=~KMMd_z?gj9$-KTTRa_&UcIPpIdf>%Aqcr^oaiFgc$pu0}Bc#a{RA!`({6{+Mf?y`PqLZ z<^K@1KX27isuSeS&re_d@Ce7hDo5Aw1(-)I9L;XGO^peFtmLmy4&;?LCWkMpXkpDO-}e9Kph-UBwr|N1kZujKf% zz<*s`-%b1yVoQa%^E0H^16Oim#i* zFV~ufxcSfCp7bckm+Q+*aSZ(O>&yq%npb~bVSd#1esd0U{O+6e7yeNBcgK(R*;l{5 zkP30fKcx9;_W91kns5E2t}l_+v6pMvL)`q-kv#@*@!zV)AG|lH_Q%af`)^%$hL8$z z^RFnrhn;^FSRbFhD#Le$@fA;rW{BnJKDSiVV@dwt)Pc`$;*mr3ij{nMo zDkAG;l^<_$`21UpZ&)`c3#kxy{I4W--N^Cf`uI|OhgJDTS|?wwl@D?AZ+j}eA;-T^ z^PP3-{5A3YV`v?IQiz-X)}mRBIetk?)qV=SKb)J7{Cg)P38@e_e^t@_#T-_xr9VB#mIbQMw|?)+pt^3dHJzfU9G|H&wypNjE2mv$9WA#VQB zha0lR@=ks8hMsC_6x{r?;}KbfA-mOR@kpeFvz$HuVZCv!1A&`I@wOnl$R zt%OvFJN}PS!r-%Bh(7$f}6+`;6{i|E_{5oH{%D>;m|GQW*%YN!Cq(a>M z-PiOjRP|HwL-ilmU%O5hAr<20xBRL9(;R>8>ni`^b$xww#UDI>FQxOB z6k_2AZFeRAI)nC?s$0BMCFJLk(*t0+zk`)T`_o|G)IsWnUBoB%dysbRl z)ra@Dk$ihsIKRntal#r~Rbby;r@i6_d*WME0lWE@i@*K8q<6UZyA$6>d{g{3y^k%$ z&7bDtKl1bwa{tJ>B|F07AGnP6A0mEm|7M*Z8uko`iSNRTYtCvpm-fG@>)s#h0(w8i zlT%d)y+5v3^YMMT9<&s9{PoqZgZBZKJiAx!PkFxW+J8%~&upjA`tnPL1QHQxeP+=i zRH`U{*yB64jHLZ{E9}p-V=(&MY7EbJtGbRkgH?aU{!;r*QRS|~4#o|BTEY!;IDYf0 zl$(GkKKAE!@-<(N8`yo+XA}R;8%Ek3|LKoZ{i_?Z!Z z?{tml_#0kOd=)*lbDE2NoWaFs6MxRlbEk9sRo{j4?JHIM;Cc1Bk@#%lmp=8-aE@QJ zT1Afh_}^FUkni)+f%@ccsOGgs%m2{}=YPoYn>^~`zpJh@mF2hl_vUjre%zUA%n|vw zo2Yn$=h-4P?kBcHuAlGL`s96%|H10;{CjT+&p+yGwEVA``^<5U|LmLLe0y3r-}|PD zI~u=(r+qDsKU|+*aYFg=J+8{tWKH$w{h{fHIR4_l6c_c!#KrGT{LGOFSscIT2A+?+ z3w>RS#{cD~lr-ye9)l;XBy03{=|7&0N3S0koKCEhH1-@?AJlkSB zziRjS<2x??wXXBm`9#$p>kq{hZ>!H}hfMijY<*RY;~$%?#@tc9-d(zWey;PPZ8Uz? z8?UnM&+DJL>i_QW`j2`KYl?r*qsNDF@z-jkt}ns%p{D95g6G%cX83I45B~n*jvT+m zi{bG*N5bPr{fx$+y{T>|j{lu2Ki;F^{9wOD*C$i_`D1$=!YLj-aiJZ{)D#C z>i^^Gp4rUt{Q*(*HZ01K1YlHlHabs zh~sCO_%Eq`P^|phMTb8*e#7ro{XzV=ZlQg1dd1fM+<0Re+y5y#9GP!l6&wHCy8pb& z#s70zWWI>8{ak;{d4%Ji)b-PpA90WFCr0TXzIEBdO*#H|y55-h!G35Ie$MI}@8|e^ zborwF50PpH1!a_#e+?&#!(u z|7btmJmg2{_Q=HF=)7FY#h-7=zrG)Wzi9by_h-)+IQ}b781k?AvF3ka@AYjse!jl` zy6Y$U&9U;!?l}7)j=$27AGABM@}Ky)_W+K6P8D_Ca>tK$CsuxUd)l2G|8<=ocm2V5 z1o$XtQ~mihZp=)Mf5>%zf%<44(&Ga9Jcw3*o;z9dFvmZr`)|mPJyi9}?Tc0a*10aW z>({S^M+!Lp!203+6E`2{RkZkPwOg9U@ypt(mI3((-+Pz3ZXy5C_~)N`Y#zt|wr2SK z3;05>XB}&P*3BLAImb_G7k>W|<@ZOi z<8S?HN9M=czpdN+qb^+h^{YkU$2h(>>E!btb9}G9f2aE6m2H>1d_@bDALku4u4QW9 z91S+lM7{PweI5f6KtfeO;{lSFaeli{npS8s7d`tJHlF+I!e& z=Wp?`#h-Hgul4vI+Gl6D9yhUcy^OJaIBUqzq$NJya)Vf`MLGbWqvOH+cY2fv4`n)e~511bU!E>f9y?HS{(l> zJ^qRM>71#rj~A%xqyGhU9gfDYxozO}9Dl+?;q5>8LgxoI8o%0g&$8p62hIpTzubK9 zn`*ou8vo7X9j9>dzu;>B!4KA-82N1y;@S3j_8qEzqI|)}emtH(^*BV7>(`(~S>+QR8pkOI7<| z^-$+oG=9xqXOH9f&VB0s0{8FePr;&{j>dm)^;0ZA?MP%k`sva5$^AE9&BcG+TjBRd zh#S@(rqAan<(t#L3p@U~=X1pmwh#I_2>9YVJ)RhaZ(q0gHZJ~xA0qSZ82NQK-S;2I zkNYAr-y0);`FoH3&hZcE`eVwEcXVv+=cFDZ@8S5Zu8$l)${||)>2b-i@%mty1N zd7J6_IBUb8B98y~g4p;Tk7}n){Mr+Ce8ln3Du~R-eQLD)T%7b%HICm_^HnQE&u4Z0 zN4tQ}u%`IGy#1zcIDTJ4{kLD${j3wh%(zD4l>e$*S`Fsn zKNY&a_R8;~opidZ{t4<$wER5R=kj$N-wO4ASU&tk=?&i>l%Lm4>s2L&uX5* z_77LBQJF{o3iZYwrTQhFi(~8Gj%ZY!y?^iFI)B0U+@-E3o=;=z|DRepuP>LMKV9u7 z_{a;|{b>0g_wKNI9N&J*RsVH;1RwtJyi?XODVP@p`}o`|+2;!bzA^A!^L{WdNYN|u z*SvF(J%39tQZEpr{Y1RhgR0--n>n74s^nfP`A7WLK0Qto<@&q7 z<_xxfnD%jGKK$5vUWzII?VG;KKEKQOCo?X% z;?HPsc_WVhyrF$_&uhWF7ZbmA+gp!v{Aq^#WBe2O$GjI4|IdGVG~oDCUG>MS=Zm4e ziFJJM^;t*G=lJjH{xkY-;0wK;V66Q9Ia3li{+Abq_s@|Rr;_7`Gka&U_wVCfe7t86 zjJr_vN8RVIdwz1<`knW3^OGBu(fYYZ=qmTAx{kQ__bi)5?~l;>63MUE6TZ2j{XO0M zCkvO?HS=fv`1q$BKd}GTAc{Wd9O9c|IzV7Q#iidpUX#lI|@IrH&+DyLl2+o&hZ2La}A;VMB&T5xx6FH z@h=-&#^zt{&*dS$6NMkxo9j9=f9>`wZsX#Y`*S&xk8xGQ`5V}qD?Ht7TiL^ikAAr!ez~`mH$r}!`{X8!8oU)zx72ZFR`%l@|CJ5Dw7DDb%B*hB+OV+2J zCs~gwtAAbL{`$KqyPoCva{nn`1U{~7(fG+HSIy@5f&HhhGska_RQ>;G{I|aC_#(%b z`%ify@%4EfjbHbPUPm~-+<(f6z{h#*=F?`tD2jmH@aZYpzSS*ty+0`Thw_f3_F<@= zFIGqOgYa#XceMB8HaxLK=D))GadLksKk?CjaPM!0_EYW+<MQmnwg)b{R4pF2On05tzmzr9fMllO-6Hyoz^C-FUaPfEYPiQ_i$;SY9c;~t;U{YyPZ zzn}Pve*d)o(>QZgAo+Kz@j@Lw4ns6{=s3&mg8?q=t~-*da{Q4;!}+BK{;PDJmtW@+ zT-fDbo%oaEuYWt7pS+llzb4%#MT-CZ2VYO&_{odH`NanQ!d_IT=spR8xM4p#XUDS~ z|DqM){4xVS>CVXcZ`P)!e7~SV`Fi#G*oZ4l?=#~r->c+%_T|dgegE}qx7jao=Wk&D z8V|Jw`ugSG9|U=kd)JgDg!Y#~Jh08%b@+jMKlh)xRBi|89$WKq-;3`_e^QWV^+{B? zf9(Ez)g@f~a(@Lu@wD)g`BQ~drmq4?$c22!lRzx2iQKrFRp7{SX3}2 zqsY3|O0}kB=N9D`6?C(5t=0uoa*MJjWwxDEn4g~8%^I6tm|5=skDXqWSs3~}q1@k3 z$V|_-W(qN~b=H*JjHK2@IfZR|=jCQ)k8fkC519o;*;&~c=|!3PHyJtEnYl$*XHM@k zEn`A@?)c1W3h9q!H0?XLvXXANQU2Jqjg?tYkXJxw)krqzEK50@l%1Pd&~{j6Mp0hD z;N0F5(zA2>=Vs-#>Sh%NerL5d{Dq2|%SX}l{Lm4Op--6vE6A{>npsuE52H->A18+77vvS?jh&Kpd9$qSX_@0XcWjf=CNICJO>X+6 z%pNk`W3tD!xw$YeH}IkVxHf?=bZBPD-(B7ee~~vSyC`!~e$n)1LX2WFQa*xiR(ekM z_}p^gO)nf)lwM@DmdWkhv71GQ7%cVNyrTZO{d7s*z{2SOEL}3)tnuaYGoDbC8lnd3 zQel4R=k%N$YiwR#PN0U-AIOaJ^jp%ii&FCndgYCqJ~T6ZoF(gp{%U4kR)+eFqM8}- z*m^=yQGVO}%!0z~!Xm11xh{H6UdBW#SgofNWlp2GL&Yk?PA{04IZnHgwZ9hwKR2x)Z+t;!VPQ8bGe`Z8QR(@C|2Hsi{CHV! zGK!{I8F^HPrWMI^MOul!k;P|GP?=ddRF~Th3!J;D*_k=xx>++a3-T=dpKH@|rcfoN zLl~baYroYxP>I@xenB-dVR%7$MkZCs;T5Z7`%slEl7AJflYvhaDrN9*%GXM?I>GiH z?f&91elN9O^-5j+%azpg_KmJ8x>i-!MgQ{fb{4>u-PBLux$PGRZaRzOKk^E-kLCFG zivJt`P}eJ~aQu1?()HuUQ2f3a`RXczqZ49z{+6b6{j1?|tq+p^5RDI>Oc42WpCF&n z;kdD`RsJ^}MM-|LKtHOCKIi8phrs%$CYNj(Mf?Wt^-Vr%OxM@HakoZ&yp?=@q<<;! zuRewTP1tnlUXFkAINg8#6XHAnNB;7jb3ftuKPS`pLU6Qzu6ufZd?+&YlRJJ~SMhf( z><;s(eB+8;`9Fv5JDjRDgk0xEu6%^!N4|^G+KIH{w&L~4;r(NG`F?-THOIN~&0j_N zsa`{PXy1nN}uX*DZuapWX4_^YjmQQT*}l_{Xgy ze!Q7qvX6MPL;U1#T8Oe)ErQ1hKX+Vl;xO^+m$>q?^-~&utYPN+{S^PLA%4lX=0s6ONQ7sgSL7ud~p*IvN!Kb(d4Hx%D~RrB>aFtPGS-2W5%{QLME z#g{!;Dc}Y3t=F&dE>wO^@gI6)c^xkPAN2bt(fDFfWd4aq?%u)i+b>u5^cX?He3)n! zd568f-G&1k|N140kNBf;@&CbvO@Cm|+Z_MXWs&2@eFM0#;KKfL!31{wh#Xgb{1@r^ zi2FJHTo&~c7F^i+g`2i;@sE5UJU=Er?ypV!!(-35jN>=c?{~%N7Q*hQ#sToW1r}UW z{XBa2&x1IAij~!-PZ0GKF=R{f&Fn;BX)g+>H7T{)E_t3^ch^(>$VKs$HhNQ zzu$}c51w5|jf*2M!Qbom6u^Z&^SX8OIsTOfzNb{LW2T?mMdRPJv`=G>fA?A8?Wgek5oxi5|-Sfl{H|)iWyKd$9_v!N&`N8{WcyG*YP4WM}{QVC&e(m7=V|{(m z@7J09nD{5Q-pH=6cZq(#4)NptG57mvI1Us4gAwi4bMg1r^%Li>iSMLFZXf0!ExL%~ zrv%@BQ+*WhgYUl`RQ)ZS$ENr<-cneFam9{+>R6C+O>=9!K@+`{7_a zWN3d@*a;pke*Y8U*LT~+ce;oBGsS<`lFRPn_;vLAA;J2o=gnciTs(J=7JvQi@7~Dq zs|V*_>ip<-4Lp=DKAYknJmdXV9Dj}%?|-WLkMz^ua z)KBmcw||A2ACJ$b_}5ID^B%{4SkM1M{RAJ@-&u`cM{A#NJO1aB9REHYKgu^)p6Ius zo@(okANNPkrj|WV_g`nY?@!O8=a=@GHH80sc?6;HjeZm9e)s)q!nec{#d(&PO`qjH zbYiI`O6W844u0oFs~_X|#bb$oRz?2kx9Pr;p2wBUv_x{D6&ycFo@I&Bf{Oevw$+sL zhbqMXc|95*VEA2aikIT|QoN;;Lh+Z;XOTG3a_82r-%sloR*!Ja{T&9akOu>oL#H9 zUN?V)>L;4kIYF8hUwj~r%g;V~zU%EB8eg)Wdu zR#jM6>h<(u)BBL zy)W|l_s>u$dpE^DCPMsG;zhnU6n_bQ_RwdvS2&JqR-btV#b4q1*LI5ENe4fa-!J=7 zdsc2f((m_x#M{Si-L;O(Pg^;EHyfoy%yoQzgZ`@0jr**~|qU6I`!Tx7HeRk+GB7$vwP1Tyj@8sS;;A`5S&u7tdAQ2p<CUC*b| z==rRZOZ?Js{&iVGy|*;4l_(pX6wH4KeYWYdn_uhtC9^sHIO5y+X1?vEeX(u|@g4e{ zOrPESpKq(tljA=*oA{H>{N&qPiL@I+{1W=?8Swb#lpo^DeT`&H zsNb7Mg`ZzZbbggT-@t`E(f*Qrw*FjA<#r+VprEo|&!1m%-yRwm*ewan^7t|2)`{kd{qWvtszl$gt)J6PsrYdhmtN8DxFPneP#oxC-@tcI=_io_h z_eJS{zP_%%oZnyJ`CVt4Uua!gEfBkm3iG#;bcmjfs$Y)#F7GGmd8GRYKEJx>crJcV z2b%w9h2pngn5W#d%wqIhm6xOy-)H zojWctb*X*l@EJ`7^yf4kPR6RR*6PalG( z^$j;-%9Hi~<{&(3(q496TRH10v!IO(DzhMqCIDHt&TK;yzVat#Pow`iHIHUWl`EDu zR$#W^aLP%!AGyhU9yU)IRMdg_Tk@Zj-hl~$at>EFD=@Q&rlL_ag_xQpCnTxA5B%S@ z>hFgKeodDU-bGPxa@6p^1iq>1IsFUMiV8GzV&?Q=G-I#8QWK@*+&P+=MSoP`w{mJ$ zdg~if{$Cdc`RMTfgO85?KlteU|K3ON%qTaHbyDH@!q61HF*LO@J0s@FisSM!3epQ{ zYO9>FD9hX|=$FBMp1ACNZhx?n6x9=Qvh;f-eZuGYHyU*Eqm!AA=M=C3p+IL z!dp21zv=N5Cr9}gTf+Nc4?aQnX?y7SyR{5xD#hcc&uN#p3}~$WNA@cGn)5$E?|*9# zQqS$vT=VEwrl{lfT$m)JA|DR@EY&19ZrH6~et#$DKj~)O6OLEcaZkX1XdcODGX6`(G5 z{z**&zp!n8Xx*GU{vz$)iBkT)#VJB6{QHY39#WIQFYKiKU3zo=pNIb_$De;oijWHb zVmkSjY7qE^U68-zEY5%Di7NlTGa~0d|1$DV3jZbD>3k$L3H-wTd2nEB&cB>r91uP4 z*Hr%#uO#16_4)6mpQV}veqk@Wq2pJa|5x<>vv|NQ%?K9ZUQeqkTFwrm^c-*T*eItec=2)Fki=>$~XF3poFBe!LXS zyEoOpvZ+-6N#Wl^ZIM)yz%T4uyJ|eg`QNIq|Gpp8xP{4oehbP!Dg2kTqWqJZ1b$(= zopT1efAsgd{q-eAu7AaORR2lg-=b@gRFl9j?1{BYFXWDYxGsPH*^%p?@5v5AD*UHC z+d)V*3H-u-^5<6vIR6LG{!WS9|4Dp-d`s2suYX+!A=M=C3p=f5pRJt#Vw%4o#joE( zROKHU=bcYoU3)jZU%RVgKnK!bwe0^U?&%oNSp5&I+bxar@6-OhZ>#>l$$ts?lM4Ty zy&dU!Y3%*qoP`MuIsfwg5h-{tCDMB&@?8@5dnB-RrAsZa{iCf{1_>AFE!81?LUofaXoSL zOlVJwfa3l`d_}&c8U%h}2cEb0X3l^0bCrMbE`R)Z&&Ju+LP*7XHiF^_XpH_(ebek4 z&cA%WM~YX!m*hTv_?PebNQHm-o{v$>FW=9SVm~k}@Pn!T z$@jFR!oPe^OR7oW7uI*`;whYeKm1=8`TR?qMePkK{1?xp`bcUL_=Uaxj4AB+!^0Ws z_^l=C`s=0nF>(Y7&pCFtqxOg96?)#U7tp8al4tqih4WUufX3=S>BEz3{a^Nr@-G_d z{)emm#dE6sS?3C=HF~Rf@@La$Qj_4gVgFq8V-lDDP6M?6Cd&Uvn#xfA_~GA5Ia5f5 zf17@mY7+Q`O>K1D9?pMjUH|<*DgPeVb6)sQPD&M0=TD&Hr|0^Ktx^LTtN)P++q!Z7 zZ@)twzf(oeKl>wm{P84}zqN*pKRHi4FjqYA?TY`vFKovx zFaOE;_w-Z#9ew_r%HQs738~1xzrQ7yYA05k8}P{w@~@FtE%?b=i`q*aW7qO zN#VbAU#gI568MF!{?zYHIR6Xv^G8SL-{ik|XR442|DN5cLaIsN7j|-&JuhL;op0b zekL^u{K7t+)At$9|A^5l|33Jy!JmJgYx@eR@GnO8rB$a$4FbQgsi*F|i}QccW?lXl z>*F{0FKgLXNQHmno(11b$&Zc;Rw({KeX?^Iu(`e+K`h?fVL; z@Najd{F9mleqq1g_!Haz9Qmw1{wV&%x#Wu!{;m3y4^orBFKm@9|FP}=ZQ8#bANlz6 z?Y=@P{QG4Bp`M)u8{VTnI@=pr?#TJ!6sY&1$_M^{Q_T~KB zbCiE?izw$`BAtJv@b5djuaIgI_=SCOLF#GFf9=7#{B{04kMq~x()0mBD*RjH1_-Gp zfnV5FjYjn6{7=&7pPit}-{e1k(f}b9{!4Qy9#WIQFYJp;7GBT!|6#E{{wV$vmkbb6 z;lFt403p>R@C!S+{m}uO{|_%!{>4pt{K=4i>wd~NDg4_j2MDPqfnV5xZ5I8<`5&O$ zf2XCYf2RB=-!ec*h5!8NR34-zfnV5jzL>$@|Kw}`o}|eBo%{hpD*Ri8ln+vqz%Q(4 z*_&+pTdeD!XcgIi*@6K=D*Tr$8X%;a1b$(EySL6XF8>ef{)f|0-T#{M?`=xHrRwnq z`(i48Qj@?h?E0GhMsoh+m#F$@w~l=LRu<)(6#ktFR34-zfnV5x*W@R2{(ZRqM5+JD zGpYWO!oP3M03p>R@C#e(`GspZ|9|vU$M0(tIse61)A>#c|Ng-PXg*Tx{*Qci;s(xt zf$slV_eJ(^T}JsQg@5M?%0H<|aNMxfj;7>u{@>O4_l}9&{&-Rb2&wR2){)K!Qj@?h zZ1>lzW^w*K`ubMENH*3H-tiYT1~b{}_LZZvUhBFI`608&ddB zzL)AFsY&1$w#UT9?DNMfE>QmcQO-Z_b>v&BK7QwVDt}Uwz%T3{Yu>2O^Ev+wv$cPZs{bbciE&p8sqpWKzgkE&3H-vY`DZjc|L1R9|7WT3C!_y53k!FfA25!GpR}7 z7k19gr`Y~?SNOj)a{fg#I#yEnPrR7w1F1>i7dE?^^9OhQGp|s`FWM^qK12W0Km2MT z75;tK()mbg68ME}JM)oKod1UN^!Q7a`>Us${L zHD2!cZ@E#of9)cdfAXDI3#st$T|hsRngo7ft5tW#a{g!N{9E^{^UqZNzHU_CNa5da zQ+be@1b$(w40v!H=Ra$eI)3li$n{TLPrgXuzhv~)^gclB{tvG1QH%4xKp($f=ihHS z{~qlx{G{;jeT;r4H3^OzcGT8&<2nDI>hs^x*B_JrlIQyisqk-=^cPZ10>7{?JowUZ z&i_x^zc*RcKa+p)1NkC_f9GI-A=M=C3;SDtag6hSscwI)_L2SjpP>Ac!oTO~{z9rr z;1~ALtRC$BS2bJJKS%d}OvhikuD_59|H-fR7g9|Ezp&5mwjbnqZV zgZ^J9|D+~?U)aazPGH}Eu=V_B?`-}2%~1cXpU6Kc{1+eXFQl3Teqn2$aehDU_}|^H z+rL_R{L$b)c?TUYDg0ZXQ#_<5fnV6G2oQA#(XU zZ&G_l3jf}B=x0)sz%T5~T{GD6?>b9${m)R>KU4c-mr;3>!habxs8US=zpy6{jA_Ij ze>?d1>iIvkP8|3AJME7CLMr?x&!_W|)Fki=TiEpt_WdVsN7etdo2Ye!Y=i%j8C3sB z;oq4>XxYWw@yqq|r1Q2&n<{;hkdKTK*8_=SC-bblSr z|61MubM$)1a(%t>{xScp|pWTZ=8RRZvXAG)cLRchu*(@ zi>jsXi|QhOOV5BN71DYX+v$DGHz*!blfWVLZZfBO!t47{xXF>*7{_ko3 zwq9q^UH|0LCNlr|e_a*O|9Yv<4tXx%`(6(DlD(dHyNr3N%s|8I7^G?Vjx z9kP83)yPFBACPCg|SFZiz7w-7y~2q{4q$aWf&+B=8Hn_1g)%IRA~h>f^VS zf3NHMBmFzCP<^}43h41{I{tn%ANO9Ge@bc+_=Vj%eE~cF!>`xBu&-6+?@bJ^e@{G0 z*XCW-h4n+9fc`w5>OWn75)bwXXsrIXo!4atclW z=;R0b1hnzwD#HFEUO4nws!4F%uxpa5u;c$fl<537)W`4gzd4QaP3N1hQ=fo7K$jeQ zJ)Mso`UEsq|Mq=7+3Vj~K7IU+BKt4BvX77o|NfqRgjAE@xM7dH+@F2^=y_Tne-!`8 z-6;R0@b7e?{F9mleqncXKZm{l>_F>tO7R}n^?yrv`OEgtd%C*tY&tKXt23!QKBD@t z`MiL}>VNNZ&tJpUzo%(^FDZ_G|4gn^TfY8HknbPJby-h!59sjfRR0gsdLXB}2Q*gy z154xB_g^Nzs{P-j-hWCy9lrj{NjiQ}JzgYEX%f%_AE?hJzxX}!4lAC!yasptWy#9F z@BE>GAC&*l`3L{Wc};}W4o^@%wpA0w`Aq@}e{KuEu=oFb;3Lj|5uQI;s{Z?3=bv2v z#afae{FzMyI*;BzwZ5QENLEv&ZpZpF{KEcpK(c*cYqz&vg90@lAzP9KU}8<%85D@C$oU?bj!9`R}LizkSWr z{h!HyS)ZmtD*TtEH5F1#0>7}o*6sKY=ikxK-~898^WWq@v1d~u75Kx?!pF;kdMy`KpRhkK@@NZH5lWG$9g^jPeVIt>0Tj$?dsK@_I_5WrnZ&LX8<}?*j zO#;8LM;5MnlJmbG&p%s4u7B1PI$l!v_e^anq?!bNVQY4s`!DDJ9)12>KS$0#P5z-1 zFXTU;%0jA1;1{;~YtOOo|1aOHuYdV^{Kt@gyIWHsHF*3z==e!Z0>7|7ZtV3icl`af zEC1d_=JF4;Klf1kLn{5t_NR<~mTD6Ch5bIe!&J`yLS6r?!RGT%`WGw67b*OE>1U}X zfnV6$2GwGp|6QQRU#->V`X~K6JDUa+{?m3f6;e$Czp!U6+RCoK^qf9^f6K`J6ThYQ zhZO$v4^VlKngo7f)2rlkx`w(5*4cDF zM4zRa1b$(^{JhZ_od08b{T(MspMQ^q`^Wva?~TSnD(=4%w=@<~O#;8LTZi^${fh-v z0tjc5+E?9g@Sk>76CoA;^ZU^IkEAAnU)Zbe9zU8p{$joUhutdj@p~?8LhH|k{QK!= zsV0G6*pn+hWY51L>ad0NzOH|+6`95?K^)OPIrw>>ET4^;V=HVZ%h`qBM|=TJ4_?Q>B;C)53ar(V49 zrqX9plfW1?r0cLLHB?1bMpU3+quA5HNF3T)l4;|%S0+sc8Tsax~JlF)kPYFlybUEHC?7L zGo?~Gh(Z|GlG{d-`}hi>ZygGeZ^pF{9faI!NaX(iJZG)XIcN4+d*<~0e}Ajj)3f(E zXZCwP&${ll*9GSyet}%-)9*QGegF3NDszR7I{y9mk)2JH2>JOq7V!(@Qjfp<*g~8A zT^H#qL|W?hzaKw%potP8KO4s)et}%-o92IQ?f=R)`A^-V+dqE%GO$F*kKkCuFOW<9 z@}Hku>z|dmruSxy=+%gB~tn%`akeKpt3+N^}81gUTcg0TBiJWf7Jdjo>)HpcSL`)toIPU zph;A&?T_>?_0g3`4-mgVF7@#v7H+ojZ!_gz@Oz#AvLea-A1=zj>}Q%qWln(~vHa)c zQWqS0?m-*>rGPGf)K%L5*-?J{{afa2Z9lKx6t6s8>~m0AAeZ{KMqgUz-)3Z+@~^wj z|6cx21v-6@cR$u+O(l>^ee9k4t?S=Cc8|IK58D4_3(Cho*I$Wz+*paQ{?FRgSc&)r za;e`8ZL~gr-;e#nB?M;Z`ez!-+r;u$*85WLR8!$`9ikFTf8#r-AjB__OIKR-7 z*O&G25dx=Z|9kmZ@=Jx@sHVzlw2R8RbE-to14pz&d!(HoK56}pQ1#cX(`P{_y>0=%qe*@6|`~{bwnTMf?KoroO1@>*H+v zJo0bQ`QOWD`gecstwfmqi+}2^MEnA|)Ga4p+`z`K^SrVDH9Mc_J#$4LB{C1|A4z*G zYh|CPq{>g9(bGErWpBDJe*(pJKJ734rI!++{lSC1l!#xT-PHfu@q~5!L*F99A8U_) zw*P}~^}&0mKI)kPRipJ^7{?-hfn4gs^ie0<{QvsBnjhJx%Rj&PSMP!aq5UBoi}(d{ zsqa#+erMx1GwV-<*68}zkM9mYMTx}tLr+m5h+iO=`j3&>*73Kk&H4wS{dW7;;C*8V z@1HZrBK<+w9x1`Gh+iO=`pVybA8E5cG{vOrF1A~+ZE3*=JI ze5Bt=HvSo0|Es1h|Fr+(<*)h_>m4D#Wga{wDpkHg{lCF8D8h0Rwmq_M+G2$fn4erYu(h@#vgyIPXF$U+J4!mPCnuL*B8z&PsrO^ zzCJ4dZTyT}>Ryd%j)p?7_OE+EUmrSre$$J5{cs{P$-!OrJw_OGvD>YpLH{paQXuiD?6zuohWjX!w0=7%5E=}+&I z7=QoD^jC^@xd`_e4C7eDFVOGQlQtYR-^Q2y86|{G{A+&P|DAAqhqF&3?}uFKU(YP8 zW8)wFljb`!wg3I>5B`KP01(<=hGP-GKrZ#bF>hMiKeE501nwK@$CrH`MPhs$%U+Lu zfn4e>edqVL*?-9RKhQZb{^R~HL3=MT^hA?Wp2sT-ZuQ%y3)p;n9$1we^w)4wO{0Da--XR<7 z`4P*1PA>J*#l5=Q_)8wp{tte6cJ#n&|6WgjcQG$m9+z~+pHaVj#=C=T{Oa(j+cr&w z7hh=QXOGtXUCxbZN<{1r?oC&v*t1;3FOW-}_Dy5!`ggKFss!%4s_joMf3vG#4Q>eY zzwDDL;upxJKD(^jOE&w9v45(B;7z*z_xhjlpZ{D{CDPQye`F1wgCKr^T-FE*o{YjjQOhx(k-}FC!-}sw>HvSc+{o{P~e_Q^PY<|6& zjeo{!9si+w?DlU${TD&{V~CuAw1V^Shg$f#SJUs*&wh61SvLM2mjD09_V@m%_1iZ7 zilwIfaqadWu~x@-U}#k(qWWSyF5W*xhM@d`_yyWc{p9w(U)%Wo$Lni^2kH1-)doP5KW#p#AU1&t6nliI5)-)m0*Xfn4hT|2nOo&Hj*? zf8?yLm>(>xt3=4pyrixY@eAZqpa1;X*7YaXn(;s3F1r0I*Gqi<<@0~`(-?0HVgFYt zjz#)iWmj zKbpvozkhrU7mj>}^5+E%>*zE6s_Fput(dke2aZh~zO8X8=|B#uBK2QkXKR7rR@eAZq7q&j`OPl?HZYF(=*3Z9w{F1xT-h_~! zc@ORf;upxJzU;QH*79FvX@1~z9si@BDWCruWB!x-AH08UjP@_2F`h@9Z_pmYv4~$F zm-^0QZ$DtOf5A-64;ue(^_2h3`Xjzk-#AAc5f%3T=Hpz%FOW-p$!o8t+4##JH2f!Z z`t$O0fC$3=th;MP!_JSN4ZaBZnK%~l z3$&a1`EebG+xS@@n)KIQm%rh5<@;aR|CHYt<4qv!e=NhXh+iO=dd}9N<8A!MHs~w3 zCEEW*(fl9Je=`0**bjOA;Ul7QGyESNkMPhDDh%-p&3C)%=buQFAFuyn{M^>qZ=$stT;Gpa{&RAv4^8X6-WLByeW&@M4ch;H z{LCZUD3K`tLyQNi*Cs0Esqr&%saxIo(^EG7WaIz9Gba7{_&*S8qeSTcFpfq10=d*_ zA5C3hq?|Q2<zm7;^K-8zm-?RHs#)KE{KxP^ zJ#_h-nJ4)#p8i?>hHmMhM82t`^P`vNJtvoX+{|I4ZT4^F`&VPXAHVpv9@zi%zvn-_ zYJj!;yYNaK|4J4*K!|KDU;eQDUv@+fCBpKrxCZVAqEt@X*go?!XHS~p6wJvh%AJ+d zan_uooO!*SyqtMOPHtXNm(IPNS>oWps@vw^{qY#|Z`K|WJ$L%(aZb?_+5 zNFQ-TRdnC;E&lB*a;cZESbL0(U$Ux-axP3$hZ^XCKCTacG}>Jf$Y(y&pCL{ zckQt8*P(oO$EB&BX`1i!wcEea45cBT`>rRG^(W*~uc`gb)i(ZhL%|=9zT%&Z{XYCG zw0k6w|6~OD{7?V)JLFRL9A0I#jUR;l&P8#)bE@5bFaN^XxS!ur=da0{Jk!RX1AZ`p z@21GlJ4}AoZ+CxZBzxT4Ls!+!oDCczklKoxf z*fDlQ_UZS2fkE0Yvc5#PteOh^adK3WE!UsWZt5fVz24kr{~N8UqTdSdj@p|1-_P#< z&_sP*`v1K!{J+iLesZbLJ^rZ6Z2Sw+XX+;K9kb7;_C~z?_wwD|RaCfw^w0aG|3jY~ z*$ezeUjNJfuHp0y72c@d?|S!_EVsXFqmyFoE7{w%1m}Li%g@Pb{~cdz3^U- z{pWk?zgNSDm;Q&ZKiyjXzlZVV!MSn1WAeE-{d@Vvm85^#O}%Y=W?lF{sr~f^+7-^c z_{1A8l@te6G9TX*Knz0=0;gZ8JhAkKGFbu#R~G{OE9`IWVQS?*GQ=v?2Xs-^yW_HF$O*;PhDq`U6t2)7#Nl5^9Bbph^M-E2`0_VvZs0$sB`YX6$Dm!H-Y7slE5*!NyL>rQUP>h%6ib z<{R|8bNZhg>TrM4?`+y9tS1jQ{nh;9j*o2o{x?_54-EX@@J~E*NJkt0q1!9wt3m%8 zey`0Rylvy}yG!#K|MYuh`f&Y!>-~K`xA9k2*ZIyb{zJ2MdBb?8K3x9C_tw44#y|Vs ziv1tX*Yy#()Q8JIW#Ch<+W5CzgBKbI^nc)NQ{LZa%H3_Iyfs?&`0vW!wr9WJ*T#R{ zQ~r?ev@q`*y!@NBKMvRaW7qe6+{Q0Bv3&hQe!y@;19bYQ4(67B9*h+@o&%OU)Ti!S z`;v|S`IGt=^uKCg>feX;c$2_c+TPG6T`mXC*5{F~x?eaL^ zO_Bd0UM&ZYNZtM=Ge2Ho{op%?*Ap1x=N38rrY?v z#Qp@nn<9TPnyG>1y6s@|0lC!YA5&;8|JNb?MH2YV1*zGe{Rqm9aO(aKAGiKEoBglc zg>wA5xc}W0`IEsvobta(RTK-A7i&))}5BX^8aw#AM1W=G111K zhxZSW1iqUh|8UzM9gq5YfsH>J<4YXO(}~$XHZ}W8F|;XsLh9|0zI|#Aw((0lBOTp< z`hTZ>|L*$mW!>vU|8t$|=!cg7nC_`BX}sbV8~=H%Z{Xexem@ic7uxL)Vcp3@ey7!F ze|_nn{@L!PKKI*Rzk;9i{%zX(D93M4i;iiN>xZ$vvV^SY|Csk^`uk$f11a|Z(QfK` z12)S0kEH(hiP+!DS&8-^)BiZT{j%<|1g3wk`)zJBNs&waMw8y3*!X{AeN#7q@21G- zy3a{q^8vZkM>xktZ2Z3CVE-Kn_M3H{liI%?`-3jpAJtP&|GSTVA=}0u1AZ`p@21F? zb*@8w{P~P0roV$c(+MVUUz99Wh{m01@ ztm8j|UGe_uPK>{(qw}A8kv;uo4KAPlqUFzKfBVU$ZvNNKzij>=z7G7m(y&*f$^St+ zKkRA$-?JI{AM;%N0=d+`6pUMI;}@+)`RAr7ccQW1hp+A|Z+~>1(_2&LpBAZaegC&} zC(54$zB9pY|Nk%l==LL)*zErU^Lw59(^P1NvEPR;>yAobx<1_c_qxo5Gi>}%`Xm1( z@STZv`@Q_bt$%C1^4M@2zwWtJ75ew`Tm?B)k2x?qedqD#jlLj!HfKP3p6Fkd42r7W}^^&UaJfhq6&uHb|ZS z&#E0QZ2X}E(Edu`J7%3tZ~5=FpX;2a>i?ZxKfc$-U-J?2|3eA(r^vsuFWSu&w7;28 zSpM(1`sO0=lgfWtUo<=c=uc1Q`Q$PX`ZmYC)O6tc3S$GA6uV>>F=qvwnegQ=hZ(8+req)c!gV;}6xC`1mK` zB#wVl*X#RXe;7)G z0|TA)dkQ~3{Z9Sx{@htM|4+rR2lv@DmA%!Bf0%0be~AIn|HZi~y6$kQ{0BzVwf29_ z1J-#i&UaJfmtKwjhoS!QPrIql?)lsgHv9M9iS(Dicc!IgKgT_%YX6C?AGWqX4+?*M zg8eD-InOdxewE=9>)Y(l+6g}<@SWV$?61)e`EOO~{SPniKGpjC{V3u;lE8OUc zlXcJh0^^A`Q=_*K#W5lP^?De^haK4trx zUuSLqord^#UP!Rttn=xu|4Iyq`G4QJNH?$e`=7sK`S)(Mk$JE`ss54mMFS)8D>MGk zyS``Q`l9O0cCqn~vbJb3&iw-8o%-b^-;cHVe+q`(xqH%7#x_&_&9ukA+?NE})f(kb zMeF>KOMTX;%`e&b2jKrm0^d!MKM?*u9R9{1U$yo>ZeNe||0UwzjK6he+3lBg_Y&>j zxddl-_{Tr(roQZ7yRWj@UmN2OBME#rMgHvv@pp&O|9!bCw2r@wOhNna>jeArQnSBt z9@5R`)Z5={W*xW1X8-R^@ci>_obRT{Z+pq%*?+LZ_2=67M`C`b`vclvtp8`*?O(5> zKbHOvH~l^I?$h&a{7iZNt(C5N9&N_I`tVo&m-Am({yZ8!ZUx?dA5-EP{~r7S?XUXr zc+528O}ypbJ@@P9BaVwO?(kJi_vE*F8>jWyadR+%v1hrz7@jkK(7Z|0Cge@ciT+(q zLBZ?-%%n9S%%;rE!{xkMrcUb5#8KDV_K>_D55D zJNc7%L7B2SB|bGY0aW0$&C4n3cy>gS}QdCsKSm#BByBD?8#@&nbkfvp?E<5k!O$4R^}A6cP8de z?Km{A2#K7D_MDu&$!F&j%_+!h@8rzOEt)iYa!$uVI2eEfWU$1*dV~7t`bW$A+ob-Z zx|kmy94+tf^aDbsS@NN$xftKyvHytuH~idh93jgs>c4w7Z)hvOGG+cm!u;jPJY9b2 z(puJv(Sh@q9dpk91HXP8a;cB``*v&lVc9CwUt{C*mxJ@|e9m7ce+0&_xf|2ftpibx z{-ejhn_G)2a;e*Yy76|K{pwEmAM>XvjA=lo^zv$9d{e^Ntj4S;WH$CFE4eg2Ks z{@cgVe;7=dKOJ0Px8KVrcM!%g1wKu#$H}Gc-LI;(|Dp)~4<^i?j`;97f0_0>i*@}y z9_y#r=24SNeaGixGHw2MF@My_!ThoDx_uhF)Na4bE0y3x|5r+ye8JbNtLljQu&m$a z3FK1$UFVJgHvSt2(0-T_=SNcH2Qhv~#_#RTw~yl?m->YpJ})eZanHLgZTxLmpUycs z&W{`>KYMH^^uHzZd7soBZgT6{{O@#v|BF!eoB5kTGmn+!F15^SmEc7G$JT6pk^Xn5 ztLcabTRWOu)<1pz^+7xE8+)H$&)kV?ew3kPex|%d;NR`ZM*MEan%EaNR3$$(P>nHO zG$`w0;oLdUAl8poT+k5vq%<&h6<53t_0m1p$@`61?+Q*k9t+Dy`yqJdAhhzI{)y`hQV<&8>zMAc5&Dv`Jr|=U&b9 znX3JR_tXj5>|gqmF8jz2nDGCaL z-d}j_ zqO48@qY#1Srq3-4wJtf^BB}ymGcK|UTA%Pbq4k)2!=3z&dlElUS+qR z^LHF$B**XgjiaI6)Mu^FwXR?EH~Np9E8_e}ihOB*hMv*wPi2`$LoW5>)2{l_=Ks4s zK>fcgK7KiPwcUQsAEEspY(~7}{pp)C?Dap>J@vB>uGtNK((~s^%wLFHD>c7PU*ve7 zKf_aWdS^bYEdSGP>c2+4XI;M_vn%31Vf=P*X=?WK{iWY~d~&J38nNX!oBxa70w3e2 zv%Bg17xCej%qpM%B>tVdYeb(v0{6t*k0yD>+EL_JE1qfEuxKkL7-#uAaA6O~ z=BHs_^ib^~s^o*y)m{|80a>r7&Jc|CK0Vg%3*%hvI6V$BN3@%I#PPSUwAnw|#q-;s z%I%l&%Zc`L{BUR=_KAa37G^ZOe}(P&qv<@9zk}oHCwQ%nfA96Ye2$+k`3L;3llhD% z>QQ&qecP7)KEU{K7von$rvE--_&T-6`+p*4{JLXqOxCY+Zm6MT9I5kO{Qi00W`6+vwC>vY_`RSRFXy$N!uYx14fgb3Vz}h9-}RXXQBGR+2_cty_ZwZqHv6x^W4D_y zel3zBpX1k3O@C!o7g*=dtODOzkNVe)9|+!_lBt`xP z89#PIb@g(J{(tb*CNh5~ssH0|@ZAJ{usAjQ>3=`_O>&8;?IrE+wbeh_m_HR68!x{j zh9CPwb0Fz2vHqj~vz|xVe=0fsv)tu%UK-xy71&?3*i-+v!1`rwy_%{F<5m;ve~!<~ z|D>@hd#7=1UD(V|8>z^+$e>nIl=1=t3{m+q` z?EY7mYJy`xnbIGI`J-8=|J=Ra)=qqVVe&_fI%%FQ{#}%R&hGg5vEa>iKDub5fqd?p zdToFFy=5Ldxr~P`_x3bGSDCflXisRLaujrskaL(~N z5uCd?_XcwL`Snw0%KWjU_#gKI^50SZ{H!anFU9w9ehJRAeu(qck`5|>b8n#i)CK=J zr^M#}U1z}luj1pUBDdK6&+%)H0p<5ZyY;3TDr*|j!LG{V|GBSE=wRdDdO7Of1b*<= z)cA8x1^4ZARq!a<|CVuV^gnft*GsJ9*SE^}vAyy35A9_8C(uQ&V-x=6f@lTE=RRfb zGu8Ib^4SkPW3zt^_Gb=)&+&u7+fuXtiH}ik;QdFPPv8g3I1a`;_0p&QV;w(y6UJ{i z3FFryKK%72-WmVgx1zHANB;DQuO4Z$f0y(>9KicWGkz*~yWM_{Un8ISll#?~+lwj2 zJ3r_>PK%mKt}jIl@Am_TEiiqBh1VdRCF~1dGOzqOIn=xkb)8qA zKgDMM_ZYty$xK(HY5xkl{p-#6F~F1bqRr_uI z{vqPSmwj6#IMM%=;=VEep!~JvKl8Jgnm_&e8*TOPu=kLTuZ-V+aHY0C_J`&`#&1am zq&*zJ6*;-5a!-=nnxFDGA{l8^m{WkUF%=9hGDC{=@5&D;YU4yl`UuiG&}RZh%@mH9 zkgu0p$M~P_UB^wFJsYEa3JY`drp$KQVlnodf{y241kLP%k$D5AO~}m~iZAek=tpuK z9poV+HT19KBN@|iv7eO*A+uvXd@~?z& zZCyV(?aIH$WIMU6;SeRlc5C3MA(($SL~$MdvPSqG!ay!{r|q4s`>PGRT9=b<72Q7| z<5X$$07{mQvXo=+V?j5hYX2U%PLS+^D{9{B9YH=8d>{W zs;Fe6yu-Tpp|X}yxz?Nq@Vy8FxzzQ#Z~fNB?|O&f|EkL^KfXGMYeQt*jPSF5!7+sV zOnfK8KrVHM_MMcCf6cd=uX1&NrHoUt*&lwWCH50)sW@Jx6vrZA^kd0;^wP(04q+gd zy6s6@towVoh99nkAGyCJ=IO@yWjGcgU#$UK!~}Aw=ik}u6`TEk8h&87o`3K7#D7`c z)=Gr_kJN9iMCgB2ueFMb5C8nfW)HFP8v}rOZ28DUs;&654IS zRjs1J@k_xwaSmai-P8x$RnN2W>u%EdFEm2iudx0_B7a0*#4q;pEbh=MDx)#(*4c@1 zGo5fhkY;ss{T*)KN{KL#OMQ9an>B3wb?Cp75Gc~=PsS-F@_!zQ>u<(>QggdRrS=j$ zFT(y3oQs66!rx;2PT-O*QSswHy{o--fAMK+48Ok4|6V@ZiOyGD@to5&R{n%=EW+}q z6vrYAw3|Bb(5q+I>_3F@OA;bJeA*wL-$jYg{!$!^(0;W56LLjNAeZ{~mUXQAOXZ{g zLV|OnF8{sbSY(`xtTU4}tYK8jPCIW2&%eFtTATe_O#TmDs^5#tIGx1w-#Q&U z^pj*a=^GV}+bKP!uM(mCCHP*1fp$}mxZ$);Hh#%7ru?adufP%^Kfh65B|?4>--$4g zOI>Bd4cVBPg@51<5386~(WexkH{T1gI<5-0JY{Z2K1G&_> zE53=?_+^G4u7qEDG}0S{_6HikUI_VFxEB!ya;f_a|Jd68YK-;wqhV3S@gF*>uM#1@ z3~?<&egxl%Fpx_<^vLDaZT4ql{I-NZBVGQDj`ril=O3}3I=H`%5@COJ{((A5WXl}< z?MKyA{yv;T7|5j_J^trOHvS*j|3ZR$ysm!~-cu*$|LPbY65NAvgpnapX@K%p>OXha zkf@w60O$8rSEaj$M8%KaaC-ZrZ2ajPjQ@|(_RBaK8Oy-uWR8;w-F3VY;dqr|9E;pn zANPm%C!tmN9>PGosoVGHGt0)$y5IPJjBbDU@kua(6qmf)Bbm`9(`i` zbDU20pW-HxXz5!SyY zI2MW3znxCQIOx-eSL9OXto^v1&Hu}n82js;8$FQmJBjvB`Bb-Wo!R}BNc4FZ{l%F$ z7Ge35g<}y0a;YzSZRwjf{+VA{2P>Im~5*&*#kW2mV8TU4{ z@zd`!_WST@e^x&1gV6p6Y!#vX0emOIKrZ#ujnBQn#(yMN^8>w1{`2vF=C%A zi;!Q8V-W^&sn;~XjDw7f?%w{}F&`NF>)ZWL`y;bpFNFM39E*@&hGP*1a;fKE_WD*E zKi}{JM^?;tacvRui*YPMehH367|5l5^r+s~*!b-k|2}-CKj(L(Hwe>TK8{70{>pGH z!ay$dtl_U%%b$SZ2ac-5{yf+ZiP?|iVo1z>9G5^C$fZ6sC}+RT{!z5Q6260Li;$m* zV-fPRa4f<=F7;PE|GeGCznbaqa{c`4Er00$vTxvD2>l=UcAyfW|Fgaus6-gZrM}~X zg{y7+3tlwo|LBVSUxK_YLi@9EEJFLkI2K_bm-_1YJFM;Rou>R%eJjcTz5A;Wg!~|m zMaVD4u?PdX)Fp4%>uIw;&)6SmSh4*P#H|SVr8pKLzYNDB4CGSZvZ~-A8~;lBzY=~B z*A^i^8^@w^S$ay7mmQe8QJHH?ZMe{Qdn16KR>YbzCAs`H;aU-Tsv;^hj&1p1wNev`r0=dXWZ{Dy?k38wwy>3>r_;C~nW4ey;E zmF(W=f7w=D1>ZkCDkV6Vb!ay$d(9>&mu<@@bHRWHz`m2e2_W$LNK3<7%-??HO zi*$Jq_p>csIfchZ#gG4e#()tvet4SZ2WIQ%9~nQH$bSL-LD6-dyEj(~vg;hAH;mT| z^lBaz89y4jwYtje**q$K{O}ngUbFH0xSFr>E9M8T1P>zo!230@W_H{BexJ4dAGy40^iKlIb^g=#$Dco?ypwUN+21#hN|Xoti+^Yyl~?xSdz?G_n@7cu zU;VzJRc-dKep>Ux&2{Fg#Jg*T=?x4da)ip-`89vd(WJpYOkeb@99j;kfM*9E-4h;M6-+ zi7=2${l=LuY_aicAJlxu)%CxO6HnxKm-Y|r4WEH`oe=sXGy?CRAr8jxME!AQOBH}H zkW0Pvg8`q}`0KI$uY_<%o&LQ1<(Nkz?VC`+2~pv?!=a0D4&geyWjGdLAeTDwOOvN< z{OLoq{bA#O8K<7u|9A-fu`)hA^YbQAQE30kdG@DGqVmjaeSeu>;(G`Kxzx+@`&#>7 zUY)4jyo&jydz&Z`@-x2z4?_P3;C~SYa;f)@`6B(S;C>+Fmw_$9 zKrZ#J#q~e7@h>&`FEFQK`!m0Xy%6#Phzk+=U+u?tA|{Yaec!`Z4zuyUHTJ8y74wU~ zLw;AOy|D^rJ7015|-;0nRgzX}<-+}K%7|5l5YQb;&Z2W9vf4CBU_zTzvAzw*efYAOR z%3cu$a;Y2d+P~e#uRF=)zndzyKllT#4JQ&y$J0O!gdh`a;dkS-uP3S{UOHx$rZ=H3$_UP zF4!XEhrkwLAeVah$Va=|_)oC?SFZd|&VLGR4UyJYqP>ImUonnFct6=6BK<)a$fb6x ze%#H*ul9ldi%7?c^PdviL`?gy1Zhu%_UEJQ5n&*gdfjDL9B1Pf)Bl|+=9i%DCqjPs zN0i49w*LZX`-w1+OI`Jc8h6|H4UGNH1r?{iQlxzm@*Sjo5vKoaqS@69G`6ckZ2>qW0 z--|GiOTDM+&DQaspFgkvB3zmOQTCN4lz$3oPlV|&jI=4jKrZ!pziqJgzm^%kn^lSZ zXnSNOv_G=J79l?qXl z7h#~?)E|#2JIluJY|0P)YuWZyoWksei*Ldqn8}5Xu4(26Cyd`n0C? z{l`F)|AS*HuKzOe>?uON1GWhH5!{;y1G&_t=ry<5-}p}R7h@Co@%GOH=u!-ST}?%5 z9UGPA7~&K-8S}PrF2er6(j$&lA`IkG4}P+%HT|Dw?03uYE$x3idqonSzg*ZZLi>a8 zy$A!j)S-6UtmR+Wg=zoQ>PlV||gtRBZKrZ!teg3kJe=1@7V^PKV zuMBx#g#0q(eG%GUjJOwJAeZ``E!$jM{QqRqe`H_9=|3N~i;(Zab`jd|!gdh`a;Z13 z?0TJzA2#+!D)E0Q*dpW?qwhn6{8F$*7|5mWKfR`P{L3_x{sQP8lfU)re+i=PCqjM@ zWuFN74$3|e26Cylb-i@D&He?3AHJpH`qx3)7a>0%X5ceXqzXZM)VIY_Km0urNW#gBc_z!fcIQ=Pn= zi7=2$edwmIt^F^x-_rI6ZmZb-0DLb(eh9u7q5lK$y$A!j)X%NjVV!@IX2zeW#TBPN z2W<}#@?E5T5&Ay@--|GiOFd@a+%7i%H!yssYsLQ0hOb4)55raw`acBUi!hK&J@3y) zt>tgY&)WYgsLNkjrzi3K6URT4+}=!yaQs6ljzzeBPhdqeCBi^1b+=O{e`2%$HS({} z{`cdD*EUlk$`QtYJ{%5rPkqO#0yq|7AeVa6 zGlN^%__BUXG?;Z;$`+KLf0Ve6jI1TY_noqijL1EB|HyS@WGxv6a;ZlwZ*r}TAIUZL zFV*oc>%=6cKduww^r)vqxL!<2w|YwCm;UH~#rUu=z7t^}m%8y+k8ZH>)ft)}%+>Ml zw~mX`vOV7Sw~zTh6Kl4J(Ekd@Q870_F7>lJYCLb{chP)jwa)*3{4lOB!uWSu;eH_G zXX03dfn4exgC-Z*_}N&$LxMZqZvXcf|DoDoeqVOGsBqn!@LBDY2-}|#9E&iJOWo^} zZPxiGvVM+)kXg6K&wg1)M}+pvIyxe>U)IqPVIY@!!=_8qZT1I@|HHj>|EK21$3K>J z;}x|&<&pB|jf=~l^Nd{T`imwO+xW76Pc)cybNuX=b$mo|4vD?KmPo|@-OqM4oZaOUl7M4EdSKi;EVY1`-M-;u<=`%{1?7U*Z*Go z$v4TfPUBws{=#dJA0Z61oBF&(rOL+t>0ML)JgCbbS-&W8`~}Cq6qof@BGpmFI2ezb z^+WHd>>7ykGz^OM1ahf|=G|bOfBwaK%@6m{=}+^M)1OoG6eYs+S6b^7CBpd6!gnGJ z!^5?Wf`{Vv+{hRG#yeZ_2ClLR~#O?iY9f{>Nxzt}Y8r8(+|7l|k zzwMZ)BeebT@<;Y(k@UylVyT+M^SzJj@!9;Inq2C<`#R>^_%-%x|EnTh{(JpT`%7#0 zQX(vWR2?Kd2+N-`d?&&{F7@*}dwy=?UpPhc19K|oXYD|GgODG@u?YFuI2K_bm-?CM zPgtM7n{)p8TsxoXKXXSPCBpO{#IXqXVJ*e62m`s)y{Ff*rvGUpO#E-v<&W3@IHL-QE7_U#=O-=^d4OpVox3NxhZG_Y=_m#QJ3+9E&iJOFiQ9y(4Y> zx$U+6PJf;M!?#NNKc4^TZ}*QLN~GgMI{%gY)x#L_2i z{E}`a{oiitpAqHTzwb}e^-JjptkVc#dn@xyw7(%mGf@6w{DF(_L>S1W-ucKi*8cyH zY5%Adn!g?wNNj({;{WN|DhOeG2iM^ok}&}O-y-8L@%#Z{AeXxK7tj4=vw!=Q+WyD_ zo&Nmz5nNk@{E}yCD-rUGaV)|>E_JgTrWM-w=^ON4g!}3G$IE{c>yNlKFyEpc=6^#Z zJp^!`nOP?)lKVJY;y3a`y#86=y*y_R<^xIk z^9FLM*PVY|(8mAU%>Qy0>iA#gN&k~^>Bu{1|9qVh6`B7X&F|l2sE`Q!FW+bH&4>!` zgIwyDkJ-M&#xLn=?C-DR-@A_AXYohM=%p7Fk)ZV{+smKxj9luf<9@e}f4LR=H%M?E z)&BSLIXuj{wyF|2Undt;a!u8!yh#ATM)PCpgGFCh-#_25L-Rv_+4(!s)Rjj{(J2&L;Ol8xuZ%{nj$`e`{LP0WTw+0DX7sJ7>W&Kk6o%)$gr~PK* zFSy$H|Fvu@KO4`V(fY+;OASBt6zW9CHmtuO!70(A&ywxG>4{_CxA9x=)cn9!JKt-6 zE6jIG49nt8?!=Fi=Koz8yyPkyU)Il*5Hjm_dj0?3uA@o6Qy0Da;T1OismA`$zx4B$ zmwy4u*F^t+0Q(c$-wp8mm$hjOaA3R!L(alFXgKYbp z1g*PYQ2v}}@jH;zX`23Z9ZY?Fk=dTEkMHtAX z?zFJj`uySaHwD_iO#8!A|8bpCm4}FcNPnZOSDHDyZd86gT@y>D)Kwx3y#$8e|j#~@tr>n?_43x`s?%3saSIb@(0=jk{%*csz=3-zv9%}7TWy( z?F=3Nk%x5rYks``?K4haF}xCO3`n*)58i<`3FHc-Kj#~ahr1npbPxvGO?^i8(li^t zt66_3c%d%;)gLndB;NiAjMVm(&FG{=o{S(r$ohj9b&ATA1!(``+#ATHzU--`*7nyM zJ#_qshw1t^QY!p-`}_PUun+Bv;P^IC87$@9hlu}++C-)LTzrpxptJG42m`s)X_wcV zV6#60TO|aBSIl?EwNWDEmtNRLiI5-0u?PdX)Z2C(oM__*h8p`T;g>mWFyAfCcW^91 zekP7Z7|5mW*6zT18$bJK&3B&G>Ceyq;S*sWg!a29z#kCui*YQ%KrVItx*OKm__>B3 zIHO|!m$ifa5b_-yi;$m*V-W^&sV7X{IN8SUXxiW5O8AjUZIlT4nG?W+kgsqY6>|gR zQa@Phy6!gq5W^3QsM!AePU!!HkneVc{~_cT<5+}&Tbm{q7yqFi z=wF49?{tR$A>?P`ScHLG>JIrGtnKfGhOhpu%U?f!<|terLVjsB@*jl!FpfnS$c^b* zw^-}n+v)!^EB1fcP^3Qy`GM2hC=v3ra4fGC(^nSUFa zit-ly3ngXfZ-B@vK51`c{n#Ta><=ixxd?-oKdRStKiK%Mn*QI=M(uyikJmra{&)6c zeb?uDL}ew~qf+1HztAHp@0H;G5}ptJ_&2}zm392_Vzd5O`{}1&APsV$% zLi&c>|2hcRN0mYL@s<8)Z}8gR>-rb#+w6b%D((NkNFD!v{QR4d{~-S@|H>sRt>aHN z7=GxvitP`9E#k*7#&;qNUi;JU`{rSr{SD3YXLzG-fBD%Tx)ywhFCX6(Lm0gL?deBa z`+sVg=g&wzJ^xqpSpQDe8_V2){12Ha=@I!MdmHL|NOT`(d>;rSKSCH9n*-j* zst>PUjP>gqdG~K~u>N20`5lnd$Q&jl z@n5Pv%*Ovo+Fw6Z&M$5X-WPFx1n1c}CqKVgcU6LOhAea782#&?$1eo`7~22K==srv zFY8Y`?`Nozar#A^Yu2IGxkC1=(LvUwme5)&rAF%CbKPwIj$eEERmOM!w~app{K&qV zF}`zXRP<839<`T0YpvmX?w9;bb3ncS;uD&HpR|8aX%_5H*uUL1{513T)UqzN1lk{4 z7d%_HhhytNo4*SgO||)~&t?DSW6Ivv_r1^ff8$W_%W9%;Pk-*1b)acCwX91mf&3<| z_3wk}XYnWc2j+j;O@015m%SnUu-QLozu_-ig#6Sl-l^gG@VCCLFHC+(hVj4I@78-0 z-t>Rnrp2FtpOpV({cC4OhT^`o6|H~mEHA(QwR3$dmAL+O1m_Gv9vD64r-M_){?d=j z`~N)fL%-nJ^`sF|6WrhJ=`VnF0VL4=J!Zdc_h;R2VlXiUi^_#9MTH}U?_Gbc*7T~% zoy1gzxcI})4|?K1zpB1p?k8Ffh7-m+^+KogV(^pF|MZVgzfQsX*74deuHo~JsAXMj z3ACT-pXVqk1@Zrv-TooZ=nK>Tlbh)MR%81K#VpqcUj9RiKX}i^Z*emA56X}8-4ywanE(6h z`}N?H;{WRP7s~!kN%7wX`#*%bV*Q?0Iz2mo+wBi|^4}wE%9lTt@!$Bn!wMV!l&Q#n z-4e<_AHJ*$E`k2P_`TuL4x+R_)V7jCJs9LKG8-Ekt|A)KB`HoqKT+`z9@8R;j z@xP|HfaX~IS%}!@-HIw z@BB3NJ)-qBA4b1ZhtB-)6x;soZENdisp{+p+pg=gfYGd9ygIb0{O`Q?;Z1*8 zrGGCH``P|v`FACre*#Bj#P)A@s@m=6{_V6s{2y(9s^#Cp<#&8*wl&@Uiqxq4>cCPH~sg({Eu*b{tD%Pn%(}ei6`hiAWPk(&MY)*f<>jlU55K;s1aQ{+dsRqTIn`n&Y9R(*u;&HuGW!v168e5Z!p z{^08J`7i%B!*6cS|6cya3Ce)UUWe*)jBnVS7)bkptS(54I7R3bX6$>oP%9qKdQ=Kr;aV1JAFuU#L$ z>`Ne_wYlKp2TlGr?Ev#}OnKAa&7IeD5xzJ5rw71q7w0>*?Dj`I=|5o7zhC_qzoNdS zoB!!2`^P7xzb(7r|Mu};yD9R2`p+x^teP36nqIT-31 zc_m%FldE;OH?H%V{*6Qdxzy8teQ>ai|MidP|4iUJb+rBDQhWJ3!FTqgtJlB}LZ@%W zeLNX|4?>Sp&%C8;U+|O4zjG%c&ZixroN>l}!)KvF9lEW&{l}Z{UsnI= z8=L)mR>6)d(_(z5uHAkw|7Gca!Fzz#xGm@I8mc;qr@%e&=V)@NPo43W^nWD9e{*DG zXGxlh4A=cBt`A?_bAo zQ+xUI{?hfo-}5iI)b(Eb;9s`*4_<-tw{x8DrpRw);$MAY1~3`FQ1QNbUON2JKV|>k zpy&Bt_Fr*7=UpN$%|0ajdup%!Lx<{mKQz1I@|RbxHFdM>pPkhIA^Wd5Uu3AjCY|o| z`uEB6Ph{_vk|pu|XJqe{;8pScXJqe{FurH-mcK7eDC{Tk?=632{}mT}2FL6}Lc6KG z_WwTE*ng(oex`fsV?X)lJn)m!e;LMqyH_Qof5T_FL+#~HH}B=5@1ya4cG=ZfrvmHH zGsH_m{mFzK_Fr+njQ`qAkzZ@L@xKq>8~^jVO>bmNf3p9I3x0t8DJW+W$DeWho$S3*+O&VH z|4sH@iQt^?|77o#EE$|;g4h2uwlugx{2%hzFZ-`JUnSUY_CcZFslEPZ{^Namd{Vt03zk1uBZ({#}K$nE_FGc?0 zmcJMEJx|`hb@Ar^dr|&5%hFUj``=7G6EKFbe=9sixAVjQ(fOU_9>4eYztMi`Q{O55 zUHl(5@z3{v8*6c@4piK@21G_#P=`e{eL;<!g7nu5bDR2^^na|~elP#Gqs;Sn-_-h_dcHd4MH|1Ki}ZI&obUc0@jucbfXx@8RF@mM;Iot?kd>-uCCWP4~0|KUV(o{aZ_nKX>QWj`7_T`Hf8exE~nz0rTU(_}ck5i~qg#Pf;$)zrL79YRX^N@Y$%KmVKcT`IWtY zXZ%wieEya*ZG0E+AHoTI$LvEzF7@H^hZslnG`jF$ueQR^dP&zColN`dxBI|9Ey4a2 z`OkLM=_PQYZh!GU4NiIU|BjLCjs`!e|3&uSa`$DZV75-jVyEr-SN7fto!30}{40BJ zm7O2o|48=UD#rH=UjF*)TTB065?}V;a`sowm%X?0N5%Qk{kP7I^JVX?5WZ(%zNc=r z?kE|5m{k9-e;UtU|I||MB2)jLV9)=uFP8-7ze9iO@?TA{_rH-#z4Dyz?y&I}4ng`K zm=WW<|401#BfgwvYI!B1-celF?n9+t9b|E9>_yVSHlU$pl> zdh_3PZ>?S;{D7zay9Vno2k(vZ9kUM`g_MdZ8;LF}~B?set z*?TVZYn&h5e-7U>c==;L92m6mW&b(n$I9)G?mxFb&X>LCLO;g&viDpV-!m}%QD1oL z*1y3|s{b=;f`4C{awnSdueDD9OcB(wFP#LIe_WTP81KIVA61L(L+8i;e&)mP*!az+ zq5T1VaW~Wc@!^-vD$i%X_ib46BXFpiT85>M66b}}ZsxzU|CzfR{G|N%!!nHjLix-7 z7pILq|3@Au&o40J75$z+z41S;-nLD`_vXLiHQ*28T_XRd$lvm&u7BA7NWW8i``>a; z-*LXJ|7|(?pPVWv|L5xGX{W8-e)Xg-2^jyUndc9`{x>iG`Ux$zD*pHO|CNCssut%v?GDp^pYa#*7}YV-EB~iQZT#*S{~D|w=evi=PqqKC z!F#W_20tnPtIP2I`hheRHvABgS_+*yG>JpLL|J z|NQd5xBU4m@QS?uOyd6w_Pg*ugPS5ha{uA=e;qq5)Xe7pWitOHf$x}oDCu`@wdzdIh!e^1tn@!b^pd(HDlsB>!VufJ9< zzSHJ^*?-Obow*csf!T+Qc2mo`@QL<6^^U23{;@y*F#S`HT5??}_(|o@aWemHZJHWw z<{!9*&m2MR<#S&&g;(CPA1U_%(s!BM|K0SpS1z%|e^Bb5KN9RW`*6{2YA=8H+uHts zxnFXrX*c!t?auj+&HmP~KbUC0;nQwvFW+lF*FpE=cQ4%(o&VuY{~@veuLS!$+si*M ze>dMhn)@Y}ns!sa_IK`2Hv7+j{gFib4WD*Xd--1bxemJ@|HHWxt^CoF{vM8}Kc|bm z{;Q17b@0g#@WANX{w!!E<8Rz8y53;_@As?l{P%d8DtSnkKd#|3-BD*o^byOS?~MN= zdG`KS`ki|F!pqOH`TwG8(EfNLO_dtHgKbLWmg#qDSr=Xc`HlJ_-D3RLkj`kcewwcC z3@8=q9)JIc({h3KM=bUSpGs3}@6dj64WD*XXS|~?M}B4Y$5XWayGAYkh|YiWw*USC zHgu>Co*gyc>1I#=vM#&?@>gG?f6sY3niBt?ey4uE;9hzEoK*e=-$VRAm!`5!d)hU8 z`klJOT$+5gzxW*HZGU;|pP{c0m+~j6{>{Yt^MMO%#Q08kyZv7N6DMl>LtX6k5ACKN z|H)qyZT1g9vUfkl^Jjm3J=gGQH?^!wFM;-RU3#uZ&voeauae9ExreI%W8-(f3+Z=v zn#wTq37j7G^gqqq2>D!>lk2f^T}<*b%mMYdwP()(KdJqD>x;-YpVW)-UBhR(r}pyi zG40>5SvQ=&BcFaJfBb-tl*GUH{i}N>%D+g=%gX6#kAE-!JX8PswSUQ_UUAW%^8P2u z{klOHUj;w7JI;5^I`s4>wb%Z`WS#JIRc>Xz@_4h;9v}5v1djIg*tw)Zs@n!vc z_o$jGaJ_zyDt@;0|H<0-fj{Hx&&%5PS%1aXpO>}ov++FxS(`G1Sl|HJCW z@}JW?we&yWb>03`&yHmhAv&tbr9QLM0(t+Nl>YW0{i*7;Vtn_1#P{a^A9r^78vLaE zzw2G3ze(}&XO3A1o<>p2y4Vt0Yo)%w+SGqO^Y6%~-ulBEM}ePI|Bc*-=f5ve|Ft#c zzu~h)qW1FVVqZ4r?ey4syjN^SJM!yzuah_ZKi~DT?qa|9`AgQncN*4=@twZ*`1kTl zIRCe|z5b)$jJwp(2fiw`jlce=9r|Ctrj@9RQsn0xtJ{klhe!@J{Z75`u6gqOljQ$- z&*S+QeEQ!x)n5O3?a%LtcGFEYRMs?K&| z&p`Ww@o)I_AGMd?`Yee^z+^?(R*n|FqQX=eS_M_7}O#|0CaR zDE)6q`EPJvJpa#5u;1`$H?`OPSpP#M`H%dwLT}3ak0gG7%)bqO7f*jqz@Gk{C-t2$ zUMs8rX+QPE51;*1_}=Hw<7E6-0^d!MzuL6dyyI?}{>Y{7-D5y>{GXR!4EqD;(@Q8* z%sS-sJGHD!FM;+yY}TI$_>6yxUs2!DrAx=&BldfrKYl^`PZiWqquKuV;jh=1iSe7T z{4whUn6G1seClwWZ6AT3RR75O>+W$iV|>S~!%e%Xz5IzE==#s8W}p8UyAgA+u4Bdx zQvPLo-aoos@%&l)2-WjwQ~vw#WnEqg^#6fO{d=`n&jZlk#{Z|?{N$BS7Y!4>*Z;Eq zxZA8|jPDGvr++WMnOXlNbhZ8YJBh#O&Z}(k-|uSFKfkBN_-=~)5vKj&_x$PQ&sf^7 zn~mQeuib*RYQ^}@z|`zNeuruQn0349XKM1PpX)mz-uy`Qg{> z{g34Geu~D-jFvy%_wm{#ou)KlaLlGX6NJ{jqKa(qBEypEUic zuHmyrqMnRL6bY@hQmlWu9yaIUn6H!8KmT${>3&=KD@OSjyt=lkZTQaVcKc;rXbI$V z{$0qY{H5L0{|-MQ<4=w$_00cJS!jPx&rpXJn)1(wKiaeY6yLw9C++1Qxzzu9>wvs} zOY(nBy#Ed!m#(In^4A%n?Wf+yAtiy4AI{4%qBJ{{ZZ75pOrUDe^08|2T{Yqwl|a@|p7fz4(Lj`F|b8 zzl3U||8pY>LIh`+-Tu%o<==m?{0m=|TK@lTM|Llp{XH=L+HI9!zYjm?8Gl-t{q#HC zaQCheM@s$gdfFed{<(9K$=qW9aJ&7oF0usX{}!ga2>Y!67`G_;XX@^59sUx2$itWQ z&)o#RnoXR?eU+PS3ds_ZmHwn`C5-Z;eFD6Z~lKYx9MD4{+IQy z-S!Fg`|xF5W(lB}!lHsXlZu>6oe7gC7dUhB3MWj- z>6kq`H?JtCptqCf%)wE95f1YUW*0d)>C(BkGiBz4sfDqV$vm1pWlHq-@{@v`qLY&@ zhYvf;j~#R*&u=?rPTr)}lV*c7uc+eyt=l{HPjQ>Mc~jdvTDNgpj~$nnQ`B*2c0b&9 zdnc!$V0J+peogK3Go=>B%^n=LaN6v`A_I{7zu0Lzt*9u!wK z-?MDx&#c9W|FKwqv4Kt(?%6v1G5=7HHto+W1L~E7_eNM8e+0I?aW~@m0Y8*|@MJ%- zP|NDE_CN2d+N^u!{aX!h`cL11_AA!EUWxH7xJqo^%pMsRhxgn0AJtdIAJ$h#PDR@Q z>&=$oJhG#{0#dmccM|xxzRKTOU+)Wm^DxfK@ICFOe(vSovi^5c`MX2r|Bl1^_n(aY z=h*G%`q#8S{Yv~DcsF7{Hg`#edSjYCZzJvTo!Fnn7*3s^KHK{KvoXe>2JzA*w*K!Z zJD=u-{O z8RA{`f!zW>xNlceF5+D@--CP0zuG6C-U|Hc-uUl;`Crb#no8D}OpO2WyYO80Ry9>} zsiTVLJE|+}l=G~Gj>??psLLF8Dl2lB>|%QUJ=@z#`Je4+ zf4qYA2LfH=ck7<3{U7^7b0G8YRbc(8>Yx7lJdE>fobz|o=Z>6Y z9sik?h5U#4=aKVG{db-{{sYCj{H6a(&@c#YO;`JnFM@Aj|I2gW|CiEZ`(x4~>S~8t z%lnsZ-u71n^>4UmhKjvMHqWzxy1HLKGc&UalC%n8{(GYR58ekJ_I(b$IVdW;k9?eq z&~EC%TNnReOMiXVqWy#U$Fcdp=iBY){9oF?z(st2f%0Zl6&31JT|F=z>G30se?dA7 z+=%@tO}tTWntewD8-ESf-*j&QpYvb+_#c<|e{^3;?7MJrU&MR8>Z&Ei!O1=iZ^K#c z>*>nd9&wibwE*caBj`zgolt#;{zm%)?Tf_pAHE#%it;b(Nk;`%JF4T^`n&|^#Sb{D zr#TOnI7;FBYmxqBpQs4Vv+j42_@TMOjs`!?%l{VqK#e*|##bitvw9$3;(8^gw^V^$ zC#X<1%KHY`_j*W6Rl4^C^RU)l-&K>5q}KU{~(ul(70`l`Rduk9^=GVX`{Rk4>_qzdeh_nYjm zhj{&ue4<0!o8s@+0>i4SOEFz0_P%Xsb@iUUJ^nn&{(%o>TkYQ_{V&gA{B3_@{}{Xd z;RQNHG5x!+-}ydW)spwH&{7YHUWD`~n(3Z;$@Ay_+vfi*7=IMO_#cP;KR*1B>Hi_$ zJN~IgKlp1^4b=nu@T2keEFH3O-)VJiKP(2kCk+SqqgdkOl zE=5EIjDm^1fAm@>k4u?F ztI6N&tNI~yzPKNAbHyco{C9nZ6e^8{CR8u|;M4 z`Cvc(qiO$5cL<$Vz4TijlOsSumpksi?zLyJAOF?+H2qhTzxkHJ4SqV^TzX!vAOG3k zc=?CI)k}Z))yn0+>5L`o{rJzQ?UjGDy8Pd)od4?$cW(9L->asVe<-_p={E;d&i~c# zpZdU$f4q^Gf3%wXMVeYatLq*26KB3S#E<{vUp4(ts$TkIXIGy7Mt5HHwIBast+e!4 zmw(@}m6pH1ZkzO;AODl}{GU_3^qci7xBqXvzxEqH{#U1K>8~dLaEHq6&;6$kZ0*PY zdtLvNtCxQ9q52;3n@(E~9I(TW|8*MwXf^rAKdGGm&7Z$B(U1Rg8vjsk_0k{t)So}< zmW#KZQs2!VYBke8R*l0$-a5T&aD!qufB4^b zYxXBvP5#ynul#lXdC~Qs`SIVR@ek!yFa6=KD(8RJA-!XM{EIdDN2|$SeC_3*!HNfc z_{((#ZvOi@|E2BG@_&By(jU|K>++9pd2EcEKlHy`FaOo#Z+x%z?*U(wJJ3FFt@PMG z%)dQdZ~slJUiwX5w*&tDS^k+!$LF>E$esQ+JpOi5Q)>Gk;FCU#Ax} z?6SzsAM(HYN2ULDf2jFnq4WLIKLO*-TKjhwKevAJmVd|{I2!zs_N*WOiLZG1M^ohg zY(q6}fc{hP)9H+5`|kDQzm)So#$Q4Osipr<^b2(Ix4*#AzWCntA5DHE#Y}*#7M&`zHhBA5D?}x~n<=g}m)Q!~RvL zKVr|)+y8d+hyB~5=l`PA(m%ho;*Wi3kl%H>;D>SJ{rG>x{U3?+r^x@yBE{b-Qu7dW zzPL|+`o*Pw{0Hsw=D*O))Y6Z0P|X`F=ij#Fx@ab-lyvAs_MU&?>u~`U;5{9{~z*S zs3f)Y;~bW_ReAqI`-O96`tkpLneu(WKU!V>FI3L|>6vHk_2b|BFmL_~l~ynP;TJ3C z|J^rNKJLdqU*jLGCjWR9{CnSeg0KHmf4?{Xg=SSV{p-~CU~hEV;jc+;{nEda`@a(U zuO|QaOO?xiL62dd`ti@x?ceO`r9Zy0a{lS}U*wzr_ptw$NPl(tzg#*0KO5Zb+x~15 z^_IWT1=URdE0yz~{INLCPyWYf`7c^c{^8du=U;N|IhlU^+t$;{|D0;3|MklGcRl-A zU-|FV{I6(={4K%t-&Sw^qnE!627m3_|5>_MEB|v-OaFZAL#5S!I{&92)($lCb7p8iKlHr4Xu zKlXQ}fAEi{$iD{m;oDoe{5K!5=OI7-Azs%J-=OBdg)T`g{ZZQJe|}3mw)=ffA+`E7W(mD$Mrw>ha#z^e-7%O$Gqc@X#atp z^v+^W{}=k7`=k8v`HRsM`S)Y{6L0Pve+FOBTMq4bqdWcJ{|ei`MEd8Ymi}kh{_6Z8 zchDnZH5Rz}qyD*v{Es;Ge}jKCMg9ZPFMY5#{osrIf5+n6Jnb*!|8(|0GI{+=Xntzx zAKY8zKa1CafG^|@y7aCoN4e7v`CHuo0RGVw`6uiT&l?7R)IXqi{4nkcH~+tQ{O3~c z|HAoGq03WC|2@18$yng+e*+HC35%Nh_WzWz{lom@Xo~!=LH-lo@&~@q|APyTJ>Q*v z=zr6#s{Rcx;`(nvYU$6|uKYh;|ByTM|ILas4|DU!`0ple|6%|AXo~z_<8xSJ?^WLa z+;8wfC2syGf90%y?0+0um|FU`vi`%bs_#MWI^CGp#@GK?PyVNID6K!{{g)*cPSAXu8{>!-k3H(EgQcFMlzt~4!{{#Am9Hx%j<2(Kk;{FHlkEY1~T<(92 z9Od=DkncddwtjWDJN>Xf6+Hh2{6mXVOaIr{2O`H?{=gS>!ho0S`tiSo+yCGnO_4v& zVT)Yt<*&;>qs3R#-TaaNUpYdx|FQpWXh~}6AJB*G|NhGJ-yfgv>FURS&Q4{2z(1NI z|E=tQTUz@I`3`j2nl0b^@&AtNp9t?i8M-31^kW|geg3a5|Dy0!ll=HEVf$-LRC0`_ z$RGXBRugajN4h~feKUNxAO8n<{0;m=SEiQ!%$lr!t^KX1|L5)7J^nZH-_D1W{wsL@ z*=UOVA4B=?=}o`Rf9!7`9`Bd_hO4~%LszAie(<-d;J^Fs;lBOPnHv9SHTetP2ORp= z)1NhHhwu2?qM*e;2&C= zTKaG1eW1)@Z~4>Hf8CmIe8>NH@cbL>{})Y>e_1QGKUIwXmgh!LblRhA>F$EHyQuTaPx=%F+t-Wx*@gnkK%pk zs+xZ=qU4q<{rKm7uH>Ice~SE1VEu;=ue|+x;l%ti{rE5A@`wHRLN}(C{xG+H#f#qZ z2R(rPxpvc=e*D+5{RjVOiu@Dv&wl3q3(jxg3%YdR%V+!XZ^r&V_=j#vE&bphZ(n)& z`)U7QPx7o+pZnv$A296|ABw#=G4;PjoZKC$IA8JW>}i< z`1epv{?Qcq@8|ia*7KF~f2!uKBmC08ko*4=>Axkl^iM(kS4IABba+$W`40tp`cveO z`Dezs%In`|O+E?xrN5N@k3{;HrI!BwWBuEIdj5;nc(1V^|2f?L0sm-<{M+*QlR3v< z|EPaXdUDDXH-FSWP1yc|f9TfK(!b>f_CID+?*E?D=mp>Lw>Dh=f`2qc{)co7CjWEq zTH)#cM*SDz_80hvZc8owOVIyZh5b2vRh@I)@(2IXy8TO$f5QLK?7v?B-#z1L-~9g& z_rE04zdW_{gMYI6ANeo#_u$#?^dtY>p_RXAiu{|M!}*WTA=Jwq?xQ6+zWv|fJ<9(W z&;D2F_SDjk^$)S3-tk9W{#C7i0RL!;{FAMJFf>2lsW+B|-10~M`xfhOqU=B1ky`rW zJpV{UsinUi`=7D< zy#A-2{x`>T`PMJ}pYi+$@Q-$lPCv?jY`!Xg;2%wqKlTAmHva(pAJ4tbcl~MBwO;kG)E&W%Z|5@w*c2=}0 z35?EaKA!g9tsl|$Uoy7Qel_*#i*@ud&;Ca})qYFS4vj>#btCb_Jau0|_c6L(CHMcL z^G~umHWFoYkNua*=sv4uqr^Uuu)}}eDm?3dG5&f+Yt{b%J%#S^Pk*oas-D3-2Yi0h zRP`MDa2osq6ndCD?X?&ECKB`ilJGaKWj=G1p9TKO%0Kvm9^HP-&3^og z52-D}#2@o7LihTozXtm`;rrD(OYk4OO5qBx^I!i5`JedVy+b7bqRr~_7=Qek>`#pN zqyIUYg#WMDXNUbv@JIU}`+y_8{rLk}|GM(Q)l1yz-^cdvUiQBd{lEA5r(f*nasDN0 zogeteG5*8zKf?S1=>|pmqdw`6Q~DGAA4&M9ntsRuIKP{4o^5|(TKNm}{G){bcfWu7 zao(_g-oi;3|K)X|;F}J{OvinC*_N8L|8^OtANIf5cG`dLFlYb$XcGQQaNg@?Z~o70 zqw*8%KllO%U~IYVI(z@8xW@mmwPgQ8&iN0a75?ep&GRg*Vd}lT*#`YM>VKTW4Zi)k zS^;hM)(d-N{;Sx^QL`zLO_Q&~#LKbnO9TinlQ4Oje;t_|q_9^svT037(-S&uHa z*B|Tpe~;(if`8}%|MVy0Zvhv}1$>e3!GCnWRv*js$G52TL;rIQQuY`8qbc(5%Kn#e zm3RHO$&53ZF2Ccw)snyQmg3)<*B@@7{^$7NPW}t6^iTh-16Xfk)I2Ao>ooSia1Kfl zzd-sSkL@RKw%5NP{iuJ_Y2Qs566sIEe+ldl>mT{=uw&J}byifR|6t~CG6nx7(+Bjj z?H{Kf{68i6hnu<5|Db>R*KJewFYm)8|9E;h@%%TKUS81egD7fwf=`_ z68_8QDEXtG8^61Z{STBs@Qv^XfTzQ$y_eeQXZzQP_1~g?En!VfPsl&?kbnBOuTlJs zOx4d1`6K-}hZcO(X@6E3cJkKN4|fV@x%tPkRr!C3_Wy{H{W1CcuV@nfS$mZHQU8Mf zc&>lK)4k*YZqF}W&VqB`eA<-5`Qy~_Uq;OC!y8; z>Cbpi$zQBcE|7!G9HKF;3>VGw8pXM|{=LvAdhjZGD)_sMHIIpdUu4TlzZ6Twtkn!e2P-9k3 zfeUnGDB8yl-!F8&gbY>{_@XWQ3K@YfPS-L5Ur{T86>b1D$b3c4VHB>{{sIUAA zB|m51me(4p_hp~<5i&MeqT~|Y)`!le=tF0>sC)c>ph#Us;(dgS$pYjCddZigI{4v} z=VQo#{RJyKCqtf<;XWrro|WM~Cqtf`9 z?*G5p>qi-vDSj30ItUpvv&e7yyS50m?_kF(`972GW!!We?JNI4T@ib?y&Z$%`yuVS zO@8>cJgt5qGL`*v4PV;j3SZ>C_CiLS=aIRsy^s;-dc^3Rj5y!JqH7tG1;`Dwtl?u< z`{8@;M3&!fF26QDr~E>Gp#~X3M#wMRFoVu*%@B~ELGNT7RYLykXLK$~dWIc?;yd=# z<+*Zzc`4;%dI=eEZc5Qv zy@ZT7Kc(#KUP8uX0k}Y4dgSse{P1=BO{F({gzC3QhOg+$-auy)S5TBstuS72N)*l5QQGVJ^_F_PW9Wl;PG(JPvaUh)& zv61wBR)!s4S&n`94yAsxg6Hfbwsq@U^@bTh~CMVEC3g1n@cu)>W8nK&JU5nxK{Ol$a8Ys zD&J_{z+#R}>@i{sNL!RqYba`t#-c418yw957 z+Kxf-O_}h;%YOLe`9CsP<5au9vU7msSwQY{faF;~?sI_TSwQY{faF;~$pYjC`pfK< zzWJ~Hv+5TtmR~$3bDwj*#?F;B=zJDBKYrf`JFc@xf1T=3Ssr1>=4968`}p1wc8pMY z33sd`;$PD}#bg1vKwq2LXR4q49-FV^7wfG0g~IoF@s;-{esqpZ#cL7{H~jE@-Cflm;Vr6P zRpE2$w=TWZ`{*^t2^ljQsr&eK#|atl|4t#uT7I06vEj+;K78A8LdIkPxIjOB!#Q7)kkW z?_qWfitq6jPj&LcSHbO%NS?AU(dl0Mg8UVqO8K24@>i%}gpjc&`42KbBJ8|cU75#@ z5HcnUkQ?a1{f;@y58vxgaQ?eO`B$-@yz`gkyNi-U1N7NS< z-OCuI@?q_vG3yUcuwzhs&l?RbKYT5?{xzC%{`=O8Z!(ESp2HMb-rkPW$UeuuriZt; zwGbPIxKqhwq2?6~6cfN`CRVQhrYP zjSeIKWQ%hiQOoa1p04}SN4)QUx!!vp6yH^cUw5`2zO#9MS7W&U+JG(ACW)M zs*N4P4QRaU8G6{7WJ57R^|N@Uj>w{G88c_nd0dB(eWq&}lLg=cUGn8!_5AS3^W|i) z&Q$(YW#`Pvv*z6A%*nIn+~>^6v*uuLy=;L ze6nXRko`NgwH>#T{G>h1Jgv1IyT7E~SJ1tTA0MsW$HtOBOEFmhF3`(A{%DOKzF*e! zFPwFbElBG;Y5!^@+P@L9f7b1FMC8z8?U?hqmt(PZzk8|oeX={?0$uu71H%trQGNDb zx~lT4&hc~l4=Tn`d00pJYg#)yHXTa#gYM(!x3i->FE9Kl`G=F+*>TA+s{B;s&^^Uu z0k}Ya8P}$-AHEfsF4Ixj=ghdb{=hk+;)zy5#*LSgKIt6MBD$6l=ZePZT1K4jSAJb9 zA!D)tT%h@F$KU6NZ^`pqKISX`MaPHwEdCJjr-=G2ysDLuG4?#^|L{7ZoUUa={U#nJ zY%(SZzy&(!j#bP3@X7NDWiZcDWY7L{G(t4afKfks=*Z|;Y0*H(ou zJXzW2EZaYD^53h(CHxuHU!Qlj<3REUjK}MWvM)Q^u|7>(4^#Wx__nhhXC1F#Wqw1S zrfbS-0=bY01R4UeJs6s7+x&#yK% zbhTqpe9wH|p}!x#9jsq-puhY!QTsPmm+FsU-Rvmyqe=Hg$9J=%w0H78d_p%nUP$HF z-ChccukmG1kN3lOXpj4MUIqw*p91FH(a1^U5> zZCm-tZ&^KM@MG<{ecshu|I*Rl_W8-;7#gdh_!iwu{e=hgv7_`~MIXXHkls_2{i*W2 z|Z&3 zR>oujxIiyCd)MoJ_~iNk8BAW6u#T?X^+#q;RUYki0<<>ZiFxW?t`m^ay-q-`6@dRN z*9pj&EC3hiz+0Yq#1G$4wQNFQUhpzoeopz#A{DvqMY+=ywpqVEBVb=HrgT!g_EBXY zO?oF|vH)D5XSQ6`!4KaLi_~ve`~BtDod)9E_31MB@9|oqg5rG>)%(cjwSuB>Plik?MKb6Bt7+rvS=jbGQ?=7;Y)%2P5#)++x%$5+_cE01!zmm!PFgp7Bx{)NnQ6o2FLlSN}kF3=+fb$ZSZ-^Tlt{LIHx{jture@_2e z+Bo7s^;c+OV>{mY65T&iS6Fl}VJG8lUi*A3mk;-6{H`H4(ClHio#-b&IsaP*ljnWQYxnpd&RI7% z9V}$rKUB#lOxH5@{Msw8X=J9VCdX$h6_$ugH z#;-JdS636?^EZ?}?1xXzUzfqELVhB%5gENk348`!%ee9zulzo*Ccfc^jPv#H<@|OT zOrF;+ul?i~-CR$|2>F%KwTv6dUv`)8)l^MZN53_b5%xA4S=|l=6~eZZiHw?KycLijfVXIA=gIMBeAX1-c=;!`HsZ`Rg*6Ja4|T zdF*m7yJsFd&1Hu_E$6Yz2!C48Ja#*JVI}T>3-rP}?{4HLzfs%OSIoy$`>52`uVeq_ zQn8T1{H=iSmpH9Q zblc~0t{?EbyGP(k(Gi5lr1?#m1vEE{;zQ(L$zaaNu%o&=@IP>Y9&`J?(SG=fxc^F= zr|=o?NPJHJvsgg+{bkB;NB6fQ+Upg~`wJPDPOx{;K)Y*=2lYNr+ zku{y|*!y7`f1~^Ijh*cn6yM$b7hK~fzxOXy`nCR4{!8pNiO(s&Ru3xMAEt>&R$n{L znMd*=|EYrRWei_M_KxnePVH;Q3fW9BQqOlrBDmX zi7I5QmDe>A>)w0tx=1rmjk|+C`diDd=pT zHEB(LZYDPx9~>FiLl{H5C-CSOz=iVL>8X=DN_=J7 z`fEebe9faBe6b|>!d<0y9sQ2j#Q1pK9ry!ZbbCjU)wm-bA3$|{!~R)a?uYN(TS*MP z9DL@N{_;x|U*<<0MR_IoAUDuM>R(<&_>M6(`Nf{DAtL?i3Y=dQPlB(=mY+zJk41)B z&nA|ueS09F4ad{f4P>9Krgp@0okD(~e>T1G2EY6_Vk-4-^mp(@cKFLr;dAucjMtkZ z|Dl{izp<%@iBKNRIZ6^BH_(Zlhd1(*U$^=6%f~qQjIS!g7hHZ;SyLfnvH)D5XEt6m z!4KbYgfHyEXZ=U`!Y`73DJBcR1$xi=9+`gl-k|(v3~=NZ{yLcazUozZ{tInrDr8I+ z41NLH^W<~p%lwD(@dxj3F?$P@4;Mc1O)z{o*UM_D{6^qF`H=TTtCHi(z!#W~+i*h` z?f-Iw`JqZT*57uYEa!6_Bw~F2O)LpMLGu>f_7D3mSl?oRTQNfaZsx%!it>3QH5ATm zGroj=FFX95)^7O$-_t)6z6R+6=VO^W{pBa;^}6vT_C@1!vA}uhsmfn4@22?@mnEMc z0lNZxm%qIG5s6Q)KdyP7e)+h%!d#|0qT@;MMQ)N_t7Bh^ac+@Te@rIlQO@rOzdAyc zuh5)rB!Vb#;nAe?RvaSn>Fc9b5k8CX;e4&gxBl|e@%3+_@(K1eg8c)&iZ@1xq6d=W zgZw~OU0%?K@Ezd43@~Xv&?4Fcg7cs8ox%sd1ys&Ul>z?CnvY3NZ>NbfJ|g>MrHLt@ zs&=NFPbS-&$cK=RPJs*bn-})%^TYRk3-ZqwJNT@C_<$?gpX#3{|2@7hUb?c5AHLgZ z{Y?1ATEe(j<-hRv{_=}_Tj={K^=Uw%5i!}==w7rD}_UpfC%&Yvx+(N;v~2gkQ) z!!sZI;p;w~>bDUnMfBT0CBaAY0^RZ}OIP^NzC?aP`!YJJwFr-^x_*QF&Rwy@_Fwe& zwEFDKfZC)FDL`>VcjF@Gpt*c>ltK!8|DG3Zyop_xRA5{ zdhw$*GXLrROLMutVgmUuy#Gy%@gYBf#wL0DH|k^GOU-{l`Hj=SdgkbZ4g|(efD82d zvy4Xx-vRYUdL6Pa6Ul#Rr1Wd@JS^Y>jnKMpcmBh^G}RAuwS%EMhe^TXnF@17rKW_R(-4~x@%vH<;p{;=(g zWm3O-`Mola{EtbFeUAL%Kkyl$am(fqePryvH-n;4te+K)qeWz zGmqLwlWF}J=Re~&e|&P@lN(=RKfZTVzb0@%zoA113K^3H$PM)C-5r(w*lC%^Dz z>lWrFFLjI)9-~p5#I%Mg~k0t;xB*w%5hD% zelOyE)y-|*_D77yyR0W@Jh5YcJ0^jbm|p|=J=AqsKR^Ap*+u^ILdQRdCBYY=bzScI zx61LEU;Byj#|dnb09>G7KVQdpd}~2Vsz18Y_%65K%)kBhE5}`BfPOQ{4jcc}7K4aJ zi0&9l`rcbx{7BUNtG4)qXpE>3i=6F`vJ0lpFy{2hJf{2D{HcZ6rL&52htMP11u2jA zGb+rUo@XEqO*%PuuKc3< zt*lv-3i5OK5&u?Rc1fO*Q#`k*bVm1)@|uS67CS&(n?aplY82;ADIgx*$IUIGEth8N z4`vlk&n_;>%Pt@mMp5w$`pLv2i6?P$Ms|VUd++Z_Bui+&C`#z8oKoW=<9{oZE4!T2 zv)}(eU=mU(nOm6Cee|r-+&Ke{Npr`@tT8>i=p2@c!{lCMMi=69;Pzei7`|N~`QM|jy^>kCX3ZlaTL0Few7-+tne1ajWxoxf z#yeDL76Mf6OC^J8{}L=mX^7CXC9Cn+3PHah^)>MvmUeZYMjo_#oQ*h3mf> z{_-<5`C&g{Yl_#uhWxOfX%+xgLEkMn>q*&vnWgFXq(#(!zQrZ&n%?m&{Oox0A8OGb z>I3v6lpC!?bYIKFJgv+&t%ODQn5Pw?`!c%M1LSA$i(fZnJuc;k_B+PsMvkQRG2ttl zp!5}Ee8_j8A)Y^B^6w4jd?vKE<2VW%3Uw*H> zqf%gULf+GGAblTd&%qz>LGc{av`+t(@Ezd4mecracoK~-b!7WjTj4{`BdAIJt1_7O ze<9?&OJjbz7(JLCMC*!`^XUGTI$|t+ApTUEm`HA8jOJrra-R_44;=rFzb*{E0KP*H zE1D$bhw_2>Pj4?Id^wK%EXId&0UFlyJMvxCzmI+Uz&D-u(bmrk!h2BQ!u`Wn|FGSy zU-Z9aOr!quKb`c2>-g(e#}_J4`44sue01D84tx&JVcBZ*eEwBGd~Zs%9_8Q@b%Wu1 zRm*4KyM~_wH*nxRXeM76OsCvEMz&89`i1>#c0T#nlO6rWlHkMqF_VAK`bWtx!sov8 zV{!2~m5;4vYF+?v;5{h%SAqYb&JVSe_$s)5L;m~yIclGDcjRZL`^!(qhw_W@5%7gv zBYa+vffpJDZoDrx4!Y7$e#P4;|LvyvCp`Zy9uVJiIJZEnKQbTm$`v>?c(is%1>pPr z$?OV0eB)20_WNE3U!-0z`6a`*Z!qIy+`v&4zO<}%$NS-1E%E*3;4|v~JA5zC2!=1j zfI)Zfn0FoFJHS4_M*Sb*sm}aLi}ArOgX;MY<2PMsyj70Zq&kiRT%fnq-?B~05B>q_ zw>v5S#R(rmxIr-ap?sj8#rK2OZ}3YE{^H)lHVyaFZ(p)6=HHHfMZ;kDlI6dvXqlyC ziSrIKnZHi(+~60Xw-^23hwq6cq@RBre6fFtZ|6n9@?QcM`6xWHPJtgjljLXZ zcjRXr^zZOlB3Su=+(0M9@2)NJiD%XKaX!UCzmfm9yM7}7Spo5-GY;{)H~+oI^FGY6 zsvi&hg%Xm4pN9aEELa#*oyqxX@-Rr^B9xVRup+*v4**2B`px@n8{~FsI z`I(0Vlizu>)$bU?Pqpg{u$wd9`&`F?&l!9HTBFlbcKHoy<>O+KpV;G+k9a_Q#u*An zb<0PX@ntdH|3zAcJOACs{X^n38lNk0{Da7${_>OSFJv(7|Mah}!e{cirg%K3hk9-u zdX_EMWce?IFEBk?)VA$&7RwL%J&)Fh7}FhmMw4LpM!x5*C%~@$J!+m;s_mn1N*-V3 zmLJM*G5IfX7d|T>zIU?~4zq>V{!Lk^o=3*2al5MI2RSys{i3-NpYH#iNc(q%3my4| zn+B8LzxDrs3-s(O?i%KYZyePhaTh*u*#9j)Shkmb9%Z*bAV1{4^9f&Uh9kdNKzwLN z>i%=k_IZReY#!5+TI)x+^WO?Czhkyj{Z{1QGY=0YzhmFw{+DLz^C%xrjNo$plInM} z@Is>o-=m$L898;j#24oB`wRE4%_sR8GixQzPmKq}m&xbp!H);~%tnll=am5m-h-mt zfc7YC^P$97!Rs3uv-}oN@rw~Ygb2$6{Z^p5{ab&M!V%_kmGS+SncnB%kN2QqzQ|%a zc2iH!`UcqNi%%i@;=*Sf;jdr0FTD(={a=Vd(4%IbU+Km6uL}E|!M_7qYkb$A-1!gZ zvzF2PS)=XHW|0nW|ty;jbDKO(NxZ1eSdWB;*%WwQt(l4#wLx=^$2R+8#Q|Dsf`+K!@k;(Ln za)<9-dvbbR>HigJ;~!Dl|136}{Ck$4*&>+yUOZT(6YWUwsVMS3*Ky!;d3*u=o^af{ zChqcq`r~iXZzL2-;EM;u*Dy`tuuk-jf4tIBJ;!;Lupht$s_XYuqsY#GAx*yzb))vL zYyDn?*OMXLpnCbhx$3%p6YHwjJ}1+!!9YQ4KJt~}mLL49&*c293mp9#t%B({aqg|= zU(GpP$uC^4){`g07h-&%Q+nJZ=g%I{|99v~gpUSWc4Iyw<3qn6s66*V2Gjme%Rl5i zqF5cVKA+~FEUhD!Eu?W7T9;%}Qz(3UUGd`mL}|V`_IKs4C5XXSpl|LxqGd=`soRL;nx20)A1#@TthzmwFCh^y#ISuH@p8d&iK&(*ObPmtwxUg%r^e=ljnxWVA}tM_~AX} z|3y}M@mx>p1W^gD)V*8+!NZCG{&dDEY%bo%}YHkAoe2k+w zKF^C6{M_K@IsqyBxTi`daDaa|_FFBM zYchNp{DlP0M?Utne<8nL=aKxHIQXn2_~f}TGMM&%+Un_WE(e^?__46CE{(^J47|`N zo&(==$KH8~l%JvLx6XXZe=dCC_WttI@$DSxFTc#1s$T(e1r80Ki133VrWX~iKTP5? z*?(Ea?T^#XrT)LBj{HQ2B>2+ROjVPA??o=Bv2t(zThT}1i}g~!WAW#8V(F%#Ok2_b1!uNDpO)0V9LY>$V!H{^w-&1-L+mL@u5t@fB(K%z32WBOqm};{)P* zWsf(X0pG@2DqlvPSAMmD7a9d_(4y_n9xCy{KBNBqiK>CvrBpW*DEUP?`O8n9nU`zL{eAB#_~@!|u2ya&zXiwvfpJiPuIcloHz<>Mro|BiIzXJiD!7v^#r`9k$W zg74mL3SXG*Ulv|yRL8w$^KEwjDddOpQAGI677jiuAimlUC>*HAz&@*n(mU|!IPf`x zFOdIM4tVi$DZhx8|Dt!3{9O3Ld=6Gk{ywO#-+x=b>9{XhTycv#|3QB8e6H{xytq+f z>Jm)9eXj7ziIXGte50PD{j1}^=M28U`*{znve(DKKEuDNL+h8VmX3a70r4f%Z$-fQ zP0%YiH~;0gO}6}4zmVT?EhzuB!KbKvb`2)K2>Su3#~_z07kSGEa96G*lyQ}ADw+F@7cm2t7{pb;vhA-y=!q?7`U!*U~z1;m%Wo7$t;5%vowU1o*B0Yo2uYZ#I<3?_OVEzH*#BdS> z&mrHgU1vReo;=61Z%?rJ! zuK114zl#4^TeSR>#<@SNEB>H<-AKJUqSgxP%OSeAh}y6BI^!#lpQADLr2N9i2NJ$I z`u<6a*3$2i{37H($v>nA>tn2%?L^VvZAIub>Q8==`j>09qtCY$#xayGx{uO*1>J9& zr{0UScA}i_u|HN8-G}~a3s?yXy9fH+ca7}%FIk%Xd*e3x-Te&{`-{c<`0H2hFD8R& z{}%%5kBm9q_FK^Qxh}sqC+xpeuHVw-mqGithA(%`Th?$8{X|9LgQ;(--c!-*0^D{t7A|f;OGuVDt-yZ#ep2W~h9N@4t2emtTIa9@3-$+0wr}AJz+n1j zzh~_6U-$VDZhpykh-#OJTA8}2;7fXCs zIOW$E6b#>mypA!ce!1KjNVrDv9JJn#yX^H_y8J|M@}GOt_#p33X$8c0em}1r0sH*p z)N}EyDksn*-h(3F;l8|nY>h0xq36~2QGU0Qe{bw`%5QjZF!}vg&+Mc0gZZb)^b5IxPW)?Y!N^sW57@!SKHqAu4~?*X;h)~Kh05=u zPy%0gXcGBp_(Uz09SiZ{Co5&y@Kus+Et6O36RC*2#Zj zSQ31+KdKC-{l9Aa2Yd#9UMG+%-j92s(?t>=>bE^S|L@eR2w&8}7Ym4Q%V?!veSYks z+UmL4xpMy*xIhO!`@7x$SH|*#|8mP<^6y>v%;Eoy{4oC%{Dl_q9Qr-zgj2dm`B|EN zW3)e;alIqIctCv7zMTKG{WBlA&-)xWGSxmJGbKSuf;M*Dm6{!Ye-VE6`aSM77_9W{>$ z{PlTl;E(s9zz6!r!=Kpmb1E3$uUtMpB{s$lbUr5Ivy$M8Y2_FDpNXjQQ^0o*w@XB+ zDjx=3XcV|X&$)c^5i`yL6Dtu@cfntAh;M4afFN#n<6YWcmeaerQO&U614EvRHvJ%ALE8tsw z^zN(O_7CmL*97ga*xuQvHpcjrHFowNiv8rZ&rgq5^{cqTtKUyPRpkbLA^0bN@r91> zx^G%+@Wc1jcO<_K4nFflfBpW~_-I<1CwzPTHQDz1y!VuShyVO2&F_reREzd7QR$8+ z!Drp(mEY!u>UWF^uYWLs*MC^qylxK_vj>elKUD>TY4OLC?C}}Bej6{_=eIcJBXW|z z{EXMU`2KDE#;_9Pn)@f1QhxgWNSU&K=m)e?sL%Lhg)i|%zL5Cb>o3=5Q9twQx+4C^ zAQ9g=NZdwSX&WnOpUXdK-&VR`zmUH8HtlOo_hodi2iQI2&j&lbY_HFYSV}J_AI5yb zcN_JObNj<$e0urN<+q3ZD66&dufYF_)#~?C9Y25nqQ~Eo<)e)8!9Fi5C;xA6JyHIG zs+Yo}{Pml;S7juVfmHB16rAq^e0u$1;Dtsbd|$-0#*=x%U4Bb>epBWos()Sk_lwc~ z_$;mcv4#7Yts&m}ZFa7bpVd{Bn{o{oZlPDu6B^zcBYX$g=TWy&{dPN*Uv7WI7$591 zsE)7Obh5`Ze?5n&oY&ry_U{URmL@VL(fyBU;%K7bljsb{3n^dHdFpyF_yO`^!%iRA z`_E&4Dd^Xt`5WeO&i?)87=QW6{rhDw?f*hti}ukDw$uFla-PSJbq$aYzfO=$zA~7e zG4FpUOmKJJ|MqWo+0`DQ!gPuBP$rbs^llQd?b@!h9<}FuX;Hu z@x@+Hd$|g^p`#V3jQ26K`aSAdA@}V zru|=t&+k_L4*L1{u~_h~_qmP(pELLZ^tT5eoaL4u+P~vzf4#`8#=_+O7jvw?{9;=F zMnlYh*5>E5V*6rzuYM;JfHbP(-VmN@kN@iO+i?ZSZ#mBE~%Ln?0ntVXzcfW%#a#k?;Vg8l%s<(e*2K4)U<@yCK(D&<2e$R~$`R|LTsr=S( z)(0482g7#}&o9>X8#MnJEJ)z{rSwwY`E|o{DF4-Q@L2)zeZuE+>G)neQt9359?X9M zzJu=l%O3wVwf?_m%SnE99em+)g2`_k<`KW;)$i3jf6{nO)hpnSdpc6m1PWjJ_ z5Bfbr%Fl&QoEr>Z2VNhb%P(mDgIxhFz3Pt#Wd5^WQu0rwae~Svn2mi&A_OG6U&zulUeur^Aq03Ll4gG2G67vl4 zyx+dHcKa9g2kc*=v@Z`j{&PGaKFqJv@nL=)o+rbX!N4HD*NeX~Jb(E~{4$vKe<8+V|DorU zo#V&C;B^C5X65z|`h^_-88OrDUn|?F$}jR?*>6-n8d3irw=ctCe|(wo8a4#r)7#;| zSI+b9!au0rG4Mj8kQ?aj?;O9M-+E;YGLEL@*U$**Pw97$p{-4Qws%oES&^{9J z_tTP|0|;E8EswiWmfr*L{YLnVN1gKtWB(DpOu}b;kQ`qo(#h0pU&r2`0p%C%-=Ef! zejB^&-z0zi#xC^g7xRa#L0bOfem6V^4u+8+uq()azpR=$(Jmh^d-Gpj4=Nw$IP<&X zN$_Q9`7g1*o;Low6zjSyh1*CV@?HQJo-WK5Yy9Rv_n`B$<7;Y(3N9a!9Dn)g_(pA2 z{=LaKz{kQlmM5Ft+6hy3jYfE5BN%M z=x^_TTEzJe_!h|hhg|tDoa-;YG6rBW#rSV^_eVGQcYtsHuUD`1lV3Q8KKMx}alWXS z;*U?BFDip+{}GWqvrm)>NbuLt|mh{tEnCw!5%4!&4G zd_Q4-ewH`05ttVkygzvH3zxdf2mFIY&yub# za^|;(r}@iI$9E&k&-mnQrFiD|vev(rtbE`(@a@>VY`Gu4EO|cD!H)dI`Tq{z7S4a> z`KsLx91K4}pjX(Jv;Mi*-ajJF`h|VDc?|iHpE>@0EFiu!fJ4*o#XN7;h^CVtrs=u{L?FkD%yAi*#YW5_-2*rSJ-j^-9Jm`7-y4B?~Px9^yoW$ z3H=^)@rTDs`IT$sW6Cb7e_iKiiz0vh%JaQtFzx?Bx4inr{7%eo(s2L}^a?uvqh6o8^B??|(9wjiZvDjh z=;q8|^81wiEAtfZ{2{bI;$^}77wC7y;Klb#d}XhC?Q;{F|7_(u@{0$=_h0L`&B)(` zpMG~;N%OD1sg;mlq&S%T@`}}b1?Ula+i{voKb}{mU(~-dCk_rt`B^MK)W7Cs^b2$7 zEaWcgca4%@_zd{ZZ+i7>rFn59e*r%zo`cqSpk_yjuY&QRec68swSQgt&kBgI9sE;X zX9>P{^8Dw>+m-wG$aj$66GgYyllVffDLFxYb!mM{?C^RC`Gre^$xol>2Ykdhzr<4E0tYG+dar@Ug-n;%tuRowa4W0ll$ZtxA^X`-K zGd200OZqjMIr57I#FxOK+2^40L%j=}JJ-CJXXE4XBgn6i@P)s1*Zwn)#X`l<6Cw7=I^%IO8z~`4o7JLv)YxYeQeq+-$nn1LTJCU6T2`y}wGFy3e-fw9)aRu3z1N`TMX@9BM54FU2uCHQ@4<0Y*I%Z%p&FrcC z@h{u!8!`VG^LO{j_3^FhiHxR79+8Xv<+nt`2R|9}#2L1D z67wqA@6W^wjiUTQGS|PfRh}<-gvIhh`FQ*T>OU=U%CB)rFnm>wADKMw-OzC17SB;W zKFeF0?XG`eUp}P%-8kWc{H%cZ;QvLm{p*6BKL}i)Pp!S|Wr;7Q&3|bw$KQUcmB1Ii zG?@G_juk#!jUzxVGr8RvVf}(X-h=A$%j^ABd$;`1e*1ys7k1$jm!*a;*20T#JkE9G z{b`cn>(3?!wEUL6_Wa^F=fARvbL|S@hf`?%+oVuJezAb~diLk?v`p=9rfL@4PB&@&N3MgZ}7zmD#tg6sl*H};WhYO!r5Dee84^;nOxRclZMY!J=b{qVG3$#C9fL?N9 z+iN7g@~x`;9?j#w{YZYsXh*-XfcUa%sNXTWs{R+)zjnaQ^-36kGzwgxo11@Y&+pXn z9Y*pCpXT5*7Y38xzr_c+LjO-b(Zb#z6Z(b!5|jJu{p^e%#RK9??Bl5QpVsI0N2>n) zj6EARO8x5NzZ0Z>e{uYS$f98K`?vE;4AwW~xN%GkyZ;pU;9m{8pUMZ}%i{KtvDhD9 znbv-5gZ&S*@sEtZRk^XM@DG3sH1huK!~M$dgEIg9R!j6}|Jh1{Z<*#luj2VH;$(0C zRhjl2{I%kdn171*O>dd|m&9kWeTMwrBYd&ax(R&YCI0f$@xedEK6T(<+FO-t>jyQz z6a4WWRDZtyoEv@Hzx#eB`Tg$5Ph1fUUlHq3-(PPdubann9S86=;|tKHGuxdn{}?_sNBCY0F3E? zoS6?x{i1&Z`W>`^yTRc0L}{rjIrk*z<)ve{8TAFSNVtq#23Z>tb@JdZ+CFH zG5I<813xI9BOjLUZvUpA{MwWJB2P6+lwb4OVDgKy9S*CzoXxHKzuzKsNb<3^WrAj<;luv6 zkz>8~uQ!hyR;6Fy2Hm)A?k{e9@UNnzUo)JZke?M0AND7-hO2R2$OYxbdZTjx3Ub5u zc73oZ?q{E$A$;Llj()?}2a{hi`fz ze9b&}`GtPxWYPGg3t!}>{~P(CUjwv#y>*i%KD~cqoAjRvAKI73&B5@YoSNOe^)LEg z;P;0$J>u5j3&`=sw-+8I@#*dJyQqAa*)IDR5MQGGrj37G&-(+5G0Oh~f8YW|yAAKp z85XnKznPm<`G-Hvj0S-?ycI>cVFQ#8;Jm&GKOSg*<=ncyX~?zbL=W zTT%Y2=j6Ze?ZM=S^W$UM{%{%GzY)}bMln9>=(|1ps{r2|=^xa0@QFKu;ln)Vh-P1& z)Yfk$%YXXwdDl0!_t(??tN!HcX}XH~B8T*m=@9`HQt*c22#zV_2ijqK+w&wo_%En`XHxxZG;;D^R;&h z7LuPe+0m~R5MMI;2m5TXea<`pn0f&J53h?tF?;`mIQs{{x0=dFys@L-FxRI%{4PNC z@sF#xe=WxSh2XOQ{cb$2WZ;EHAy?2#R}O0Bm;W9h^~4Tx+Hc|>fBjD8DQ+h7xfkoB z7I@3=F+9J-`l|Bw8{`Lkn>V$x*Y_BkRr!T~FzGq6f1xxnlE=4VN${=I#t z9_R6ys{Chz(+PZ?@9bfp|Dl)Pa_K++)kutIeCECW@>{3j+r)A*UOEe=#pYSip!bf&jmy=IzQzs6+cpYEMT^CPCDC-B7s;)^||^k8;UdSr2kEItvsR zb^RV=y*bpz$NGhRiOi?@FD`tM`+~`D2k$c}hI#wfFuqllexX;uo>O+)Scy-se~mt5 z{|-(|$j`Vx7`~7;4;Fk*3g{nb=1=rGqRvRa{pp{?D(>1mB zWkdF_FfUNYfpj=4D%F#x^ZV|T_+ncB^HFyQVdkeN@P$|S%TLFbSf{16&lCN=oX(*5 z&NJ&4_~F}1{r8qje&T^(_zL(OI$yWz`s19BAs-f3fJnLe>u|eufnVR<@cKAADnv<<2cuA zM;e~!eXipGo+h|p`eWw3Pe}VGH2*Y9mJb&`u{t$;R$3B#RqQVSxdMOdHoffq&Gh0vZ1aTzhuQ5L0zSg30e(oWG#?2Lphw3jIbHDCGOk*0=5c$vE3T*q2B> z@=q_VEArUCHy#a!FWLH;=h!}rwMwoA1g244eiz2xY~Zecf$wT6zt;Ik1?^=V5Z@Op zC-eh>eH-2%1kZIG_*@2G7)(D;yT#t0+I(B(-@Vx1o7!(i+cXj8`IF%?fB9KmRSjnH z@9E4vw&%B_{dN-1FJ4Xll{r0KG-3Z)Jm!zDRP&!# zVSiC=|0}GEGt<<%xMcD(7#B1*u6VIr|CZ<1lJkp1iEeA;~6Uw&J)`VIS|n_BtB{^)q_ z{IVAy`c3fkvige-m-eqn!?%v`8J*I^x?5Ggi6_C=>|OOsCjTJDkA&90i}52o*Kq(( zO*mxyAnT*67uxcBU*UlKvgmxySSM%wU}TNI{Nm+`6Y%N#_<--@Sl8b{*_UMUGx!V0 zpP#+*{$6+fL;p+5wbZ{c->H9%CxYR_`c>!=_!9HV$5ie=8!SK2CeuHBQsNWkN`4D? zeNUI~$^I3g6p{T4i0?42XN`&8{uk_DY>ig)VvHmThWtRkUjOiHiO*nsSRY!}iRxdH zUt}2#WKsyP4JN;2`=2J(^#@!Zihh`;Uyr#=;wxf&m|xs~7x|~1(}Z!U!Y7{e#}|3h zoByh^&**=Fd}P|)0d~jWhl@Y|(Z&b+4EbI4G})JhbwwG@|4o7~ROrQ**hgTj%4guc zf!poYX!RU8@E+9Q3zUyTYGqyJS3WMI`RzuxdcxxKXUwPk`Oc#KJ34y`}ccz-V<;`PQU>Qx#9k#8@7Kd@#+5G z?X-SNEOzWmWL+@%VgE4T0H5yg|G3{*$AQo3cJXlYhEJq@j&b>beV*Ho#xJ{(|MH+J zAI8)E_^i*p`gO+1z4>o9=AUxCr{e%V_*c;Ls?$!f?F-5W%I|jCUoWz*k%&YUJ}U{n z_-kH#7{5e01>ZQ&%ZJ}!;Dts}Zt(v5oZ8p8%LmHuW6x0g@(Qwlj4%9*zx;H3iSm28 zSANOM@6s+MrNy&yN{x$*5yq_i!qTGB;(2PW);(ClD#b|&YhhE%zx%Mf z?EFIecA%lYdVFDN@m%-!XAI9R$R(k5ImZ@#-`FIs-{+-)zQ;v!?TjkU7w^BXSQl3 zWCXr)x|R|6%+~atBJh+lRABhG6pr)wGIJ|lA9zB0O&aSH7>V(zXjqD?dG zxKi%J9;+h^dM6_SaDhHGEhFC#-`544|Nc_)E247}-1!gq%43;AM&L8<&J;2NUxePt z2z(XvPDbD>qH7rufD3fiwy)pw!*|ec3SamjW%m_6+EQIEh7SOfu8cg+Sz{iE~fUO43R@B z$5(L!@uLWQ#?2%@iohpsB;FK(FHF}m0$&zg%ZLD6pmWZQz37K8b~NK_s`6hE^^;H* zO31H_Ho%eTFRyi&9q04`2StscB%f;>FXK#_jvN2RxnFV&eV^WE()VRV04~s+)fcw$ z!q_{4z05 z%`-CToLM)%Fio$B?MM?vmmh1#X@oCE`CsH5XUAo7pQFYkpVv)0%JLj*MEinHI?j$u z7Sa1B=>3=Uo+1Kpfj<4jsaN>nTltfcUw8=1FXY8{9Bq$fe3d3**70`4zG>l?j~6n^ z`ozv(FC8y3DO%6b=RYTT(zT4))A;@cx~GT$T%fBq-;w8suNC#5$Y8Zl?R9xhxm$iX zr@W%|i9$v@KORJdrp<|V#Chcr<3u4N&MPmXYZ==OBY7^P^AqXwG9myM=mi@;spE(5 zQEETPV706qpXfxtO%eFY=vu}EKDv%j1ip%nlpcx+d>Mp~A_8!Mo>^z(tA6<2qVvmT zuv%4)FWl!uAtUgG{~vR20&msy|NpP*R=4@6)GZCWK`N=!oTPSxN|PfYY1pNb4BZkX zLr0PfAI=96!lsb^6B}?@>i0!NkIS?^dB!5 z-Vnqm=NFbCK0?J0InS{-eI83w!+X=;A>;ka|GuG)FB;uUNbyW{<(_x%URNFT4_wf1 z4<0=SH$QVzVES?c&F>&X zdY;=SHUFzX_IQB!T2TH$Qb6SwnP1rSTS@_y?`)cP+o9i5?vUy8KNUqW{g$$^pV~jt zlJXuB1aLv$^II&id@ASfmBBt)`JbGpx1y+UQ2tg(=azC6#Rnrv`91xXg7{HCB@(5^E8g; zgqE(vW3*hil89O@U9rhtGJeKsSxTe^@$aMeDf%tNEuXHY{U_4?BnaSwp4lruF#cA( zj_tSS4EIMEU-F2SLJIg|eOn4C;7ihPDd4jk(l(MbUq9j_K>!!@hzpPF5M;k<{QhCi zRrZtf%vKbc@-q#+K=F>=7e8z0%8>h%KNWu6P)MPj-R;FY8wx2XucT<3lxJtC^vL*% zjwe9?7j%mw&fOQpC+A0#A<6T$$$7@S&o^?{X>zVK1aLtg+x3h7L40=Sa_%AVtCaoXTKTyf6***ljm4_F(tVIxwntPKQu4?x z$};*ZchWAU-)iiwyCzRs5Cnuz2HdM3(Q~ zq4cCio)X@4mQI$xbV1q*}tj->fnWUxO}iNoX{=Lt4Iz3AH{+3*Pj4Ku7`|ldE-?hiMBJ&HQ3B4cDvXmF+_}}MltF7WMxS(~u z9nZdBIfyTRt9ri4dzJmGB?nELuq_&8It>z|0%wV|6Sah;s=fET6|M4SCC#5CTLt{l7AlZ z+h^9JYB_R841dvUP4M3pE#Rd{7ACp`|P!WHwN*o&QpAr>3zPL z@(bdJxwwarg7{msu!oR>`l%RgbLA6CUtZ1l>v;*~-$mEb{v-(c^L^!?^=pIpx^Vo6 z->mWvJ%03AsqzbFD)~1_J&GSPJ|kEZKfK|e+1@1~=E(FfAn1HIw7nwm{cYPCb+EZn z@l6}<&wuApdK2$eNyHy4aAmVBFYKZEqK67xnIOx96u+&N1+KJ~=w0c3iI$~|qQpQR zU-WQ+D?ruxo;0K~sK-F*m~V>h0)Jcw^I*S{nOo#}!qzD)gEM=Bo~uT%PRUpZGseyP%r zVyZWk((r(~zxc{>Ldu1d{>k?}$EI|e?Dzq3zy*EdVdFjvdcIAleWn{a1V7)w*YFvS zru|4}X!+Udht+oH7;0xivTmS?PsMG@3n`Ule*6Q)_txcI;j<8v8-y?mFoknxukf8ix({Cvg`_l7mSVEKiSX4TYi@5tsH;eyuOkvl_ngcYdyG2Xx`FCA zNZz9SMTXdom0YPiPAxmMECm5v&|9{SIV;G1bJkLN(5`}rKck+n;>)Ce1NnUd=k3MU z!*WbpUO@So)gr_3$S~~b*WiL4S#{{nAU@fDLxwo_+sKwLb}QLO3iDY@$bKZ?i`_!o zNV4VITK&{=L40#<#b>0r{IWs5A7$Rp8E>;^q##1TIP@qIN-@rm;f%@;kZzK{aGWX%F01$@q= z`a%l$qO}Ty6z~~ztP})rL4UA$%Ns#_H?aMjbt?TU3bCI(yFQI0n&ESfqVfp|_>5U} zeG>4+S{Dc@;7ic4QV_reecZd}1(r`AQOym7If={9A$*ZB^@SAJ&!}D?q=3&kgX~8F zz7+kI0zN^1#^=@-QovVKo64Ic;4|uwJxRc4(r+o?E27_0 z5Wof9pxOn2^;a+P^A%?u`uPg7jTG=D=-EmEUy7ce6!0bKw-oRd({CvV;DSypx~)c# z{VG!#LEvddCh;J3rzxNL9 ze_{sRI|=yW5qcjX0bl9@vL6ZfifNk^@Dcu1wu-i?=s>e0biW9NdaGsj+KG{F6b6lo!TqNe(la-zL_Q1Zy=qU1bj{q4{E?>HbN;m!xY;0bk^FN*_tU z7tN>qg9Lmg9V-O^T+p{(-0eR>e7)IzX1znFFV>~>d`ZApOujA!eAeL5Da!_(;HKQrag4d{Npa1$+kmmIA&Q{g#3NF6a;D z&pJ7XkB2K0@x6!UD=e%pq=3&ljO;}MK9jad0bh!?Ndccl+oT|X3wm6y8!imuyJfzL zA13!_ko_RM<>%9b_T-RMl zDSTbsANJZn+nqn;8C1x7OKImn-RZrqJ60d`{&xIJZ+#kMzjGU__g}Mz@;}*5-ur$T zT}aRO?~20ysEsSVXgN;Hk&oNB@>M^@6Q^YAlfS_Qy|Vbo6NC6HF8?{qC);@k`JZ)ocS?V| z3;17A0mToJAif~~i!`G6LxKP<=sNp5R}JFhZehY)t?U=ZS48KQ0zP5TwMeq%vs%#o zksw6)2lSt3KP21FA2k16r=KsD_g~i29sgBt|J;`9%#u}MWr};>DL$kc(AJOTh5T#HCtQ3$ zB~1GG3TVF*Z9PyphYu8sr&0Py^_!7414W|VK;Rt2_gwkYD$4!`I$!4(sb225d|}9e z>?t@QeDSq@z5zT=i+CZ1TX3%}>&xSm{#h^86NR_d6U(O1IXBYx;WhQBy=Qp)$!eRE zvVYyNI^PS_z9cy)pW3vl=Ntb%*nT#(yDKlsrR|6QokANw!>vzxiRzylQ+pGVeQ=Pp z<j`po9c^(PK={h@$)BP0|an8}zy_TkQ|B-(&Ys{1}n3pS3sGe#P^I z&wfSu%s0(%KYY)2J}MB#dj;w5VbPDNyhVZlF6cY&pDX?Ep!B65)el)t1(DDF=>>nM zhTA}6e)_?D0dVwKK=Ct`CmuY9{P?!YqSHDd%>I?cz(RU1q?g~Iw45*3ybEU&2hD%{ z#v`?EC%*dV--P~G^82|}xtcIns*31CeLs(mYn!g$mEX@zT1Ne?{C1wCW$*WMYkXVb z{eE6Jp)JgpPG9ik2DIw@6!9Gte>dJs;{%+MpPt{^{4x0X%I}8W_|bvKp>-RWq^~Lj z>{__>SRn=9JB`i93MmNSg06D=weJP-wQfgzqcVI>mVBLg9w2*+`Ywj+%I6$kPu~+C zIL?)o+<&2X#c@Ik0{jko!Ns4rIFHucWkzLS(#(kCC4gAALr31N1obyVm-P z|Hk74B)R+udyMVL={@)JH28c_h5Q4$R*jm^dikO}|6S92^4vYaSCk`PEsPT|N5wDj zt-gWNpNM*|F#yIIc7y)+-o$1vAME#aef6#YzSz&X*$?CNSgY0dWAF{Qkkk97in}Df zrzZUMQ4rrT1%AHb((-NK_bawfu6#Yab=eZc_t#zi=bQK?H~XzTRXs2(#b#ZmX7f`Cz{nmnuHzWyKfSpBo?MV>TaBB5-|MMM=dAPq-^B(mJiMaPzmoi~+sUt`g7`kEtMU)37T_E&E917AFv8z15Y z^p(AqkM`OR@wagu#b>hpigV;U4*qw$KmNjg4zEW%K>Pp~^tFwKEDz!v#^nRNpC|s# z&3=Olm0!fQ^8FBl%lF$4o&O>}o&Nbnf&TYyMP)zmMgPf-uMy`T7>5Mc%j5Aw;eUGk zfZd>**P6LH$bRRwsx0g}RG-7oHE$TcuM^MnV6{=@nv(ctKHs``5Z_}Qf58_K>N~4?>Ow$=z5k*dulpay zIX9oq&VCyYH>(HnEm`ijUr~;HdOZj1*MOgUSosuw2Yvdli`ND5ZRPS6>=!GSoBhK0 z>TtXkJpN!w&v)pOab1G=F5>rJ@D=CCx0vUvj2HUT=RQ2ox|prjm&EtfLvuF;@hz%S zK{ynD3l3NDFi}1?`wip#*Qn@EpYi@HehH2r;D!F{$8Hn7d?>$sM|?)z3}3WDZhZYY z|3E!C{I8$J9hUxK{~Is)?~7hOLzw-&m!x zvEOW-hXUmToex~>j$*=sZl8Pk@O_~ZzrW%67U#&foyQZ5YvT=%(bgj#fCtOaOUBN) z)XRtXG3{SfzXrZU<=pIt_g~ES4!b;rcr!P+{0A=R!;b&BLlECsu73t!G(R^!e8<%1 zBlrdN=DV_szoXt-bypDIC`zAY0ADIcKIFe*uRnd+hjMF3`5AVDy&s;|?*%U(;&1I* ze!jvgx!Lb{ykBxUhwJ@^*PB_U&kbsw^Q4y#{?}ufKmUkS&5bWTj;S`^b~VoTj8Vbm zzaAV>@SeGSdi_0KzJIy?>bt|#`#GL(QI33*xgO2z?=QcsAEnYij1y`y4-}p+^yfqG zo$TfNiTRo~^*`TOwcPAC81*ll4&(X$$?+rpqpH_20LB_z(8pZ&PBMt^+uDA<;vD&w zX?_Mii}PQ>`Ep5oHD4JzDv0j{Eq)}b=VrgDuph?*@U=tx4vyC)@y&SbVc+`)o^O)h z&*6X38oBZ99;5sW2fh`))$g8gqZ=3^e9>br5Bm-#*1ywM+jNAo<* zSdaLC<6u85KRIT03&|JL=Ev9_rGDE5nfVQ)wS)OEZ!5~lIB(sSoX=|I=iUGM+Xosr zfHl$;tlrRa;YP`4YvccqsOrz(QXzc!j(~YDa9$e0)BQdUZd`XI&o7Aey1fjXfb}Bh z>0Xl0((LyKvr?mMd>hgPj+6_KWkj4{JA7 zod^9Qu^;+h$i8v$Hktk^vM-!N%Lw3tzJK@g?)+^!pX^^|*U#_??ni^`LFdXR`<_|H zWcXxXvm`AefD8J&CyS1v^tpk~C;Rs#8)o?IGUAhce+oNi_+($76fFyJTi}4yQ)d}% zr_G*S*k1nYG;r3$^X1Us=Ui~{#PiOf@u}UBqmMH#oH%FXl(R27ZzAn22i-o-m^OLJ zS#)F}4K?0=z?8FQOjaX`pHJgdpK{JT8ipE!cb`Aadx7CoW=|YEWg_i;p?fVkDD~}a zr(SfyS*_a`tzBI>YsTyu?T1gf@WP2_PibegRm=S@nmTpLtTt*W>vl%ao;2WiJ0hol z+A*yqayxZso1kOcsKd@2M@LVYHFe@yQ;bV5r#=hI0!?<_j2Y)%R5)nXjEf5U&z@_X zHG>YCJG*^4zu1c^-l2WTtnVoPw#~F#H5#b&Po;{o zO{WUcqsvk2Y-;Pu%OCRlnR&dbzu?v4eXQqpy#{YUJI_Rl#+ZA%C3a8i)t4{YE$6q1 zY57~LeH24~u9Ds_$$aS*{6mhrEZ^jjzAZk5#^t&)Ule}XMZ^bm7At7kh*LYvueyk& z*;(9m0&S<|B3gE6`CVEzX#d35T||WTM@+`~9;!WCw%=_K}NF$ zw%_1q<&54L`#o|sr+;s%`gz>XX_$AI%cZz}y4~mK4x*@M`}BQcyK(o}sge)vJHZ#N zNaJR7uS{bTtLup)g8AgQ%Q7uA8D!23-v2K3{T_S?{;n!`J+A-q3A6`|Hy}f5{o!do zcLn_$^~j~4NWR1xbzam@-gY%zwO7V|b_k!jU-k~j*lz^qubAfv*9n{dZZ5UsmHjNt z`7l~{A zKVmbv-RW2rukn1Rbr8b%h+^128aHciuXOuy+}FHWSDiq7)%E@#PL$q{&aWoqxVDuj zHNpAP<8sPzY$rDrTa(l;fyT`)oZVCuPHQUG)uijmaV03&lbVX!bRfo^GS6x%9;0P! zPtx)&lu*fWmJnb!=oehEH)|&VZ>YuW1JEbpn1@duK&uKFs-V30` zU5YfuAYY7B@nLZ%>X$;}$tOq~FI5r^`cfLcv!ZzK6t(PJP4VJYY9B)BpB$HH{JBaS zd>-g0mfq4q+AqoWL;1j>`U7WJ#(rkA5c?6I*M7HMr|g%sR6KBvPS@NsobAf%n=wZ( zs^*sC;1;bjMDeqR=)vowtQU`a?q|tYxLzG!o!>vsqWTwWOoq=1;Y(2Yz{_WII&A-> z`n~dH#6VsT|AW2pe9crt5x=(KLC^Qu#hqmN>Y(TQ7!_=-&ocdw;?0%)@LZwM{|MJZ zKN<8tLiy>$6?8u8j}+Dq3H?=C^9>>X_FwajJO4Jy2Z+A|$ei(smDByBj26MqSMtec zXyUwe_&I9n-!t5<#O&d(S9{@RdQLo!o71}8LFwPZF)z)L&o}j^Ixo_{;vXpgn4WpQ z$q+u-|H$`zG2i89G{Jx;=$y_7aKK$ENdN_|NQ~FFj6tUGaQTzFJE2yTFLZodq{Vy7__kuXX3I{6N_cd~*B)yOHPpm&ZXsx(qGHMesgf%(G~;^7n6ilIJ}X z{5|9!e){MaEXPc+XeF89xW<@1I8Q2v|v0==IvtSpi|zoFSG`1u;|O1@0| zc#P|vjZggL`y+R#dOtjmC|}>EuG7g?m4$J151KEe$3f3`!rV?1g8FyA`Jp;Nyg*$i zLeH_1=Q$!B5&gOeDaA?34`{shqK@5MLAp}Zio6YP`)SUmvZP>DYp)w{r{~fjC|_ycFiFE z^>-?M^Ar`I!uTVRCPE7M3memXQY7F{&~GW=H)&rfapo_gZBoFWI*jg@BrJd%I$kps zIR5$zJpPFIRM~&SyVCwNUI(98rUS-;eBu1l%9Y{Ne^?}FzPo>0xw7&~+J3v-|0q{Z zF{ymg>~OI~Y7o``om$`vzCe4o*H8(oibWi<8MHMUd#_AW=cau}754B9`@iTFqcIPUY4d%`M{k_|~zrhXNw|||$@n7`kRh5dRgE6u)t$N`J!mi)zvJNWgC{G=voJ zC+W8o@S9iDb`tO>>9-W{Cu`F(Nmu|k^vr_6w+8WV`%&@RDdqo8enp@CC-)uQFtEV@2Pm%hAwF)fp< zT1flnQ+_aSkSld5J#xr@oSB1M*`=xoMd4+GT#?rf3gCu*_t9T}58@wkmO45jkPX~Os;D+UTF;EygJD5SXjl_-AG zZz(;AUl4E6{d9jMl3(7hNx!9lKXu3EW`0B-0GtC~4M{E7S2`OT|T`l<6Hzp}UX6;e`*==vv;fA8$;$~~`<|G!P+ zKfmAC6_cW*H~-pviGO(rm9OOX;x_$U$(H{f>+itvAL|~a@<-D%Kb+V9F+ZHy=tLm} z^P9yQ)BI&5g>mAi@qG%L(r=QMv?-ZzY=F?L=4P_;)t#pQLS4!UF6L z{ru@~{2FBcBEkHg`PqW_i+j*~a3tV&j-~n7NWgE=HYwmQl-o$aZ+55qCjq}h`$`E5 z;D&zuh12f~;-9UW&5HP9E*Jwo?b5BLXX>9PcPR61#m;}{J7$6LHv)kQvPGysmc#YH~qk=1pXK|waU*@do72pdg%tmc ztu#OEWzAekQ2HpB#r$TjH2z*~k6zJCNSXZvZ)eb-sUA-5UwC;lSF+__dhH|QgX}-x z4#jWW9nK#o{^XaE{~ZIc4~$D7c0lEc4J+ktl( znaSEM3rU9#;D+9K)*0o4?0?rbbslG`;U~MRokIRW-(@3@Q#~(CuhOX>{HM~Yv5r|_nq1F8IJt)ld$V_R3AruTvPPD(#IwRNS> z1?u?t;caO=6{l@d!sfH`(;qzk>ABB$UKzyy zD1D!CgJ*s)Z}}g*#-v_CO6!iwzOh$nJ}VONCuy6MFn*KnRZ403-|4z06~w=@mr8%E zUsU?3+ds`ubAcHoJ9;brB>k2G{wU3TCMAr&h_*>7Eq{wbu{nr;-_eTSTybcAo1VRt zfu|^cGB?tEVK$rVf;zjCZ)9efA={|1o02PNBNKOaIpU){-&PlDWo9&M(*w@ zq|Eu4?q^ZHupaK|%KFolI~L9BDWpUbYB~A>{U+Hoz8uY0Qc0~m#DBzF=zbl3J~xQJ z_YOWuf5pF=7QOE;QTBJIX$>Le!I6|+en9nwMh#c`$^4Dx_lwZ76wC*fqz~oSTF!4JtrOuB$0&*RriZCaQOwUHz!UDLV`;V*NIf%dc;q*W$Bp*}t zKk~P?{D$&R(cc4TzUKjAF1-)P`$^GnDGMk*Ta+Ic({Cv^(6Zbf`DcJDC?7>>S;`L= zmahC$ZrER4g7~9d+5V>~|CjR@1@Vhz1UR zDNmFC$nskuZIcofV0Y+pOW$oA#NT1D;*Y#VClJ=D{{0< z!To+m^=;AdG`|8#Bf@mZU!oIfnFQ_a9hwVA3i1Pc0?mg*g82?&G*^<8HuTCO=W8

      wV=PCOU1o1~`ZWk$Oewtg#CIP>5KFyy*lIEwm zVIm}N&!PN^;xhvHg`6wKGhYn0LxUT7?;W4@4YGd?{{Ce=rTk~M8-EXee-V4h@ktCS z56kqixVV}tyC@1;aOvx)z0O0Ryb=E^ybsqN99s7)wISO7P4 z->*|Y1@S+K^3N+O{>u3&y!qFM=aRqvn6cmBH_89${mO8Jv6oeg4qyN*1Z*BrQw1jq_vcBpQ#Od|K{`(xS>1l zdH$6k{^zDLzoq;~@n^~pXVCXgZ+<$OE-T+3i>A~4kZhxb*6ZJ>A4$+QDHCP>OZy`v z2uRkyIp@-R93)|(HE#fa&qp>*_O|aq`y-3$Kke^oiPig6yBuSPst2XlNH;(ibWqEq zc|FE=ijUw3#Ou3oyI}OUit_pm$EtQuN$%ff^7=5P^Z)+i!yAJ53yDAeV~sSwlO;d; zzv}$y@shbeKKMWA#r)jQwIu#HCyThh22~$BU-Cz||0nGK*LP(9ZTU2IxjMf+G}!(I zwJVST_TSTlc@9tm6HnN$ugBJ=+Wz51H}`C4_XmB6b3`vptzA4W8`j5|V?Ouq#Cn_8hbf)^^{X4t4C1f( z3iadp5V4%nk}UZ@V|#)J9A9ed!T*i6z9jy%WDTX?zfpZY z{C`BS{bQQ{ApRO{{OunRf6@LC4GHV;cqCX~K4UW6x=+LJq3t94mJjm(L>Ky=aF)ma zPYULj?V4nO|2)F|6LkMy{F_RLu^#@9eq~s1xMvIh7u7b6zpu+Rvi)hXmi{!M>MH^0$v}UR|9B>tX)`f2!vq{!kx04fkx} z|CaKm#jH=*@bITz{)Ifge||@bzvsisR9A3vu>a`%7Zj=V%BrjC-P0sI&aU~II*-L0 zZk(?6Pu5Z86gz!D@DJD>y3al0vLOGzgX$5C3o`uH$n5z4*XcjFp`8g2j|k!yR}ue= z48L(ocKpuo{&)&2>hT)>qsMCl2ZZQ2uP}*-8TpHmGBRcba9YGlm1(Vl@DcBwQ>~E@F zE%_6ekeK-+$g{#qn{G-~Vsp@vy`d>bZcw7mo*n^>{8} z{McT=JDk4yXt)0|{0IGiww^`rU;ApL=dZIy2lHe8I{3fE;1r6&htY%srLs~0-hfBh779=(76MU~Zh@vz^29$U=&b3eS2_zM8UdUWsO-Yd8M`<_U|`R@gx1T02-p< zr!n4s|Mp?N^5+8PUr+qWrWt-GOa93`&WdrXdLIPFEcSoQivo{~Io(^ruyZ-QwQ^Ylk_C+5X^<@Ov3=K1jiTpliH4 z!~On({0rmP)VzuKJ7oCnvx4pKX#S(8^8omxo#Ka|!+&0y>h~)H2ZU&B2ieNq=egw{ zlg9@_{C%zi)nCOkqM+tKUK8x2I|d%}qL#=l>W#{3kwkbXRZuh5w{F)BEqAwbJv0*;9l4 zNA^pS0ruD56WPpS^gpUz4)2Mub5TXk7qa~RXz&T4mk!wB)}PpHe~b^aoYGHgA-sgX zf1RBjKl~Zy3?R+41Xk#`SOFaca%4RQW%`8yxn3ecUe`r)%6F^oG~Ykn%MZ0V{uXzn z`ojZNM6|1_pK(I?6V$Ik2KY~5HMM{8Z|=av0L!@k3h^4(-_7+`h}SXRKTILrF?ffo ztA2B<6fWLw9g5)e_Zqbu<@hzu%GDVgcyHs((fybzXxx?{U6vm zyHSw++sOKd8!ONl0xEu4(?j@aetQ{U|Bre6ebLHae!EQ@R|nT`&GXb?+>ny&4}R$8 z$G-ltFo=pIA%aVlzwB2i!)W)v5XaAE{#E|^x7CJPZ%5R3jR@~Qnaf2EkMCyi`Y;7<=vN=R z?IY>`#TtM0Rg{0x_<-PdvgE&UmEts?_4B{S?PQ#oD!-MMA9jMC{+~%7dgJelZ2#mm z;@_Ju;(e97;-k-RhAN^Kg|9L#_7|K8J^ZD9(+dW(OKllyw z3ICn6Qt~Hxd}h@Dy!i_G|Ihj96ImB3e(*piCzKNv=nv0z%=H|9Z&3b>{m|dgs@a?R z2_B#B?^#64$y&YB{W}f%9gR?DtdM}~K%Y6`^2(Awu})oAu>GeGru1iDhToVSZ2#5A zsSCmWcUMy9v7hk!55^xhJ92wo=DQi?PhKAl;l^r%e-yADa?AB|CBM!5s6UBzAp7sn z@H<)ZckLX^e!sE8$d6@?h`&Yp3(5HTGpD6kD`m66Ik^daX@LLyW$3Khff53yQ zcf-69n*H;+{>|K^o{ND4LbPuGfkoR2gY5r=^#6Y{{KlN@_#ff&yv`5%3*onaEB;=C z{ml?=tcKm8XKs43h1dT0er=Qg8zS@l&dHL$C;JI_aNS=}fBU*hm*79^_`6J!*Bdw> zL}NR2+m@HQ?KdK?sd$I_lWKQSoxhxPhl4#gJNw5%?61EUga2ZTYun8KT@2UNwZSWJ z{H4q1TrTY&Wq!opPSk$DE}yZ#bxC&oXn%`z64%$`1vvD05yb%^8h!)*x$E}2=}%1K zU;Yg7SIF=i^RnZweqwO?*@T}9`~=s3ZkpO3GVIx{0qlFwZb`D@)t5c>VGc2g6!|%w=d1k{(5={ zJL>$f|Iz&ZnCz6@_fyy%`uQD;drAH{^P~LGX&bfet(dXDby;@&T`>N%R({Z*3;0WG zf5d~`wesBe7n}J}en`pu*TZjIo*n;NA^EQ!ufhMLmj6caz(O?a4qc;5r=+xhO7s6B zS^mk-*x$*L|7LFIsr!GVjQk&V$NitYaO48XFL?ZNq@U9${WPj(`0XpQvw!E1^24Hv zDxLZNn*Jc(LLas&&mI3d#{8&1uW%ySzj}t>nx7qi5tnE5{Pzufm(E>opVDu&cC?5 z2l#NDuHpZ%?EM>Gll4Cb%}>~3E%A4waSWQPa!G>h>>WQr_M?&G#T35PP#8Bi6zOr= zH#MYs>xN=FZI}HsZCW;NXqcYAu$Y!pv^=poZKwXTiFauK8yku{XxV5&;~8ykD5A7I zEcDi-5m;tlR^`}{F)NPb(JAIhfh zr%oPy|K;|>P6&VeXuti_e$MSAah<{Nb8WuHXa)9vUJw7qak|EK_<#PVLmkPlr#}yx z)P7)9rvA!a7;OKT=0EB7B%A%|59%Kfe__WVm=8v)m(#hi41OFx^roiQc=<8E)T_jw z9G)+V;r~}>$3Kkc|23}mx4%lFo$7Lb{qtKlb9%-1YXCGvquhY~UVdco8Is?6U7ZK% zXYF6ef1b_Q-&hpF|A*gyF#i<3=K^B|>Up&I`xx5QWcmFa{P3UQ3*N0G`H}u3|9XVV zpUx*0gxOZzmlMJ-$0d_tv{K>;u4gb$_xC@wF)u0m3DWsxE!6qpS0*2p|!>`U!?S~B< z5TbG4*zf)2Yu)-c*dOiB1-1V%C(!teD>?mN9L!&+#ox-PkL{}b92m>^I}y@<@ITG% z3ef%vd^k?m*bYCM@XL*={Sv32=>KxZcJiM~DO2QNTpP?U$5oR7_P>?OY5M#YXXE?3 z=0C6V`xojDP4{f!|8)NAjh}q==iq;y`0dLw{LcRoempna;pn|<=ga=5dj549wg0p~ z&&&^GUzeTzM{+xPbDcl^pLT|dM_8}E8VE6|6|et8?XOyMf$m@pzrlTU`k~?$Z~BAu zKXp0TziyTE{6W_B+3`=}cxqJir$4W9KOOivuD=@nr?N~xGby^dw{1P^{U+^iZc}zZ z`m>hW|Jz?=_BL+Fj(_wY>U&~Rv;W%Z>ip?`)@)kTS73cf_V2;RL3jIfy4(L6=?~g( zU-1FuU&No!`Hqt%e;oaJyZilTFwgspc#3$amrG*@yNquQo*VM7KYn_8lJp<@4Zr=T zQU5{f%Z&Z)|72%>gX|YxPgy=Z0pUZmt-vuXo{r^_}esn6` zPV(ZKY5Q9@X2+k*Q+B|(m8x_h#DkpA!v0CVev4h{9xP^%rD19lwq_|0{!XCPyF`(=`H@w&hsR}{{Q(%tw+9Q@Oi=% zwnJCiSYwInKN|m&G=8RaPUSSelO_LA$iFK1%b&lapWtj2FTk(+Ke)p9k$yrKOqlD| z--->&{^i+!cIQ#~d1S`^b|N?X$8S8e{lTf*KN<$k>v3EGFYm9}+im}8F+b`LA0q#; zzpaqAzxChj_%VMw%4xvS?F{?>g7G)F{9h73wu8UUm*Z6X2QL3${<}DhUu2$&REp{b zZqANh|IPw_y<7x4>gA#s4hYdbcs=~*u8Dgmdea}2f4Xd?@^iInY5O}_@;Bx3q^Rgm z|I0U5{)y)TJ6^@@XRyB+!j09iJM?!g-*x-{;{6xxH-^1H`PX+D|FLh$&i=bG-~Aqc z`T0nctF`!Br%>IO;PQh3&=8ILhW-C~INyE$Mg9x>&pCp|PxwBQe_6K%^BYh4-ye(7 ze?-fF_4h|`)E%Vw@%^YI{{c7bf6wasANBeV>|gu3h0CDwLk9vrptftBKeCs{i((2=aRcA&Q_s84LLX={L^S$M;S&d zB~Z_d{FGOVUU)Co=6BVfi-`k5v~K^x8MnkGe`KS2j!1usx>Ec-g38Z_tM&G6!S>hr zZ|bY|*ZBwb@~=0TZ`mzsJ^aTE;l^s%9eUW9v;UF&QRavJ<5d4<6F-7=docfM-k~J> zcjNa*+?T<}6?G{6y_hv+lu34J1GE zU--|b+sJcI&G?U#C4ZRzhxyNYHI!c^v-BT>4Fdi2RlD8tXY4I?9=v~DL)C`%&(tmw z>Ho6q?Ee|3S8=WW|0`{MggNkB(BBGNy!jxN;x*8d^L~BSYya4pm$*sBcp5+4oLyP; zV1DcFV179+w+y3|5)U?EdyepzKikz*>*KxE`Y7+eZziwrq3UlfULU5AZX*768@X|* zmml#rRhilk@2imJH}1)fe>Bp6jsF|2*NSWXuYcwBCOQ+ng7qR~! z|603-(w|>5{7#nqZ=*g|^B)0zE+@l(F6Qqw$u-&KU*Lv*sq&TX_!~%n(0(sP_2-pn*6eswH^Lqi}i&298P2S#v^*2v7z09@$4&{fPIRCm; zj^FZIhTpQY<41fn+xy>NTCn}aP*r}g`1%dGTn+yz_+cE|lU>$-B0*-uRfz=r6Fy70-`~YfKY#z9 zX}^my>5r2o|I1o@1P1)v?&W`fX^(oL!tA~u!Tvb!6-N!cUD_Z1kMyU@avFc^?~MKJ z`?Iq@zF)&1aGfIleuwq2-{l;CvEIM|Av(tEP1X;Z>s|lR^WWW6ezQIN*7EH5!~A~( z%5RJP<+p#~KYg<+zeV`Qp}*XHn%jOU!Q+40lT`jyt_jt@jmyuZ|0}ZNZ_V`~uqVt| zi28F*S7CpL`-O?|rSqTd$r~RD@}Du}|K|7%zmp|D{9NaMu$GEnSP%XoTKZ$)hC?*` zAG*OWOY3_1QU5TQ{NMi9o|FIs-j{kb@KZy5S@Hc*(IkozSJ-71u?dpC_91x;$-`ITk z3HJ?<{I=G9=8C=)f6Hh1jfb-1KhyO439f_j&rL4>fa48(f9Lh^3mm6wY{&6u4tV8r z$#1-^u8aI@EBTL8y=vP2PL}*(`B$R6I)D5qE|LSoKm47N{ z_^pSt<45|F-0Y9P80Qf658%MK3WD#quI@0}a;8Oq+EB6g@o&iSw=Io-x6FU5WcZCo zvg6113-~!Me+u$h_H)>8b{CE>N2v54_l4th4gbM@ogJg1oBnK7=fV5?JCy$0b3Emr zEcw&#@0`!#`pB12{>1f1T*Ulre**`EXz*k6?8|Q+=;eq1v|K^)w_3*j_M_R^KgIDB z`4p~mNl5pCANQR;@8BE8NPa#298dnAoSU(~^;mZNjq7rH!hVA5jA_Gm*3!?` zr}O?}mH+7W#qrQO|0(b7>>>SM=l@gsPtA<|jmNX&PgYRvo#NW~tLJe$lQ^f7;5e+K)^glxN=XQ%s{jg_=Y=*hH;xBn^n@0bJC`wR9%dtzr4 z&F?g}YPvmf>{MzadwkV&`(cNc6SO@nM0o@B=11OsQuXlU z>x>P_zv|(8UzXqRbpQJF&#T<=H}w2>IJG}FB6(?kqbNK6^Lr{g2#r6#nSVX}w>G~& zB40Le!yy{mk$)UC92u~jdN-IuD@!C(QJPwgnzZ>KbSv4_aDq3f%+?O=<~n8 zuS4(;8ozq}^Z!nh{$q0d#rKQ#}$ zN$`e-{Qbh=`95qM5TY?8Acj_LHunBDUVg_?@4vAs)PCmD%4vS%ne6x%@O!%MKRs_? z|8MPo&ppOa`Gwh0S=K+3rPxmj1mv_83MDiQ&s^^RJ|2Xo0r*Y{wY-dBd(|{rg8ddJeM86-kt}Si?Scaxts<+Sj+jB zGg`%WJ%7US&^QjuPuDxJSMuxSw?>Pp{^va864aJEOa3pooPcy5*ZB{=3uxuf$WUcB z+*e8b`u5?@%Qr~=$QHl-i_W9`*T@rQ4V6CF&j;Jzrg_O_K>S7h8`4SeM=GfEV?FG6 zBI*ybEI$~0LRj|L2RnV?`j5sxirSypE%HQNe(u)lV17BTq72~2`+I`4g8q;D zcToAw!*9Km9skpKPdN!CEp?&QNSAnhl&`=48h^aDczu|PX&XAu{OTDQe~bD15&Wl! z+AoE9K{}NBu91HhIFhg2#V*IoSSkURN2wznANC;^qDIhn;x*I+TCF zv5@PZvA(4C|Ct!6Zlvw2XE@USajpK`xsu{a4;JZ(x{45A z@^@-*g5ySQy`Dbec<3nqFj%iTudzFR3*Nub|FIsm->{F#)Snoy1oIm_*E#IJ_<%~! zkx${eX}{w72iQMdE*hcYJNR&%t_yetbfZa4eEnb0{$VtIe|PFtr7`T3|2SFlKY;c; zTpy0>Pe;2HUJw4cT>qb(ul(P@0U;XC4V%Z_yz#3b|CvS+%( zZfAq{UrYuyw^tTLJGuySc~lIe0*)Ma!TP9+D8B#T*o@NaCE$9F8^6T?4F{W5K&|gjf**e<6YDn{Zf6z+A4{s&TT0z%(HBUsgwGu|X zRyaJZ4gLkPUM=q&AH-kraI$Gd>?Oyl_}}nPIG)b^S)NFK*h-i;v`UYAA$GK)aV*05 zaUVl^&Uf427ABQ_P<~rU{+~Q9!*9GE%rD0u_S!!^P7$Z`FdW7yLce%ie;Uo7ZG1%e z{O`SlDDEXj(R3!(t~?R@qnAk0vL4{~(3{7O`bFA5$^2>mzl-AUKU6pWs(OEPLinT9 zf8Wbrfbq1spFWCP7(dp^Q}u_<7!2c%#4cWqV?C}v>1B$qy()=lpOzx> zQw!1jB#O_+(>N$*OL`_PaCoRbvH5G0Wc^P}EC2jP?=M#Q%=mTIn~GmQk>syPf8be3 z{*ZjWl1NQxDa=7FL_9{zb&1a+K3cXZeUan7#A&&ZmLoOD-uo(w6fGOHys|SbucrMc zwiFgE>mlROYRi94zI>~E|0?AEgGhgByg=y>^}js~jul62H8^=+a&yQuSC|KCR*R(Elx1=k~uSuqGg+w^?>_^Uhw4=y~+Q( zqWl2+Z(Bppo%*k#9t8FC$qL+mq99gIzDrM|`UkK7%%djvaq?#;Uf{}RS~m7jCbfVp zMk3QoY47Nw0#{ng0zp?w|K}IDBGVsvyrAP<(QY8ZPZfIKQ){c2_mqFC^Zchj6jTt_ zixq^;{S#wvDgTj|lL5Lef7jK&mtM*BQbr@?M~EN0xgD8ktJWvf=>*z6i3Qv~1sNo7 zhXQw6A1$5_;@@AH*ggD_O{L?vng#P4t%Lc^68Ley&`s)1_}9xH;r8d|J5+x5@TW@2 zA8#JQ-#(Z>4t`(khxLU>+nu*>JNc$lz5MW>tA3{V`%=b#5^tBz{!SSG(ZT#l@Q3&h z><)e9{%bz+^27ecztQ(24}a{P((zj@gY9n}5zH^HV*d}Z|7d;`&}}Mi>E`7h!t-b4 zy+-ZdJp7T(rQ=VA@H-*)H<{ngxQy=?><&HtzGV%){MFh2?|Fgz-@~6OWBz2fVEe~Q zu)psA8~5M*i;thv&yUBD|F7}*|CZ9(-)~DGa zW2w^dCyxr|H`@i|ncv(-{_o+Byjwbcn>i!w#mK)Llkbb; zDe^C~1b*FruH3cgYA^pX_WxEk=#{}Cy%zxtG5AmO+YzOFnUzxYi%fFQE z-}NH$|Cc@f|6b|rZ-w!*{SD@U{gcdZgruMF8$L{&{Lh#Dz5FP@J(@=aFAC}M&-t#e-{ke+0l&%Z_~0ktgii4f=+o}0vdhcgi2dhiO8+g7{UcjT$1kG6{BgFw&M&T3 z@i!4-f7};z+Z!JG*2}+w`9CK6+aCT@Df#0agZb^oYCSm9_Gf;c)(U1%>q7noz3%Qg zk9zt0vHx$rJ&)#&_W1t?rL(`)IfTEHS|4K`@W+`yl_vK805^26b#;mfZ#puF|HNGse?9z(k4k6% zF#cqd;Pl@tfxn3JW$3Zp^A~yf*YNwx%9RvR2lOp z`vv=tSe%{z05zT9W$3EUZ+phekN4lV z$^UJS{bQe%jz68w^L3H_n}*^C2htyt?T>sx!xz{e`oPr7>>&PP8Gk+e5vOeVEq<>D z2l(S9@N;t=0sZ`?!%|-U$awYr{gS6B{=S-tzo|0jPjdNF=T9xu;aA{+{o(&%{*z*G=*i2EdC<#`^7F$q{+s2of9#90viLXj&{~Y;~CGaP>UJH6~ z)rIGK`BU8fC)FWOSRVe^*QMjPj|;ZH*@n}9F6Y31#C6L5BO&Qeg!!RQPPCin$)FJA?TZp?G3#A zsQNYZ0!&K*ZGqr_)lx?ffT@{kexf_I>I24YqTHuZ#Q_ z^(RqYkNAu7o2hYP(dHk}7t9^q+RMM2{r@HT{ma82*;BUsu>V2)H>mg<4M~4e%nyC; z(Pvlk@}vAVs0O9~9{yA*`OV(J>8IfO6TSQvXZ}Q%{GXqD`urgNCI`s>U-$U`-qP7W zjNc03Pv*#f(ZZpdg7{nKR}hwmKlVe}@}vGrx4-yLZsq^SFYJDF5dSc;zwP0V{8+a9 zMpO1H_LFq{&5{4BK&ZqR>!yo&pjQP3!#zFpnUVf9y z|L>FiZ4ZCs=d$HD@Lg5+f99v5CjtY~edzXIUh;>RAKzboqxwU~!=EZ+e!Rcv_K!1v z*6DxyJ8FCR;s3R7rSGS2di?*FvbDe2BRKs@mcWnug)aPH$2VU7HC%sk9koBPJp8eJ zWy_E912~X=ikp=G!@qSWDqw$u9{*>{_Fn$Cng5pSDgF2GM}93GzvvTOen9yRoZvT^ z-{ALjoj<`VppBi~&+zi2{oy^IlK*@7Q>EljhVh5AUy8&2A?2S!=7*lKy2Hs{etf?u zlI=e?c>I5V>FjTSldp^Nv%&RmFve_o&@Vjs%z0k^$?QMfUL^nb@W*~D z9e>)-HU1>G|2)Y56Sa3w-Uj!T+%= z|9JRQWz27K`yZV@o+E$q>7&~O`OllO{%51d|9>xA`{VnO&Y#SYf70Ve{20U^rS>P5 zhd=g5+49@`{Y&Q;|IN++d-wVDf*}5S)c(Qt@JIeETYiCl0ebl-NB+&f9Jx7&e--6l zj)y;0#{9_;{&|5dj3H_$IYvwt#2{&6d6Z3(h}5v4zt zhd=gr+47q$g3E8>=G^>$>Mb8!8^qs@z8~2h{>VRN%P-I`K(oJ@BmXN8jhzt0pHJzJ zbHj1I_Q%6e}$EQ1o{PN{Nk2F`+to0hyL{aKEC#EqqzN2)nCZ}J^Yb!Wy>Gu z{$G0jWr9DX{10yE?_O?lgx7z-{|S|!9S?u1jQO1q{&;K6ResL@Nf0q99$EYDM1ld1z zHu=AYKay9r_BTT6ugo0z@7l7(_x%p`|DF0zIUfF08S}?O_~Rw;quvm@)5LzCcK``jbLPKUSrT`O&XO;}^Fn|Br+WgayBc?oeg?Ltg%|Z2!3IKjPt! zR4rTnbiWvl-(>y-uh;DlZs=j3#8!Lx;s38u{_A-7Q)SHWpkI&1AJ38h5!3$F%MbhS zm*xL09{;aaw)VHsFGJ%`=Ey&8+F3J$_}9typC0~L^|Iv;`~D(sKXm$E#0~{rbLaP$ zd-)G={@aAgpSFiTQlo77)BQ3u`Z35P#i=$^Sk4kx1F{TipH)et_>UW{&*(I`s5?|AqY* zko_GGf2xf6lOg=^9QnIm+Q8R;0sM!rC;xxf_6+_Pn9vh9l{@H{zQoV6U+~tTs!DXFaLVE%cHp@&TWJ^Yb+Wy^2&4gP*%GC%yIr1JlUOQ!g~AAx^6+28T-r^=XLaQ{d6 z0rIbS3H*h8L(scxb#T1)NBf8FRR3(e@A3corL(^cJM(qX{=w$&M=@Rx{v`9mKXm&S z^9tzr7svnQgR_3r^^dI{}@BDp@@B0h-|K{(d z^vA;=JECm)O&-4m9I$^J{2~62{h?Q!zkHL|{@`Cp^*_eeO!^aPRJQzau0H_>_>)=k z!>>MiqupCxe#GC8sQy8QwEveeKk6TJe#Bqo3*dxK@ek-xUq9e$|JI1p&waA|;IV(A zaT(j6+r{bpV%eeJA7i)?*3Kh0tqZdMg|hvOhd zKXv|O3I0>ac7Wb=;*ux5{KL5Z?JhZfg@-?3l+OOi5c?zl)%nHUTz=3UhnHd(=C>N^_$(Dv}hnw5^<=pWpE81|1c5B$eu{%A=0uk-g!{_Jc20RD)qKk@KKnwO40 zo+E!eNB&MNnx5qKAMkgO<3DWk_`z_%6jyK-5z{`*E^Tki91NZLB)Vu(ZBZK+JVO|a%w~9|Ie&cbkoj1q07K`wP zx;@o+_VGDvXI}qZbu~{2=8ZwT#`&NP{sF!8uv>?F`TrcP#y{!*E{`yNo_bQL9Qj9$ zRQGLs==Yx!>ZtYBF8_Ql)0e3A<`L??!uYWsx?Y3oc=6H!J%)LzP_;t#Y$} z1%58#ImHuUyDj=i&Cg@MKh}LNu;buU`M&;C_Z8#)b%p-F(7jGr<*Pq0&-~B5qxg;O z>UqbG%8kDV=KFn3&9@2u-aOxtHNwwdp7%FLs`2SzU!5QK3tfHCpT7PJ@ShDe)BqA@ zTV>)iN{WBWU|D^BqD(bj`wkhVUIA9jZx^Zka~y#7;(?f?3b%KrJA)bmc|$dCDQ z?O)V9JmA;u4F21B9%HLO&5vP<;DG(1CpW3$i@%tE>bsv6e~j&)Xp@`$4fx3>KYy21 z>UqX_9wcxq=6U0-CW=2>`+t1I_wRV^5C4C)m7hP>HaGqbnAa=s3}5=WoadWO7OHd& z{Jq%z=CnieV}IzAcHXkY%Mbtm<842GP z*U`(5{P*tqD*XX}qFrwG$2?BPD8K)w=l4Edtp|Vpzv{UlUX;X-<3_&!sIUD7;&1N- zssRr8W5?vi--6RalR5FcBRt=lZh!rLv*n-p;FdeR_J{v}!~+O{Khi!o{)X%i$)HwYndPb{BQJu}UQrTY3_b z)jbt$NkUjsNytWea$g9EIMPEDR;BbLIZ;$@TS)H5Eh(4(m}`vR-g_-;v;Cj<`@ZLU z*J(8OysWu?W6m+hywB;!pJ?~@(*FlZ=V1Cj)sywV`ik=fIO^ADcXK+sXG?#Chq-Lo zvL2cEf0Xv;wt)VLMgJcDpq@ec2lWha1k?Yo@FU-P*Z*y7CVuFjI#+Y~wZ513Py4@z zAMFS81AqGs`p4Pt*FWFNeK&vA{x4GgXHJXLexmz>Y9s>pPnn(Q{>N)-sJV1Mkgmy) ze&5tqG%tzO=SrR0-ydI_Tj;%;(*BG0r|srlMd}Kwjx+u5T%TdTvq)`|{+K`3v<*05 zw)ni}EEV&B7RWx_$roT>8`2-?hV@L z*GFY^-&E#P+MUv8ZJPf~Km8lHVcvf4_n&F}?q-$~)W1K!K=+^4s+PiUb<7Pv`YqD_ufSE!FZ1I2RI5O zyuFLvqu$s5_#eW7HItw*~00A`HQu!3zgF_KZQSWET=zk!_0;s_w~6aFkcXp zk`|H=;to8i_J;8LSNQRsJ@-@Z{!K&ff5-ia(VcXE;-s|vSe?V=$34n_|6uT*T%^-t z>BpIJFCo5<`v>F2jg+&ySQVW><(KY{t024j2wEPou&zkkXnv^dx9xQQY1Mc@f4*}U z$syf8tM4by)Spfd(o2iEZm{QfQPnTVj7_O&C(`#juzzA$7j?%)etq)VV}AQtiAp|w z^9zOlv&Rrma5k*wXGyJpY`H%g_usun_b;1Mic2KfGMO6&!qCTrh=|=a<<@zkJ+wBdzKXKv_bpK=H^!Bk5nJ`ru!ZbR8cnBR`y=CFJ|2Op4`lGuxmHR?3~|GX&Ukh z+moX^DotPh#G2o{sH4&}<1F?!CU#VsR(&M)$z&&5{W!_se#)0g9X*=Xvyu(-2!CO!{$A;loU|@bWi1SkhErYXzFtMS*Bc&nI-{~@ zH|H5j(>3R@-KF1}<}If8%d05!2J$DGM{=X(-lgA~?Cw;qTNNm~E&V3K1KcqCcD7#( z!@v9(#&68z@egyB)&%n$k~O^Z6P z-J#!_fLA5^kVhY-ucvmlRZ(&Jt*PWO=C^BoA=I9DMM-6=C?t-_QAPbm#Uj z<1a|1e>aLcS))KDjyT?<34^E{)+D{z9;1Ne{2u=6X5}Fn47P;``e%^+-}$Qi`o12mo=uUxPWg95UypX|tEB95x+nLlz8)QZ zw)Z(zF{7_XrB87FJ2U$#O?ZGC=HAAgehMJw`yGuxEkASVo?PeEDk|3e zB#$nldrgzINuFAqU{;uY;}@HTgmQFc$54z zE!<4@H6)~g2e@JW-fGkvVfd?!7WuEt`o|5Vzi~C;rF+8T57+ew^5HyGS82jM;xY2q zG?wsd{g_-**CX$qU#CFXEW-OD!&@9J-<*zmo@ch7NwuPtx#FZn|f4cGXM4qO_ioj^uG2_zSNYdHrt~s z>3yQjw~{=OfBB0|J*xEu#}`@ARB6Hk+%RvA9sD2+|7^N{SwD6gF2C-1l}LWl`XBcy zmq(6Mn&Ry#Kj_}-Xr1Fc+UByn*kspako+gxki6HW-$XY}pz`r)zH;cdCX{DYj|viz zL;BzSnd-A8Jw5Wk(0{-U(~5rdRT%y$g5TM|=^st{@i)}>p0CYUiQ5}{bX7Hyk3*?^ zEN|@5%hwYAt@M4eYwAz=<-DJ->;+^ey33@r=}h{T-q++%6|2KnP*_cnFYD>XN)sO7 zhS_}JfVyG$52yaSevH|i{xJ`Ky8ql%^fTgpn&dUJ-~BjsSTfs@@1H~IPvr$q<8%G~ z`v_2G_}@?QhsS%s4Rb)-qeJ!2oK^D11g^iv(|W){m6rdP2l4mpQAa6F$bW}^YpT_c zzwb;ZJJF}YU)kuRl%|tUB7V!${A|0F!mlEIblFiJStBSvJ5hdKew0Vq@V|Izw@6s} z-?4+=aOd*5A=&W9r?gd?fImUMH37f6uC3Ap{N}W_N>euc4u#bO{PDRIKM@|JJIpW6 z-THPI{$~Zhef^)~Hx{&2ntCfe-;w8dE1pE=Vt4M8F>-KTX;2n-o?P@K?}pO?ZGC z=71AlJu(b`a~Y1e;#_}~jnwi__q0ny$p_K(Bu zpCJBeq^7N{#Lon}XP)Q@YCr4x-rQa4QO);QAC-|^6Y{5w!fN{M5kKB3RK7L-=tQ~) zo@mnwAoiOn+~Qp4?3*fw;lJ{0mLK!}aQy8_-)p?dWu+d0ALl%}cb;haTE_2^zb4=} ztsY8KHvBI6Y04G<`i&2qABKPNSZP1>Wc{Bl{bQ6?no{Zi38g<#D*fqq84>VTP*_db z@W&_7I3iK5`1fCY-`p_#qrTzvw?=2mf4ctqaS3N&d`~x}=^)0qhHPv&;W6$J>X7 z;n(B;`mtr+;(u};K*#&1^8nI(wG3z z%VI|y>n@XD^sdq*PcZ#Aod4*$F#N8hzx5HfKZE!`CjFhMue+Vi`Uc;LnCu@XJ*sKr zCh?(qL1}uG_m8i>Hl2E!fj#cpIFUrxc#{Q z&iK>%^Z34;zXoB^)EW&7`OtjIMu&NDv!}24L#a7p7_~D<+FORM|*qG z7kg3v{2vWHdSWo?;;*TFM0QQ6&lJ6{Nsm7m^nMw=uj$BoWPg#ylgLjKo*@3ucGOxG zhJW99P9Hm-i9anr!0+~Hs5JdFn&jgJl8@emj|lvz0-9+c0^VpZ;+F_`-MSuAB@BP%Gg*F&;hg@-ay@>PZa-UHSU&B8B}$Vj zC4L7|*`(i^&Kyhmul4=cB_0i#K=Sn%)gU@7(ZGH{#Ad%bY`PUCO4HH-Y`1@)_=)fY z@vj?u+?Fu>dj3m4uFTv0**usI_h<89+W&uQ9xRCeqMKVj7KVR3_0{!by4-(sKh)`; zm+HS@yv;tNv(hx4%Ab8F>C1m~_GsuFO8?nKDnWjl+6?icQ;{<}dt}o*pnj~gC_K@w zK>b(Jh5V@f7kq|_1I)(L_I;)2?@XD0JWlq%ynH9ghgDtemvuSL8C(z0FogHO97^qq zO7w^LhQ)Y(*I3VT$0(@|mi3*L)(iDw9`8>z-o6NuevoXz=9IabC{8)p-@#}e|O#J;ehtEGg|1ihzjyv7M zX-K^P+REXLW}MGaamT!*^Ab7CuUp}MO%DM=9II`b9tkPo;O$xsuF7q$D{ti!m z1pfg^|G^V0Q`^5#VgEw%Kg8dl8K)2C-+}+FQg#QwNNJ?MJEWa*k5A)o;pJY69d%dl zf|Z5&`G-c{;&`zB;qI$w{PY(pl&yIkturJ%{Vf{T&6J;WYjQkBAC?n*Y3S*K^GJ3# z#p6O*4}o|{&`g=jnjsnm{tR*X;ZW>&UL&NVh+W zB~?%lc=Dt5r~60wv6t6W=0wJy6#USeFr5ee=@0oqc@(x(P<{;Y2+EIfM`W-#IHh{msw(>3<8ggPbk}s^BF`_pSx1 zKAAR|(_)maWPVBWPENN1wVzDYy+F+*aZ2vVSHte3x}NOklWF&$@MK!Y6{u^qJDGT* z@&o2)l_r;J`7f9BuP^&A;?)0gPNeyqnvCB%J6!&w{ru_Qb1LVfyMpT}e0RR=TQL8{ z?nuAUvL7I6u>LpXg>sr7bk|YeU{*5~yEa{ZOT{1c*SZbU-pDM!RRn*Z(`f(N$r<|p zoN)YlUM#cxW?R2>(KfE9l8tyg060He%>0`Dxcr)e5Bk$AYNnh{O~qBIx$F&+BET|B4;~Jc4tn=*gh|4C+8A$SJ7&iQ5E$l*Fgsou?`uVf@B$#t*#@Q_t(^XS~Gw&^z>l*1hbym-GjQ zTD}@i5$OKS*;F5BQ_pwn@gMZl-t0r+R^=-_j%BP)x1%99hJ3Hl>b4K*^tU%~x?%ll zi9`7}qEKP~S5ojp@59vdVw!`Y65nB1-!J>4#95sw`yNp*ARSv(m;8FwU;pm;nbPmK z^tc=1k#4zy*|phY4K;qW|Le>C+08WnXpT(dcg_o!AI6_<|F_0E;VLXA`0m`gew^4J zTl_1_588FKZQ6TKevONdRt^!KV)+67KRb5p8jat0h2uy2VRWO)${e58Kb94aU(X9< zmfu2=f9$)!caJOP_|*s8{wWfVVJG_e0xsZppP)6wOS&SO)ciXfJ}Vh>n{I!`1V7rJ zKlUK~pMl>PksJOS2Qr=@{?&pL`-^~ob2Z^h_Dxao@SdI2WYguxT|oGEqSjIh=@0z3 zU)%6Co&K>`IUeBubv5-LFDXo|A5Lb$ug66*<^N_`53ODieJ&qr20as44~=!h;Mb7w zzt?5_zzGxhVLsli#VCzGxsCB-|ISjf8i!O@v4ph$M`lTX8W+lxpSn?w$J)zs!rF;+ zi}Wj9ahKr|^^)vUvaaL)FYsgh$f!}QoR&bFPJg(3vi^h4Vfel7Si>}aYt;WY_!ETR zYy-6E{ySV=EjeMZ#%~7J5BJsQ_s%L*?jmXbj}FIgY}NHwT7UKy`GKB9zPFTi8r+f2 zEo9#{%7rN}I5d9ZuAuK9U8*7_rHDqsALjI%*Dv?*OaH}``ZpG(^+b==RAu{Eza<4f zY7&?cYA5O^&W0L-eblnfT%46F`_s_RGQ&okQ2CGw!}RuCd&V!DQA9@ zi67;6{l5tR<299AL*#!9r$2DRH2SiH1Ali(f8dnQsp32?7r+S|`(-~N+)a5QDf?8B zFW{?0fJemadiZ^}XX1CP%RE3sE0O*@lJZaRTVr#>pD%g_c!0lO4Jp^dx&Iy!j}qCp zsp_-7iipSWT{%4Tk}2*bcu&mDv7cLL{DzEQ<%#^1b)fNwA8Eas;5WvF<2M88k9{N7 z3;zClf02K<1HX&%a+<$ifc7@pt5M(}yoblo5A3e%1|KH2G8|Hp4cfh~-G(R3gJXQ(6C@t^auXyKd1KJ_M#Mi>-_&t{2P-oI}E==_>H&H_>BqwUHFkt%fCOeMkfA< z$j=~>A9Ej#KZyJ!|3m!0WYPbr{+Gx}Oyp!V_E|~4*cNv~%5OyMyAQV5sqtH)f6#um z2*16oW(vPEF}L&|Dta;~|G{!<$oGTg6zPic?pE@TmpbwujCt>@n&FM#zRBea`sc~J zX#9Kxoxe0&#(yS-<5w@T!iY-0x2opkAc z34RL+BIdyF?zgo3m%rnep9$3eH4fBJNvXe_3&Ydj4AfuPU+td5a*NNU&X>86-3{?L z1m_e;Id#PS8EFT)uW`GgOx&Yl8e+b9`runMen-kL_CIc+`Rn9Sg=(XmA7xDr$6rG8 zNBW7gp$1^zsf;Ixvr6p?mVLE`cvM3FPab&L7W|AUeB%M$60zk$Ky)A z1NV5r598UB20yCtyCOf(pOIap|DUL-c8L5q7lo&PX+VB(4v3O@QhX;U|0UuPl>ahu z56ZtQ?zWiI#eB~!Ynz$=2c-VJu{VwX{7m~ThI2YtQ^N7<`Ct9S*-$THoFUNuTzMnM zV@7yh8}iWgNp?p+r9$HQOxoLU|4!V|?gam}&%WH(e#89r)YA$7!8CqD_CccG1v6Lt z<=eR*2Ry((=Vo?yFJ<}ZBsk+|3ty5Brnnno7K{17$9weo52^7(jGyTJo5mE{zbxsW z%n|=R(jGQN@5yJ>fZB`)?fi&%yeab<)&w4JF~q%^^lRL}d1T-l>HqMw@jWx~WBz5u zPHKPdC`#dXrsgI;=S}mc8}LK^QGS8rlz?6`<%JbZI382-B_{531LpNxPhFXbf3)bI z-L(F}tenPgU6LFA-H`J@`tOfP`inc#|G-%yS0X2d;0u-);HPCs-m_B7@2(#+BNKnc zx!iw`K0@P%7i8%FY2oWb>#25lAgf7td-y0 z6%XrTaYsKzD!c<{vOYq2Pl&sL2*q5WzVYTyZCQVU`fL8vdi-0BPbNFr|KVxbAn=?I~ z{>EkD_y^FsT>Zq^P}$~xmCT<8$3Ii!JXibW=bN^S2jMM=A94e;)|WfI`A5tjjTiaJ zr}e{jSxu#$<@`-%!Eb%z?|(JHd~QJhEc%JtX=o2e1WzMrzZti3y=;hkiL6(#uM@sR zexUbJf4$Lu%VC-FkNWF@Z%KZ7(D>U6jNiFDJpIjme*8n_{0hj4z){EGe87PI+$HmO zY75JIeR*MXVEiY=m-rWnIcWF(jhXl%|K)_=tWlK0Z(Wfa{@^&Xd`1QNii$^&FH_uu zeDx9cn3$0Ny-j;Pmx=#Kk$e5dRJ&KI~x#N)0<{O*RhcYN6I9u;@U z4a)H;qfc#=nf{eTettQcT`NjCjf^%v8?ZIm4^`F;d!7uA46xXK_2_KXBFH6p?2CmKqhqn%}T!An6!`$|G_dc2B7vooR-Xi_;Db-(c{f6z&=J_nu&q`vgN{)*4~(0OOat2`RA(ffwY z&*>bL;^WmFv@Xcd>u|s5qsqwNkO*NGKh?8!CVrehIkb@GujkVGNx`2K{L;NpFg1St zApNIfJ@C$#KXI=5xNgBU;iQ@tO#Ql{1 z6RM~1JJ;qWKZ`MLiS>BIn|}JrI)98m0DnySxp1dt8{TsQ^suzw3~>*Z-;a;Fz&HPn z^;hM3{p7rK`dhPd!=EkvA^-Lqzx@BuQqo`Ab-)=MM@9Oh{({+kN!d}E^3ziE|DDwS zSEtlg(PO#&X~;P`kQX$3v%bIfwik;@_Go(fy{%bz)FXnBYeFEf)JvL+x%$QM&0iX%cXXS7>e zMW=s!E0-hmzot?#vnJ8{TPeTEEcnX<^$H2TWirjPLw+QC)J`d%=*Wgmj!>I{zbiG4&?Db`JBRerm79MD-7{i ziu&t$c8`hszoz@~TjFktiF_C}@}Sp$FWbrCy9@sF=TrOBEK;_VU*m>w{CfSre&Q1E z4$M1`Wj!y>YV$c9Ki1D9{e%5_Q(oBG%O4(m0XO95j;&AKrR68KhQs6ji~g?@{@!W) z$sF;w7JaU6;PNZOHmb%@jz8GWxv`EPXH@XdlKW#&el2kaACRNTk8e6f<4*|wQW?KW zUPJR2U#IaqH|Cc9!E~0-Dp%4U`!9gAL1)Gfeu2-H_8#&pE)hX*M#TQ>9mDo({N;il z>o*3`LMZ3kBASB~`M)U~zoK;#`a%4ubHinxS3aW-LwiidsSNS>3hTARy_vYD)8C9~jP*`0#`e+2Uv$N2j% zQ>6dyJmGH-be8h&4rhG@eC2_7VgcO1AKg>`NsYfu_K(yQ{5uH0@lzVVb8~q52k~S5 ziP@gdT|feqNxvBQ4e{6@as~Xrh4m_k$CU6e5$>r+`*{6#q(AWgqVfNn#&0EZ!#_*v zFW{8Vs;AzN@n^}GhLA z`agnpMF*BE;18xha0b&K`2v5We^;w#E3f>nV?BWO&rAIYf1XUPP$D|F=9d21cWPvm8er;*^loaD!;mQH_TL2mf_ z2J|HGPel0*$WI&5pTYEp{FpB>zes=JM*43(XHiVck0JOWKl`?j{8UflPv(d}oBV9b zB0t#I8N~lh7Wn~wnDcta^#0#N%|QCsc%AUqNaJ^I|9>X^_hMgwwiwG;cpK>e)>r}-(1V`fbUo2b2|a;3gA1v z@t?OJOo@2TF*7H7=`Z_7`ilIUq>ha)HC42Yl&^n=<4=s_h~g68Tp5owhwyx;IIDc@ z>kss^Y>YR``Y}^pxJSlI%_ck!jQAn<;Q#Se_cqb^6M^(U`~oV!kEh#j$sF-Nfcca_ z`)$F|oDP_e#`l+^TnG3%H{YL+;L8yHU~Vm1;jRBf{e|)KyJ>@Da(NoRvnV|Mody2( z=Q^}ApXT~hKBw+&$aw5AtPg?zod+d<^VuD^w#{aD=Wf4V#e0Z%^?UtC>-D#e$Pe1j zKj`uE73ux6)*a#av41u$5vIm1T|fT5vMyAuVRzIli)6glmhiy$0Oqg79sQP|{0wY( zMr|!W_Ilr2uZ_EBcq;n^%_Y2%RQjGi9 z#NCwdM8(AWYo6Lr;mN=6;PK?vNwM-!-Rg>8b@;vRo>sm9F{?5I*rGMwc7$@pq;BN(amUFI<{<}*!yj9M6-V%K8 z*Aw?u>>d|)BVeB0^t2Z>{)D7I%I|fA->OnAh2Of5@uS?q)a5sG{&b|&Q@F<$_%B^1 ze93xR;OIJr_Q~#``)URrt;%mYS`DNPK)_ouEo z`9_UDDfstG|F>uxeYuGCFQfe<=O|;|3#Q(`uOFmOrJjt_+2wElw0c_b%f5yPzou@z z%bxy$+t>57+oq|UF|M48+ApWn1FZ7N71HV51*||E6 z-;r~mfg5J7_}5@QB@2FiW_0AXG=6!0W=oL|uYj}dDg3?+4QOU9wk@J%}H22mD>uzR}Xtp8@>)2arru zP2)En{Lkirv8NdM0(Qtlb>s*<^Mm# z-&)#%m=6lde^Sc};l=qa_6U-vC4Y@SzxX&``v>@cIEu>ev~>DAi~qCq|112?Xu5BZ z$}8}jV|plS!yoYn<)_J^Hw@A8lL*L9A>{xkgQB+-Y`{t3!YlJLeKP2;!6 zlKhiBDF2Wjn3bD8!TMkDWB+?&(*O2^!j$|N4>Nw~eVDrZ>L<>ILOL6He*OQm=pWpB zjdc84+W(f^Q*KB+!E+d*;$9jstM~2W$$xAkrw{gDH~xm!-wrNH;ZNp>KQ;f@!#{qG zevLh!`vt(+9OWX=PYL3W32wXx{!h8pyj+)GSMa0%m7w!CoG;StXXlad^f#X58Y(XF z2hYP4XSGMhqfnm$$5`3#0QY9{!kfo%dM5Yrcai?4_`~e?eAH_{8~^6;{iXdDr~Zq3 zW|4%ZHpr52{3|5{@MAtA*#4g(^C@sQf@g&pXZEvh8pWgHCp z#*p`*zlQv_$2)%m>nE}PWaa%d{_}O7Dv|r^ou%RFukQuW599~u7nvV(yPbWNdJOwy z8}j;L;4cff8}fpMak(x2{u{+zm9y#Xh(1)|wiB#dgLI`5*8$ zwV!{;OP_z0BYsorBXbe=f8{gE!TqNq4~BT`mHxilm+K4QY$W}9loy4{PSf!4DcZRvEL+kAN+otgA|be^hux`bBjG& zmeT#Xhnli}2I;@#0ZRX$()g_>a>Jhxy@CBWz+W!s*TEhAp9u0x^bgu4b!1&7#(z*= zkp3_)*{i(yYotHcpBK%c^1DBc-*_@N{Hb*pd;H^vwM7qOo&xFL5bcM6T>UQl&Fw(? zqx>RWdR*sR<<(zr`{lp5h}xeA)A*A);>S9xp#0ZeDEd5r(+Idj{x=`*4{ri+QB(QF zW{q2#btC*|CAM++*r#l^*7v9XlE&|p<(B?m%KAyCv48zuxyV)WO1Lv3^GyDp+5>&t z+ru{?=w8I`wxEZx^p=zB>-2YC<#-_fm1zII@p~G-^;B;7(Kz$1Q zJ8s}~LwMk;HO229m5A^j;yq(k+ooal?{Paw|1_(b*8e%;M>$1%2H!z?!X5f#8s;xV z{{Y{;n3oCk*P!?D{>V?-U8dy+=N}^dubN2stETUNcb?8I{r8KUyI*p<5%}M4?N3kO zdGH+||@wY!a z4Q9UFfSf>nP%i-gB$;n=zV)|14drhDy?y7W5iLJuf%N~J+7EWkYH9h;5&ss!@AmQc zf7@VQEP($vk@Ms|tbc$%f%&qlSbj`N?_y+}*f%eH_FYf@1NaA#_`0>y_?>5ROMjfd z2Yn)+Q6~r5Gk}5ik8vL3G~|WPv0p~`HN*pQgz|guyyOoWKgOR?ehoT*BUw9N^_TvO z^=vr)C4u(yLDc)FqCR3k)v>QCFwfpq)_+2NOu^p(dP(*x#l*c-Oz`pSjU9(-{LU7Z z&tmES8u!pVLW`=Z2IdD>hU3@wI_W3QhMFYf_UdV#PZVdh4t)L7-!8gN!W(Duc#$D5 z>~1W2K;{c9aS!UD#W%dYC^P+kmiY^Pf0i@5Mhbs2NBqI_l;pGOIyq0qJdw*qL_A#7 zvocSFbbU8)E`b@qkM~Kg>x8i%2el3MC8_0H zuK|BeoL5$f%LQF{ig=> z&jdO54C^uQ9qhAE(tiPt9dcd-#y_$DF&S{jyjKAdL?T}B{h+D3|68`*kAFsMntyMT zUcYC(5RPBp3#OmA#1~x8AkHedo&hBb@@59gb!r_&OFlnGU!$TQ$Px7D{#|!@>t~|n zj34{=htc{U^V*E_4_^$&ug`zh5AYA|&+%Z~#`C2AdX4wH8{#ot_GKfyDeirsuSEY? z;tv0)*gKu_g_|k=4W<6t@FumNkE*JSt9buKG7Em2&Uw^N3V&t6`4aOhpHU?;o`dph ziASmIvxED1ai4vJ%oj_(Ab#M6x%=eek}&)a>-n#%tEccgf(Q8yGl;)E&TSs#Z$DJK zi1~5_55C{52D>}kxtyAU-@cLEt#{cyChkQ6b6VGbH3++Z?fjFtptuIFU)1Mp7pe69 ziF8FT-S0&AA)e95qq*d-?*)pU)W{>OTS)Y8q%<`n0oLc?my^Gyy&Y(L{)2p)<7wp4 z6MCOG-6LU{7t`$`7^F({k)Ox>n)}FbRh+_W%Ju~Ld-JXdd13tN^EdTl zUdZJ@pR-w{=sY}jrn5;1FYVj6KB~jimGHeh*!AI6{F zAF3a_7U!RNRHabZ6a+pL@7&ot{QP2ew1VKsq2JUO-J|j;3#ti#YdFw3G&x<(%|)B`Pbr3 z=Fb|%`R922rS%K$cQZ<=(LK}ERCE^UlV1rh{npfj>^9je=(nc+WKWXaIRn4PZ`McrJJ4(a&`{`*Zf4iAK^PS4R z{If}aT01DeUTWgeVY5`r9Pd8RJ@n|sV7w0RgAJ#VU z$nH+#QFJd+*{UWU4eiMO#ySd5^gd;b^*X)u7f&$%ijO$9au|P`?&OH zA+^!^c~tv&@~8Wg46+%Ju~LE1LDt`(ga` zr}ek`F{g0GqoRZOY&1bM-u$OIJ{7ehqq8Q?@6_->AFZToA_J4v|miNY1}({6*Ffej@M} zrQe#sUyOch0)O^P^+?}R7|I{5Ph!N2Ch+G{SWV!sf_`fPe~Go!ej&>C1o?a5{-#HU z@t15T`PW9qp`X&K9}yb zIh6U+_c&&@Kcih}{EhmfWhb`q2=_5Y`?pYdO7UIN3Ep-mjngO!B;;jz??7UPg9JjxL{DssH>6^`D8d zJwg61+E=Yn7=K&t;uy?=b38`NJpR({Gqg{lk?u+p_>C5jo#^G42`{y8@EFHY`#Hm| zp5*j#3cD*!?`~%PjOyKK-*tC&;;q!4$rx|>^=EpYDQKY2OH6_@g$#LkiH>5O_6I!-l)8p^jp(V8h#rS!DoVdKwWs{l;msNCJR1Be+aom4s3}JI ztHWE<+j;cFYiy5PL;ghBo*;kEb(r%~7=N?w<`~=}me1ryfBRGK)6(V1xv8^9uaeyz zSfDCqb@r(F{ZzhArTn|DvqyB4nb&@HDZC~{^@HZ$rr(;n5dZFDG`={mvq#N{pUh{{ zc@+Mpzb=2Kyc894@AJcb_uJ!qyTq|n|76^6V7|rUFnRJGOnpB_W%{G;jQ8MtHK#(_ z1>%nTnS=XFFh37>>IQqyTw+D%pZPZ3m~l@uRlh`bc2Z?`1HA;!FrXh`j_T4w??3#* z{l_tf^w&T0lzTJJ9~f^le>Ej8mVgMD$$c%cseEoBexYa^3s{-Mc{5o zdnL%orM#{Ke3VIeCGN3ojEQ?`!0hqXqK`89Yb*IzMe+~l z_a=7zJ^ox-e}wbiz+dnjS@7r9Wd2M!_ZR$KF6*HX&tLHexr8~f)jhj1`NR2q|9pbw z6Zfmf-}!s|;hr;dhF?B0PYHQ8B)yRy=7ZcG1mCH9E@fUEe9LQpFyN1Tyl~q`Z8Q1n zB>6Wn#<~UfugBi~d;IM+Wc|PFcSiob_!Q@pbwA4?_;^_6VT1F?!TX4J#*iYts&-nrVDr22mV4wFtWu328%U*q{@>&8N7)Brx8e2=_-lvr3iG+&6&Hkt zxMLrnE$(||9b58EPN&2lIPyE7+`()cnb|RuKb#LWeG{*3D3$d+6@QaI?E5o&`tuLx zoCM3Cl67uyj|yzGhm64-kLhRU4>m(wU>-Acc&|+UaQ?ug)_(rVKlpq32R(v)A;`bF z-Tn0ga9kq%q26dFIH9N9Z@C=>zQy|w2J#JN$2rAkW%8FVMF{w!HfNDW%A9b`)QYzFu$mH_w8o;f;`KkVH?x;=BJI zf2hxb`^i%0_XP3}=L{jg!5`!t?z!>@d8xQ(Mw?9jDrEiLh;Ny{{c;|5?4xl0e!{v~ z!HaZlj&(eN{7da`lyy9YywFkB2ZImr_wWLiTde!}pXSf_h3o0)$NxL|!};xzPyToE zhxSXw|5EHk0YgZ_cuYEh@pvP}Jn_RGdjbazhue1-mdVsAKq zyX5{+;|}f*h&uekJ<8D6-LPL&?rVgeylfilN#}H4?`TOx!Fx>O_&^r3_*fdqpanwJf*hO|1%oor}nqUKMUs%{ZC8wt>d$(|KJY(fEVjg4SC@U)H8wo zTvMgLVSU8?2c!qS6EyK1xcBP*{ScjhuJDKT^Z%mui$naO{Sx~;oWCdJo+7jx5$_cMf>$a8EvEe=WwB z>ixi90DsXh!uiX#pXvpv-<=*Tx4?z{OK>*?8SXiNJMt;nL*!QCF;kp`{{UZxct zvS0I8A^C^$H}o}{S7?~dzsQ$=kH110UqZVP{Pn5Bc#+@05tnt>&hh?!y)E*I{4)i2 zHUs>@fBiF+7HIyI>~Dg6-up(8vNHIq_?!GqmVFP_C#)~P-;KDBMdZ*BAg1g~FazfV ztiF-kPbjY@fM+q$u7-K;vjyJ%UF;vl`2pT`y2I)Gqy)#G{EG7rS4ZM5E}PBE>!D^^=cEgEDmC%a4bJXNFj zh;idaj2m;()G-%ate%TcnLKs!$V9nwL`^^!3NtklLf7f+pX$*8Hu6-GbflJhT|8lO6)yD`<6GG^?gF{7p)Gx)Oj znC=F>bkfDKsZ)%RlP6E=ZqVn>IREl7QyA7U7wg|%pc6)n8b4-qh#$Q%aKx00$B&ql zdg}t%z4*>Nf6AD_BgT0UI(PCS`;!+4kN*YZN|HH4X>!xUqNx2ljW)XhQRUjnj_gU_k8Giy($0nK8|Z?pT}8^5Pixlm0#d< z#r7(7bpBPy`IXqe)S(gW-yV}bzbu)BKfNv@lfR9M@n z9z4I&5_j;IyqwPaThd)z(+2jL!R6FmtJ>=G4a~s#a=Utv9Auo2=YAh9pPIjX(zd2V znC*Patx^xU7RPg_gioEXIIf3^E$*Rq9!Gke=B-__my;d*MCtrO^PxYUHwQjoLat!{ z$Xr^P_^W0I*55XwH5;y3Q|bM!Rp}4U8d*gsD8D8*m*AM9U2 z_HyzcJ%{7B>d^b-AAAgPfPPu@R#Q4%P32G8AC{aWhx~^b!k_AUqNvG z{1+Myb$ZoQdjDyre3nN^f32tTaa;{r7gk*@e~;vc=C!TkYtVkK>S~SH%gLS~`>lgG zylK`@28I942|1Nrx+b*Q~+(7LkfYVcqVUq*J9{J~GGcMWB}SY5TA$l=S$ zo}~DKPvwBa9rvGndSRtXhsFctZ#(U;u^U!XW<`y3&PHATrS;2x*$=M*#ky_(>fQjSLkUHgU7}Ltaw)BAI!5B z%ne=t9;w6#j1PDo%B1}SRTZr#mPoOGFW#o5(v;f2*QcdQ5G^5`djDRuWlN9FFiGBN z|DHj1P1vtjc6v*t3H$Y|(^@J`-%-7;AN#159<^9U^0b}SN0d-}M3Z>gmx}dm=@Ezi zD@K;`?mC^+MVge(y6BluOUZnKjO?{wY*kxr+zx|zy5R%RP z)UU{Vifa4q@B?2k_l(WU596<_fZwIB#i_qZ z>*&hoQ@?-+>&qiI()&asXnaBYCtjoP5#io&V@o5Y2@moOW_kXK>%;QTl;(%Kkn26& z52D)?Qu3Kk>-&<+X@BVjjXZjqGFRh|kX=)pnucZr;(sdPA?i)_ytSM5hsB8>BHhk% z$iM6odY@?C8nQn}{8Cs=di|VLh2(!)Baig@cWqBxM)47?t;O*>Qz*TN@PIFv)BFDW z!7%;~AIXMLE%hip)BA}c+i8Ch5!UxB`mG7;`>h@H zE)mxAn{U)pny{WfL18t0IGN;O2j%}x+K)xl{xPWAX#)Rh{L#uIVGw-59Fn~5^)UYQ{TTW&?`8R9{-}PE zc$!f8(d8j>aN6D^f<{5;a%3q9rYr2u_+CNUeHT~Y3?Fss=X=P`!(>m1h zLyq$3as8nqh~Iigd1PEd_1#{y>XlkOfPo}x9i=qk0belhm@p$A#-B^)U+5>8=lJ6Oc45Ql%-@L*(PKQe_e)eq#MuaaF0(WF61`kx3LE z(Y-HA_&9|p+Di3B*aN;`j`}S&AdJ6SZJ9r_$uKV>&cAf~tgHr&UwlaU(YmWgP3H6W ztodE(-jc3r6t#y9;y2!${E4plkkdcfqN~!hn8NG&#BABsqgK1wKeoH8(lq>HKmLcw z?#WB5uBwdaoCWM(KC`RRga>@Vd}NKWD2%`4Lgp{|)1T*Gq@3ertmMtf1eTpg$9n>D~w;=uZ{zL5K15Na@c6{niBiXokH8%_4zUJHF+N0r2A*o9x>MDdE|8R>xUT|S)TyM z;g3^z(uW4Uuj$h|@L}`PFW4+|^OPoIE5~QQlBYb9p~1*HY7-OT0bejL{BGC{VfpvM zbN)6Y8*Z>9Ho?I1`O6WsWoHv8K#%COy`a zInJcVnli_k^jK5oIFlZ0LVoITCQX^+OnR&d&l35uNX+*is-wrxQs-k1ll8^%N;E$I zRaNEI;Q1iC8p|p6ExdpgS% zzT0jo#}m9i=3AV{7VXd&?_+YxnKH$ zd}2MmJDc@|d`6v!{ZbdQyD1)r1kUAk#r+xR7g?uUF78g?T*;)k!`OizVpjR)?j@Q( zJD^|m`CduluR{29<(x0@1yi5whTNkjpGom&%6Zeacm(+)wdOrR{u1Keqm<>- zmHjJ@xJz`(k{>Wn*?FQ@{&0Ts-6Eg!=TiG(G^CKqVkEr$>HVep0e?$pOZlkpuOB{< z^##d={`Eyy2G$)wzZ}3qR9%i`s}b#voyrmUYbrQG1VZlK&?q@jbX zCo_LxeH)P%K9==>);fQF4?iwEJ@6e51F zrr1x-yRwqzuVNLyH$eCsLH8qCozvs(>X2~$;sO2)><2Imn2 zSI26M2kS;+624g4L2wV|AKpj)owk2n_00ThCHy%ZDF1$@v--a0?<8~N&ys!2>Kv}e z1(q6HQ_@}J3i_rmK)}bGsp!tig=I@|>Up9)` zpBL3u`%(Wk2+zNvBEoYezSMaFtNiB=EbGGYTd%WTM|b@VSziFTjY>Qnz9r<@6q2{t16rUl(gn`A3Hmft`@g22N&(DBia)zJH~ub@ z{I+lQx39sUaWkj8A>YTnE#MFNu@Z79@@z?XCF_ul1mg)z6Dquq_|HhJI7##8Nd95{ z^n}%ve;*X7U7)}B<{Aj!zhyp6Y5Fg$b zv)(6tyz|2oFYtSZiT=EICh>Pfnm^;PaQ>{tTvLNTSI*B@^;wU|XViAl_i#7F9kD+4r-#=(iX8z3*{`MV5?a#(({?y^Q z@i$u9zs3R%kMDLnmie$A<@`v9$EvZy$4fj9;D~$ex&H8wJLe6*yDQ;g^p_u~|GsR# zU_d5+?S;Rahw1r+G=Iq~{ONTE`k5>7S_2p_@=2W4E{rQkz8d0z_JA$?nRua)<8dWD zkbmEcJK8lC!i$M;rr1AhH}1Af{&2slLF)_L7HR(6Bf|49$X}2Td_KsB0gnJ5QE?CQ zVTya>w!(K4f4>6JAzX<#w5hT0o=pDGzHYRN+SeUOf1bkn(`g*epFVe1Kgd6e}w%o`0iD*KOOa4L_Ai?ePB4B1-Od;A^B9F+d;_J@<2b!#0SKL z9egft;ocOMf6Hf4{&h^}pJn96-~V*}*?%+t&~5?SJ!VzEQuBxXHE4fcPUl-1pBEvR zGMh4g=rO^xB9(pPXEyprf&O1rlrwQh{_SZe`6TOD4f*1LvDE&h`Im}=4V3$018=>B zdtZSve`%nc7aFLSY5u{W^DYfq<62JscoxYITg-oKI_$j6{97veb2;^ojA{{O^y2bo zGz-r^o7O4mXRgHeb3Mju_vCpQaaJX`|8E(WC-4`%Z>FidfN_rGC;VN==c!G(et?`C zf%+Zw9?UBjclGXP#Q0J*X}|0rMdN1+kW2K@=HdLg0sg*xll!+=#|r-PWq%a(I`~^9 z;o)w|3$;+cOTRuY?xUpL<__ZtAV=I`Kt5s4-P7Wh%>4U7_OC3b^>xM`rSpj@)}7kJ zbpF1zoqm(OjO^Ze%C}Bb@!L-Xd#U!dDK1Wr3;JgAcY?@gB1-ME>uW1(0Q2Xz$dZ47 z`eBERLnOcS_x~_%ZyMZ=M*iVGRQE`hTgc&D>=SvO-7UepSk|4J(jP{?inr=7KT5@{ z)9!``HGjq$PRDk_-&^-rR_1X<%9iryv<&A@uPf9K%HL+mKj%$uZ^>uW205n-^&F1faSx%dLM;`MIFoW`m{Idf2_f|{h1M&&}fL940QNb5X58zEo zJdl4IjEM>UOtC*x>4-Nn^Y3`!&pRK#a!uuol=@H3SqEP*^||@_LHR4heT=RB`UUfL zMjyYP#5qzZPnH*(Qf;NYqTYy$`{fsNIzc`iafbo^AfMMfH|Xt5{)P*G`uun|uck^I z%lxS}ET5bD>q4wBAJw3XK_L&)a{mc^D zkVb^{6bAj)glCETSS02>{YLoOXDg-s60b(%*Q%O|e=hBzqr&xzK9^iSb0xl{v_Fme z{Q39(9FeOVSzlC0c-(IZd5cKG?X1h;)oQN)>Wce#S)XAZ&F;bWnJMuaV)kEu_9dC} ziSaYD9kmzsBeyAS+lKSEQr1aTSF;u8 zQ$%nC(*w9L-($@p61Vp=Eh&P{96XR>lqjLORwYM@nA#nAz$5BI6U|c@@GnT7_h@U`_YC=HGhWW z-)X{M#dDN@mGp{FdD`d3-@Q^l{HOUBJtjzrTMf!gR z^>2;JY5tNq@|P|Dg878}>n!<-at2(%a)$gXs^ZtHrtkryzx;sNvBBwcG=B-nzZaoj zbpD-{p1*ZFP1T!2=bQzV`73YQ|w*pkNqfK_zoIudqQBxVUd-{kO}O6+9DN3|JKCS%Z(qLO zotB?_&!d=Ml=cfP)Av0QpG~RD3#$C8*YC!JKaB4d(fw%VsdRtqBiz0=x`gu=OLD^( z{Jkji=BCT(i_dM6aTBcXDH4y5>N6j3$4csEa=w%u7!OXJ<0kINCwwO+KTI)4eAnF5 zpXk4zBJx>E`!|he^62g^=1-Mo;qQQ-zxQPR-FcYnYkW7j&eIT&;5raf+z*lS&mgy! zxGVG@4hfgf{t~WK%=QaT?2=jjN`=2+s}$X*QClf#ZzZ$vXNd?S|0)T8m=6N1i?FUj z##taoR|WWhd=9`lgA=&@VoF390&hKe}{zD5M|1`X}l!AW2dL8gLy@`}R8NW6q{FV}tXGy2HxWhoW z5^-2w$iJYzHROex z7c(E$eE+Z?M7nAp49y4)HO)Z}lqF)+I|9##L8V|@%pC4m)&yBwg7@r8N zKN~9iVci(`*jbhNP`CQ!FpBnzxLbmIG5TM9IlL|IFu)hgrPnWRrTKF=@ONfP{w>%} z?U#aT3g^pOvX2wvW-x>KR}=S41oTTw8Ano6SuYp@sQ4DiC)pnm6?c?la|oxaCGHDO zm+*3qenQ+~;C(|JnqU3i6`A_wM`>T{{i#m3nhNL3nmzeDs1af6eRFv#eg93i^Ov5L zbN6um67+h!kjppp1@L9=cU5(&x~ z$vwy=3VeKc`P2EQALy6K9sGQ-FKt;2@CVIh|0dx@PXbrZapErR6jLI~mv}J0*c%@Z z6X^zXll|#b&7b`W$A|n|sLwxZkZxZmg+Fi%ljSo#zMG9d2m0az)_dTuRK^oc(HGz^ zwV&SUp^`V2ssT^Xd>!ql#PjV6{PLTnVnzH*pFHH5%=|<9Y-N6BWmlu~vqU~!Gq?Qf zS3}Z0us;Cvf2cQ5&Q1`03wKlS;oNw*$HcvptRqEzX^A_G68QnM@4R~#dHJ`IaTSXG zJoXzJzy2&Q#h=qFH~xb6W#GHepZ3M9Kao#Aoa&cDLtdyCXLmJ?!y`S;ohCp!t5ObrLkki5A9vJN9-@p02=8}KM?W8{6^y+G;$d7eGIDac8 zzPVx!kaj=nadB3VH^`MC9)}_P{XA}nd>Yc6@nGMaDdFeIyr=Unr(ay$Vf2?D$j4fb z)w&_G{9%38Z>?#4$PrZ)&L21Xg!4C@_K)cY{JkRUTTyPZ^Ha-pq)8g z=D86M_;{eT1E^zHM=bf%i>uXj5&rxBjzC~> ze=>euMfltJ7V%e+mpWfPnInI=7Y*mCyOMYze>(91l`P~h90qaKW?%aQfin}|A z!>gU#e>TM(2ILaq|1qk&H-25dgWoF_{ywiD`OM(YJu$cZ8z}8)Q~1DlgLot2aaZ+l z{@x6%0|8!J_C+9HO?*I1#0%$&$JF`W`KFurJE{7;kovc06{Yge>7N^asqvSWIiK*I z|F_0pAeV-GcuwgAZ~W5{{tig}H**5X=MQa1XXW!5_@K-NrX&mOr##_Uio)`_uec zC+Ef=x1Tzn!c3GlV~kzZ^#Aqc}gO^UoNN8-H`KzcC=6I2ROp2mA%w zJK%4muQNR4Df~c?-+Wl?a8O`hyLHQ=Y;L~Rwb%E1 zhTT3txA*_{{`%klyYJ_@>#S$5z1Di3^{n|>&yr$n)-+fD)V{T&uV$o?1Aj=denAF$ z*6YaUZYDhGwvf>)LwL$3_3l{SHVK1k!6ki}m(P4i)0YB$ynm{ukF+nRG|thNsU>|W z=zrVK7t7}~oR?yKV*3B?eIwqMX53A>Nhal!`1X@8zg5#$1Nu6m|4ZI1^-t`!@cs>d zzuJ`__5H);w+Q9x-EaD9(&z4i@|#nAc$O2> z3D>{J*BsYFmtSnDNuTn$T-462hI#tjMD6I~eQB94W_^&%MGG&&{U7rc?*D9r5BGlw;OSWS zL3h}TGlKmU%I6x4UmpHZ)^kqHw=edAwWE*s@KFw#Zf<^ydPDi-d600sLp|%vAX8tN z-#FS~;>nL(I{X3m7q@(fE{b-pI^l7_j`k7%IwT9~x zXPW*AXw?kkM$Wr!EM*R$ek;l;0eoBR|8X4c06!1si-{kdUlI+HszQS72N&G>Nnb6W z+`p|v|EF#d`8>0+ss?@j!O`-$FhpMl>2q8~`hKl6{3Cr9UT|H8;VFk4uljqK`j!q5bq(b4_@TuPx;FJKPgTe76ui3`e&?a;Lv^`LX?E|Ng6%&n?Pw^tp#d zmtUB^f46@Rw>!E1Jv491_3yy5yh&!b{EqR)o)J}kwv?Yep*%;QQ(Zgy{%@Bb<%0CS z@tU(wWA{#6#KL)G(XxCdU3?pH=n8Fs9y*9 zWQyFsrG18Sgnx?b1LvFeD@+gD6}qFnABxUz?u_74nfcwU?gQsZv(yyCz*uVEVN9fz8iSnK` z=U4nAqRUUMF*S+w(N101zS~vQXF)x)k$ySO`B}J!l6>cSeg^j79E8u=MZRmR}6|J;@uS|7+V+`6xfmvBDLIy$=iVv~x???bLfhv@S$FSUo6 z^01Jh7yBCe!u8B+UW|7TzEwycfpUP?%EAx2qkm}|=!bCr!13p)5`AVyW98z0Cxv@v zIIgCfSyD{j!&sMf(#8AlOA^K96k~=OVt*g{0-FGTDA$)BG4+!9Jqqh>{$&OqXFPDl zEM3ua!1agC)$NP-xJjSwi@ra{>)k@`j4|nFKp)3XboISD`u$e z%ywp6<>JL8%!fH2aM50zv1u_sW&mG!uTJ)fHfrp1ve$rnb(HwS&y6+Cik z_a7(v*8|FPijVf25qu0i zNa877QXIyz9eSJXRkgw4SHQFcA)Tg!FAr%k9V-pMkf4|4*&clRl2q zPCKu`l0y3GgT9e>7t>cWe*Mai`wc2<<{zXltbaiIs<1B2evtVb3pwXK@HY6-oAYI~ zYYE^<7u`RaPgqwgVfm#etRH=}^KBhu#xbNXM!PP^mldRjd=JS-LJ-7e^McRF_fSEi~83OguTh{(D{x=p>Y`Lok=^G&zp9o6EaM_W#`9+axaildwwY68@cx>EB=%#V;_Vg zottdm?nymyZaT2;YjEEN8hns;rNX6hvkpS`17nhefFgPE`2$>4Ol;8zDb`~ zUZFBu=jn?zsZe&Ob?H0d?ImwU(f9NDa{g$uJbl)Q|6Tf~tul7TIA09Yr&>t)b19vkDdKm!~f+{-pRB zj`Zz%^-o3i*-788y8ac=m-#Q#=i>aWUqU`rBcZQ-p1!2`lj0B4*ZIW@Hjk3e9-_bN zZjqNy|D^wJ`R&K{1@jN)oAoav^rU;`=}R;gdV8-+-?xvPctjL^J8J#ic6s`|$^TvY z{;vM{LXTC@zQm=yam8;&CHZ@rFKzQ&Wz_vniMUzFaK}^!KVmy6vF0OlZ1gXmo-O^3 z+$UPItK4@g@Xs;EpOxPl<_W{~{dcNT?*0_Gb-c{m7s;$~sQ3l+{ixPga(~_~au=xp z?JYU-TLbS;Q-dVDK+T0RPaiJ#Ioj<4P#4KO{%NrvxqG_+Zjf~fXQ}x25WhgFCrtk( zw{H`9zufZ=8T##G4gLC_Cq1Jg{qIWpntncwZ!7liE{3@a-#-PtO@=SOOz3$g|NS%H z@Qrc3E9HB+|BTOF;@3~jn|%X#U%%J(n(#Dxs5n02!)}=VTXuYT+o}{og zl=lL>4>-H3wbDR&_vCvGV`V{8e;@m!bpX7N*8Qcm(!l!QOIQtqPcZpQ{@Ge-SPXw! zZK5=kdcyQK=yJ;sQS|q}#_->|%(QDt>{J%kf8IYI+jO|n!28+L@>|1#bESUE{quI4 z;Q@@WgVk?+K!Dy3nl zmZux!zE}BP!{~!0ypCUfYbf=E>7V;?b*Cu$%g!<}xTl%&cfK#C|GOt8KetKxzYGmv z<`~J3`2FvO2GCGUrrCGMU4p+34M4Yt)~(`iF)V=Z5|ZBqa?jvjLj&kmCh^@U^nNej z3*_z-Z#zuRNe)v7iG1kysg)95;4`t;=1P3tpR%qe!28DC3W;B!)Dxz^&$16bh@!vw z)u#OYF=ijjy|Qeb^7rqN@|`&>fJ*5PwBMa2=?iFjGIvS-E|B~S3>3d5{`5t|0;u`G zgtzC&_X2%(H{lbP4pSQ1Ncm=JWZhQ2)u8Fu@h4{t3t;K{GJaatSlP4Xdx5In!Vd}W zr6fIpQcsxv>sIcxJc|D7WPM&gZnY_Y?`B>8`T9Ra%3H5fJEyk|fcM=y7l~hh_ubdb z6#K>kyzjndmiPsD-@SEaThWtho4fBmdrn)Wf%n}z=SqA6W2JwyJBqwqD(?h#7-}d? zpVwAtsFC~bEl=*}o*~~0lzPJS|8jk+*-`Y5eZs_G|7hyJ*GJPIasPJvHYzJnBjW={ z+QWGFHUaQHRd<^fbCyQerp&j<*VC2r)!%4*xqHgmiPtcapM<+*}F^m zOaGYY*d~CcqeNb09$X`FX(;uC>2G>fSPk9}qySMg3AF7vaP7KXKW1nJD^){lmoPY(6qzgg)n5*#2|;mucKz zY2f%zmCMSz0LOop{MNwnpDn*NyUJ1IbUNXc&vq(3dcHE{fwk>46P{!>llw*bd~ zarv#G)Dx!vycYXL_W$a5Q~rJrL%&|MIS2 zzEb|OAIwLO2X%R-2iFhaXBppE-^sq$9y0G0xa4FLGCrif((shXx4)N+pYe>|N90TF zt1F3H!(9)+&j2OdF#RVV*?VbJ`F8>R8Jr&o(=T0H@MNVO)-X=!(~tL=jC%xXS{lFm zsmucf4%}1d`#|XXQ0k4qp;hL+^MUMR3*3IM@p~W3_W}=#Ux$xNTpE7E`>g!d5P!vl zulZck5=ag-{=fSlrhnV-R&NnS|1z=9qaWu{Q_=K3b7A@W(%%$52Q4zbnzQ>U4ck6% z{MNbsl!kwPWc=~-`Y8?j%q;v`sn5}6+2{9D8oHb+X@8iPml>A}KfcNP)fMLZ^jZB> z0Ift{rClRsOWGPrJr-V6z}@S?_V?=fZT1PXUdr{svqwug9Gkxv*ge;@gAMQ_T*tieJLOe%`O!=?L{hQM*WnXBi zJ|pD3rTBgE`{F7ET;c~_a%R?Nq@Csh};nRKPf9d2fk5U-8#GGDvlsBK1n* zR}z;i{!$O=rhCBwhxgLuAEy7+@zM^RTtNT%wWI&xfrftPt77^|uP1r;KOdq}{U!eo zOMCF?5M_Unr#~hBwD>t*$cjI55^ygspT zeTVlGoF(>CGk=Qy-dSdU#GM{3|4Q_S3gv&=Kc}$QUw^r^;mU4xE>M>al5r0hlaoOk3Y|=<&v|qxP zdcy5rcBiJxh5mKyQ@6iKW_t7d{@;w~^4IkLC(A$8yP?uh zO8%WbGDi|%`PWET4J?0KerqW8bi)g}yYI4faDF`bm}#GyVt;p<*cY*Xmq|Dtcc!7A zvkbaRURO%nr?(OAuDwk>YDF=>?u9;rH~)yB>tuMYBV`+PRZi2cxpkye!tZQx^ z$tv$E_GY^(t|NKkx0-iVTsMj}>8euV=em(6{&u-t9D zh+X*gMTPVq0Qv8~O!~hG9OWzJUJ^}zRY?99Y;N+wa}`WKtuQX$-mE8Dcu}?5>?8ZY zlP}FLH1UM(LoFC?@T#5Biy-|A+d(d%U*R#~klP6JOtNOf{FL<4E7*7>2zn;CrVR5bn7s3IQXU2;S*J-Otdhs}15{b%_h#o;;PS=QU&!~I1C^tp() zkif!L#o;MOx%Baaa!>c`_)FVs`jeoa{lDJ-aqn%B``pDo5c5q}?+g7W`hUHLl-Oc;F8}feIfmL!GER3;XE+gZJ?D!d*|Dj`pNR4op-g?%$FQ|(1H5D z2+w@~1-&+g_Yr<2#@+5}6HgZSu*3F0ffx5(yH8-h%X!ks&$FOEEA`)hPZlZhxK~8e zpD8zEO%LJD#Q2ZvIsE=-=(iJZ;YImHCSBrf;H??OcnA2C8ymcO#PHDt{)sJ2|H634 zFTBn{89Ms~hBK!X>LH}gApV#hKp8L+leZm~~(dGTh9zurKzZk*#u7BC}v5o@$ zavKpXM*r$shJKdg#m5=G@P1>L35Q&Uw}C(Ho1R7bEwtZ#y4Z)byA{xXWpw#_^G%E8 zA->+Qn^)WWiJhh<-{Jd-|2eUk9_D*-zhb^PNcX7mCcF>%PXZry!t#IbrVmZi^*{BL z`MwkM%jaZeJ0B(pjCRU!PEYkg%=gnql3Pv4Se_< z8tKp78-)IkbcXGwrw~ur83zR2%|1A?WnueQ2KvXy`lt1=+|SAN&wtd8{#iH=?yf0b z|9N3oln=%&apdDcp4Y52>+Cl0^$$fk;~b|8yhHtG++RsLXH78idyCEbnvd{dryCG- ze|&e^b(((VoA25GeLA|n@?-f$D|eoupZy+Pclm#&|MT`9uDlWX{?Fb=`mclX{a=mv zGva6em)Li>at_Y-f4=x@#LxaOvEOi&JY?PeF9G`L9@A`m)57u}i}tVbU$XvjWx@FW z>JsHI_p|E93;rt=mRq0|?K6kREiv|6Aw50X^=Eho5%E4Bj-!&mSDj$W&+b?}FJ}65 zDfe`j-MIR+Li(=({da9E>#Zj=%iZ7VUK35fFXJEmc)|bD>a@b`wszbPghav6Ra@IA+G*|@O$ ze?|GXze)Q4g8M_=>uN`TsrymSNBPt4XbkCB^1Kn+MH~1qo#YGc<52z`gdcR0DL?B5 zlTY#suX7H=)7@t61>0)+U6j9t_J7FLvY&Wj{(e~Z`t_sVJ+8R@56cDV_YXJu<~cAM zIc53VkDGB0^Sc!1CCEq88NP?rLp))p3J4qSl{@~c=zQm3lz&3W{@*_vir-6c)@?AhG5(hUjOKZbNehe3*le9)zI&{#pj7>FMxb;5I%fgunT-;&tdsr zh;bYFWh0)j9S#Th&0v4P@{ByXz^AZ|#CU3e4?FDlEAZm{?k$4$KMwl2|K0o-8UOuM zp8MQIdYqrr)$})zKl1Zaj?YmJjG!iTPL}k?c;6ewa~3|h19-M`Ht_w%ntd;SpDrqW zMCaVTu)A*;WsBc>&b+tx6Fu9bI^(OnlS>z<{_pnG=P%lX_kVx6RK|a|30=6q)xFX1 zo0_F`!{tBd2B{08w=jN|>>rAIrnpw7Og(ji_{B~36ZfMs<%;Wx>z^&_ETYGJ&6ASv zm1SyyxQ@6Fi|dJ7E%9Z<9lu=Oi~hr8?H6~N_J3QZE)v%f_bPEcaTm#VS}!am@oRmW z@Dm4u?!uq$-c-xKgYxJ7cH?yUFOB8tzbU%?3)AmnoNu3C+CQ^8CVRQC=V9$?^odvw zTcbS-w+qRw&G?t)&-`w7s;Q@p#|Ax}fVXcnxDhoLh9~7&!!5@xCM4y|eIQLi1ueS3gjF2)-Yc->2lmvgm(99`g%2vQ z&TGR?9rJrG_l46Yyp8ZjE--w|EHU^5@L`8|x{n;Va;HN2KL!0&H%R?IwLt!FuO0ng zp*>e0n|v_+r_&~X9G}JTA|1lVfuDrKRrg;mdRqj6yrAcj%fN9B0dl9k+5&(yl47(pjFt8d=f7@ zp`5(|#rZyY7to1%!T9%r9vR#Dn-I@olZwO7XTl*j4u1^pk`Al?q3O@QW4@>T>$&>= zhmKA1`Y(4z)35bk^y3BpmCD&&{k*vS|ATgKfM@!&pX}nCyM=hd_K2Bp>Q_)-$VT{w zurEq{0{F0F0YUfoE$_Tp(@*=SZ2ynDQ0V_Ff4_ixSMBKUkNtVt@nQPQVYf+PotN~_ z`_t@y+vpc~a^Vq#r@jFDi)YxsA|BGQfOc}AcSn9PeY#=%&U?JRPht6U|ML=|-z%j5 z?%L7M{+Z>#bUT-r|E$Ekkl{(s0U^5%%=aN7yp05M>tC;$b|JxpL#_pX4DJKRebrIZ z?=Cg+&;IYzC#C$GV(z>|bGJh+(7UMf1qCcQtO1a=T z{+`Pb9&$u}F@3rWPj|twa~{<6bNs{c@4)M&{cD}KZ|vS1O+W4bdPrbm%;ZDCE-KTF z(+&yBhxoY%neZ%s^5xn#paC*@~k)(SJ!t(@*=k9^(5?+0Xsw4xk_9S&sN=SJy8y<6rXYUpQ)L%iGVZ1O=pJfL&;<8eN3;YH5QU}*n?_Ffg_-$D2)>dPT~5_qmJ zaK7LHA9nH@o#xHj!$&p@>_@+D@=f{Q^C3O|Ynrp~>caji*Zt_yzAMw?eF5yxnEsBm zX9Ia=%}T)z7sFG|+jT&BB0TfmV|FnPFW$|p|8Sf~IS=bs zc?cgae;@d;lK{eo`^)w}uPUT}DCqx2&VSe!Hdg-bp#Pz0`mNK8<-dyKJnUyMeXeIy z{#kCkubOxZAB6AOivyqi)wCn-h~joWtaqAZ!XYF#CpH7j!{?9<;L@?YE#h>65#n&TYhV3yt}N!UL)tT z+lXHvHD2^dmWgirX7XF$3GusgV6w7XHlUt(1oE4wgB|^U_MSll*DGL%QiUUetO_6#dI;4E@eB zGmqEyKbolqIr`rfe(3b$*}egg{+e&aK8HYXerZu7<+SJ*z@H}wKQ58;$qnUvpg?k_ z@vHiBR!?B@3-BYKvqqX9UekU`!`Yvj_u1e2Dh;isnDo<4dcp z`;6pI10T{&_oG{0-ztiJ8}wU)%{=_Ezcnm4SJv;vK15o6YoK03jr`U?y?(3NwlWUiHmBF%%Wn-o%05To z)8#qoul|+S*O_R$x`*KjlBuT-paIfB*5G z0ZiQ5_`TPAimpRXHTz=2f9H{&Vwa+)dU&XLpYnSu4HFm3K8Sp;Ug;S?|5oOGd|6MW z!N>dLCq0#hDZiWW*>`#>4KBiGzZAc~2s!@}$m37)y@rEKd^Jz^R2uk@Zo1v?Ui()R z{Yzy0s~_8rrvE14w?2=Py{A_IcT6_v#~$jXG>p5`_`UmjDGljC#_zn+OX_j29Dg$Z z=%qAVa|+(yCGQ0)NdJw!R8nBVm(m{mE@xfd=oP@ouZ%yvLgE(q<8Jf4`))6#VVXH+ zqO7lb1yG9q*It?aY83r%iT-!+R2xCkc8Uwj|7KB*Ej*9(u2f_Fq}MbFAR~TD+ABwN zC^W1Tziz)`a;8wj^Z6zz`0i5KQ1ia#s7R>`_X*Isf0v3sBlg4j%oD$*&wt~I?IQ6P z_-*m)_GS>wP^w zIr_JjQ`Q2Se!aiPN7JwO`S@u1^?n~8O~2mv<3sxGrcIRwKBSv&!;7}KHmdwro{jeZ zBh&9|J?FyykL{n`RP>Mq*xsd@4Obc(9VjV&D*fHEssM8BU31Y>7GQgqZXtdFws)zP z^1T4{xYDiUy}(pC53TJ*#on$8pik2H{dcOAhJ>_7`n~&RRRG!^jwkkTlH%9Ehji2J zI=|z4QS^Uyh^hbT3q!xwbBm%sw!hf_5tt$Up|*FF*+cZy1jvuHywh;fu2Md&nI`1L=d15bT zsPI#O59y}+Ok&#DDEg_c>Gv^u4DR;D_1_bFB!%Y>=Sde^=%>9e|KR3I!%tI1ex<$S zGi?-p9V!_YNGuiqS|J+GCo7BnS8r-w*wxLIhOysDdIk2s4m`a$eD#&Ze)DzS?i=af zZTBx*M$sSJ)s(+`vzf=}eXhd(|94s5_Z!Mt+$Y3dhk!5Vku`nRWBmi*K2^r4R2sTT z7Zki-DDMUOJtO&-^S#+e`v>s$K~mqhY@{slYv6fz_vlI$fY@8eyddWc6~DQu|<}o9?5R$Kz4-uYBBa%)PxjXb2XHx0#aq2S$D&O^WVsV~;ftVD$*& zPe0mRY3MLm=-EN!UEXV0BgO2$*igChTf;QzKMSA3MAfuVK2}Qm7>o}PXs;uS{S%KW zrhnAlCcT;$nkx-jUUYgj&x>Dx59y|xI_vrtQS{ebWb&7}$?VH7ly&}Qq7Oj&?`RwZ^$!`rTUq^mxpuHD&PYEwTdoS6lmP!Nd zy~OsC_yuV1#owo;sP48D8&t*oI70U?1@)s8{byBl+dYc@#m5`^-L&cd4gKrRf8zVK zR2n$`Ps(o%oc}oc3w;8q@n-(xC4_zf&VT#^B>w`MKU%-VI;3R)x%tls;e`O_KaRw$ zf%6|rzSWSM{~Xv-Wdw5bpM!;W8u0WFxxaM3;`PG$e{anHXFVwW%TdkLDz3vmZ~6hY zP;{$BF0_5%8HjiE=4L&^KG3wAl=ATYr-kspV_itWPI?^pZ?Vqj-*5I2ZQyh3{6mZN zTm~E~^8T*a-)rANr8{;|uCy0!7pZ^Zx2+ENTB$1hVtjA@>!epT{Tb*#?g#o0NXYun zFxC=@YjHIF8LyY52nR91AbFE(mSL;s2AU*FU8R~69zLNxta|EZAv zvQWN}oFbj}6B4mJ7G7Mw1^9w>Ueezk`a-1BM)>BSpXVqX;HzZ(;YfXVhjvkFO6Op_ z;k0R_++khB{!V9v%Fo|oz;u1G?0jARe#rjIvwHm7LIDI`2U+p^BV)Ptz+Kc@#g~Y^$O}w+7JFXoM~dGTd3LUA ztdio7z1TWe|Kp40{o%1({ZEU(M&5f8-g~{F*wU15UusP->P@x4TbjI6OjMg ze#V#?_hTeqH1u4fQTG&_Ao6#f18*Rx%f(|=07yngf_%6k>w zHtPqZe{3himoWV=Lw}KU#*yI)=(|`ICLSC3N`$w;FVg=b?=9KHtXnweU{#SD8`q4ia`DXh?`d30fB=e@Bhjgx?{z6C(aOd3(zZehciSyp7 z(EgYzi{3XN{p|nfE~p;1Zz27YAph4bH8q^~J0xFOKl;P_5u`tSzk`j8h3|J@Ifd_c zApO&MKOXdBl8A?T1}@~^1)dJ+rhC+V9iJ(re-7w>_Jvrm3-cuo z{7$&9l=~w#@Gj25`Pc^}zy6MX2j5r2-D#WK_b#M=1?c~&pRAj-7K^7ZoBfvLYti&4 zpzlw;PWE@5px0?HHRCtZzeNadAs^Ra-;C!2NPoCqI0!!t`UDK`0#E%Q-oKFso=!K0 zgZpXY6?X>X-*-$sQ=osEC*z-j`!U=aLqEs8ba_9<48-@Jx*sE~|4)86yl*#Q=A|~$ zrCoccso1dZlecSMBmR{5`7k`=YrpLKMup@5cA)>G^X2@X3hoU_$UP$VHhKEl?vwtfeto%trr&+dl>cU+|3O{;6$SLa@!zF? zc6o8T&;0UU1NH}D`rVk^Yp_$k{IlYZ#q;#Xz%RO&Onqar(7*2aj|*fy=iCO$uQua# z_f11T_toiImzg!KG~)eDuREt3iJFs)Uu8Wg@s!M+WZf?<_R_7zWvZDp2i6N^YQEsT zPvqRjB;oVjjg;44){|~(tftDksUz?AI#J~B`7+f`rg^T|jUFUR7~VzY>IoSaTfJpp zPmgaUT!pw9ao0=`{E{+t*|R48J~A)U>v4$@vMwriL|07|zql6iNoTKy-70kXQ~!_p z5B(lfVvpF20d!dREki$7@aQ^n0jswEmqdiQ{cq?kFdg?d(~kPUlmAT`n{p=J!Uv!4 z1bpbcbg<4U>%8jswql>5t=ea-&@Jo!p7`A-#7?v{O#VN`4z&2yJ8jjX3*~*4%!5~p z-Dr7F`7cL0*Ux|RN=<+AX_Fr5uW+S226L1z^#9AyFPsk^x~{B?*ONaF_^Qx(CZN^u zcriT|Uiia`@p0gnVxAZ7_g?K$96o{Y*TDV*!#lupohjy7Dt(ouRJ{h>r%auE@-b7b zGpu3O$>S$YO-`M>i*?M&lP4cLY3d&1jvhbBI($_3X?^1ZcHHCG$y3LV9e>QxQ;*%n znlk>lJ;oh-%<)sK?%n09U94j#PqwT+MB-qe`K-#aPlnB<1{>0=|i8;U@ za_r>sV^7;ZId%Mrlcq@AI#2TM@KKTZI_BtO#vN;QKjG-);p;>zUqpOkodxDZIFt*z zedi~Bj#?i}_BB1dy~d2Q_5NscSqY$Aca-Uau7B|reF9i3>!Cq?6n{eCvN_Ve$oi@K zay)>_YLl5vO9)!n)tG>#Fd629~(bOO3Hp< z;WJaFn^pr#t;qA`=6!l;Txs}4rt5|KRfXRc{w81Oc3v{=*C_sI`vLl~=9zk<_fMM3 zANj-mqu|`Xoc-tiN!phE5&`a?XgdHJxPOw~UET{MU1=v}zr&Zk77Yu|m9%6(UE2xJ z!2J|$CqM)DQ*8NG1NT$3-2e^TPtkS*H0b*kl(Zw>V6jUe!2OlDe5;|UCAF_}PA^#2;(e6{)Z5*g*A%yZ@wrb_&M7;7>ouPpqEw zUp))fzdwwYAFUUrAIi_mA$pOFdLe|5;l*tsyal`qxuU&T^6i2U-bVPJaUVA2CjoqT zKgI#Rl(PUY=pOUUD^;35JRhMBKP@0QCHhf*uNI2;V|$rs{?I-u`STm-wMUutZ{}m# zl}65;CFUF$`4h)^B4?r5PqXlW&GSCE7n}S!{7w^(^_%H8Y=jTrmmNd%whHUZY6r7k zEX~^g@v-oh?k0aUc{ZqDuph|!rS)grU-RLwaSl=v@T9ER(kx?4g8_I`So8OQz$Iq$3}k07rJ&}U#ek_KMMC4`}K@GAUPEW-hthD%ELm)3Gp^Qa3ulfUD+Rd zx}$RL>!`LAwFzJRDZiug9_*-A>G9Tka=*Yc9aSpb(cC{J`c?L`;=i|}s@C&w@mtTy zextl!Q7-Yx{S5j^FX)I=)^%7ftMKa2rkfPiud~6Q)yD~c`sC$DeHvZAtd=HC)~~tk z(O+~l>lVyG>P@VRhxQp~?`6WfxR=7l2W#6gys4+mcV;5$DeUq&2*13&2~YcbN#NVh zG~sEN&;`DfGYv1s!QJWGp_PU5b2<1k_c*c7k)o7HS$!7GANMpf4H_#fHZ=ba;U`qTP|7cx6>+sU; za|P(2W6d7fS<839`UADis~QmJpUuj zXz&~}!NkM*7z2JD>LcT^fKS1`Hu0T+|81O!hk7SnfG_2Q>(}JZR#$8OB%vSE4)(#$ zc|ht{fqgjd%V_@4KHNei7`6k(eC%?58 zVzeh$gYaQHYZ>56IqbLSKKb%3 zFQ-3s9`vC&j%7a1$37tEWt0c*v+_KsjSqg~IYF#9JHY?a%<#wVX2uUPtqmUDzm|P= zQ(2eWR9z`eLvSD8bDOFf@z0QJ=>q*$`JH-xQ+&0q!*(KpSD(%6)`$q0qveP8 z$7UeG=Wt$Efj=D1|D(Cdr)8P>g@y2UL$26gGk+=AC1CqwBm9Y{gI>s00(e(`_@Zx> z*j?K5}|%Jx#rc;e`eJq&Dzz;KTN;nBTBHD+l4ZKEQaA zz@LcnvY$3`l>)w$!}`VcXZznj8KC)-0e_wXe}2^bX_DuU{eA8D6V4~|aeX7hfAY=3 zi}uv_3-M=v?gIf&{tOI-Cm(8>nD|+L$%h-T56W~sW~hYg0MGPh_d2y`e|rJ=v*Zbx zzZ@!O3A>wgooqCJQlm|TlpoHs{J+fjme~lmGcmj<3$^EQ;Hjs;cEbjK2K5?lG3!gD z!vfxh-D3yg9o`2LH{<6N@TD9-^kT1j{`GqxKW`d7aQxGLjILB3@W&mFj5gW#B71y}A0K{Ctn~ zAGLikf7p++e@`JFr=cHb{(ayFKwpOAy&B;E=xXTAtTpoR2Jo>%i}?`80KWq312*l? za^Mg8!%jCKVsLM1IjT(|e`r5tn`@JO~b2ka1Wch}&Qtkc>JL z;~#&ZIj_L{FA9~rg%4s_&!@b_f!`H&Cy94}fAJ8LPvTR+*T2K$hj<_OQjUukbgybs zdAa6Ka6#OSqI%zTWXfdy=+K6MMnrhwby;+CE`< z-aec4o8b@V6?FB!sd!Z)9v1*i?-jt&i$2{tHgfAu6g@? z_A0|4G>0hI$hp;^IDE3dtVdqfSY^+Z^J)U|aU!4Zi+<6_$^e=l zQk>PXCou(sPgEBBQ@@EmgXl-3<$DdzZpH6!SXAtPUCwvc=5Y~-?hkjrcS2$Nvkdi1 z-*4_dnCFl4dvyKM{Lv5VSNI%{d8-urcmEMHE@HX=g#OMSWX9DlJ_zpvdccpsxgYKi z`oJ%NokX4!$^ics?Pncq+W9Q-r5q`?;7P!(u=fn^zhwXZKKS!yR`fx>%XfzE>S+Gx z`#<$V{)G3N%v+^aw=?yZ?S_RHtam*BV*}57KAg0fuQ|Zq1bs0Zc7a^rX)lH2!xZob z4J&TPeBettjGcOVasG8!1y8WoUHj% z^R9{KH_YGdgxFvBHP0XakJ|AktT)bljK+9|_v(^A=V5$Hx|pwRK^Mcv5z#8tBZjwu zkMsNiE#%AL`o<@w-5`Iig56Dy2hxM^!NI0{xgO#J-+5{=zJ}rPS=b57 z&x-Gs1mhpd5A9EmkZG5{``#b zj|!brS&4Hul#>MFsUN~Sz?X8E4&VQ9&OI+``B6&^pE>^d=0edMZr(I!pVU%jznk+e zy5aUG!*dfuiuX_N*~Y~0fDh!)N2eG($2k@*a$ysZgD*1&v&8t zs}a7G!}usi&96BvSRZ5mwIkZ+xZcj6);Px>yI$@1^APG$W;-*EWjfJHb6Y~x5euKSJ7_py+#hnpYGV#rd%bNp%QKd2dH>It>0OJeXm%^ zzFo_SGXL5#AK0lM%^%u#T!{F-!TKTF0cN9|`_3W#?w6^@54?pB4q!hHJXb_H9#E)v z9G7xj;eBS>tL}&=20O_a+!NZpoH>eiD?;e>!xy}*=NIZVBcH5a58fi<(~f0o+-8v5 z2DRhQA+t?*8+0+buc`L}JUQ=-Mf|`s`v<~~9P1tBt$syuc+xWk;{=AcknkNLJo(9d zgOV!dKdfInpnheZlJQUHvYdTPuPmBBw2w*oVf~^!GyVUs)Gt|94jz`% zYhSjzxsX4UpI#5i{GxX(XFt+!7|kErk0gJZa(!k$Bj@DLyq2ciE!d%q<3-K32JfT3 zQ~}=y@vt9fdlKI7a}a(~XRL38&J$XPA>AWQ|2qxgOF3;gaYles8yzx2*Dn|2L-J>I zSDC+WmtUXHG^!nc9%1{rjalbmK3?H^JMqZJj$Bt~eMH4e(H;To9q=~vI#`clzz@Q{ zHt}p{H$gi_yv2&mjD=hee)6$-#kC6x<;O$)swc}SZlYDr{-!FA=8p^eo0OkY_BXq8 z{QR(yD;N2gzl(X}G8RnQyfsVL~ey>SNt{Nr(KM!`0e*A)$sY|ed~Gi@7hAyR z?g0Rv`P+l@r_eZ>{Ttie{)p!e?w=q(Ht_d__L0~h;&skpx2QZ1tSb2Zl$h8EAaR$;%zZD-~IuhKM`Mnj11~z(kI>meh%qHJj_4$ zwa6cq`=lh|LBB`7&0{@AJ8dKWu*2|ldp|rnXrEIUKgZF3RlF_Z=YsRYeoMn2o*1Fa z^Wz>8+R*36Igj8vq>XgL=gJ-6d9FOxwnAll=Fb(o;!pHq=^(H;tQT~jyW-uZQRjD- zG^!tbV-x`(=mi$S66Kf?u0({69 zy1#FA@`5P-cpNCqGV7B1p4k@CDw997r)CZ5q%=&IjU#ui&?CP!tgdE?#ywfiPwFQ< zvQq%9ZWsEr{mvsh1@P`-X?Ml%j_MRZLhQBb`}s2RUc=||Ufb_X%5M$r<@-P%%tWuY z`NZ&7$@d!ih`-Q2XOoj9{%7-@*QY6b7;?xLx(mPh;N&R&EW#O9f1qhs^gdvVg7b0g zcjB#jC=E&37`&y3=)3EQw{;N#ecby`31Lv9X zv(v`#$K_Na+V6K#6U458 zwvXz3(@CYC>6ANf({?p$}eBviRW7$s1m-J^`DD9E9m#qDgJ|7!D=x(>yO^<2*q@e#y`)}=K zeqpU{qB3dd|7>RX!{Iqy`%7d0U979X`%*_Pm;PWgIS+n<^mCmX8n@86#e{Q{^`n95|DR*m%S#M!I{Pb*TZf%5@%!>y!#rKz z7L_ThY5xFjmHOc>lJ-da8Up*8U&;Gs@?L=Y&MEn=f$ecteru?a`r{3k@0-he0dMR9@oV5SufF+}g8Tc@Nf}+gxPF+y{Pcx)B>zV?Q|TWKy_pKbAM%xM zYGs`gp{z0-oyw{*h+9 z&IU3(KUHWLzPb$YV?1pE&wSDSzV%)63;8n@=L;_QN&1g5`Tcj*E}B0)UrD;2#65ui zzGfW**;fZlH2GnB632_C{ju&>fprhy+Y^uZy9@l82bu6b!jq025#EMfq71^1ISJvB zpBMx>Jdd`4C%;$X`%Nx;?WsckSkOOwU^hAcH6_mgkUz1b%=*vlV`P1!Ph;s*4gc--CHRB$1(ct4 zYp_5F~H;(7%0 zPx<*Hq_1n^gO53H-^{dQ3E=DD{IY+e8P~I1o;nrv7j}Ow$iovj??Zhy8~9akp`BczbcA<}iYo<#3 zTyXx>x1#yO^SL#MZ}e)Du8;L8pjA2KnfMr9R8B$riSQQi3(($%`@2KtgFk48$%m?T zCLW#xauLsL^j|K{?WTaAngoBgHFD(v&wNobuI!r}Cj6-g&%eGuMv0wsxvS}g`l_Y; z@w<8#%X+TZEw)b*J4QzjSKrCHjq{q!d&KV^F+4wynmk;o@p5)_fV5*WPf}Clz4#aV zB8%ep#P3WTuHJ&*o+|!Ha*xJ&lCG=|Cr*~{Ck$7A$hwgolXaa_PX<{eo$lqj@1KRm80H) zpEbZQh5k9iXMpExXAJ$9i}y_LlMzdb?l12H{`8UcF@G=CLYcd46U`rX`zP&ZQvC79JLK%ZXTx8};Qk=+l*}hCE)E~V2ls^VEYDt( zz)!?uA^e#OfL~zbf%LrvJtF&dgSQcW1@H>^1n~Th?u&a&+dhyV@TUU&St#|(PRPzE z&y#km9e=*M82u*75y`40I6uO2$MS*dhw(Gbzu@|+w(pl|E$ge)6UDgHZ(!z0F_}N> zvo3mFI?C=}w%$M)6Ao0g`{y(qs5H>-U#e`N(m=a^mi*R0yMM6;1C<8a{maTb4Yd1L z(@NqNsIA?Z^q(nif7)Ok z=RaOtzaHgy3HSu!NyBA&s|IXRrupN%Y}&Uh&KIcT>nZo)7PR0_MImjVxd+6aF@CGeQ1Q~`ej=fA*{53QjWZ8bFO z8xF$rJ-}d3zkgVdqhT7Y-U(8Qu zw70}3@j+v(uM+P9??aD)`n@UOujyyl=PZpQ9Y@k3G+f0~IHuw~Wd)F7eZ`J%^|J4HR zbE;g<4~{O+$&VYa9e+xlPYK`e5JUQ2N5cp9;}-Bo?pBQN1pK}C72~@AzhD~hq58P# zV1u_&UN*w-41GM+#I*AX;HCKv9`;|GT=&Hrnm;_B(g6HvDf-WT(|r5m^{gF#;`K~^ zoHtB8LUL+8%AI)fXBUn`5Z=NEtdG>MVtMWgdnWd-rvBOpe?I2L3{QH04Yf-S!h4kG zFU;5}6u3vu(^_HQFlMu(o-e3DgiWzN&vt<6 z>QbAM{Bf2TO39y6>+|(Cf&62?#zH<)*mq|A zN&p|@c;-7JCl2so`w~gu(@o5{o#SU0cn^5Sp92003*kGOcFY5we1%tCa!EyBEkD`U zisk302ZcW;veYDW-)R0&f1dogl=|V22d49MPw)r*GUen>=x=*p898T)39i#3Jo6pf zuQ(pc!<{3F=QS}TJac9-eiPthoJT)o+Go}))-%e{JJ0O4wy=GE0`ha-PNF}5VPml` zWY#UMe$o7~v|^1smM`BVPq%CD8LAqK>N36%? z*{8*RzCbX~S}68CZ;uCX$FDMO7yY-I`{kX$(vM7h{)2I)q3xwy`7rpl(wy6ui#_!x z;sH!wQT*P=fF%96*xMI)qqWRwUZoVu@3e_0eUH2sm~oH!KKYQ?`xp4~e)B$apWF{1 z&_+yA&Ru zae=o!F!{|k>n-{Ny>s`Qr@rqc`cS>pj8jCPL&7`dy#wI=<~2XaedYpID_L*R`V0Mf z2XNJ56FxDhx6*Le-Qq9MpX2@RaY;+VJba(+DCrA~6MF$VzQlI&y}-iXjXy0Hrf4_| z?^Rq3xe9zURMMCD(>uv~fl?3oM)$eCXE%xBpVQ0m!+O=!OTCXMx1{FePwQ{!@^|)V z8-S=}26`&4E%%rRR5Ua4nUvoehKs50fd0eVDkY%rL-d!*{n`n+*F<3Mg=XIANLUS9 z$#T5DZ=Fw4+Nk+gn`tQ2 zH>(kUp}v{cIm_*nh<=&YIV;pR(>iC1eJKyb5^KtrghFbNr#~Iikw9f zw*dD&wEmffLj5zXgU0&+(xU68!QDmpx2@=_ek}T`0x9upeYNjrZiNaApH3@FHgG- zHSs5ZAF4DY!=LbblBcz@x*8 zIWPeW#IYvBl!g=-V3$e!0zZiS7Ur+`>%5PAqkGkh-*<@OU-fWPe=`S~`J5;6Unqan zU$eL9EbGsm)!w34mJ$BgZN)DzTkE-%HB!lTodfVie@p8RtBTG6j2Hbht&goX7r%hk zN7MQDY#F%f{>$2`a{#<=+LCt~s2^P;zco-k9r>+cljqF$ z+4h~42I_xh1uDc}DBnu#)p&2^>q8YcB#N`Wj*on!`*g>P z_KlK1`yA8%`jd_P>2**&*5vqQ!l9=8;&+ym0G(c%6|Ioaz`9k~xlZ7F=|H<4lAb`TS3xAVubm#wdz@RAp?fahj%HP+F zU-UVXLjIk#homR>u_Wtl9zb058+Cn**WWyVCLa~1Dpgkey8OMKn+MQsh~Ym&#ijkz z^)VygYnY`ID|lXm{1VlE&*Ja({V3KeQlHi40X#T`A&sm1Z~ZGaYKHxJ;b zw8>w5faG7G)I+|}z5Cfwk@lnP8d+ccA+Nvc4mRVMdWe{=zW<_`oO0J-~~)V9hN_~QVf=c|Uwy>goX7Mv^J%l%Hi zywfnk7Wy9%{a|^oA$MQF-P@>?z*+O<`?nh_?;c4{;K%2RInw1hslWefoI_4TeaRt8 z{9yf~J7~o({bYW&j(+qV9c6xYYhFLv-^1{43&cy8`qA$KzvUPir@h`tb&>wU-no%_ ze?Q@qxQTu;zYy0ESM_hCepn{-i91^QnT*^M^~v?Zp8;~-LR?qeO=LWo5w}vuH?Wb~ zQ(RBn1I1Nx?x&@kCvwEC(*2U8*Gl>$N6zmYBz}EwR3~|F@7hT9(C3cCbp)>lHB!^W zb;O-6t}pH=iO<@tk!pH_d?&6i`Y1ua271Cy90gNzpUnPg+CL9=6S6}L z|C-=?x=E~KaQ?{jxIWDFB9<5LTOpqF@gav8x#c=D=i@P+i^Fl+sE zheMy=2A*`L&>`AbU$PONc6eOi6Tp{p7$4pHdd@#QihoDkUd+Gvu#J>|=a=9g@T7A? z@vr;U+jfZJ-_MW9{OfJedw~2U_uNSNH@yV^fZx#kOTL^M5yih2_sjb4J9+-4t2R>p zU08yDz;9^&o$<_RZ%6TO^Vu@rF5q8w_{PaU_o8V25x=4N_h7#_Qc?VyFYTXKz`yw3 z8z=wlnbG_sena!`)Y%We6U9Ggvj!?tz`x`^8z=wNtZ4obzoGf}{+U}m6~#X{)c>aU z-AMU2y9ED$-_ZQqCAoX#_@(#Z#p9Rkej6$O=9J(c@Ee+c@7;LBswnx3?N`jdcw*z^ zpId@|#BXT+9dOyIF;V>cPVN`ePj38oz{bfx`_gFnBYs2k@2=k2dQtqVTvW`z^nn{E z|J)M%BYs2kZ`R#SS4Z(LA?=^_Zhrin9kFrp&rX$)Kj1es{~k%+@kJE>mPr5W6!0&8 z@W#nMzXbn?-_ZQ4-s_&rqWITC`VX&wf5}5OPX5`Km5@K+H#GlZx5svg;$QP|vVKs& zzx1ISC;!|M{3Cut^Y5YM*G`J!-^%->{d=#V{j1(c`FDA={JFqyX#O?o@q6DW{&g4m za|-wuAGvYz&o9A0;x{z^ywRhNkK*5tE2RA^;9v6ajgx=&718oX{D$V=eV=dhRuuo1 z2>&t#{7WCPaq`bC!9U_RH2s z#lPv-if&Z_|Kdk&ocwdIjOHKl8=8OjAN%GbQT)q_{UWb`e@SN}<=<5$_y_!k=3n1o zS8o!N}4|@$d4JrT-|9zwGFZlYf2*{t>^S z`S*`wzrQ7lf3Z8H|5%>yKjLFHQvS`0mOmf(4b8tB|KWL2{QE|)9~AH}dF;l?KXr99 z|A^nv{A+R4jAx?wr(Eej3iy{EyK(Z*Ex|wHH#GlVJ7MCuDE|GtrL=zq{L3D@H zQ$qfL-_ZO!s?0qhihu1tl=koag7$Cx#>qdw1pkQN(ENL)OUt=Y{QJl&UcXOH*f{y8 zt}P*dz;9^&-9LKOqfz{;lJ!%kK>pIlZ=C$IuZ!j%@&9T5C7{?=1-EhaPZt#OZzayR zP3~%RPcwU)^KIFQ(fk|5^M25uL$r$LdwH*93@>ik-RSM{ydvqlZGge6JIr}J8{vm< zYtHWx&-}k}mkIB;F?Mhqgr7SFc<2izfq(D8;_xo;%g-ndp8~#=(?9g$_j~TUyO4i8 ze|yvCMniHT&fUc)Me~pLB6yCT(f_yXMNl7-`8T-f3=lAw!aj^*B;*O;VAh_uQc^HcBGNN_>{WMKWoT_kw5Y; zIkj%{ueS0RuD^fR|E^^FcXHk4pS^+lU)pERo>I5@S6lgW*zmzU{*mn_M74hlzr^?j z_ua*()p7nEvSHf4Rp4Lpv^vheT8{t1?cd*xpE-X^pZ-7o=_p!Xu+j9Tk+5g}c zQT=Zp^uOd^`kXq>zY(?L-?$v-%#T4AZ~bQ!|0=&S;}`NT>(*`lsiSMhKdvW|jSCz7 zeq0p){1E@*=hbcgWhT{*f9u`1Zu76U^N;oApAG({r~i+Cy3Vd||LfrXrtAfE zoPV|Kf7e(3$iMhSb)0`2X#SS`%8Z|rGycavU4L!;ui*K+{SO!Rhto6bHvek7|FOR9 zANiM^Rk!))ZlLy${EN@7aT_UqvR!Zn}4;fzw15!1^?1>>Nfw} zTF!shSN`JQU-r_v&A-~p-};XK;@z?Tds*G)Uv1}a>)ZcYKNBL^#6E2YWn)R z&A-~}|E;h5k$>46>NfvsD}U>&|4jbHy}Hf6+Uh^A@A?(_m%OoV^RKq+SB@UU6g+>Y ze@gzPZ>r<`+d%rK`Io%2j`Q!| z?0^66{6{s;=cn)bAOCcHUElFb#b##zEqiy}=3i~cFYDX?+StF0-&?o&SKIzKEPsDj zf4f2clIc3mzkjp+`@8u^fABATU)|2py3N1Zt{>P1eTV+}cm0P${lCZRHvcwM|3UtxAFtc|t8M?WzVeqyLI3ZGy3M~0 zC4X%={(Gu!^RKq@x4z>)l`{4>l28ASf4aX|-}-BvZTOe=>o)&tTYuMg{7n93pQ+pY zTi^97*5m0<%zCJCdHEJK@0xYeU12|VwpUNNZJH_eANF&Ge~q;e%R@K4q@JoTe+vy- zZ4x)}I4chfE^sinILJMaOU*pm2fj7JKMng(&P7KAK`r3#cmv^|GImMhz&mdmyq%~H z!rQ>#hw$$H2G4QswmX>o5bq%Tuj7<*-YQd>t`*AfR-s;Ru9PMIg#5O)t3arAoob*c zhfj@J-cj?<-tGP%KQ8#!ZhSrE&1jzEpSx(|;NRLE!H*LSUv1FyA^JJLslk(fR|9VY z?;ntx zSWD`w7V;N^Kl7yg=-Wso)>NvRFDliu`-|+oRHi)fr^NsLu1aMtDO2i?N@cCARMQvK zQ<=}C+{GUk|0(jy`dq?`-xL2Q$BF-&GL;p-EBnVSiM#}zE;uHUn^W^=CGL;g) z5`U_vq$mE2_+#RC4-z?etC5QTRjJaFermSVtKN-NO8mCGU%k6h{u_-{R{R-xzkIOd zPx6~sTd5p*AAW2g$l=>gniMaTzn`j43*>O}OiA~&=Bnm4GyYRA82&ZF_jKc#da6wR zJm9_6s9y&eyUamk^3Hz+^>O&20m?%7zpf~jrzG&d^)JRx27da%#rUbfce=b7e+uwt zHt-#>nj z*6rCkuh&|8t+ijTHBY;`iB~!*Kq8KG!aaL;n*dFE;yvywHtwW00nUW@{kF&#|7a87 z)eW5R#B_uQwEvMcsMW}|8d^nF&b@qnQyC(cWd&)F#1KtI$&fjfSCK${^o0_rjRCJe0#|DRMbv5_cyK+rxS{4{Kuko?wO&hqnb=K5+4La1wMl*w=P z7>?h2ww58>gm!`Cm0nvbz;_~#?D|@UFdy}@^%~j%{3bL%nf+(rpD-En@*q#M4jl;~ zH<4)vzX_M#1seSe7k&v7CNZ7BZ^Ea&IXr#QIZl}V6fYcvFCLc63e($Gad`Ut&I`h{ z^83jTwYP15`rZ8Yqx3XxKkk@Y$yno1Ugi9>{UVoRzE#XXl5CQT*xn`dti>%>8@)f)f4Q*yhF9j0RDMUwebM@T3XNxDq@SY68vlp9xAcd##yU{tA$;vG%@w(7 z_|+wX%@IDT*T7u4Jsdu2hroD7^dRADPj}OPVZN3VdCWNSL+z@EezPLTe^2mpi)8%q zpRXXlu{HHEV_qpNzif3>TreuXt7ZIVH{*6k0~mO`q-zD2BTF2PtHOL!kHe1(f18A( ze9f2H$?V^`H(c)e$~aB=u7q>#liYuGpW=R4O8C~iFy9mY$wR{YwD8s1EI(F=-RQ}4 z`sJ73ho%0zXd65{h(=9}{c2(PIq27rQTds3!|}`GX1}>2KY5RsI8<4|e3iE){9Vg9 z9Oc`>|NY>we@FP^b)5S?mtR--%_oKZXM{gm$JY(ne@^(rMbF-m!-5(hDfNIjm*u~N zFq|iU96<83p5%DyiTtSl=T<70pDX=9E&pm$zmSZ|&#ORwcSrJp%Fo&wmbVpzW=!>o zoE}%|xw!Dh9aLDZS;KtIe~$QH`BT_`Quv)E->ZI7!oRvE&(~?ZY2mBYPkyLV#629psT-Ex>GLI@$@{7N zE;*Y0`=@jJXi2)NN`AGk;rFwJKjq4>JXB6?59aW-f8>b&RCCEs5^qxYtr~{;I=*h# zFq}>uU&~`ABjs7`!@fVUMZWxYox%N=&tFIT@k^~$l5pyVgax4z{0hD(L-9L(W(jXB;sguk^t^X#?MT_^mPYjHT{2WuL+Y!~)^7$0U~ccbvS6q~-VJ=jBF8_ZwT!MvCQyC355 z5MSNxpfL|M6ts)*8pGZ0UTj*y_Fy~Un;ykx7HkLh9N0eWGZCJ3OtIPLHarJAa}@kP zU&ScL;3q|w(w{DD&b2#nh<{H z=~AwRKV0}Nj|!J}NBHT=;c_}s_=icn+P@@q<(u(BsO>-TGhh1<@c+MyZjfq{A&Jhx{&>AJ#I<*zMCfHeJj_aw(z6l8GN;4V!q>WKQ<-~+xj!#TrcA*;k$jAulc|czW+x!e3es5 z!qIqL@&B;2Pu{oOpI12@q5XDgS3L1Q`9Kcex`g}rQTa6xf7QjlIo;wx$nQX1|IqQ< z0;;!4>KY^8nd<(ZV7a{UrV!N3hGbH$0UZe zHkr09O?C*{bI=*kxp+%s{lM<_DXoolbW2mTo@pPnf&bBWpq_$%dw6T(9M#ga@|pHQ z+ju^XdMR)}wY72Ev@~1c?mb`C_@JHMElqo<-fdBAlBa?0)Us^;$37kD>(Y{@c#Mbi zXNd05(xhnq2efr2!fW5s{5k{W3hzTEIiO`=(|;xMOXaY|Ow8oxzns*6SB@<*_VIO$ zo}ck|aQ@TgNbNK#jvA)eXnnI{y0l+K+^%uyHs;EzlAnffe?;St4G!lsThg};^*71K zKeL<3{S)gVJwU&Lbq&yoCEd(}+j)N3JqzxjYrn(()1Z^LbThM_W;z2p1G;Sf40L>H zH}m^F(0|_i;I#XhcF)E-3Ea0lED4ENX`$8reBiIc^5wTc#vi>=OyRpjsz{ z`7z;F()H21xZbsd-%j}6XjLh z038<#KPCKc$BA5}o=XeAuGEVfzAyaeWgM;itnk(9CqHblr*3LBH$VUNlJ;ZgoydPy z4Ws+--S-R2Z*fF^C2w*6Lcias@up;4XYJ4JX-pgz$-0~?^{gd){|yeu-^BfwxbQ9M zzi9Zj@N2|GPLY1iVws0k|Bm=SRnqBx&fzD8AD!=Vg|C*TL+$fFel$md#7X^t#Y*`d`HLcqPK+b)zas+9ho@d-pZ8!RDP92e!V7Ryl{!` z(!kRn7M9=UNdEg>=Y>SC8t-Wh<^4n+D!-V{3!ZUeP}8V9ewTa8++N}N!g12Sv?KE} zjUwT6l8CiG;!ApL;omqmoF0`^$!;k>68>;~0kKtX%0BXmrS+>76&++t{?q=8bt2|p zAV1wdZhy3A^4mxDxoAGqc=}5FtNbEyn5*d(x#~#iT&Wk;e|7P{ztn%q*LmiSvQI<# zI?w!b#J|?)uZVy5TW*I`pHIHb@^jkq`$pxZwA$~zIcrRQ{kM{|%ck-@2Xix0cHz+Kd06xjfk7-&87XF@46g^G40EF0w{Uo;-Eb z*lAXcC|*0n>uRzm{F6;=*d$@jvORTHUCs?XJYmYr z5tAp3PR^L79?lstdgkb@(=ta*rpRH2kDvhxIOJBzg`Ubn?Ix zd!3laIw8?>@X&I4NUtHs4(^ptpVYf|9(~eDz4Iam)vny{Nl~(Q`@CesvAsU}XW>A4 zQR4_h?RqQbZq5JxQ7`HLxplav(C@FtKjZSN^^MvUeLw!&d$k;J|3K@P(WeRj3z^50 z^k~1;KZgBleg31g&so{Or0K5Tn8Q*3NeSmavhT?3l6pt@+jPFUEr*{Hes@_Pwhv;y zC;VN%NISBe`Dx*6eWCVUg9f)OwEtkU;Tp>B$MuQ#RT0L%^vC9e+tH`Sc+O_+#@a~hx8pY;te<1);RtSlpIr3%>~i(Lm6CkJ#6J1L*k7g&Se+m6+fAsj9Jlfq&rVr%|6{yq0+%@d5vN z2JtUJ|00X@0}ZZ1`gUUf(R+OZyf6uD3Lkz6rW@A75nc-KOQ^`GT-Dxk>+Y`#$@jxg zd0>yCG~qc=WvU5W)w1>}PW0pdSPclpsHoyNB=z7WVx) zYpWRd0fYy5$luNe%wHfZLQ!q@pF>!L7-;*OswTb)@d3k;pR->hzo!uvFupy%pN;n+ zECy{M{QqTCu4<>=ZvRCg`O^Ft8S5RcS80AMh8Z%gAM)qNXpSs2KL$E~evIbG^5@5B zjx2wEjONJl=f`M{Z1f#GKST3lgjPP&G(SejpC7X^C$<&tIzL8pWcl-BG)JcSo94#| z`SW8mN0vW7Mss9dSFR7NzAX(Qf4+?5Qjt-)sy(RZs>Oxmo4bqa2meN%$4<4R{JT$? ze79mhricA(39CZ@pXy7jSC~c}0xZ23^ILCVKCn)Q0Mjgt2T=c7u?_)VhW~(W4jR}& z&u^(}Vn=icuxbL_@w{EL1EUMV!}A%?gx%;i`mZCrBk?@&tHf^|0vecd4#Goy>on^S z;Pg*eBFO_g7{b9=Hwxn47ybeFI0?TN!Ut;Ifag*Fy7l1(EQWug6LGvRP?1r&s(s&4 z2Yy~izBfwOBKtAVKh458GM2Z$?h$lG820%BTdzQQ+=~6OgAWZbPTX@t4mAYLe^v|l2Y!+ApX__6A)J8n z?$CZ%FFiYJ>3uf0qqaO`@=ub2>l~^ zK84?ecaR?`d^IDdh3Sv44bwYM3(NC5H2L|@FNx5bJ_@_1cOX2(uV(G;Fs=NkJzf}U zU%%_aRQ~wCxr`sG(Ej;RHOuyox<7I|S52N*oA!@ZF_p^B4~>xixR*Pb3xN2aEBoS< zZwY@vg2w^Mw}rp;)G*%>eoVsGeUz^7FFTU`+cFQ67XHODA7W(xs4x7nsJ}?x$#>hE z*iG%s?zyO+c7q9%x}}||*IQ>OjLF^J&e+$NyZg7Ivr>UkxmFkV&f|*)l6=i8oIahO zYLP*I{OH;yEAt=O-7H_#sMbC)udy zAH}$$YI73@eHNAhyxXwfp%~Af)6875oXQE#2~=xt(vzB*Z_rQ6H%*^`|JOA)88bP& zY@P2l_`OCrX|WHPv}|a8{>@1KeLRl!#xZ&OpMPfg>bO^J-T#a%9GL7rGQTvK=hY+{ z(^mF@YW|9g!}|-u`3~L8z&!l`^EIE^!f$&mhi`u7acNTc*XTT0jN|o$|I17cN7tP* z!mqCTPc@yA{>`%9uKwe~A5&A(Bjv*pz64ihrR0~Z_HpAs&6jT@k#DjC^i~(+3E5xn z{jz8BP5dPDld>MB$nEF}ynD;T`xhP(zWTQ$xPL|b$A$lVgl`M~m9(-wVsv!MGzZVr}ax}Lywe={H`a$_xueXwYF3Q*W?Lqf( z`1UNWA7T>0BF(?&Gv5+^iwoGl>QCSQNjuE9#eZDGk@P2oKSS2bG(G746f~QKtG4&V zur~Smcc7e~n1b=K|6|?q{r`Uymap#r*ZNn_Nm$qN{JSPX*GaWJ>U(CTzVlw=e68;@ zMb`D5`aJ*PN78=^yxlnjdyZ{ z9}|bVjl%VsCH(5L?v?$L`x`3vn{@qA+ZpjcSL%J;zpU@Kp|Z$J_SL)Me`6`ftLaP$ z|3_VaY|Qn5C;V1}IGpTyp0CXaKWe2Ta&NS7>`uzRai5>p{@FfIv~xbre#!n>x2Uju zec3;&`M0L*gR|s5Cyl?Oo(t;6`PvnS$`QUN{JzTnn%~nG{sFq*QTBWL@;-M;KTqS$ z2*17LUt7XSNX4{J=HIm(B&4a){R_GdIYju5?vIpuV`yH}BuNXbe!^FK>+A`e^6Q7h zSr-H;OBbVk>rlIFe{!~RVfpI*WR>ra6J=fC>Tv(}bJ;&^oxu7(R}ytkZT4?3VE?Ox zKWDnMCr!9s(%Qy7Ui^Q;^~Sj(FGu*+EzBPw?-`TzQEMslD@k#y-iX7=%Kqd^JhU*Y zk6^xaEBjw1{C={Z*_VCG=W2tHFI@aC5!w>_g5Pg@ndF<;$ocn2*?%?*6;HNPZKK~$ zu&c6swf#|><}GXBPs`)KWnI~7%pGwpE)8^FgY3&ZT;gvWX~%5g|MWWd^E7`QC;V-g zccyuw>?q73j&IHL$e0I7jBagW6Iz>2m%*L(<$-oV7h@iX)OuoAhk@f z;PHYb{HAlI-IMpXh2O7F`296sr<3Ae+P!|_zlW4})racoe%%+iiQmf+|MPX-^=_`m zRE}0v318Bg68}+4{i}U{s|SMqukP>tPUJiAE6iV?T;6|hYV4VOb$_{YB+F6b|6;Pp zJ#s$SD&lnOemqMas5L3<-xmHs5q?7WQ+2<~!tl5*`@85PvcJ62$r5iLZa-CCvwjTM zOTL6(U&c-PUK!y>EiE6)Z#3?UH09su{7$p0u%267rF{R}K85AG81wFdk&5<+WB7e^ ze^psL5x#2f!Xv`|WAecJQm!=|9S?n`SU;Axw;kT9a=y=)| zep39qqK|~|hwFO$McmRl!jD>7FQ`5K?C16;`8wPAJsruvzb-@jR-;_LR;@jg?;zoTTvIll@~F zjw}4-GLNJDl<*%=emAc7JmE*JPQuXqaLeNKYLaj6C4SFur2k-li~M_-_7bpmTf4A) zb^oEZZ*e_WDf@Ue{yWBU`0o4R@#`?zZ>;sB%6C}}@h|mnTM1~goX=4II^Q-j!Y>v7 zS5*s#qwl{(>JuF|+v30W_^|&n{mDK&_3w!PsI^-dY9BFo$%_2;ZL*Ay+pNR*_^DXg z{ZiRFh2=~4a|K2$-QTJ8sm5;~&*@gaB@Pcuy7m4nTljbDK4sC9zUMCO=XKzEGb#Sp zN&h5kbG`2gf0oWSp1|cgE&T6f+@bRFB>gQlze~NG7JfIGzc*WWJ})bL39ihVCBL*D zKK!_Oq4T$&OZ~9V8_2(HY8YS7KgJ5n*SfHXLzMU`nm^P1occa7Nr&!NRlX&B-509- zxbUylab2X|_)_mzllC(q{+G)>T%9*?grECC+Od;ZPp*}n(Bgtw<-{J*Qb{+qiWyC=sUV+cEVy2<$S>;PX0 zZEm&=;qL1>JJy+U z)@iJJaTidRJ^{{$yM0GBi~;)uSd0wl8tgB#`vmxsGS~`?n@05su*S#pxWCCcvQGfI zKZu_9j_VUZ?{o56fd;a3DRt$h?F#-K>x1+FtCQt!^y@XD?XGmAKz;>QOu=~MW#re&y#rk3A^&2%Hx8OG*MW9)Y+>JT7t1;YCj>H8Gv0nQ-$bL59A*iQuX=n4PWuaw1a!j=zAU{YTo zy?`2(tJ)XM`|Ykm@_ltFKjAKsitM7We0L!KTF>Hr533vCEyy#Ac^A7?-2gj5le^!t zZh#>WHOV)1MBM<@kB0k;$lss|D|;Y5s~CHo5FQYNy94)3v$_HP4R^aS>KFJWyo&mV z%6AOm6H3-|eCBYRDFyCF``|Xf{#T@jpz}QGHgydlj(Hys^=};E6S6~57aoH1rLEx( zd_nEQ>v+HBNDuG>Xew_meiKgb%jvaS;C%r#D%Wy*#0!PwTZx-j<5lDSj{6AJ59Rld z={#2Qsg8!w0rGZk$2$Ew(7^5|L8E?f9_<*wy&UtMUqIfV3D;p5>%EKohu;MIY52$e zc)3S923T&f|0LW9CA5DR`7H}~LfJiuKEeldw!>Q65&IlFn(r|&;|#)GaL;3Z3c<$n z(65>yXisP!&VB)L13OouJ_a3owqt{YK+y&%8;+ei9mLx*8M+cYRyO!gq|N9axfwX+9SHdXPrM*O7)N>$?xepWBHZVC^kI?>*E&Po#f8<)>{%_TLI9}^M?w{Tv{%x7x(0J3rKkIGG zue^-?hx05GUtpQ`Clv*>J>N2E(3hUgv=2Idjb-L9NB+%Vzv0zzCz|pz>L(v`e4!teGW z7yVGax%dR6=hZ6at=l+XCpuON-09vz5BynFKObCd4)fUm({IE6uBw^y6vBD2*vvuu z>EB;$YCv!lZe_%0H!3!ZK~p&yjjT!G(7lEZY`xFWIR^d_?y`3fKf*Z+^#;l1w(%U# zZYY$}*Zy+0bMQ~}`v{N1KMnOZ`KR{NL;av~eXSSxPgF6_;GR7Pwwm&KfjO`J^wZCU z>W525vAfIdkB`j+0)2TeGe_SNi*`tj@f0nVlVTis&g zfhMeg94y=;8~>($fL|}=_wYdzz8r_}&>ykBMfiZz8T!V4P5Zn00XF)GA9NNpVXM&Y z_w`Kx8}6G?|NKxtfXXEYns87Sa{M>yvmfgR2=0%B{9?P2USL-e`owtvdn4ilQeBx& zz5@S%?hnqvjj-Zmq#w_x@GPMs6P5oxZ(h2gko>5`Yb;WzX>Wodj`S-^n5|$JluB*{JH}1#nAtr*+0NP z5x)o82Thn~v;MsE5gu>`>U+wU$yxmaX#Xw;nxOhfUI2GM`*-Py{S86opPJO)1Q7W< z=iq$+mA^d|=>`5V3HgQU`wKw>6`82~=ih(cH-+TC8S@u`$#MTKHPQsRU-N$h)E7Z} zbw)$<*BhD}??HjTANw;$Hw=(`0_7V0H*ZwK01rt$W5F+BACz-*Ao?5QKm+wI<8p1o zjbMQ`=wG-a8#2fp?PL6`h5@vmFz`z#vf&@$d1DbDU@*R+=i~TIp!=}B`e-jFHw-X; zJ!qVd@Fz74uy`WUi~1~ccEbSsqdj)eerFxLAE5e+BQ8R{^Z0oS&lBz&i1=Wf@eKno z_2>UxVI{@RO#k(o{PuG{*&j5aKjPnwyG~^uz&f1kcM=;JwPUD<$TWcX$>@4gbp2_U z-ghvI=hv;kw=uOJhg7qALIBy>%MR)`&QG!_hp?p+mPQY zEBxp_EhBn-dS8xL^M8@>*GPFWx9|u-^MeHUCo3i#Z3osasvqn>N=NQjr~Z#Ow5~DR zxPR?Qe_W!~WEtug)x}?lggZ^wza#4d`TZsL<@zSSzhpfV?k^=@sBiN7O9uUo{Qi=8 zslLhYFIlgL`%5p{4?dAJxBZ}gnz!x6=M!`MH&qAMcppw=fbanSuDS}( z<*)uT!mr4Ri-Xn|i6&zGC@g=vcb|;PU-!4^`l&=` zY}v=8{FpfGBlqyQk@a#M>j(n&eQwt@y>n%q+sOJ(3km1wbJ@T0TM7SK319hbgg;x# zi@AjJxymI`N8*j#r&3n0N_r9!&g9_|?|M$>aN$>EX*~Kq*5vEv6_WoLR2TjUv9kFE zuVrER>-@t1Gx=}$e=C3gvA-yPNzb3;|LmU0U*)d)xvS@ne~|oBTUd{}KeaBZ+3dHK z%l4O8tqaRv_m`;rcSr7z(s-_ya}B!xBPI^JbRUA$8x4g2^fjEGXt}5%_pWO=`aZ*? zf1-TNXGIbJTJN@P%HgYjTjK4Y`CsJOPxzn7`2)L@>-hn~|5f^RTD}GgzamT1rRhFy z{op$a<$nwEcP=l#-^y#VXY&8Qu7BL;_ALJ&|2OL&f9qe%|7J6%=TG^6%bw+bM--#= zlsoR&;C{g5^PC^*NdIRv5g| z=|9-QkBP%t-KP?fe_Fp&A^f=bpFN!Wu^Nso{FJoI{`cYh`SL8zSKeu|f2BG|8p(Y8s+<_Ui-rGr*r9KwEcZi+q>SJPc#K*s~qH^X#Uxbvm&!^%RCq6 zIrq=If93YkJYO7dgZWrsGBTXI7Uu|>V*VJo6%(Wu=tSd&0d)O2)eQ5$gb7$bdaJ5Q zAK5U#tT`C}zlHVZwxEIFevk#2FOI`6unzv+g$TbT!UvX${{-SD{IU%1vmO3R;UA#= z9o{FHuRaXv19bk_!f(RA?=r!BeX0fg15XQ`ZH@V6;7hEhc+VpJ9T7h8TpheG_BX{X zga^ERCO@zFYi?)##rEwN^7F|q4Glq!%3bZ^L~c$Y`R}?-3X*)ci00Y$M<6i?Xx6#d ze^(jn``_0K5R)wq+2R8XfukF8jaTKa_PRQ!Pc0<>2S!Qwa=wwyQRd5k;0jKkhWpdKh!5)($u6}6 zR4+yTAi57|AOf)a3UE2`O?jy1FMS}=f@K4_@P}3UW)AKo`mk`YltFb{KSbu4UI~0J6 zujTmT9cvrHomkhU`yBjUwF9(;{OP-*nVz)+y!-|0(`k$J0cuq4YM;L>*RzoP>3j+q zuNv3;bk1jggZwE0E&87GSGHYeq_4B_I%B<& zs&(f8YtP|;(iYr-&OF_YdrA-%Fj_mv-B7TB0dTjn*sq7*1ZxBGKh~So*!PF&WNq9( zly@J?JoqOQ|FLs`(`F#Q=D9z&Gn}6~;6-VFl^S;?-WU6E)MRZAFNOCdeD@K%*qu8Y zLO+y`{O9#KmAl&Q_G?&h{jum~Zda{I|6Ts(m2UWU7QO{5^0)Atpz=@PH$ml}#czVj zU(==XSGr98!ch6E``?wnKL39ue+^INuk@bE|G63GK3ypPKZfy_)uOVoY~J`v^9=d* zk9QyIU*j8%B1Zc!)LgRy`3d_p5~C{x_--TTuWUQ)3j%gu9roX>FUosfevZ}$bK&j} zD9?`>(D~+52hSR%S z=;TR7hOnXw+<(V@jP`gx;7Qc~WOCap1z-x_y^ zVe&lf_oelIv#L>m=l21QGPkO>XXf;!$f1z}@ z`K&MhK|Bu_)ZY|e0`U>z$8h~;t!`up7xv*Nv-dYLgdv-m_Wsq#5U77b?Qsn0BP@Lh zH0pmf>7HSI?SlNszna64|0unw<#<2f_lMcVy{C~Ol)&BpwW>+p)hGbf|77BKBdvg% zHS$C4K?mH`Gr#{|Mb2+*#{JUnw`ezY{@-RjV4G23)J`s9TDq%7??biEh4&F>4O zU%lq!;6+uBaakX9Hiy?`Y@L5@6P}+rUi#a*4rogR*GBFuI8OL4uHtyre=p%DBKIVS z`b_C+N#}E%o`m>6{eI?Ka!-^a{OCP6Du)>|-tk*<`W;d4czLcw>&#YIQu%YUiJzw$QJccZF_Z|JypVfm-gFC`O~@GCk$X36}R%Et*Hnl^4IVC(EW}+_N}Y&R|?GAmn+7|wscX7Pl^QQ$G5w)0NT?d!>D~&(@UP$-S@V$^((BGj6q<$3L329#z zz8BI19l96t^6S1=p=OtH!`6~Y-xhwimEmv_!ndl2{X4=x zUGEK$@RPzHs_{y@;0pgs-Txr`l<;fGy(n&^9VuHclkeuG#eai{{ljx-2K!I4TRHuD zKG<4@cBEdNGWmP`S^nB1Q=8;ZeIZT%5!&uYzE6^p^$VRhj!8OJNWG+dP2a7$t|8%A z;(uXnl!v@==%deQ2}3>`g?lPb6_2nosH)dsT&yOIDdqUea@rYL$;>(zb?ZC)HVFr7 zPBzMY-Z*3Uf^hy{^HG@okG_aR(rKZ_hCGS*$DtcY;|Mj5{7}2`yqYnpf08e-{4bXN zPaSldviszne?NZD@_#j%=QmGtzf0pyc9#4p^{OU&rpyDoud;tj9_T0Y*vgL!zlnao z@g=T@ZQ;+kTEdt7oDlxqH-`C+@SoXV_|h**3cstY-)X$A@P9j2{7X7h!awx5Fy9lt z_QSJHp>&wE@T2Xo|7^)i`St&1X@6<_Wu1?+MYXy7dNK~ve!to@E+eD$k0t51CvvUg+EKy$CYmjznQGp=)DXH;g@|sN#yAWzifR|+MT5EXUcrO zhVKdg99^e)lqaNAZZBAzeqE=?ihoPiFZ}((?eZh_*uQ>fUfbWf@|>pQ;`iDH-Fk^{vY%v`j8jk`+6yszcsjU{@3&KD*uZ1e7Q5-xvS8G@bHYx{UBM=W#k!Us>U=)_PLL zH96s%)5HFaRC_w2Qv2+EM_*oO{-N$t38)gU8`;R`_43wVR@Oj0{0PSLZQ=pEIMcb- zaYLZ_24~hfWZ?GKIZEaakv9>b|8Il_dCS{G?>Hg<|rf_u)3hW zg?p+?JV5(n;g0y@ct66BzM%8W&znKuebn@rhVb*|D{hXd3)?3Q2-6i&su#7_Kk<(N zh4hn>4DU4M^)Y`=5%fcMWV6xp#kSSh5b&us06=GO4bO0~Bv$7r#SeLs&VFX|GFTe7CrpDq(9fJae(h}zK-a4lg0u50slms zri}y4T*7n~G{JdLo^OulfteDXLD+R2^K{gYt%pD% zw!q{tZ$c(Mx+p-44NO~OiVR^s)<4N)#ufz_JB;09BTxo`Ip^U0(XX^mC<-v*K6dwU zE|<_G$+V5%gb!r>$HDj32xnmEN&V2+M1%*FZkF&Tg9d1Rob;O=hWTco@mYuu{Y?9G zga_RH3H$djjv~x~zVqv+K`1ZeKRvT3Kzo_4jL*RP0v7Ze7`h-4xbbWz_5aiLeg?e1 z0j{0JE@_~RB`8|4n|FMz)Uv)jVm*IT zNq}DKQGbGVb|HKM=q$Ov0C!+C+8b{mo?naSf$C4A>}TQr3fzJEpgqvZ?Ii&YxCZH? z^Lp@0_#EqlM7xid1Sk>rENH?(n9d}33%?0zglFDEef1ys2af-d-Bs@W>L4G%zncE5 z^w)p4RWE8^^3hex3zZ+*A4A5LeKE8TCcpf=b~oN<7uFjlmIn9&G@0zA(g44rykv1d zfSS1M53rJ@hVb|)oL`gEN)2K0G`t_ei%%^L@Z@l=@6u7f_W_7GDSwB}b zIS26rR9^f+46J4K2496;`j5$mf}2Nsrh^}yTnH!e!#NXJvkET1GepC zcW(mx10M@*#voyUu79MER>IBFAMhua8p0;2Up4-U?A_v^_Hz%`+BbjvGG5j%zFCL& z{i8-%FwUvme@3$t7`5rUQS^NW`bTD!-oM&{%N=uZ_VZnt&y0*8GfpCSQr8!-Z6Yua z?g;ZKZ;)9d^T7VZ@OZO*WPUi#-c3!N*OmF_gz)=HdTg2Bb0z)5-r{(bpB8=}3CDef z`{!BVyGKDzOHq#Y?}4?R?q<|`5`kFL^61Qn?q+x1_})1Ol}N;Bxl!A_;Jup*m7n&q zzsBj#6)(->9sni8Bs|@(`>v^PO{e*g>b zfY;veewSUKfeTPSQ2iHQ)iuCe^#ADjEZhiNuVsOx9_(remt$Up<^k=MT?0HTbQWO~ zCa+}w&T6C&NUh}Z<9rMnNKyUsVtM`Z%X#dc{&!bHXix1A;!ke^4O}4YReTH52Q0si z-`9Pkt0Ao0#POxu!9Vcx1x%Zl@qR!C`*VW!?G@0#jxQwruOt0{8ZBm?Fg_hV@r?ZP zlalfO(r;1Uw8nX6UH?0S%TH~2PHkQP>nF+4`^9V-hikk8_5M&PKPs8=eR-UwUBbBWJ?G(k{luky zTZ8eb_f2{IW}n6SsVUE??Os^PR5nFr`!nYsDDsecL*rd3@1gaE%I^o2xA=GDfpd-u zhof@(ARgxX;y5uW^V#cnu!z)ku3sU_uS zT@LF2pHw$lxmP=TcH#0v_sWsc@)JE5E76!_O5`N-idH=-#`%Q+a+j3sA_ z|8_d>_y)HFN#WO%^>Ed{EBx=8alF2i=d|!|eOS_SKZoNBzv;PQen$9dSqHGie^&U* zyU2V}6Hce*i@S6^LFx<57fxsKFX6-^<)?v!8x#A`bf@6{Po3Y_^{tlcFwb37e!k8f z!TQk^U$yCcU0v*287|?ee(YuJU)W}@?hlrEVU2&bo`*b@*W(YD2WEHU`q?`RV;uCG z>7E(qCDe*%V@waa-_ha@I(UqT67EBa`MfT|PlL{#RBTS4tSLu5a&ocxipEoU?Ny8GxV=<%ZbKYBIRU^%u6f3MWpFIU%g)toV1TNPQ*W6;Qpo%ftR- zqKD4%zGgbthpJBruB;wP2&40)#lMk$lCpj?2!CG=#yq9>ykEurcuV+M`F@J#v$*h+#o_mEEBwa~3iHu@ z4@}ekVLnEafmx&BOM7Swf067n(Dq8@6y0y+i2tiZ-u6tEcT)I+^<1dr)0FV(9vuhk z`Ci=yxF@s$*Q=mou?EJpZt$o5jg^o4y-K0+&(ha9K>sn;i+fWQQy+gZiRVXj*}XLG z=Xsz{fTvGDeT(sk^I)F(*+<2TfQsrIN89!2HdsK8#MNfA6ej;;Z`vm_h9i!ZQ!`2{2$P+5_CL zm;_BIMtfu5hWl9Yo6r!&)m@47KaB8!9>{RsRn<-6--sVrcLm~ahqmq!gbx_nr-kr+ z{3bL2ods<_+9$v-6XAa|+(8qrdz#r?@ zx{c}dMXd}WN$vl0n6H6ff_^8&I-#{8=y=%1Z^GS}Z*w? z=+DAEjj#y%9g+-w6E;BKeiz&6Iv zzMHo&UZ(d;&x3q`8!(>T6Qg=l```b3q9*Fc&Z)@#F0{Yino<7!4OjNrYkj9SwO@4Z zp+q9T%#!-N3zu8!Xf5r?$>dIHD-s7ZKf`JnJTIXLKL3mgBPh z$+BrcnWsy`in>HRwz@2j#e-2av3Ziz#5oSG1R zbe!r4e@kRstM4&azaJvwPFMU#$K@&EpE5)ADtglXw26#smx%w;gW115jOU&25WXYl ztIZl7XJ>?ed#7;tS@mBn+%JA#`H^vRPWVwv)35gH4?Xx$zW!d2^4A2@E!J%9MPd#) zSy+GC|5yF}Ci`A>{zl`EeqYBDhuu1_BmJw7s2PGe5Ut@V1DQ6AzzMStlA85Ih$I7gX z{PM;A{^zBk{nZzX{#Gu7{wkO6uXCpr)}QV#RsB7t`)#&xIn#)B9?F+{7-HhkQ}1Px zc@aza(eHc3g&&vib7(!L!)?H5+pE4cnR_+<{jzfbZB<`ECX z=tJeM-??^&^fLtg&b2+VpCPQc)CAwTP953L5Kgku-^PBWMALo&uq;s+kuz_dP~ z-{DRGJF2L#x5G{!Ta&87hX zYOO$jepRutSHVB9q$lL_5Z3FL4+t>+ZS?O!$5svq;9z`bgU&sG@PNy_O<~5?8~tp zb{E!@{)PB~8}U4iAAPtJK6(mm2;7~!kzT;3_o<2TZ5q!5YkcHae80o1Hy}XuT6llN zm++7tpy?cp7eL!9@czK=w-Nt##J3jl0rlv-Cc;no0|K~RF+b8AbEyXn2vCv!){gpl zK_UIUb{6Lk`zX$sbPgzAf3vX%#M>X^vp<>y=z;Mboj>#|Hw`dhKH>+RuF^EX#h|S$ z^jo!QfG5v^J7}v~(*VaHKRBPGd{%E7AXy3;>xapGng(z|d!U^fO#}F|A>WU&o>8-D zfF($ewF~nWb(#iP0h;y`c(p+Tk5GC+r)o6~FdXU4f=<^(`he56L%s(f|5R!kAcOSL zeE^xFrU53vozBO5F@y(2JTqVg2PU{_pxT^1b+|{=6r-{@qjk zncEAOKliG_`cwYis=wnqwtcpc{@Sh%>n}a~zw6JhK!5(Xysu(U^=DV0KYLzb{V9KM z)!&^LHrr81f2SS93#Vo6pZnkSXSe2hGFtxZ16l5Ssz0{^{h9fN^{4#3Re$SWTfV)J z{`!p%m%sRB|3iP$z_{`?B`XQvA5Px*VR{*J9)wR0i;of4@(bC>^3{eAk^ z^k+QQQ(Q8F_CNg!^r!s2RevjMZ92M;{?5S}12S5Frmy&W`g1?~Yx=V*(4T!>1?5lp zd#nDIT;{li^tbA~u>O)){XPAe&;OeK+zRyPR-ixS@2&c~_}6=@71CeB==g8m-_xJ_ z-Cxt6Uy=TX+A{@z;t9?vW}wUGX1MD&+j`1kZ@ z{_6Oz0{yua=ui23tNy;~-Rh1)`WrnsT>j#zzp1}N|62L;E6|^PV+G|;_H*}eXn{>+{1KQ8sHj{n@73hPh#d#nDcd{Od3A^lakBV7K{ zH~c;Qxi+s$#6%zev;C_`e~T*6pYZoq{hiaP!R>|gXSrehC2#tB`qO#sJ=LFEf&ToP z3+qq$d#nD=J9c2f^}jnJ^Jnp!|DOKLT`c!K)t_IH{uWoDKjH7K`dfQI^>+%Dzl$UK z%Psz!`g`E7>CY@<|M5usXZ~4Of6Cum^>@hw$rXk4*J(kx{!B0Vd-}6C@VTKqEq`_e z`g1GLpYr!s{XKTY8T%E|U!T@t{Uw+FP5sHb(w^$itw4WfNd@Ik_c{^fy1Uew4fYzw6JfK!1OA z|Cw1{xc#%27A}9v-&^#j`*zjtKI-;s3+?~RwdMW9)(w1KBU`d(_3E6 z^xOfq0wI2I_m*KqT7(5T8 zI%EH1E$n|ir*D9={j4?mnhdahg>-Pl@@jK^uiVq04ey6O5a<2#&G0Sxlrh~S?n`!r z{U;*stv80<>6<6{=DknzDPtyH5cZ$$6{c5Ve{H_$*FH=y#(jq*&;MmquWDzHZTD0m z{nGcB$@oWdxukm_8sy!-b{F=i8tfm=wqd-5{jGFgQ2HqBnFi=S2MhNt#7eMd7N~It z`_Hw;o@<~og7+I@fA*1#(U=Y*|8@)PVFtd$^K>7B-3&CK_dED-Bb(W#E}+)-k;($Mf^Y~+*g)wUh9SM*CKuJOZa9Q%QK1Jgk7iS`^FVbGgyAg-7rFb zvHi>iNDs~TsvV0SD(zuUmfcJ2I!n+Ce!I+i-Qga}mN2{Ck#Fhd2FUR}i z{B8=*67>9T8ovp8{x*Z(1U-M7!*7C~zm1)Q^Z|PQHjdwf8=pq_IDZ>Q`~*FJn}8dk z*WHls<<(7YI?@Nw_xJ2uklv}Ffm&B#|M$(`6&cm5+Lv5C`;bEV-6-cP{Jitoh4ky->@h+0>*6;- z^_#|Tg6cPe-vrff@)n$@1~TiBV$%0Nab6nulFrMlfjn<*6+rcCke3LmUkkqps$Uzw z394TQzX_^e7rzOrUk|?ts^8>dqz6#_`fwwpo;Q7WAKmels54 z1t_FndcWkq5k5fr4c_ljydO|VzZ9Rlu2lfiFNGgl+bTds`W3aA&Eny~-rHZvKYutw z?!S77&i^Lsl-*Be-&?ro>3o~Lvaa#ue6V#t>$kQ%ueO;(-#;q9Kda%D z9FDh}=hZbiE#;how>&)G@RXcu(EEHW3Ew(N!V&+f-{<6-xdGwM$(@W{_Y6h6aLN!KP~*+Nkvtv9F%^O^SOS%W{t%ss5%|M{LF)_U)77+Go=2o z{HQZAL>Kmtl#8}@GrfA0NZeu?l$oWk{)h7%Y5U5ADF zorLe|cfTX|5FIu>9DYCXf8_&VenR-$^&GQ=GhFzK<$FGw9!L1L+*hG|txpe<@4YKO zDgNKOHk|%h!jD=iXXSfUR$PMeTNJ%N<$T;fY3Fc%!{#D$5N>W&Jsg93?aZAx7kG3> zlY6t&(78Z+ImR&UIvVpK?g7TZVme2gYTwbspDs0aCyZlpPqE#hBhK@cntnKEnr#RF zrJ%nqH5137-va;fj(Gk#+%=422u|B#IX?{7`DXBzhUfH=wh4 z{^B1Heg@-(E**{kO{qB>{W62^B$}=W|H4x9A;#TK2aG9*zNpj;MZcWFi+2P4QK?xz z72|HCC)pkJ7o{e4Ec*2r4|zR08hiha!FR5Md-0A%`kHn$<1tQhm*AW%==jH_rukin zZx#AI$8|KRU8TXeiN4dDCi+>V|4PJnMRnYj)6vB6e2<=Z9^<)0ua3s6)zQ2(MKu9` z+Yvv$JE=1>#wkIXB1ZMA_RO`TJ}%UMcBJ9=`=1g-*Z_LV z*E8wSTaWR|8+8KQhekN~PS>_NCIj3-<5!$NO}||yfR10&a3f5{_?7Oz&V5uTfcCHb z59=6$exKa^xQ-#rf?nu*4fdyX0+ii<^e)^1{XThY7y5*NevjP!9PWUA55jx1jv?sy zHHY*Qj+n&h%_40C{XTi_6SxEVeR3PW3EIE5-vJF|phvGi&ij6V_yB|PlKm9YyA$rf zZO=d-FJLUZqfP+*zPa^&9YaWTfIH?7)X@F+4#wj?(n@G`9lyWx8J-6k-&mdx^ck{M zuWD~@{KjvE^xJ6&&!5;ES-*6C`5^phIX-wa(*Fwd^I4MsO=pAdhyya2}W3-LG)o8E`Xj^L^L>*5-6(xsFn94|lK_1|d!U^k5H~OcwCRfU!at$T35XxG z5C4RIcpne%m;3_h2kN4pa$d#U$nQ-8423&=uiM#;@PNj6-tG=}8|ROKR-ir5v7Zq? z;K0A>0ry|=JTMEi13LK&!UyJn_CfpbOE?qhvyMSM3BQDWZbN*alfS_~;M4rx=T(f4 z^bpjjUe&I4?&^OR((jq5pUHUN^ZX>;Pj-+&dYNr>ej~f91!6ppSCar9iKYi zw=e`9k7n_kpyN;H2e<=T9+F?RFoa8bNC{%n04pJw;Cmf!w=gMy?jN&gJp38r2ZHhLW7Tm+9q$W_JX=%3_POUn*0}%7`2_Aj z!SOKa<@h%(0?>Ha!~BY$YY{+0Q@yHv{hO!EETms*f5|v$?pOV{c9`1Y{C1ey;{0}) z+T#3nnA+m}c9`1Y{C1ey;{0})+T#3nnA+m}c9`1Y{C1ey;{0})+T#3nnA+m}c9`1Y z{C1ey;{0})+G4HW4Yk8SemhKUaeg~YZ86pV+744&oZk*pTb$nxQ(K(h4wKyT+hL;f z+hL;f+hL;BX!%pS%hkh!?+^NNKiyZuc_KWxAJRi67Gpimde&NBZM`?LMEqst{vhi$ z&hY9l|31mY6MgV`Jfsor4c#Z1THeRx-zS-ad;Wcr?vs5?{(X`;(E0aCI#2a6B`BJD zpJWc<<=-cnfxCx(p57veNwX31$-7U|0iA!JWEQj|xc3Q}w>g>lapAwyFwD1w|E2JqD~1FqNeKU$Rvf-7@jAl4P4Af(ep2|` zm$84V3Wwtgf9n;@_m(n0CHz_EhSTE-fBR78d(Yuw6qvN|os-4?@67jwf3$x8RNglu z{FR-;;b(|>&Iw=BC8W9Or`d~0zuv2yejWdgpNw(Eq2=vW_KCv!-8_gxN{N1} z>-Rt(;eMIMlm7Ymz=tb*OB}w``*b7YPb2rHxx!C~e>ZY(t|R>25q?tm2g`lU8jdUc zw)5^qNMtt0%b@Y~6~#Trgd_+BJEM&vv@ z5>8CzFVAVo^ygiBRiXBG3i`ifoIm*frs3#cH8fSr`d70t{;|;?NS|3dz=q4w-oJuz zFKB{C_uYa{;x|G2Pxe{04ME2XiL+}Pf{*b88TZB70e%G?+~4yO!U9$fV>&hocVYrN z?_vM`JUk0*mI;OU2el31%_;2ey@Ka~TJxEXeTe6QCHfuNX_#pRmJ6La7wHFzlI-8T z2zng&{}^y?ceH08;`>}z<9;#V*ApR+HMsw2DQE)LcWJyBha2I| z9!wkjCagr&L-EHJ;{G!rf$=uQpTuv%?O6Y%_&ubB@Hl9zH~Ozg3t{tRpl?L_5EdbZ z{7doMSM>{UD%LlxZB>jl5BI?V^t}O!&$%4W1J}O`_a8AYa|QeZ$4^AweYdLd;YQeS zEc|1g++2zD0{;O`=}EzjFctGCL3~f(dEob<9KQQ#KSMYk{Wo$?ErNd_jrKo~H-2XU z>fcd+KE7}N0EZ$QQ+~1$HlZS;dRKe>Wq00LNdK93qW`g6Pt!f64Y5N&^{?|IvCr^b zC7|SX)Ca-%xCh3^J@Cy(jPKs8YBDo>1aO7+&+B0bbDxC&+L#CWM~?t0xCiuX&_HW6 zliqTamsvdmw8wpE^nFS1q8hR^}mejUF~^|ca15e|G4VEbNT*(hWG-U>R-p#?n$i;LGS;L zug7{Tp!a{rp22t&(Di2zehIq%oWXB`&X48ro1p8@@l6O1_+kg-gZ0_m2CT;dJJwVA z!2W{gFy01q{n;AY+7NVnZ{s&X*Pk8yCg^zI#czVHKYRF1(DA>I--NRDXCLnZXnU50 z8{x7n^5Yz=hrf#S0lNO2dkHkK`5EYMG4>a{fcwXRLhH};ez6^p7ZB_(!24O*Rsjl) zw}be0B7A_x+Z2B0eXMT-6&cmL+HdUNxo#o-Hy_L8-<`qhiFD6xe*15syjX8nF>ZH! zzYEBqe)q6{C2>&K0D51z-LB%0;CpDmmDAYWxv;At(ENz|7WQL|K={C=(%z@9!1u#|(>4adp)Tke;CE@?o$+`c zn1cOX`QLXL(;M^hRDT|V@PJDyyu6B=WSNvE=|F=FR@wMXePu~$dIB)*+J+$xM4)izP?jB&j1oTmg^k=&V zXe4xMXLm!0#l`vg~`VaJc z4Dk^b2yGA-A*u1bgZO~Q#NB_dyCFO+bo#^YhOl8DPM@G4#h=gZA(E#zPB9i0s!ek{rxrAJJz4$_PE zI&&7%1L*e<<9EX^kf@9O2KbJO8vXuZ8nPhVkmmf5ItAZP07lEjl*vJOf8df;{A7GN z!UOts4X3Z$E1*%oW^c#)0{$25Kjk7kV2Z4#q`yUcKt)FLg}OgHboy!4ii!@3u8%gk z9QApdy2efM{`%~TJpTXx*n1batET*ae04#i+sULtWp}|t$>}1G3R@~697&R}yF97s zcGQz%GWM9zB%C3HuqCM^2Qe-&Ta#;sBQeQsGYv5=$8}-{;MvptRZ{a^q8 z_cj0D@4H{m``Mq*d#%0J+G~III_th^hDOiQZ<~VlFatcF-x1S&HZ`8AEw=ryyq0bo zbzgAKSI`{%UBW+V+VPR&cce5Ny`M$gciS!4{vf>W@iF2D8?Szc5wB%@6fwRNw?77< zzxDjyW;(iCM9)Ld&+Kh(Mf*p-x1Bx~eYLajO<4RMihYI9UHBh@`kuJw2cs_;?lQkr zejn1uAw1}9F&-!GIp}%lZ(U`>XY^(ae(xkcJw8BvuUy|c64#fx|L)jI{icNe%=?w@ zdHnuK{CYgLy;4^`dCnz>(H%DJw_Ck>dpS?peh%#)S}+#z-QU10ztQrhVC`cMUa#jy z8!Zv?_4^y=E4jVc?xg>xcCq2;zUe;swF&+b@-HU%x#ZtwKca?%YIS^UOYrl^f05wl zliyYQd-(kW7AGc3#LHsCES^xAe$B^Q6W__YhT#W;EB#~GJ3fXd;?@0Vy#&9A{(sl4 zG93LL!!Hy3V*0-XVI9c(|oe?fiIu5A8! z^f*GsJc7ckfia{%KX@MHYb|s@zV9vNuQP67jJar^MSn$oVf?@t`{MT}E}st^Xbf;Z zOx<}O*Pnyyfxny!9pjJQ*#l#2c?0b=jGw09CKv!ia-@E9#=sak{NBs&b8+~<7(;#o zceKC5*#l$v!|?uZ!tdS8fiZFm>KPyX^@X8`5BTnAV?vC-=1(0MV|x!=|0=@A^@2D0 zBfYr4Jnl{KPtkFI?)3-{SblkBPVc&v_eXjaelNv;7WXQMV0iL-phxRkd%uM=(gSpa z?jgVQSY8cx`3Vf#U|k}}f;`+Me=^+%#?bFwJ44|gIPB+@<;$cIC{M7zcJffW z(DQp^-@dRe`!GFhf#8@O^^bOC-=9kV3itm8o=2xXF}@f5D%8gY^ob$u5eM}Pw_TqY zIv$kYyN?mPB=ybb;g0JC5$wzR1MH(?pBQ_NM|n=xngiP6i)oxmQwGZ8*ejd?S{ zv%46-s!xo0um`EnWrp^NG3iOzV+XW%PU{n+csT9{*QZCJy#t(%_H3|rSK}Z)!TYBo zy|AYg!V~-k{Y&!v++&eGAV5JS?jHOKj{l>*zas8M5VuDU!1L*f_<>WF!5w-5vY;Wx zqvQ914N0Vtg+W; z&*@_XEx)twY7h9#b$nzFMtT7~)GqWq__G$@)MX#etu{SD{c`(gQR<&a|AEir_GJEq;(2&*FFsWrV@8DMi*+g9Mz{lC$@O=lKEJLyMxih4=g)XvZykIFAKZXz zfvrfd9MN6SfnKnO@}u80n_uBgxIf_f>DFG{#nndOuR{Kyywc;+r=X)gqel+UUyj1x zkzYWT^;LBbu0wdpZ#^Ct`#^nJk6TfHb;{gVL6_%~Jk&1qeA5Gay-=5Zd{6uE+YXNt zmhDo{v@e^-r~Q}SxK>86vH{YE`^iBTl;(Fq&I3BXs{mP0n%@Pv2x$M6Q`5=_bbeO` zvS9XH*uxg|PeT^y{H_49K<9TAAPaPUml@y62z314fh^GeUl+1K=XZIK1rOe7pQjI5 zp!2%|$O7%Z3Ly&$uuqxaRfH@s_`Q+&U8!^N%|<}SYh1_zo!^y(EJ&kbR9+vQjrm^k z{dYa~7yH_KS5?j2Gp(5M_cVem+H;aWdc4B^mh@$N8o|~RkUsP;M=$IdW7CV)Xa40q zjo{V4Tl>@NcXoDKSeF#fgCuszCg zWR32%#-8LZDyzo*OyUZj7u!z%K(y;7N;H2KsCHb2!K zP(6%~$%8EK-D}HTmwe{mkTmUo$- z5&0^e55RobMt)r)AByB(;d}rMXFK@|8` zHXLm~f8L?F@miuiaF;EA((hRNX~_%qTxyr~{Gax+WR14#7c!q#CEC&2UVb>iFQWfs z`&!$}$@aCjmy_*lZ7(O=*8#&%wy&3vPd>+`(hN(%ONkjcb(~Yur_>}oOsOez zN07%JQwnc7Qa5qxxuyH8oj!VOP5+tWGquxkUsJNR7u4-Ee&*!KgK_Q7U5AaHIJs_D zi4!?k%0Ric$XUgd8nN~ha0+uYY z>Zvv7m2P{==;@PApEi9`&GaFo$J9)o;hfpCB4Y$Z}dux4_`D0y;8Tc~mv3y<*9d6b7 zHu((s3zcU$KKbRGr|M3y?Yn?{^WB-wUsygQziWbz$lrM`?PM4GybRO7|9s1b@7wlT zntU6b_rC6on9=9^`kmH)umK%%I2f9#&+q!VL+$Un$8awE9n(3`rqd_CfZt(OI}FG_ z%=O(q)0rp#sD5v`r;RZp-@ZMcJ9(X^(30!TO?&I#r9GtB9t^XV&yxRu-vKwZmiNhP zyGPF#oigl`y83@6jkOu=j<@z5j4{SR4^WEvKUMmB{}y z{_!p*ngbn3r(utn-{MVg5n~Gs#re}N7)xjoV=MFsdUkY+7}ucx(X_+-!o@9O1U~xD zF`q1VcZ(RSpa&bU4s!*<21Ycr=?SO8Kj3z^{VDnLS{T8m(E87;Zeawg;9t@k{JKSq z`+0o^*9x%JN}S#d(kp1Pi}fG=2H^wVT%;fU$=REcUZ5k!C%wBdK5;4H1BSuB}-5OpVO+pz+PU4QSvuMO zq3#2*-c9;1qmG!b1?YH&y6awr3FWCas?`g|*5A!HGUthj|r^Zg6lhCJPLjV!*IQfmt=0o{z^brzSkT< zN7#bTF@H?rcM(<$Ngw+2Gf10Y|8Xd9;GTaI`ws!KzEt}E3$G!5U_QbNKE-(CI|s*@ z40jn12sh*YfTeWz;Vy{RqssMLa6Rw@-6OaO&O&?<+>4uVKfu>=zX(5k8{q*H#2tF} zW84c6j}M@H&cA~60mV0Ld6L1kf|ViC`ys}U?m*rHqosU3~1 z)>IWox}SZ%5%N;tLYL=}y#?_Dvt|4SM-;&wn1uNua=4HMAFqJhl^E~diutO59=6wZ z$9^$4f7+^TdHt$0>sRhv^iMvP!rVgEA3nGBt34Tzo_%(hG~(~?c=oe}7uyL}HdV%K zc+J+Y!XIo3(hSGhN&P%(#(K^Z{N1Pj6zA_~f2>b_pUte_K5qTz$p2-f4X0FZAwMWr z$uA+lsUzb(+tv&6oi~aND`)I%PKP_*V|KpCXte>aJ54h5%(_C-Ub2Ryu!z~{@Wc$f|^`EhPu-fuD z^2e~gr}-a{=WYLJ{e6e!)9d_wOzHgbn{9d~pgz^n{H#=deR(_HmjK^af2B)|tB~P7 z^vp}xPYp0jth;#>GH~fzs88Gm_qA{bzQz0v13mR}mlzEvpnQNHLKifZ>oGq#vjP4E zm*9QD`sO0S7L0-}@n<)7iJ|j}qd#{sf*BaElEa&U_0B*wAG2jq7GS-Oq}TbwK`}aS zWqRo$y4ya;XbIMn1JA9r=`XCndTZdE?bhA78`lF>&)Vx#Pab3hJ#*IGyRnNAe08i1 zIDI|VR|6-nvi^fzx*EYYjNeOo%)7`hU=-ccTd*GMp zSOs^vut8{Jc{!0<;5x2cTMO` z68atqy-h-YtbS#9VM6bm@PAN3Pbc)=3B6xJ@1M}WPE?`i9ABB9kqQ6f6Z+(Ye*Zbh zf5~qiYZH2VjQ5ticTMP9;lDh8KTYTcQ%uUAZ=-~sO6Z!7_Exn3cE%3elr7Rw_uW-lX{Kt1fUmx+P# zb2;1&d&Ow~j1Asvv6m5arEVtSdf-rY;N&MGd|>u`>p$CdFC)m?pLguNitB*_!w>gG ze861#Pfy&-2(qZ3%Ml&8SByT4FITgd5nN1nr^#N}*BAGL_e+j&EW!gmddsHYI~VZ* z^W+7^k?M>+TL9x)J-rX&15UwC2zP<5mvm+!eqckw zeivR-x-=H{Ji+SeciI@i;7?#b&tg8;VB8PT??ULk(4LJDK5!Q&1f;)!e_$s3%Mtv& zO^obyR?lD!g2ow^1Jss$#UmaHsbI^d-=N z?(i>q_WG(A-RPcMTxA69QGYgYPhC|Nqc@td625<3Rg8Y(j_|V!aXqjZ=@Iwf=BgO) zO|kLkZbEoK>M+EQ^cI#?#n^iZYzca9IoyH8(49A-uY?W^coOdybmyU}7#{QpdS+Es zjByiTVu&w2uPR2Pb+{j-C$$=J0j;2i(7pSRKfvG7eJ1m*@^|9?fpgbcJ%#iL8ll@w z+zU4%eZU;L7jLUFg3lIM_wZWeFVN&p#0URb_!T(l&k#Kazk;{kvF@21(hJD^QTKMt zFPnq(0C}X(!TM7tk86R|?^asUspnfgburQha5&lcmmvRvjUQR}?4^hw*x8ZAW01q+ z`FDGCiOSm-wQOH}it44;8htVSZ9UWcVA~g%Sri|7j_@AI;ncV1F>FV;`&$2&HD-2G z8;<*HTQKSG_*%}ZajUFJJe2(Fi+6%022jm|uoDfT)wnxZ6tNpj^e-6nHud?aadV55E2zjly7s>Cz{ri+R z%x9PD9yA|P&WaHI*&ye3M!F%Leaej$+pe?Vn$*0LX^=x}J+|Sl{T=K2j+5FM_wNKrc51Buj{~rB+li+>wZFGIm*R~xSkUxO^ z6o%t=dGdeg&gU}FHt0g~$?=i`d1goHw3(8g=iLAH+2!`vmG&p|lf7m;?9Vj#_v}yS z59;`mMqD+_rrRv!dr5~TLoM%eJjW%!?+Er2aGcX4AF_PXd0rF958(KWzrfm)+TW<@ zHhiZk`w8fO`hJ$zale3kTOBWDyan>da9*U#@v(^fX&l$pa18T(+2x6T4)TMiRq}Yv z<72^LmUr6lcYu68TbU1PXI=U*{j?8l-WQn9`aamV(U|$#zw(+5-_vyJc-Q@w&ys(0 zIMc&@dVKN^bDY^BpCkXld3=sN?RyfCXEv2iTJO{IfCsY+2-`ND;bU^(E^UrhdG>P#rbn`gsw|{LCL)UkDe{W(0ufbW`Q-xxa z82Y`2;Q1z4r_-b~AKJXo1ogfqX1AkJ-?|C?EiWQI;Mr3V|D))?UeP2*W7Ka#=)p={ z4;+Te!n=1f`7KBrpzHaINS{F0?|Tu_1KhCy<^3^O?*LhF5w3S$L;bO3Qw!*FznPDk z#L)Hp?z>HlAf7*s@hN9plNhD>(Hom!-A)s;^)#D)=QX$kIv+ao7QzF5xC`mU{t$Z1 z?#2B43-S{PpiBIEG&`&jZL_bK8Bmd~>Jllctk1+Klu>M1-wf#L6WeVMVBH!(7&Di2K(UvZcp6* zV(Fi18bjx^JJ1EX-%#Ws7#l}eUH>QNzo(u-USNDhk9W}imGRenbA%7b zen4^rU*leYugTCedL&f)}r3Hgx; zelGd%wcWvb(`DrUyh~;H^T;nu%(G^KAQ+9M}AI%*KWLd34S5{ z4@lhC_2jE}vVMAfBAlD(zmVW{KKPJCIJeUO1YK{yd<)1oWxG$G%M$XP6X7f+-z|~; zW#kV}@XN_3?O`SPot?DY)N|KhWK>uAX}a6;(`j#O$U}Z+%zl`mpug`6@Ov-wpNa=y z{}kX(xO-1xK0p=rI{{u39s9Jjs7HrrZdNt+?4T3u`6h({s0LH5hLVAEU z-SK+{-S2|^R)AsWLcbd8IpHRF;z;<1o=18G9gaeJvAA~=+XWZ}cNsr(24cS$!1Td*J<7w> z{%{B4`B|@EzSO?Be*x-C&PSM^hOhCoRu7RD z!L9G%ev$qx(k^)RP+X5Adl+;ehw@mCVm0yua8Umg{{duy9%`3*{&4NQd3D+6(029X zOWYf6KgB%!zVC+}2Gl;iL+ta(KlU>tkni332c!J}S@0z6Q=VTDvS1GE)7gmpUyCtp zK);8VhAhay9_9Ls$iOhzTLAxA$b#8vgtrgsOOOTo1~&W%vS8ht(7!^aK8}cixqm=< z{)F%#3+7J6@0a8^WWmpFx9Lqif%E_k@H)C}vA!I#U=iHKelm~+<6!S`dLU;3`Tm}V z^yMH6bbV_cvcQ9V`$%u0d!rb4yoLKmdiCZqG==b@ukOf0vuhQPkK^DaJE%j%}f>#D0eUIaPgDlYR@u}VX z)c5$(XphPDdh9w{C3{|<(EoS=@(=!th)bY{+NGX57PlN;mwg^~DIOROcdi|u-kE(m zFhqgcrwdttzt}!K2m-ZFAF@F0Gk`2m`wSrq)IKA~0<}-G4gmvdpBcykwa+YMf!b#X zS)lgm{1NE|)INR40=3TovOw)Kge*||j35itKFxZh2T=QTAPdw!UC08p&m3fd+Ghk= zp!R8=LU@4Mrvq7__US?vsC{~n1!|u@WP#de09l~+8A2AQeMXQ4YMiMe6uSH|sP`?YpvpMD#Z2Y}jV_GG-@08A>jPro(X0kzM zwa;P(WdWe}=|UE$edhOXWCSJqtU}5Gwa*;l7N~tja1*F~77s-DfZAue3%*eRl8C_UR)mf!b&4kVZzJ_L+w)Q2WeuM&1HypIJN$f!b%#3gH84pCRr=p!QjS zEckcJPycwN5BPV>&uC9PFF+5K^nCAwXVtmCL#ws6{EU90{B&Xa0<}*MvY=$2kbOYy zGk`2m`wSrq)IKA~0<}-`3=ADm`*a`+)IPJ21!|u;$O5&`2(m!!(|s1{1=KzR$O5&` z5VAn+GlDEo`!vrXJ%HM$16iQ<=|UE$eR?7TYM*(?0<}-`Ji-IiJ{`ycwNDqaK<(3m zEKvLOAq&(#1IPlk&k(Xe?K6TbQ2R6+5I>;y=|C2!eX8C3yY{L6|6TiZ5tl#@wM#vB zpN0iojT-e%?vMBOYt}yfoBwtFGr9uz3#fgX1&9k!`*a`+)IMFv0<}*MvOw+Ahb&P0 z3?K{CK20@J4yb*Ga1*F~nm%v`)IP&OC=UR&&thMcJ%HM0glh$ApXN%WA5i;rAPdw! zUC08pPY<#{?bC-WQ2PuZ3)DV~kOgX=?o|j6Q2X>C3)DV+$O5&`0J1>sGlVQq`-~t9 z)IQDCxF106(}65d`*a}-)IL4Pg8wf2^bwap57(NVPM0!o_N%_Xe0*{f$0wV0t#7=3 zO-tkB!M?VCsSN|tvyP8vY;y`_i5)NYHrRTB#=DL4o}*VRuk9?IZ{fAC9Jjn$_en{t z=e&dK7{lpyq|Rjo^V$!wclNCvPe5}&K5o0;^4fo*<9ivdKUCh1UZTEj=%3%o@R(nh za^8tI!`8=j9Ph(s*1z&PUbmR*NK51F3}?=M*1wL&hU7rz0!&GUQuGbSBN!Vi@gzx&Gf;zf~~Sq5_`x z+vmW|_3?cim*2PYCRzKfE}mT`weuy$2z6yr9KVm3&9?{%*D*r|*Af^3kr9{Ql&}YI(|Xxr+QFN80dpKOub|uD_7+a(^9{ z{vU8F`3!kyR3-0`&sSCQS@M28%WJ$o`G;A~`tMiHODTTO`Ap;k`u|MVHg7=1 z0kr<=Ll$WLHGnM8`fCVTp!L@XvOw#v=69&e09t=_APcnq>OvN1{WS+!p!L^0WP#RS z%{2%Q(E6(fS@5&lZU1QqS)ldT2(m!yujX1@4`}_>fh^Gas|#76^;Zva4ECS;&;?q5 zEkG7%{nc5B@Bpp9x{w80fAt^>wEpTt7HIu7fGp7ZYY17O_16fpKp~W&{d$lE zYQH{Y!GDVV21tuQ54Br8KRp>Q%{rZpvYQF(wf!c2fS)leCK^Ca}n!6A_p!VxP z7O4GZAq&)gL&yTP-w3im?bj?vc!1ik16iQuuM1hA_Ul0wsQvno1!}(mWP#dm2w9-^ z8$lNQr`WGqf%_NmP`lOh?i(idugiXW9b)Sb&aeNq{iavKegL)K3}k`YZx*sZ?KcNm zp!S=GEKvI`Ko+R|79k7Nep7d&yaCjHJ;(yJUmvnS?Y96~p!S)-vF{e?Y9V7p!Sy_Uk|vsQtQ-1!})J$O5(B zJY<2|uel%L0cyV4Tb=CwsxJFIiRG_%$-gdta}U9O0JYydWP#dm0kS~tw+LCF_M7@W z-giLlHw{^!_L~tmKLl&t0W*`gHezTAT|0(vHLs|rSsNL%MjgeiZ)n&hLud)4S z;dyr4OZM+N!0cO^f4Jac%xBw<_32+@|1F?8ZTm~IZMqr3)F)B@JpuDoAqy^@h!iZw z{(I}NKNK);MLpyG1?%7cfc>t34g>0AUns0!e-isq0S`^X{8;G0@`GcfF@Mzg9oFCA zTEVk$m+*>^1^2y;__ksG=_7ClM&f&X?q|6Eaa<2v`wixwF5K0ahYyai1=o9>u>NQT z_U;1uA^rgAaUMH3#yX@wxEbmFBhm|OdJ^e@UVto+?_q>F+}~FR$Jl-a=1(rf{xa*~ z4%8xkAL-4$gzJH;Bt7?F|C*v2 z1nYlcpO=TU3+i8q{KE6|pThNktmlf_ApdwgGSdof0qF%Ma5%MiAHoAN{jL4v*1$f1 z3+SGH29#QxBg^mwTVE^EJuEz~0Tf5hI594^R_l&&}hYs_54T)3ae_{L6@fyU( ztsKvEI@@wHhk@`Z$;jjVaFjO`oEjwnL2)3B=2y%!JWa8 zWaifs9On$lr^vVDcO`V()giyABkzmz{nO;n+@q53K|bVoucpT(KWmQlulu7iRVL5x zl4!gh{jb#VYR^8eEcs`-zBlS+pG!bKInJ3U|J%@x59#{#ko+&W->;5i7s#*FeU-Tm zxk&zp#+CQ0^HN~#xrcB9e;ZS z+bRb$n;RW}^WD1bchQM9AhqA~xzC(?1YbDDGnn%dluwZlIezCKZSB+{|J6vF9+%_g zYS%g1o$@aIf9u%$4z}8Hq73;LhE|5-k?))cCrkdQsn&mTyexgP<-N}K`RC~W(CL+Y zpyBKI9ml8g&dsN&-6cIpa0Y3 z_vmYR-Jkne@+Wfsg!0dmpLa^7{};$FIK%Qf9{M8rn;4Ehmjd}V+>cQCi2OI)KU>G+ zisa{Wd@y{`j@uf(2Xr=76!d)5;>+@4zrk}hT|bPl_ABcXgZ`-<`(Gbp?N^r7$f0Lh zx7ZQiW!L4WDelkU>|*_E^navXn`O2>owC80W#xLuBJ}e0j@dbh^^VZX*E@O_Rjzl8pqHk-qF3d zz4-z^H|6Uc8(wYmkJ*bkW2j%OZ>Xvn0lj>EStg)t$cmq^2GYa#fkNel@9tHor7MV-o8dQ%GNV{OT`x-cEzt#`EfvHy6t57e($5H1BofPZ4c{ zv#s4bgRH&o%>ebR-v{vdJMjPY_W>rau;~d;wB=90^i00Ome0CRg_aM=?*r)je&TE! zj_zZUVtypQ50ECmVTCU!y#~1CS-3{GLESKGJz_^q(jHCBHKeGW>}A-jnS2 z2b9;}=j3+@*qvmO-zCubWa)-B{kp%5KCjYu30M!x^Epky?^ID!~$T#6UIelIp`RHfNXNHp_Klyz7y!87CA^9KKH;L^$U-04Ix{7`0 zpRm{WWBvI}JP>bUW3&Nm{+i?Jwr_W?y+O^dA9Q~m-FJuaoRhA!Cx`sehg9+|`4yY& zJQ%e0Y%tu3$j8B=|4sOw62wWn*8#%mEl+` zG-h{xuR-t2*50s$Z%Uz5wG_c?D#d7pey=Rd8ethf8Dm#F_d{Xa9& z#%sFU`e=dtrUW06XEv2ii%OCeu3f)zl&nuLuD9Xp`t%`KpB~(|#rA(Z<7c| z*QZZNq(|SMy%XW+`t&ms{ueU*rit)%eflphugnL1PA4b)-^6fIiFkE=dQHOrt@Ph1 z!3X4%>)G`^|01z|U*Ge8BzS$#PfFbHa)zH=N57JM!^FDyRpdt{@?kakq+Mw_Lg&({ z5hXo0KWovmb@ksZ*~Ay5zpXF(_+dQI>|g4?d$%9#|81;4eRp7tJu;Y2hW%R$&;@O& z7a}T}Iz!<;34fV-jH>|10_q>5D!z;qC;1OP*`U}zrtfQWWERgT52NBla-iP>s zbT#UW^$`982p?F#JKT{U8Tb_xC4QtY3t3>W9$xeu<+-fchl9uN*EzSioaP8=F3))d9YP9w9$6E0I26=`e(k z^ru$gdO-Hm440!nZwbN&oLu$Zz0otcMqO4`B-y(SJ^^1yT~;7rU4|WWoL;OC}o&-yLstZ#Aw5UbwsN0$lA{ z&#%vK(5f!`?qRDz`1Y?Yx1}D^1yQ6J?YCFr{AKHiw}-wQfiH+8tNvKZS;V z`TcmuREGa<9^sYU-}SR9-47j78Quaduu0D@RJvD>#`An=M|zI?xYB(@LSK{!@7#p@ zTW3|KXKBL!`3e7@Cj1XUddiRC3BBC|<*vqDnh1~G5+zT^WBq&iaarR2y#bZ!JuTsX zVZwhl;onR6Uy|_eC;V$#)b8~>?9kbF*Jc0bkF{60r(64%??aW_fAV`B7z(I3qGKvl z({hLD#}3B~fIVUUk{)g^l;_{=2qXu+e1D@%;`-L_>6P~EC)}4zt#lvStWpoSzlO3e zPOp3((UFz<@`V3an(LMJd`zlRuTALNS5>-a6Z3)7Gb-KtCUpHillo$_NLAAS;~VAg zw?D9c$xVbVEFYEZzlTcpoKu4!{dvNF=UJ8h1Ffi$UVcuc`}K+N7AN#Dq2HZI&&Crf z!`qzj|NXV~Oz`Rs`#JyTu$Qv&qa$|=Nmc~ZhMER_1nNlA*KGQG6z4%I!aRF7>}<|86~eldH`BopD&_Rc7DCDJfHK|L)!`Ou7AM zSENk2{rmT(Ou7B1m!(X({TE+NnR5Hj7m@xl`;WG!Ou7B1Iy{)-b+rriErg#WMXKmX#6!YIpP&Et9K1$`^lzs_O*1T|>~9Gd+xN+#!|FS1yUk_4TblfO?n@gzWqS-f z@{jFpD`wFdmd}#E=5h90k@v~Zo@aS?r1hU8U%kolPL1UQ@-J|GWZ1>_59G-Y{{_>@ z?_h@HPnk@f{ZU2ogV=v!_7JG8bZ953`t;BINt55Ql=;bhkX`cMbh7?+e8wX`Psg8zV?Y7NZ1VY;)_=%;Otnva z&Gmfy&==O%RsY#`k$sT<71r*>&bykXrTV|_XPG~=yAeEqjsh94DE96iqs>(OKK&8x zo4(y+toN;Zz8e04>Pw*GBb4rQ=@|d@7JhG@M0@VY?lE*cDC&;uf#a51{{j39bbQA= zpT_C%3dK4gK8@0bm62hPIsNf~d+ABFe<-JdesvAYp8f}u$Iom0BUxc(`d-t1v; z2Z~472O2%r6W>MaX?*#8xDD;|-}j7RdfWWU?}6}v!5HX>Fh3=~8aiNTa9+3WM)3O% z_CZBofe)Gh0Honw|?nbbg;YUX!Jm5oy zpKXTgfsH!wVlOkDIeeWz7wH4)ceLrrzT3kHMq#{1;@4wWws)e%J@CE29>&x8C%bny zIUoz&e`Obw-n)B@ruW+X)9c&F_5Vcs^|N#gk9uJ@+%M3U^(nt;cO#h2_==5@_rP4} zlAhG{Jz|XMWz(Bk(jDt3a1Hi@i^rc@Ag_V(FWZ<4Z4f^2@oM}0@;}G@0y{gjexzs9 zZa^sg_t7T%UVhGo&atwIiZ)`>!g8CrboddCd z_3Fmv1nghuE=B(b^jz=8<`ncNiF^Ja?3WGqXW`$w68#@tni%s~V^h65^7AV6cR@w>#`h7uZrIOzOJnmm z!i(3#9D@D45&ouA;D6&TCW3ArZXC~Vj6U53{Z5Fl(Ad0wB+`TSy5Al9Pe0Ju%)=vd zP~T1U!2Q5|^SN+;0_6?#?8}XfcR0!$#Fy!b{jWDRHcy8(e$xx?Zy-MEdC}i)Z02JA zuB691w2AT8Ha5!eGwkg ze+2r2ME9X*p%>6!vsQ7 zze_#S4R3Nph2deS>W&FJ`5%~+e>{{KK)db&*YGUrW1O9iz`<8?9YoGf6FxY?j?_F_brG5Z@&!j&lLRf!`Cr=wYsdW96nYA^u`#R&N*VOFb||tBd#gR zI~VnJ&T(c=oLbwn2mD-6TQlRt(bFf@jElM6z4|&+piZAQt@fmv*|jB)N*+IL%#0E_ zH9LLU*pgO@o19+jAY=(;>a5WdcU(So+_b4RC7)9VO`bVpLVUAB5z!2}23HIiT|2s5 z?|a^M#WJc^F7wiaO z+PEEgd+yj1q4srV&ZwC_Xxj9#$g?rircLha)K04%Jz1W#-u%R=6Kf}qo;pdspHf!I~sX((y0~d zspZx&0XdV7b6K)QwC)vJj|%PBX`?5Ta4xDWWT5HqlAaGf{Q3Rss^3ZbM-Gqe9%<+F zFb9PH`B5joN_KAZw zNqPH3+9-jK`qQ_l6r*h*SOs0%E7E2uZ?B}#Mk#NvNSj60V`+Ou+AQVm6=}1Sw^yXi zQr=#XHcNSXMcOP+hcVpBsr^9<1$0%>_h>QrIef^a7(*L02GYdI?aO5P^$9HL1TEF0)XX}R@8K9nZ{es)TIutq#i9=5IKfH2y zC9mzYDeK=Rxc|dvc z2OU|N{sQ@~j^&-7+y0!0e3APPx`&R4pN~HO$+{01_kZ(f7l&QI^lY^22()gG<8|pjr#!>SkRQhNQtIC$|9(gIyVHKMCVn%kNIqy}c^%I( zeBZWSO?#MP$KxFGPhHJ;Y5y+yYW;pE`Tje3Z`FJzFn&FEn)T8F<-f0!`ThnC>zlB_ zj{RkW+5g`AtLs?ZK4&r}8?(oG-MU^i#RMhStES19)<3e`bji=*x;P#8)ZfufT%Vxp zJu~#bRm(xHyY$Fc=WITg?1y}E9cYexavf+uKF4*q?#K3d<;f@aOAg5=_e+k*S8<)J z-j`wS>3UM->yuw~bfrBsBwx$&)9q(}UsL2CRlDLiwL^Z_Dw_}HHEaJa`TtsNdHwy% zkZ*Wor9FG(7qLF!-OqB8d~$uUPd>RGIY<6t=q( zT+9D}{zq{pxuoVfp)8;QL$nGwR1?NB!8FQ}_F;^<(}0-F7^Nl}FBqZr#(r3Rk36lvk`L&AaDvzOXxSF~d#CG5 zL;82LzQ}M2vENM$$!QAsPZ=Vj5%JvYtQs}^qcmA`Cse$WQG%v-+d9E z`v9AgJo!be7lz#}ACYg!^=9F2mQT@c&tiMP9AkO?o$A8!S=S%wd(oNYv)|wP&oP`U zYWciaUWMfQXt_lH5&2Km4tZZG)+ejDe%s8m@2Nw+$ojqV+CH3mAoD@z9nt@CK6fpL zv*dL>ym{8PAAIsOuOFTKPL}fbu;=~md$_v%{q@FP5a;l&=wEWrX;f<8I{v@+{@%j! zQ|tYjfYX1@`(pXlhz^fv`Nno&iu}?uD*Zd;Z@s>fuOfdo+cRbj>xbm`)qO1(ewO@` z&22dDE4H5OllNHPF4--4ZNCL$ZTl@CKWe27CrY&I8l7tSkoTKIH%Q3GKGwgsZ^Jw7{T9e;J2q@&?Y~IAnaglK zv%JFzcdd@LyzcAmbhhDtuKSF$9+)Qo19{C)mwbLd`+KK+hWvpom_IrGu94UELz+K6 z`3snzS|84lfB6smJ!LyHAir>5%WMAR$)9vO{XcE*HzZ&6YGpVD@)zp7kgm3!5|Q7o z<=#Wq4&D82{@l*_W19Z#Aj=QscR5^s4|X-yvW`rhby%|Yv~t*d|7oofq9_j6kh z_A!6#a8s|;KU@#bF1#8s3fi0OphApKKQ+;Pq~Qga!2GdU zMx+PW{vPz!7~fxr^Z@tJfBNutMvy<$`VXty;X9)3%)`_RP1+g3N{%-NPqoGO;M$sS zzV%=Dpsf+CV|Zq9JM6mza6XxN88Yyj#B-@(K@wbr`vbDnGuI)#z(;4;@XfDqJ&;;p z_1yZl`2Jm6)A??zdjoO5z!S~spQp5o@n@`0(qjbXqsdW3{s{&>W%c~~ZH-{?nQ%n@ z=uu#NL5TYW-h}S$y~F*r=WYLJDnQzR=V#a}^OqqnfqJ!8&;7QY5p-H@^~@V>jo{hi zU_Y&Pgf|fL)#M0zAwPiB;gFI3%(KW3U~vxp{n(Excopuz1dQjGA18cdHSbX52k>Z~ z`ntBTo3>^xetyco&tAC3y1QH38o^Tjo@Hm@Spd&aj|RiOfx~87{{d`8Fa+}ldjai1~>h;QOghBW^$seXsT0`ifge*Y$pPTWhcIo7wj}kNEnT2Br7A?e2JYF+VG~ zxOI%{-o(AWiv2b&YaK(rXB$0+Z$(|*I>u$kK$q`z-qSjUtgn&z7KLkD$EX@$bxr4@ z;VRkll7v3+T^pXaskIRl`&s))J=NL>7N2gfbKhxg1Z$tR{xcg}8^M7qtgf-l#{2BN zyW@R$3G+*2y`J;i)-k?>E=M@Ob&ToHSlwTM`vtsbVgHzan)xTf2YTUskoz?+;!EAY z=jU1f&T@nYe1E0Y^?z!VO7?sa-xp<1y+)AH6%vG=tVC;S6p`(BBTBetD^=zaM z_EX$~{06q8yb(S31>ys`d~Ee-Wor}Tfy(e+9K!gJo(#|p<%3)w72qG(*-_2<{dTrH zzB%rO&&%uY>9cM9UFMGm*QHA9CnC-xKY#)2S=UcI%y5(Yx@kJP9nN|m>vs+v*7s%o zi1pkm@+Wh@EbVVdlYfu(HSKS3$@kEH2!`X4U&;P;ZTE~Le`yn&9_=U2lFzZdrTv{g z`8jOwYB)La?=7(5xQurp`GfA|{hnm&g8}){ekm<2Um!nE_eJ~8w!@4yS99h5%%7C? zpC+H&f5szU+P{VQ?2|u|_03?J?MKg%|BmtMJ}LqEMOIV2=aTAZ>r(5-RzQIo>&*+k-tmZi~q3oXl<7d(Rwj?-3R6v z?i&-bKP=Cmge?0Z{NqozcZA@@?2JtnDs`eB+ijJ=$(eldn$r zcga7T7{?w=z7^j;eV+C$G3HM8A1UwAzsGTP<+J4PPx$xA?|O|*r~1#4Z^ChDy{~}$ zb%}gfPJXbKa~!A5lYfJDr{RR;_u+F4*&Z&CfAN>hHhSPxk6#CxiK9N`TvHq3Ua^+I?6X|pJ8BT`n zcICAnaJlBQ_9M{$O!f<_|2+8xiFptq`S$F8RR0C?ZCGw;{zT-R1YaaymEck3kB^YQ zlNyfpKk{`dof=Wn^FHVJ?dob@O!(S9KxfGru~5MJq$4oHOyBc;@I&mrjQRVQb&ApX zSI`f`ejW2V#dz~1)IXr7f7>ZWrZ@H@fu4uEz=Lk8(H?}m;PWl0pF?+7cZxCQany(U zp?*KVQ;fgdVvKV*u7|sz2;GOCgS%jle((=HbuZ!v`bqlwV80j0f@7fv(6f*QL!q0# z@P7sT1IB`w4J={^gxwG=Br`8=)_N4h)04kMw1(?i8aVu6K_>e9#45 zp$E`&2ut9>zc~{A?}L9}Hgpeq5pIIH&_i+0!5ugY>2r?4{lc$c_gfJk^wj-GFYqhm zPw;cB_kmx*k#G;*!Fs+Mkbl6$`RH$fZf@!nV-9pDf_@8h;E5@4hn_`Pf}`;B;(d(u zFiUX%Ko-x(LwhUz0Cd2I9zZX^uOLKvr9Pd5o8Ts-$HDxo^cwgFmP42QJR-OW9+LDz zFCc8e2&6ZH?!&KOB=Xna6F+VXkv^b+^htj~aVhc#m;srC z;XyATEWvE?{|WBzLEH;)xjaAU4rIag&;!v|K?l|&eG&8!Zh{={*ZCCfg@=&eK;aPh z-+=W>kOdw8fb=fg4SU7IFAyGX`zO4s;0|6&oBqrn@qB?n>k(c<*yA%u zAFzo1ZTa8hc?08leRdt(fqt`Wcs^`Z5Z+^-uk#Yp4@8*YAo)|=fcyfMV1JIdeZ>UK zvCRTajv00~-pAu$ZyS*wKo2b!^xSgPk$&9^)an2e{t3rg;qM&yeuU znC3CIWRU-V!v5;#Hjl9tdhp^dCN-&fjO|Atyj@U!6mUHd_;|lC|IuH9_<>c>WxlBs zz#SNhSHoP7^h`y104!NF4%Smu{t({Vq*W?Ua2euKOatn|vy@1Y-O)o?K z03SEQ_4pou8{*jm-%&4YKz;ztaa;Z!DF6Qm9YE1w*9Riosb3sbSN&pWXHx`9^@~$Gn-oy0UqDU+TEEDM3~2o#3t6D`iyUNu z)-Upq1zNu-Ko)5Iq9`&@s$UF4{D9Uk(vSsOzsNuqX#FA!S)lcc9AtskFY=HDTE8ej z7HIvV2wBkaWY`bt6RFb>KhPDr)GyMI1*Q50lZo50la1H0lbOr z0KA9gKcMxC{7Co*c2>X8*K+~K z<5VBC9^s?Dp@-HtRM+~3>RR7WUF#dFYkfoYf49D&{_o@Xit2ivkm&k+@Z4psrGK-y z!M5jgf26^aP#-co`Y*!3mLmr;AU*5+qHU;8$dTi`S#2j-)|d?EpD3^OnEBfO!gi;_ z3wCEaPyMIKw@mOZ`EBe!Q2(f|#K$e#U#aa{@*5KExh(liVqSqyeq|z@9QoXCmF@3< zeDhUoXEWZs`q%b1`H=jZvn%}c2NACVuX{TvLZNWKf_&uBgvGy~;0Ui&}jKSlnl z<(1((L;=ZGW6k{!N{? zraXRze<7vml$v`+Aren_f5r+_KegAy&3&+7dMEUyx>UY33a(z40 zKYONPjFkS17tp@kj=Cxke;+Muh_NNq&wzRI`|u>%Pk%@K4UqPcBlYJmQGW*3;Cj&u zkOdLbm;M;_SD**lL&2-qU*I!@2kefjoR>o-^;@I|(DqVvGWvyqwo=u5Z8wwt9@hhb zkNP>WAP2zp=UTl8S#Sx$_t8EH)7Xm) zcsfM-&>joNKnFHa_dVn%5J-BFzo}1fzrf5TR(D#Zj9{_EC(oxF(ho>`N_1x{+IPSy z6QCpi^MA$j1nw7iJYV-M)Te>xsi%&^m>JLoRuMl>7x4qBK4>pv{{;U))VBd?Z^hwn zL-@d7T${iCM|eKKc4?n2LVK(w_T~c)qW{c?$RD6Lbh-arcjO(0`f+%vt#@I z)2tYq{T=_OJUI{+}zu&yj!o zs>*Nz@<%^e=|4}t$8|P;G(92t)9$O}3*=p07svU)5&6|KD*YG9U&H!2Ot;S~P5zq3HXOH!J{NB?ld2@p0dvN?p{pZL}pq(i146*(2`&$CY0_|^c4ng_=?QaPn3$(w*O?Nf| z?Qe-73$(w*>yCQ^w7;bYS)lzb*&fI*K>J&YkOkV`;`M}IK>J%F$O7$e@p{1>(EgSP zvOxP=yhGs*Xn#uxS)lzbZf~R?(EgS@WP$d#IEUf>0qt+`A;&=fgN)}y&;{Dx;#MO( zK>J$)$O7$eF^6}?MB*L&Egocn_P2zP1=`=@^g;Z9_O}F(1=`=@^o2X1{Vh4jf>M7= zKiD6j{ViF@0_|@pKo)3!OZo`d15oO3ft(YtzoiISp#3fB!!e!&Xn#ux*}{&eWR8Tb z1OLbLw;a>S7{N}CH0oV)I6M!X=uIxK-(=6R^_yrJ>ceJ7J;}Y_mM2~9tRA^EN+R`NyiUvQnR zbEBPC<*-0JhkS5~T~C-Mzv={*_Ur z-|q{1+5L0z!IU_KY4WZ3ofosW<+VO>>3sXV)PIitvt0kI^U*@`KEE%e{5taQa-Uz# z&jR^lxSm=4Ydzyx=Cj&Ek^YNqD(%N%y&;>}PdP*0)4XX|&rcCoxmersZ%;w<@PT$irl`{WPj`gY~>z8jUFMoz`ed))G(f<6dL1}$j_)y*DkG8M0{Ar}?a~9cll#R`pJ+z+6`np30 zC&6pE)ROh-@G)DTbLqda*0afH$m=>Z-RHw2KcSwrtKbJaj-DmInC&-R9~F_$C3r2z zUeNtNn0~DQX0`v3e2V${4Et4mwhy)3dz1BP<*Vrb1DyxRc~EKci_Wm=*Y#8``G%bD zr|mIojm9*e!~6ZfmY-TqHrvng`d*J=IQQLK$&Vxd-nEtdc=G+(+39o>3$rT<^h z{~Y#vs{hI4FFW7*4|%`XPCGu)4*3_^-V1qOKKZko^L}a1dGcAl*TGTtcRVD& zKgTUJ-wNc5yYe~mc}3)1zGvEBa?A3i`%C$ge#yprDCf`K{siVH?b^b4U-Et*v*ize zPK};JbR_mQ^-JHy9-{MOIX{}wnX&v`@GiIEbfCkGCcNKmHlNYW8XqqE1#~^LOMX7* z7c1|P*Y!Z@efBmPK-UB1As2vu-iQ9@S6E5IHDBPu^6~zj_gCt3UShyJtx4#&T#NC! zvhecU|68wWR8YyDf8crwWgk1M^7`t9regh16QoDh|LCzl^zvhr{*aKI3SHL!=utSP zGW?}~Qx|)V;9hoAp8Bm$tYZCtFC*oV0a9@;ge^V!%GtsBu`TsBC-aSgLEGzF!Ok<>U7ic_#-Lz^} z->N1{Qk60?@+m1xsaC!uWh)=i86lOrRjO2E#LdX4jF;k(k5Ux~8{63CA$yov%=j@H z8+&@}24rl8UMw)8c$ftkWa#Mu8)(`1(LmFP273VWnBTY0IX5D*3VW^jXH<1E?mai+ zKF--^?{9y5pL2Wv{e8aQD-Ri-uUEc`hra)JK12U}V^e?9X31@5PJ|KXwYfBm8Jl@9ga|4IAy z{yyC2;ZG0el64~g+;4ru$KQ<~Qhe(H?}-Wjp8SB*E1_4y=Y#w28JK70;7R|*FZ_h_ z&w{@az8B(Q_kZmJ11cdNHt@L*45);7*gdvYLOg8X*EvoJ@vwVrt9(ll{Du>d{`?25 zgm~CP_EkbWEc%TP45);7*gdvYLi}ssDd(qz_*a8%71MYBjCjM3@O{b?{3weTaO?>s z#KUg?<_88;?hqe)a+Le|Y3_$Ih^Qz&_LO5PAwJgl0_UeZD^VgI@q}%a2loctdW*ls zampvyS3GOrx4A#ccl>}m|Gl5&ekjv_mHy^>PuNxo@w5AUS0%*Hp0ceH;%Axv_<;eH zw@dDP4}OAcQ!?k=`35+bN{FvLeU%VTi@u2Cln_t5 z$F@p{r#)p`q#DBCKTuW|d2@<#_$nrrU&_cxCYsQi)g#W~+owpG5G_`03H!1*cv;ETEbPjdYt z*Qfm42>aNphit2SlJh;__vx79luxs-_itX@I%*|{zpMLy%D&2en(seL{ItaNDR2M6 zz`#Y~yXkFyPx(6Z$Aby*OPL3ud>sx+^e2%wwpH%)`{+lAzrW72Q9kR>m)T*Tvaa#? z&$%AkDwVJ0eC!{q9XzF>>HLg!dt-Jk3{pf&7Sa0_c+bW;ud2aJO z7aI4NDC<86 zeteGh+^0P$$A5|Yzs&s|aDS9ymg{|*=XrzYp*-_mzW-_B>ujsAdtaK780=Xzhu^(fL;nji3hZIw^z z{(hbQ{d4p$<>$uu{`VtKY^$W_xIf+}ar@8ne3YQC(qG3h%Drp8J=lIk`77*Sq{M}LXmQ*KuL!1fz(nGX!81U&YXZIyt>jy=KFQUV@J zv#k>FScYwtfXD8!trGCq1GZHH9(%;L$`8`5PaY9JVq3-ZEqLe2&#+Gk`0Uuf=K7R? z&(dtG1bmiZTjdG*RQ50WW$ZmA;IoTts|0-3U|S`@XKX*E1blYv-*P=lz-MW;RUX`P z_$-h05dO2B)M*jD-Fi#!i_?+M!~0q-6A6@E)e@E+S~O2B&= zwp9Y&Yp|^n@ZNp4RRZ37$hJzrdym;x33%@*+bRL?9s50^Vz| ztrGCweYRDC{(Q)`%5Ch0`sXp*Dgp03Wm_fSy<@+|^(g`GrP)>q>$_h>7F6!N48QRL zc>Wh?PfEzIdit32Q35{9@LQFD4;yT&+&hF1A3xKN|2}(Y|921J!;c-phriMo===AD z|Bv|aSC{_QXWk7Tiht9;C*SMvp?J2nf&V7aj{}p?|r2e#e1V4|B``wPruSi zFCQjO>|beqB>sHnH&~B@@@4pg(a$n|2H?vmy?mKCvyW%!zaK?k{o4Di+y;-`{toQr zue{I7CxyQ*Vo$&5{Z^h6o*89+(-*(r%4>g0=f^+&JoiHZdfD*@Y^(hD7tvS0^(6xj zewBTS=6_xM3G~Bz-f!hSf0y6?E%d>Yue9^0oSY&+%XSX?HyQ{oJAbA3DT${O}>Z@AnRU|4Y6s zoXLIu*gp2S=l=d@_>$iJSK*5y@)g3rZ{q%X`M=ypU4J~FKUDq($9w<%OU~c>?{n<; z@`2Gp|Mj#USMT%x#vwi_&G&o%{h7zTdjkW1c zZ_^&V|Hcme{_R7*zj)|=j~(>i|FehApE>mX=MR1V;-TwJ96G*w==dKT;_E(rh_8E< z@Avk1o9F9o|6e)u{h#^_{naC%$By*_v>!cmz4smZ{r`BVf2NSnUViYUL-M?ENPge^ z>&PQ``q<~b(#pc2{(U5Vx##}ALHFAu-~ZweUwGlr^{yQ{-&Y>$&kr9OFF_XG=Qob| z&+mKxdozk(g!gAY_3zJ=fBoS1j}4ss3Kw4(_>|M5z%ct4K7-$V!`D9w>j?i@_kCYI z@b!MZmU|)2=ns5#h#QXHFoAo{*WVX@#6OV#e(Y}@8R+%jAFm)h{`>YfDeE0jGJJRRBKl+U$eg6Bs-#pUizd!x_kv{)D^MxaQ z{`>vkqCI{P{qOzv`@emp&ws!7ACL6;?~VU-q|bl9_&Z1X{P%nR`ADDte(?{F^!e}i z{^&@b|9)?v-+zDdrTzZm`ept8 z`@Q$}`|rn&_51Hn{&c_pKJXR&{(Jh*^!x9PKiluWKYU-m|9<=Zhy3^B{r>yYk)s2> z{(JOoM+W}?^xyCO?va82lK=kbe?2nL>%Twzee_F@|NiugP*(omBd-`g>CMgizIFeP zdh=5r-ExNTcgatA@`v60l-ob=^d&T+{R^KVKjk6*fd1vf`txtQc(1Dk+xWbIkS7xK z`+J}9@nN6GanJwY4Zprsl6TL-~01F@b$YPZ{jc(Uj6$&dN^ADQ;|bIpCf;p@NGuX8@&uY1qeZ~OJL27JE5eP18mqxs0!Kk)TW z!aT}D`4Qh2)+_S$kNo$;dek8g<*~1S?=^Ry7eoBt*MHp4j|laj_4Q|cK1hhGKMnO^ z-FSbV07HH*tl#eI-{oZ|}G@rMU_Vqt?#`jm4C*tdOef^V{UH@M6^*`D6-}mRq`1)=j(qvoX4+gb>G*2!RKR! ze5(h(KIALi4)Wvc53dLQ$k+c#KkkBjKKAvuztOkDf@_~AzWx(FFC*leJn=5eClA#_ z<=VfeUJk?kJoWY8^{wvw(Wc9j8u0qzNXYjIILp_6oBw`j|H#)rc&}^EkVl#J_0ga5 z?d<#UqOU)^zWNnk|GodMyPuH1lkxRGALPfszv{NH|E1^s{eSyMZKO1O{f&^f;_v^l zuP+{|f8y(Z#jiUV+W)Dqf8D<~B=YAUz%|ytzy9C#-{);#|CbNdH+=n#DSw~;C~Nom zwZ8sye!azkf8_LGs1Lkt_}u;pSj}{PUb6Ef0=Tj>HLf6YmdY4A0PPW$FVo~ z8;|ZCxAL<-z47V)bbLVN+AkK&QE#jk3anT+%IMC|8UoT{J-;iiu`B&yZtrCt=#y8JKwRDX9rZ? zZo1t`zVAIgkfCTjSv}9azj@rs*|Tnc;9HKfKFaZdA3&^n{j1M?lRxfG zJ5YAhfd(FZ5BE!XqvOsWJ^$>0${YT8`ZtdcsQmCZyB}tLo$FJ+!GHhpS=I-qWM=*E z$M`+v+a{?(Psx#zVolS>o@)sZAJM7|NCPv(4Lfrzuvv?q`fGA)1NQ;KIDV) zS^xckzxwQe$_0P^+j;Jla?k(%*w=AB%6-3o|L5s{%6Aek(Z46Z#q&^B{O_Z$p*<)+ z^ArAl$2k|}!{6cdkA33!fXcV~`#JXQ>{A~2^WVO}^(jyM?{CksPx(}6|0ZokdGEKo z>p%Ph+LH3a{(f#hLB1%j`ulnCU7VW|`R_k?hV{=WJO23NUq(JD|337`zd}AJZ}{W) z|0B;!`T6j?KhE<~e#d`5^C{$m^0x1fr$5SAp!{EcKmBK)9Z>naf1b>z`95WE*UQft z+Kcix+P-~G(B7249PaNQbAOb7>f7rf$5fv6zfZr$`6&-W`~4ozPx)#8{d+%0|5H-_ z`Kf&1=$Z~qgHQ$Fw8=iz^* zKPZp=`5s@QzbH@q{?qTKeN_B@<4w*-dE)Q){3_)hru>s%bw@7#WuBGtdOm#9ea5f3{yFwp z$Q#Bn}x0I@=mqY?(DvC_szGWD0(Rx zjz*%3Q6{<>9er+Q=((Yxp_!rL(4C>y(C!N_yzuf1GcUY$Dmr!Y)ZmM$7e`*4dFiE> zhF_XF&CiC1hi8T_4DY2<@= zmDT#%)wOGDJDEbJn29r6nR2F{X?>)c&1DPOooqE*&wVTx=jzu-ua8|Hzdm_=>Z9e4 zRX*1ESnKAk=TAL9{rupo3$JEhedX2XUw!q};;XG!_XeZEqt6W9I(2LM*5GS1`Pt36 zcrm`Sb*U7W>ZSJfSou_Wsaz~?l^f;V*ISk4N?d7ITea0%T&vew^|gAlk!h~;2I*`& z#VfmaJJ&jmPHQ*4*V?~v_wL=d-b}wa`sU1=Z@xA7)?06X_dow;+Bk|XN6|_|8^3rm zdU1rNi&ClRd=y=XqUucaW;FD{-JzFuhsGv{rlX5-A?>CyA)3$*z8 zn-|XCx^VvPh4XJ+xNu?SL$v$+)!9aKwo_Wj&Mw4-#kEU|<+)4o=A~x&@?!3CdG1QS zwzQi2aK858PUXX$+ST~rYI$xsU+3-BEBS+!^4vZ|qLwM=fU(9X=y zWOD17R~9nmx%KR9b}^S-o6W9Y&*t0NxRLGDa=GQ)ja+WKlPk~VI`OsjrE9tQ>-qBa za{iUL`21UM9er!?-`x9#e{=5}Z%q&8H_Q3rem-vHOL4y1&ew|h-TlpcakJ7YY?cb8 zdZAn_)>_3*Bd!&9qTHC;i4Q7qt(tFCi<8w>sg|$R z;=NkA!VAmmo3A&<8jZqCqup%g_gZng)!J_J7Ws6#Q*3mK?M}O~n{V!x^ZTQtZ+~~| zr@pWC8$a;<(Q`8q0v$yNbM(y7!3bI6wd7HhZ%5HqV}`3oQJMWpb2_STMNyr7E)umG z)07#yd63c78rpwm@P$(Q4+FCOU;My!fG;ufDWY+j@zoI33lZ)AdIC zbTe*H?hI2uOns`*YNbl$t<-kAntHuaN>yKPr5eSpRHIf(wRTIX{c2^TU2UZIhxSL) zXVc?I406??>{9loqsGki^ho;rQ0v01{%zN*v+a6$u3kKtzcRZ%pRZKrxAWC`-qyY_ zo10z8x3=|ec}l$4&X+EgEAgdfy?S}=^897q_I_n?cHv6B)m~bey}Yz~X$`qKKyYGS zoZeZPtM9Lr5uSRnyqd4ZtMOhwGn>1TSz5iES8#FbXe>)er)d})g|*rE-Py4F^whD5gOr8mlrZQ5bG-f7Y`mF;%BQ7%*) z68nUc9Z*SZ8mpW1uh=PJFV^fC}q4=Wxo}VQN~;Ce7ki}D{!mR2=xSIsvYmQ z+vRH9Zg%1}?TnaDbr>q0T6rHyKiJEc+k5$DZLi$k-meX#rG|%E(NJn^A9a-)jIM0t zX84oWpVCaUGIu(PUePYYGl~ke_Dr;`-EAG+-e9+y-=B#XUs2R5zcCZF^PBvsGfF!8 zUWf1L0+^Z?H73}3;e+E7FZ1Wz%P-`sjh9dB!lxNm)2G!TDfNP+zJl1trPN-&RZZ>1 zn~jmUT^JdiME#vPD`B4=IX5-k$hWu8GuAK67AyHGI0ScXhiOH<$D6a&5U>-Rvyak-6o1>FRY9W?_4kUv<_>45zhb`5?b0jg}c6 z8=K(I7?=;J~e6?KB0GYj> zuXN&9n&ozUbEtJ|`qiQIc>UGRSbA)bK8q0fI{jE`%;eE*2dK@crtvYhS*aIxHW8nl z&4YH_Dr^_a++np|ENs{JYK2Oj@qmqM7vs%Ni3X3G$Y6CQRzt+Qajm_TX9#T3ewD3! zr_$b{&np@Ut*uHu-!2u(wNfc=?-ex)P^O4u8KEB2pK<+ZA?fjcxz^~=TJ6y({)~_D zXKF%YVWyJbj4KtcRH;aQtK}MxUaz&cH6mu}wQ{}I$kQZ^e6tld@&|=&4U1Nzz85#? z-dek<_CuRg+s%51C#=MAqg5#v;ua6yVq8p&>JKACLuB{P{tbtSij6=Q6U+yzHZQXR*+VHfs)oIj6eJe$O=PM~|xbbsB z2j_=%qVqSo3ZOuLXA6b6(VnffXv5hicDDdD=(O5%`Bu3Q%{BAe)$;u8>ipvJe7;%E z*XHw`R@}lopswcYRk~-sUf(Il^BAgfVPSE3F}Jv2!o0YTPH*$K+>9^Po7H?9h*8WR zTwa@fW%i?&*Vfn8a+mAbcC~%E-rg=3z#XMdr)jhopv!c+pYaE9yw^@ZF@W?^YPmoIND$2r|+ zJI4Tv+qt+xYhk$ZwY)~=$_@Qp&Ax)d-)`T$rE&IZXDB^!e`68AV4oz-U9Q zytRD3&@S)B5~$HB{T(+`HieO5B$#QU&onZN1#9PGzPYDS1jdPr^=h7N8xxGyS^@La ztkt8qy*=FCkN4xkbQD`Jlm&Yl_|+ccJZfRL3frv%%wmPV?YP>GE8J?kz7y9@YGjX^xf>tT_S8hDh9nnloKG_l zsk?i3sP)!cpro0h-P6%YZmxDJI@v1Z!EpA$9@5zW%+DFnGo5fDDjpy%GtpKhU(&#j zYdBDmbS--*fKnO_Q010pq9#w=EJm#v?9yP=K_8YPly?zy#?Tkg8ETo`8EToR47K)7 z4z*65j*w`Lc_|otFRW>-j{{WJ=|)~7;B=!21Q{P00ZGKs=($OuzOmF~Y9cl6KK$O4 z+dJbv&bp6t=gv&YeBw8ZjE-=rl-LQ+x6l!mLjgk)2{i?4;7||?p&~s-3#aA zYNLH{VRkp>Xl*WE#HGN@78&+UJ~VRY7_IqA8C4=Nn_pX5!D!B}t*$Q4=g=dyg>rMg zUZca?^N0%&Z2kb@skax931numh#xt6Zn47X$k!Gt+)2%Al@@Bn^v9an@5?BT_I6%y zba6e4I_cEv^`+(I#mlqHODoYedV6Ut63W53=>T}H;tn96csMq87siJ1Tviq)?IXX# z_3(I50_DO=zF}XHMUQJMXb|ks%0V92qKWfUXCSOKVy<6YYgO~LgZz5FSY`;Xn-OjD zfrM{oxARS|#|K_TEsF~SEXbB|ODa*eT-(l9^4WSxIxJg1s8=`Z*^Z5_>|VaX*>ic? zv0loRH$kAaT)Da3Y3FllR*rSz7TQWTIlH{958N_+;FReDXUsm0UgV3q3yTaP~Ur?NY*01f~ z*cI-M^R>-Rxq_KTM`NuSnH|6`N~}uz=%Z1I_cg*8^?bDW2_I;fb^-5+e?`0wv>2LB zP(vDPH<@PYX zUdbI3K*3k0{ed?{#(#|FE7y23{Qt((8`w~%2f?w82&4|29j1X8yV`U5F9M;f-!%$3 zX1W*$D}MkYDw-0k)S9DdJyCOX)P0P(k8$@g;XWqq}79ybWBd zcHE3mLxr80oBG67L{U3MSItC2&jAS9+b4%oqv<=qC=+Jzj{z<|0abXaQnB(#^{D}( z&n-cIKIO$tMWzA}zEz*=lx$xLQCFVFTw}Ll^G;@0KZ=Ij0?4-cq;Wg(Jg@|_Tv%Am z(nQsGVeOUG%j*jR{_~4)VurIch zF!W&rL(g|r&KCPu^9T9ujpgz(PnmCS%=*tc;2URwP|9!TfoJ8_wGDH=_{^-Y-S{Z{ zlHLDWWn&)ZvTVo_dC9CVt*tNRKAMqoS*o=&+t}WXOg@9<0JI-`1bwLUuJim-9Pm*& zp**#T)H}3Przv=6u%j;Bx|y%-M?=Xi!ziE%k=vNDo=)Tbo{?83x!|tLt?jrd zjzZt(wvd|fG50w&QL2xoM#ocUx67~FfRauep{iWuytHF^YZ%~O*ya;0SBl{q*nOZV8=IU#no^ua6`ftyv(|?TdD+bR1^{LMpiytpEckIkE1R7ywDGV&qKfzw zX)yalBjq_EI@eceRdM(tPmGZ zMZ*_RTyg|q0o(L`6q%bX9Ytqh6;WQ0f?!RYNP)t*2v&3(xP#zB=Q~zg5#%G3iqs%K zxGDP3ozOP|USq0Ku9k5nTPf)`F3NK`H?+O2CIn(at&E6SiS}sT(G*^$HpbW(n#AoG zFNz9`hW7b?@T7mtQ=%KKUr$G30jHxEPDiGCqyg7O1lop3iLOpOfe-4m^698v5t5!6 z4(ADaa*z$#OEhLN-W?I86;$R1EcPg}IzA>kn~l+_v5AS%3HhnxTU)W!sK=zpXU;FJ zUI)f4$YDkH3kN4>MQ&)k&2~Vk8ua+At^CII{PrA7;!dlxQ=TiA7Ha}jb82v5#d+*W zR+NA}-qPw~ZXT+#Om9{f)Lr_{0v?}@-b>}UVu%)?xd~j0aZL9&7Rum=B@Gab{G}SI z8k(Sp7GnH?GOliSiupYN;PT@2#bvqm%i=V&u>!<9pj5F&rFw-MTg`8xB7sY*bi2_@ z8R(w_n3vde+Zk!n{R6rO6jz-)Jn6-v?n&4F2aR93*Sz%SDhzs=wP9`c(1dzf4 z>0+w3?>6EBfKuSK);ewcn0f~BDbAR?6mfO==uT0XgB};7t)dhsPq7sjq{Bzk_S4gx z1nJxvkv}gr4)M@Bi6dwZya={ZJVG?UZ4d%593(lkjb;a4rm;IUEGAmox*~GUHl+Ki zSrF?2n!`3Ofvu#$jc_m(t|rm=we}IUpmu6WMHw!lC#(++4EGB8H3}7ec&B*BG<>06 ziO`>Bid)k4h6?2cQ{SO)71RDju6A$Byx(%s(u8|T~ZmLg$-ReN0 zU=oY1PD@P}7crVLd2R#5Ti@&8Rza`FMR;PzD7=+mM7(&xP;@RVOvmBTEz!K7o+v5_ zX&S5Dpov=+;XxDMG3PtdRwwRA1*ariCr_~j7!{6Y3zl20p)K@sRfK@C6kun_aPbvv zi4hlzr1%i}yAH9#Z)Nc+iWv<(_XsFZ8Qp&M}<6!h71qp0RH7C)LAO^;6+!!GBhX~e~J zJ}BPvNCxV^6T`I^&A#U=bKoVXK=AzW0-f@0N$+9{P5TmTTFbhvtQ0Z6p+D;ULU4lc zEMk)rAcadr(C#o5KTOG2V&G{!MdH~g?76h|nCg8Qi2E3LSf!7i%@LD67f!7i{@R~OSH>dagS@J~j+UD0V zo-j=6Ig5Q576lbx6QwYm=|CTxB~DntV?;-Db324ahKC3)YpcZ;TCe1AhxDH}4vw-w zBVhu>S|C@(QJ5AtwPTWx9ujg}n7s@phdF?VY_jDg5tTkNI-+Q!+Y;zP14uJLpqJ{3 zTcE!p;c$nT9TMLvGn`G;EAr*G6#4Qv9AA7VE)?=R!opz-eBkQncfUoy<5V_=5kC+~ zd6NkEu!s#=fu$NKSVV#lLQG;D4K<>> zoF}hPCErJy9C57xyL-wOXswOz2d?~g9wqiOZWxGdze9xXCU}0-(W7AU9ZEzyJ(XCE`cR?2GJs= zI4gD-E0co1imSRw*GFZD5eq!wMG%_;*gJwqmLV}>+Vl^{ChR%4(3(!YLiA-GH6B-j z#Xv5?CNeuBN!hp9Y}b5jjHf3@&-j>Zgs&$@t}z2I99^a};pMcs9veb1J8)$&yR^38 z)K4md78LnlL_@u{xH>zxytt9Mmc1e!?`dAcv(Xi>PRnz{0_B(2a_h76i*qEqNT+9= zQU|ju#M>a)v{V~jj~kVP;aq*ioa%BBT7&F_4GZ#gVy~QAXjpA}UKZNn`fP47y1EGS z(Ak(T*EX)?I~m74Nk76r0MQLMJ0(1g2>}KErUq zLYL!~K(c2Uv{`jVN}Ixg#qzE;L1mlKi6H?Rf+fP++9YCPn_{GDFmBj0q*J2=Xefq4 zd)lnjH}OCWH!-|<#Ax$?&?soAYPh=C?M+avzlD^;#AvumQK-1RKMchb(;O&SPBA@0 z*tsHn)G2KX64O$2F|@CEbBpeH>X-DMK>zk{j+Y9?q9~wcVQH^gN9y+Q$gcrnr|1c` zwV@%!T9{tMu!9X%1SvtIFNIF-fCmZv?O-$L;vnl>ZMslEb%xe-ls!M-v`$rdpy zfLGnOObND{YwN|Ac6P^BbEFsQW*ann&4z!-dSnhqw&K}cyj8rEGA@5dJ! zG?fUb;wh`68q%0RA<)ru+PYaB-ssqwRGR-r;RQ!0$0pC7IcvfBGgD*d#?MVy88jJE_RA0EaWwcc@ zU$N`15GsK*u~_d)j0lziwFmLe3i3Nld`WGxB93r4Yy6Jb56?vxwXJ+HG(u6@UdnrA zDGLtX&hKq+T%rF;#z|qnu<1qH&dL{TwX%!rOS8+X*H-2T0oI#&6n7QZu#_bp(=KnU z=1b(!&^?ZY%vWGJoD=g#T)Z*7RK-oOd%iK85hH;YKX)LmR-Bm#TM{G?S7Ll{qEeW_ zUDS5T+i`9C(LnNz)F+HY!bOP2-!ZjnEQIQ1+)>@~ixfLMkI#suxKN02#r=RRMBC7d zZg5K766rAY!FW2+jp&_<@*_2E+xzWQZf#+$&^%zEIfTTG4&#j*|7s~h^V|rU53R0-@;G=GZq40W5v<5_ z80--$=Jtiy2DuIb;KEA803p~B1{zp*6`+tq$1YjGZSw=Dh7!p?1$359C1+LeQT(p7 z`k39+%xKT{m_p7(O+hj-7!ce?f{ywmY>PY%+u|0&w%BwZlFBRmSJ^U!nj+PA8?(EM z5^LAs9uyJ`GJ_KgBe5OnzGzj(k@G{f-KbZ{ZmNiDmfe(zC#Mh80#Tq3gP`!V8=&!I zo7-i3U!5a|BiIL0ZQut@`;b&xol$xP3dot0U?NbBiMb#X4EiFGrB;tDVLUnwZycQU z;3mXcgL~~xd3L7?E!_!n!sBY%$8T>a&LAAk&A1dN$grS@LD0BHir|vxNBTsvvwKQO z6hVm&vU4heOWfhoINrz%V>VVS7pHKzyZa*E0U{a8Uls1eKx%jE8XG$_*?rnYD#D#S{VMX5_2xY%8Mv zHm;U;@;jX}5Z(xqldJjFQ$p@nItqG;C&2Uw8!HH2Knw12G{pyc>`x+4a`HrV-2>(DkOXiup=zd4YU> zGAcgQH3I3eiDc*O=s7g8SXgh z({Iy}vj((;@TF3&Pb8)cBW3jpuUXW5LF{g=xX9$!PgpUC44y?+HME9+pxegFqbPg(ahoieA*mN zr1Ha}eflsf0?J6@;v;UwH3!1UX6@ z$4#F~J3Q|ao`S}7Ed9bxxjHNwz(RA2iC-X1fYKC237Cx|A^EYHo3Tb#~dQ zWEks>OY1P(8`-6gEw0SH>|8BmzZk7@D^ATz#2k;j1Qjkr4uH67(WKSE*)<(0V~6grP*KJgYH>G+=X*Fjr>h zwI>tq^`Z7OV2%7skb4ge0$6u@NL=$EjNqUk$+#dbS&2@JJa6JfXqbK-*67rpsb0r$ zII_b~dZX?1n(?oUU-sfI9O+89Bm~&QC?`;WoK&z|>P+;B;lF@io#sgPtfv7uc?KBQ zYolranvUe$gN!b5?=n9cJ=h?T1(G6bz@~6+gmz-+@@y6jgjclhKF5$n69O^p80rhr z;eJdP*?h>293-ciyrZ}P^iRzz3>;g(P%8O$T zv!ccI&3dDngyh(3694sJ(m7Z`vNTU7#c(aAUZHh0vSnmqQ@cWhO6cT)YCD|7?@1SO z5OKiiGG*RGt*Lh zt^8J;@=T=RO|_+kqg~9^JSEhhxE%Bl%`v|^GirLZ+iebIqk^QE2gydlw*d^tds3P@ zgU|Sra9E;BK2k_p>ccWi+B1Aa;IYAzr_Nuvc>3k(SDzobdFw-v&Ej>YBcD?m((3$~ zP5)N0c_|5CD?PmNt?k4iAeLYjg#A#P2SHk~`qBISkO=;y$tA*-a#_3ui5_ z!!y`Xj@!m0U14Bsl{ePw+nnei57kVx5KUG%7`_@GI3r+Gw>aJ|mW?(^w^_{w{pfb< z&|zJQLW-Txqf2~_i%zpIi=DvX_lo|S_*v}&a@&M`1G3G)3o{%^jN7h|bnL12aL-Qp zLese1mK%Yw!I`IWkR0D;gfcYyHh2_BLr_sX@1Q2%F(VJzV0fEt2agGv^1RlPewV}# zYsoxN?4VjF&%#(<*a}DxGdd&8TXcMN;(JLc%f+WTRY)#VEO~L^cSW2f1O_XF`WvPk4u2tcj#9*>zC_7x>|kK`P*%KsNg`hh4`{f2hg? zfD*Gnz!Qok)!;fr$D+!&L<=()OO7(*Rvd}o6|w|Uv|b2wg? z)^O060bsQ z7$SswkQU#r%g&XUO30`Z)c2kRs>i0rD1QSL)T3tADM5Q)hUM?s^{o<)@)$xJrX<5H z4()1JS0qsfAiQ_?ZgSv%j7*6i!*~v5KM$8Oio9nKYv;1fO%VPZEJeRlG+OFD_3?`5Yq zF0JI2u3K=|NbYE!`CWJ%Pym&USwv3LIq)Xv-@?Yc$j9B-m}oR?G{0RJtHRugK8@^j z?yOQ9n0rw!aJcVyCVyaJApI)+o)K#&>cr;>7^+64LK_>d4%x^XxuuoGwQD)>^6J{^ z;<9ak?E7qG+XvfR~wVv1L(95`Nb5xwI;mJj6ZFn6oSd{ zMgbMUc!jeGEKt}F?Gg6L%8=>;qPXwVt-$>cl3MEaTg-iDYLmLOj}CR7P1hf>xTsuL z+-UW5ci&C*^M)>ol!Se=@pv1-irMqSN6CwTZ4}0|cp>{rfMrsB*-(P^5fgbto?UlL zyQZ`-Nqtwg3oRd@=%DtOGP@Ijbn^RCVV|h1f%oRH)N;9KF@u)uK^MX1hLZY}&QlrQx&eGv1LZKi==)Qv;$5AxM6`eN5V;X_HX9 z?MXkl9ok0nmzcu97W&D9u%yG)-OJ9}<&GHpuAAneE8p! zUoS^wWs`G5a9K+34Bjpn^@rF4e z2O_^$5!`KAJ=Rn4c`S58Qenx4kVNz7PerEJGZqF!xfV`{A|)L1TZW&sAc{T z?CbENcQCHW+ltAg3@JSXZ~I-Ypc@6nY!JhGHRljYDIrW$g$bp_C|9l>h=8>0BUOk) z0!?Dx(2EHN6o?-T2H{qNtO8oh`)34bMwqT*I@A)yi7qQ4fV1Q);AS;T1XJy31(N?- ztzl+EC{QX|A;efWQ&(e~(4c@SVOJR-7yK$V>o|DWP;pg|Gc8}S!S;q3FEx6IsT$v; zY;l1gAcsS>ZaTQ`(}oL4PfQt-q$E}ai)=6&BMgHLA42My_$J|CLV7rUD8HiRW7~Z( z#{iZ+5aGk5pb~EO@zzYe<-l2}AO!Bn-B6K`4yY{WVultA)-Le~gLxug;k>y}!S6_} zCPEM@cGF4@VM3@Z7$&jg^eSq@ami6N4ZFG%li#9|#$p-jbLqtnBGKHLWBHh*J$kK{ zY1Ah#tdQ?H;H*NERZoJ z$5P?K=N8~@T6Su};zf8DEu7XQJhLABT+agV8$(S;^IYaIKa~tlsqE$ z-u*A2ae)i0iTR>nMTK6CVdRhM~dTg_W z`kW0`1ffl_FB`L{R84MOTwPmUTD=;b3@ZN=0S~0luw3MIgwqulf?7qd&1&5noUdR4u^w)`ICreq;W39SYs*aN zcF<(&WK}DXa)az9`9!QN&~>s>IVA z)KVLeaz2ynZs{DETpnuJIn=7DY>C(n5LGo;axxDu5y=qN_GD5|hXJw5f}xhN0s3XB zs|13ghAcUX8jY;f9P(ZQMAw*x##7UBE)b zI>%v-hy+=3yRWfTd5lMwGBB%K0p1#9$3=G2bOb(;?M1*p0dpBAWd{ zkZ{%{axD^UNq6E$sOe$@)zHrv&)sregjCVO#pOmJ)e;@2ez4Vy#Oox%R@^9!BN+*= z{(McKgE(TrmL9BJC;Z|`J()k8<9J_M%<{PKJ4D^Zkasq`3Gjp%Gd0#S0vN%m>Jofh zmrxZN$;~289APx-uIM%I0CGRhwduJbd{}2}syJl(&e|{?Q{iFbi_ntIR=;%-J=9;b z2yfP318mf~4n0OHhyL%c(G*BuGaY>lzufFpD=x`LamvL~jRMWk4Z|7oYzn$>##()Y zoc1tfj4W0Qm!E1mR#_SJPOY940I}dt(#~d)HP2Z}U4kyO?2>sBa-)ZZ^a!G-#uEa; z4p^LD3r!#-&N3*G%7x*4gL;Nj5)Q!Z(8xX7*upoiGd+mX8a4>sTW<}u{L%}3+@&3g zn2HLuq1g%+LRBrqnE zp{mCALF-C~wa;i?o1ie#X*F4_W^)8&MjG-+?qegP6X(*Sqftd0SGXC1p1i|28PT4u5^b3LITd1r`bDP@||hCc2X z78G4-lIqArmns&K>Kc@To5dwu&xP7`B|SJFY{?Np&ZxR74NR7GatA_{$W(t{gGWb3 z;J1-FtyE-x-dQua0V}aVNFuK71_#=40516Bd33pGW%5E?Y|*?n*+H`+MdlZ=cnM?9 zs>J*dxFvx>Hbhk-4#j^kAc>dXQ56OS+FHibMzpFt-hBIeSOgc=KvgaS07%)!8z2Rj zDlNPxW9%I$Rk^_@AZF2%FzulyAnITWUXJ)k2_Gr8UgW3?BG>iyGM!CmCVW2c3!23g z(uEOB!t~a)MxyAv1i{JH00OvquU5|-HjVHA7yzFOi|(hB`ClW+^wgQDlMD|-^l2oN}P9Z%&rR-q$5$Mu}^OZ zXaQHts(?FQ@3{N2o(@%Eng@`#SVvb09#|c|B=EW~(&ylSLv;Qb@l89mclS>1GPE-H z72HvXOd~!38==Z#-fop2E!`fl3K$HimV$} z(mWrMQ!uQ-b3MT_gPco*bJaprmcHp$U5IBa8wE$bJ)*}Sw)77lQ|w`@ff_E&F>!r0 zLENprXt!*BuFbh%#be7&u*BF_7k|hO5?us^;Xo9Wt}Er_LZN+CwlnCeLR3($z45q( zJz^*JpeOZE_N}DqlvTm*mKBF4912b>LLs3*Z6%ToZ>*6Cs-Sa)c@pg#fXJ*8?Ta?` zAyhdZ`;w+F9jekq-To?^i+KM~Rcp0;2p##;??P1c4Xb903<@LKl6;@UeRf2A#EkQ# zs!>pfNuhMB+{_thha|0r#|QB($6Ia9!31IR{Y3jPUVFl?*3haF7j=@Q61W*)Gswv& z(CAwDxwL8@!|W#HI+8iy95gI5b_2jd5)_q&Vo#`N*4HIJFs~&@d-D_3iz1vITJoV? zOaQrxu8LTe)6m`2noS&aRG;KNe5)tHAgN;YUbz@O-*SM)NWSnbbI0*USg*9#RrkW9 zr5Wpc4nE>7DBD{3Hr-n>UEGJ-9D4PPc%L;y{@qZv6-CW6B9dIkI5G4U$)Xn|_l_EW zQQWwtJ|AMoVZ+A9NOu_QVa%x`8Hzg1Z}KxRSZ_~yoHee5%%J(2@raNCj7HL^rxwf2Jy0Vt(b@WRjEm16W?@m~$Jg zYh+7od+M@Dot$z~oY4vL5+wJh3O1N5mrjG+C6Wt<2M1W+B6{VKQt}J}b3F*jxuZZN zdqDF@WEd=JwJQ)qqLCoWFpFk4xCj^Yvqr%OVd5})g*o>u$tO3_Usp85G&EhM5$ri@ zWJzD^^yZwqHpT8~&Jr_QM9#UoQegv_s$^<&?JWVeR1XiPAfy9}EV{}7c45LWH%tlZ zT^VvTq5G>)K$j*Fo*9!FM%CD~UeaS6#?iVEj!h9KRo)u0i7}4qRId*02K*v0D~?an z5bCf5Nn`@Pp4bF96*mF+P?TqHcp*HBCn=J;9-1O>^dTXLeoKIj)}(_3w^@^6v{<(A zA!y^Co3!wu{Zrw4;k?qqTF-bIw*@tbHmaC#y-VFGqc|KqC;7ld9J>)|XBb6)h0H1k zE}Yj7S+RqYD`614G;kHLQ5W$KwItXK0evTrJ+MVA1+N_fcaeQ%_>xyi@=|yjrw;^% z9Od7GhHUZN{;YR7_Q^GT+p~g%&CGCj=O#b-XtmE7HwI^h0F@S=h1BWF2Bg1kPwoW$ zA&Zr)xD(<4EwL#5c*OaB{dL*6y_8Td{4ljES*7OYa!e2uyV6s)d!(egGnkA z1Oip;m)7Xk73+9Hv1R%s-wXD(Q9!l$3}6RU*0r>93(v`PNsmmLLnqkO>s4jGaImvkbYc=hDa;QtCMc zKQ}M9Rorx`-V>o$7nvA4YKQg%Rr#Ba-hiR$%Cpy0#07h%-p$}QF)7>Hod+c1%$-*q zEsqE~ylsfZyh~*WV`?o?*l|#-XK<^h(yhg8fQ5Wf`T2cx@#xv9v8jnkxT3M~^tnm5 zJkh!FQQ{VpX8!@yjTlA_uI8)e#gCxU!jM;2uK3F6hQvn zV_1M=nzP#skp-6;$3mBj1Q)I)lEJ;oRO#n~NAKQ^Qkt_7z4g}3om(u;w(Iy70P4Fi zF5vfJTV&sj5aPpCyubcPkl=t5_%6v}jEc!M5~MIU01@LRrvTew(QLWKdQ2afNSJH0 z(Y6AE(pu3%esxFEYn>{!p^^l?kX$e+$e&wdvYN?dOJR#D@?_KLL-RSf!(jIq2Nh7* z@i!y6=1g1V5EM2AYyM>o6Rot3NCmT6l@dZ3R2AQ-twe;GfkRkMI~RZicC|YE`Nu1eOM`Kylh!p(ZmJoJ45@FXDO$b5nZ(+7lY&CisEcJL zQ6}NR^&L1wZZF`G8pkZPF$rd&Jz#-lw}=*Ywsul7SZn9#_3ZUPUZ^moJ3iHK#fy1=F=X}I5INe`YjVVUbx(trc@Tl z)$K+)cT)~DVRk|k>x<0uc7APk#pkeDXja1BmTV_^GH73P939!4H2gZD3HMAPg%x)Qqa@!^QDY?(S2r2% zW<-DmmO&>gMexZ+{G!eH8W@rVzvo=r zBr5Njqy#GBSED0Qq?UmJlYpG;P2@r&d{4irZcGidGy-wTG^XA6NuMWNGom-ay zZk6WB7HdXtIs@jT=XZjUv^-nba+kXRan!&t5Uy6VTI)k8DC-^7p7?vgkV61`PxYY_-Jcz0Ff$%8(5%qS<~qaMp4n=(*sP7^ zpu_uW6BEBwfnSz;h98sd&D2(j~bTPkHCtbaj{dcqd9h6A(2>^rz=a1g`r> zj~pCn#87L{SaT-O2>Px-lXtnziQ>C=yn~$#QDh6XXw;myFOCfM;Fz%< zAoK2!WuvFsCXBg+`VEo=&yJ_3CdQ|D)9ci^DH7-HEn}f2`i9R1ztjx*370M{%`0zW zeKEI@Uh$Ot?*ft(&30O#CEy1$yxo zZ^R6mc|LOu2E!KT81w-Gi(iY@GJ)VRl;M+_v+O_^7eOi6*??|%X40dDL=ZAqcLnql z6k-yGZ0~8P2h`ll?*}fwUnBIo^ET&1h$%SVSuHc2fIv|bfvg|m{VO~=kElx~)yjD6 zVxMkOfzV2lP~ELgf`~dvw_1sPJ>SNA!a;)cbh-znR!R@bi?pCgKa7KYk~k*z-#2WS zXC#v?gX6uFccv}cOo38iffND4(H22SNOuo{JP>ukYP>gJ9Yzr9ja!5NHd4Yng5ACh z=*Y+hCg`FWT}psw_T?ZuFa65wO75NbD7rbce~ZThAi4Y$%^e2!1cYQ$7m)g%(Gc!T zQ8jt={+>d0Ksf#lNTC|r+^JeRCX=YU9tsQII@r0y7|>FO!AfQiL8uVU2&2!) z6$!ImM%Ciwcnl^5j(j#1{VpajRO@#29N1xHCQ*(1BX!RAw-}!(GZjg)g;MbM+o%qu z+3vEEDOpT-7;gT(E+ZR~;90$SO_eN6$tVV*jW}6xYhqtg(bI7 zwF{=YHq$Hv(R+$_B%rEc<(GP+j)>-e&Ag1wIrb(l|E05?$^@&?G$-xk` zktj{;+7xpm61VmwZ|y#1)lNew9vH?>pW(w__g+PR^=hZuA8c`?xgpAVtj#-N=91-# zz^Ne*ht*O5dC6!osY|dQ4p3W*5PH`+`F0w)t82`Z59O&2fifxbZChnJQ${5yc#@-ui z)vPjhxZ3xa({F(Yh-?wwpvN-VtA53G*=m<~EES0Qk4|0~O@nobuwju13_;DIdqWJ# zXgI96neW(`IZfJ3CZ9NGI!r-H>}$}~l9V27EY4jX(xGb4!5K0L@FbkU>z7dNC=J0D zgK|kV&IOt<@SojTqrrc$D8{=~=j;ZPao(G1=%YnyrrrVA((3EA}-Kk0&;oAMUmcl9;|qnZ^@iGW$nqgve%*c z>~5aJsPhA?154o4J1lQ2Tj7R+45-i`3=3w`<;9>o5-i-q)2-k z&k(V%S1`G+-lw&kn4aOaTaFGqF>@jr$^f=}yNi{Rda0v8bugy8s2C2{CFWXcsRz0+ zLpB34X&*bSAsfSD$~(5^NMOJrK;g0O>N~)$9B3eeLfhnWC~6?>Vz0R%&4q4;2-0;t znsgARH{9lE)Ut7eWJ1dxG1p55ivR@S8`j-~VNfi=FdTK8FT6v#_chwyW zrTII$B=aj6Df*J(Q^I5dl-()kbfycA5D)4oG{Un2y@E%4dA=WDWMdM#-z5qLcMsP+ z3w9OG(vqr&Z8gn$2bNQ=k~X`zCSVUIfuJ_geJ`GThy8VU&KqFI-1KD14?69U72_@< zP*P;$nAJWE3*#cVV4(N)&8lv<-_@+55UR@h#gWZnWo@^|nlUkfHZ>qw>s{*7(J^{( z-ssWueTI%B(TXjrg^mAP*zi zdXtw=YLGv_WC4gFr<0w~&>Q%oOMaxOH7CzP!}CTsGQsYgvY8@&iWz;WG3dN2hJ1=J;U@{p-wrg>?xRR1dlrdchj>Liyd(3lKn8y zzZ8YzYwjvL5ozh!&D{;rC7W6J;wmR75NBk_I_y zN>ks%JMHkAd)@%*GAB?JE|6}{N&f+oN_a$fz(rf>V7K0B5|}z{Ahp2NOR|u5K*rWs z6uj9To`5}!i~|<5qhIwHh&B^<2-*}mU~58Xih|^pH6Ew2v8i_0RX%p3IFXq!Iv_|RW74{6BN-@CXShsi) z@dK{R+PWUTSA||PBy&XG{vHu>(-sY8sB@aG zgKk;i7g(NO>k_0^y9dm3?>S(}nf3}}6kks`)_d;;{nR%JJTgU3rb@%~1vl@^M+pE? z*IO%HT8qI1e@wDcuw|TT)@j2~yeQ4~fw|PyTZ#t)_FLQT6~J~?w6e~^@o5u zZrXGxFGRfu+&rmw9&qnA2vQe3T|Y0y1lv+oJI+rWRu`e=%c5;&G8IxngWu~UcgFKs_atl|V89Oscw&c_( z3;m5xj7^?PkB^7-R9WL;xV|-ffF&+PqkZ8Pn?~Lc<0R#|w8eSSfY6!7MV|9o`B7?_jS}kpj^Th;$-v$t-M-$Jt#D_U1ZK;NZw z2U!mzT7Cc~V|+C6Ko1?68c&XRndakH83ebDyC3gX83r>HYD9cb1Q$- z#xe?+j6eFFMYNJ5g>6Oy-w0VZf(2?J!81Hi2o*+$WpH4D{iu+MC0)aqCEW$l0lJ=V z^F;x|66eF?1N$j%pgafR9@B3vIb*tOG&IZJ2>FtPkW3EHzBeW=A&Zq8glLSKK85vk zi8*fhcQ7>I+!h1!mb*KDT+*$#Fu9lRFc955E!Mtn+B-y#3%}|D>>rkXBeRu!|)C9;?BTbcPII~k>5QcU$9rFV-$@kN{H=* z|LC#IDL)WUYXrbZMNNd9Ia=Ewdbx*M%&pf~Kqin=KT7ca^qQ4l>bqTXhi+hTF=~y@p`^y=|5%FQ zd9C-&qIL`{y~uFb*tuc96o`t%C_89QhYPxM^Qa^G$LDA7$ag1Uv67EM0$x{~d549=KtH5kJY>JuviR zhe==ku)!T#Q${H_--9UpRf4(c0S-M22pgu*WKAB!(f234RyEJ?vmRnY%PWXb0)x>^9e6*{eXLku1Z@$K8x6H$gTWVrC~D&ZEo2?q4twMQAf9+(cj- zVBuFb*wm~-edPKx#l-T540dVCsL|9iJX$=Un@3@Wx7X{_p+BZmdJZAHef=dC+>=LL z6KJw=r*EZ-t`*d+bRkN33>Q>q%y$nd`$8{qO1f19Lb6VlbJ~y#*b07yi~(YJ^{mUM zvZJ<6N4kz-qy41$OcZ;VM;+?5H$HZ%Cgm5UT-{GZS;@EXwZnkrkl21*l8#J_owSY9 zbY8z+SDx_xBEtLrZts6At%wBNbZ{{@&L!-O+q-KMij zQ}M2CQxeZTFC2IRAb5KEWx>FkuiknM6nOhLe&G9+>mO#5hagN~9Fp9E%}yD6QtQnx z7(F|B_T1TX6Y25EiOI8*Qxj(OXdBzn036dyI+$?u|;D`_7Win5#)PI z<>wu}n#w3YACptm($Y#^G;N%nEQ zRlP<%Q~ka<*IIk+Xn?$#XN($^jScJ-JN919oZtLrXY`bX)@Fy1Mi@j;@J0wG7t$1j zxTZB>JmOfv+HrnOa8+iR1SM(*K`AD~uTiqf%N;P6a%ukgnNS1Q^aRDloQDFVnu88L z!*`^-Uo$V&o56eKd@1@P|D0PArxz`o1FmIYHeU071Ac8m z*s+5GVvqAAgtS;mfV>q8rAPAkNN{^RPpsNsy87C+GAsGN=I; z?LSmwKw99x>^K?Elr$o_T+WS!DtGJ}0&}q`tpSg-LTsR?N+pL6hy)QPmS2m1uspn^ zi6Th*F#vDk+e2VPvk|ZTbjvk!#qf1Gc#oeG5RYh$y5KA0^@0xz=(?axL3-(P%9w*x z@xTb7V_9;3_?b5Rcah0<2Wh+(;03YLMdOlqEu%x&4r8=Z@hon7^L+{2ic;TDSDTbkofzk(*!-pLzXqfQQ%OSD@frE(%5SAnq7;$VcHW`0XJmR zX(57XvI;U-E6|Uv?EdBX5P|l2{}M2RSCi!#Q7Va_fR;hQK9Oszbj^~kEneHirKD_} z+u+BS#9x_G(^B&;5gld>5$^=F^6GVswbNM5qU!u6ypo#+Q3Y_$Pu076(Y4qIJ6Zx_ zig7N4S^|v$WsCBZy-0as0>u)G+tm;!6N`l_hxTiIn-JOeDKP>D)DDf!->mA_<@7X+S;VU&F= zn5!vuNYL^HqO}NCvn_;g^xR^RK_RjWtx^#tpwjijE@`ei73;SZ`73ED@&60{f$oYyObA# zz>`X-04~uBLp&?|2FHfeQKY(u@&2F=4SJ&}>7503U$u4y^G-lO!Ur;^3IOV0(ZH5) zh4w8?CshU?&4<1jdEOWeSbll3MK;UHF$ry@AUM#$RmIdCT`K3X-6q7~YuU?-E{X*} zHomv2Hw~;NYqg-0^SGk?d~L}1+$9Y2(kG@2 za3aH~LP`)!=7*G$Q;~^;DuCze)@AY_wnI!8RV3{>1K{N-EB71=vdF||`C(Brb6v0` zebT^+QrImI)6q(CkpT1)HxKp1+IXXMF=}+H@1XEraRPYsM`oVeoa^AenN*(mmj|H3 zS{E#h9YKll0tH#jszad&gTlqdWN<0NN+ks>cr7TDtLiq9<;!SEUDzgo_Xj8?{hK$C zps~s~rF1Dvk`!YeI!%=>203P`0~|dmT{QB=`UPXl#EW__V>Tgm3D|+WCe#0NJhe~C zW5D)_$<9dzrVm-vtYr~PKX@itTnvi+rOlthALGTW5OF0`oWA;8f`b%5R%WL&YuKq? zP&lYq*B;8nHDfeX8!lahcTuPT11yv*h|HIp-|lQ3L61`vXm59K=YWFFX2lpoMq@d) z4stB?EsDjn`ML=R!xCRC^`16X*b6Q#ml2_jMz`5*cDn6Ws|n{w=LSmj5sl^@9#W85 znh_k&As?yorPuzY)RiRkocH@VWjYYs)$b60u5>}Bpe@Q{K?Mm=9lYE%CrwD{ELZ(~ zb$EcasMuE8v3VqXaMaZKELTy8i>@}f`ufQ02*=`6*`3J=lhN!*BFaV{?22?DT$xtQ zH>^{S;0wIB&;@#*L;h9aK*}DjoYqvT6Q%MVOToI^l`;%90gss^0h^# zgUs2k)NZGT>#5fPHO?1ol46aF!e*WDd~3CDgwR;&h)T_>o^4)~7d`UQ)NFRdyt1O6t6}TBxDsKK!uTwcnM!-5spJUKf#Q6r@58xWd`O0 zybB`CPPCkK?z}R$mV>}7NHPLId#V@~|JB29*k0sTb2Va$aZC|0ioU$*HFT2A;4`*$UHYTSn6j7 zuLAS}Z>Usq6o$r+AUncUS$h#{N*BA%h)HG{cM*6E^$Sy(E$a}Icnlr>0=UJiGY&L& zaz=2rVO6u*r&M*Z}r6?xy&aiZ*#@9IO6Bs=;I!lO0?*!Ke#y=5a zw>n_4UA0?DadR=owMhD`FA{$bj0?;4=hbv|5%PnjRT!_QlbI33$_s}1-?L^N_CkrY zw`$L9Y8W40)Xus>@xnaYOM|Brnql(RDyD@HuNBI_t=u@;0vaU-G%XZD4Y<{sqkAtH7h;zo2v z+2*|zbay%USPs0K*-n`|7OfHJtL?)LZOTGdN!2LR>vqv#F?hBX*r6U|oD$`U!~3dQ zt$tNDHKITeKw2{p&7N_~IO<-#nAlT3Eb~cQgJWp>4ayq{I2m*4LA~DW^g6vJu2%Y7 zb;!-50wfOCp7*h8cY3WR0s6g8t;c`sEfrPj;j#6G3!#7#-GsLfpKg4&GgH^-MUb&e z_@$RBm-=Mq2*E?2;8*;csY(aAx__|uQf;i3KrOLUFa;I&%2jq{icX6}^KcoRN1OoZ zGA|Gkhwxj|W2+Gw>M$*Pa`4pQ&Xd>dqP&-zx7K4OkDeXsQV1dr**R+LGO&h*5&>@N z4>?Kd|L6P9-40Vy?Km2qBw+rcEE>YNsu=pOP0GTWb(H8DAeWNKSxno*A6d!J_h_mp z%c7jQ3mct5*wzz2;|f+#-FZ6Ax~wq=t{lEDadOm^bfJ71{&BCgYdQ&09Sw3tE=~zw zQm+X*K%bpFB9E%zy!48kkw3ixRisG&m|vd>h!iGkLA=2S9|R$0Qvusj{C>>VE8{kI zLqb?OsdI^_$YGs$(2(&ik?YRTI4B(d$UCfjPziTM zH5dbUSyeoB6$dtk^`W%iLL?}W;c&LNESAAt30b!v!>GLZV8SWtOfSMNg|m zUyQXB2{Y<+CX{6sf{uCE93C>qTM!|8(P($x;?-1UVML9YQ!=5R!Y^4}beT0xsFHZb zy@V?>&m~-BjGU7P1$&zL3;Ch%6Z#7Vx+2-djDh)812|n?#NSCrsedWrJ&I<#f6}o= zHnH(eX-I`LoHsScAltyW0!POS(k4}nQPiqUKPjkrnZvV&WPL79{i6OUtTi zuH$?KF`JB7p;lBdXVF+Ik*iZ4j?pbh5o7r5?r*#(EgS&FKLcIf2&rUqR#v)2B1_w}jbo7!;7?qax*4c$?mgaX~ zmJheBnUZEgJI*f`&-%wtpMUfBHxFuo+k!TIg#a6jMPuD|{QzS%w6d@@E$!30av~|RfMgD74&HlX> zZ~YFkGUUe+p#8bttg&CDb*0o@^Wue49d?4W{CDmC+=LC_IJkmU#nZHjy`UnDBBANt z;Q8xWyx~R)D%^Nn`Frah!pOg8*Go<9f4AQj#w5D&6S8k7=lDGySH4=AenkXokQHLz6c|3eB6IQW z^@WwxT@5s5T)dK>RrDn?ID#w+tb;Ogv^ppO%K7VMJUV~9jCSX*Pj&y8Jrz=i1M-Wy zH9j~T#0mPNm@e^4?7srp6_Hd?GE2TV37A&FBN#l^+srG`I=Jo46B`oW3Di9$wBics zJ|c8R}{EloOAOR5CAetTGi`ux{5mmF@Y~RwhPffdA1HN8qg#c;v*H z2Vf^Ou>hhe*6KD07sA?07>-B-dPu3=)4YR*=v`Vq}0FR9ZHa!RCb!g_RIGs)^! zC*KR3Ox2`x9dg(>AXi*F$K3>C&^W5v$_qabN=&) z>>CMi`)aDapF@eG~^Z zVn3k5GNajQ*P2mdSNxf571*A;7Du_dHoY2~MhdL3ey$$zkB1gFvvTB?4^o7e(ftFI zmw(AUVn&O;n$KD~_`%BmIBl9N4@LPr5h3oM2DMe8wJ+IXq{U>ElClOczwLekMOk*OM27X<#?N zbiK!3CQTmBY3m@dej0Y*;QvdxY8b1%GZ&wH?rdj{NdLl%_IZHa=A9*{KV@? z;KJkPagvg1A-Rw#msqq3R2?W^fb|_5-rb#TvbbwIVt6~d#5wM6^lKZNyF0C|W;Iq3 zO_@H_b$P?Z2R)@>c+6V8*Y0)e^+v0KzrL#~amhcA5oP-d zYdMr~GRXVo0o9d|=a=B^BbI)3<>(#`UC-sCu=7ks#HhJC{&*n&MzGx_8z>CvmU|AwhRWfOKq>4Bw z$!sqw2pO5lEA5a1vs$UO%|n8fI&%rMbknE3T$Wt3H;3_-Gt^qMN*|g5A*@kpf;J{ z;aI;wswuv3&O)b^Gaect8|u$|d;@c2o?UKf=XV|2Tx6U|fE`Y*bZ|;r(*n_NL+ExC zX9jq!pOEz-9zK@IBb4bHu8Cmei)-vHBfWfU=nfQoR1(h~QLbBwxYlc_;e`)~QdYZL zP$~%ZO`2+v3YNEG(gC$2g(lD$lxc00=2eQJ^YqAq=hT5vasP%c38KxX{$mK8Jmd#G{ykMx5@lUS@l5N}@Sp@=xJ zgAGY%&ZaVuU{4V1wIPx)lDQl~_y2KnD|v^=g3eWk9Q3d;>b!JhOA)Zahk}-Mnaa26 zRrJ!x)FNzCD_H0yjQFv~v2@{%$Mj!F438%4|gA$*1HLrW;L z#Z>5~EaYn{|5zR0m>(75YL8hE%{)ENFXfPSV>%hZn)8D0izIbno!BBRFi*Ca<82~y zfeSJzrSoh;lKo=7RCbGEL=d?eXg2N4fbe;Lf$|+(jofkved(>w;9!5j9ioweqx0(g zB-j+v-?N!HLFCRh-i~4Kxe?+rH6{opJ0?_h3OL=>*2}}n-_rn_VM5^1W95m84{74We#HfR_z%q+%7O~|!PHZiVtuUja z(5@*}#bEV0R=Ev`@;F4{O1LZY&5%NA00JGdhR2^BkfF3g8}r@d^Uf#7i#lT#sk>pN zNR1#7(?yenP8(dimIipSbvsay0lYIJS*d#q26)yc&P!^2&#N9dnrGj!eNbS@ad0 zhza&O0-U6G*9t{M5wJVhCuRq&e3-Kza7a!ra|2>-1PWmE=JpY)Ns*6ew%d&^fh{Ut zRcqI3{YIZZbsBZ5O?yMITU`b3Q8jP8h4!{5Lj1C)5NtUTvsPYeeemRbxTBy4CeYY5 z`g=2>VuYm5uo7M!JOM`WGnPl8h?Dx0AGKa>J_NsQVH(TBJ%7(AW@_;L5{KrvyY2e)35sk-iZP#N?BG`d5f}da7`nEs@0~o z1M4z6W@q_sOogZYY1k5sHoZqjuMjh#tWP$aAqnP5$03ebQr^lgn^MW`g?OrGXnrqS zRZ7ZQIHHu9wRnVLlOv7_jC!bm<-xYEFou+m3Q&W`vq~@|E}kpK;3k_-J0Vin$@Tod z?{6GEO;&@eOUIg#Z?~|oGy-t?o|58*2z<28FIy&!n0z9T6T)zXQwN5388an|rx1>c zh7P_Iv(Qq30hP8AbEK#+BdheRAp+ehT!HyQAxzT|Rh8@CSK$;(H6!}D7LdOYW!h|F zVHKWb>GdX+9k@S_N!V_eMvC(4BQnfKa7<#XicE5gvBgt}JdNN#i#)B$w)SMm)>F2I5(=9W1CPli0q_M}YAbjX10P&uh@yCv5AHGFdZctH-9t zy&3byZA~}|MT^C_uRvd!nPx_c5z8w#p3F{z1!4%vaJXQr&7`ykbXEo`ntt^925Mpe zH)bS|=_LIG$XyL zRw0*R4A}lKnSoY|y@u!m*SqMmOIQ<*P{F ztLhHi{;eRb`fPAEIkeE;CDgM=?cN6TAfL6HbC3~~B2Oz0vxL(|g`$)T%$ZUfQFz&a zfWMd)LpFpqB{^(a7(u~NEX>$s{1d?Wj)DXY*>Xz%_fk*j(>#8n&|*&1-iBHumCLTR z3J4<=g3`jLCygVVP0zf!i7x-@m#@4y$#g>8sW>I7)Q93z-o9cw2c{JHNf1{?*v<{P zq|)u>_|_qwO_mR#R8yx(uyB(~P_;(8M$UYv3tLOEZ;C@%*8HMsQ2qEHYC@?o2{#n{<1>V@R*pt9N^?I&mXJoU}>sYBoWA?Pjyp>UuXTm3!KI@oM8}k2(p9 zGr8ta)r-kTGWzqn3+6YI{U%04jpozhh0Ivr?rfSoG~T^S=x6KIy zO!F$-Y~HG9d3Z1}MQ$S(ht>^DNWwlGTE2tZ2MxEV>i0W!_>kbUZXuT9q;*Rrn?S>! z@r6V*4Qd9IhiWGa$4c+oGzKXFO7ey#GP%US%4Z<+*MDP{P?pwkZ2U=ol(LW=A+Fxr zADYyUIv}*Y3Izsv9r5A85f@kjQldk1N_GtGj!Y}Ll3zzzX&OS4`?wFDQkE0*l;i@> z4-=kom=tV^K%UN|)5nh|@oJ#ofMpPjwL;dWLA?L@32e+kSgu=!9Ht?}g92ySLjkLD z>dh5G`zhJ+AR$rH^W}izBZ?dM=n4OF4wP4_VGRv3udK*`EvMQa>~2wnqty)@=Xf2Z zOI@Boywj!yjYQHdyqkeSt1~BDA03Bd>bBywmRT3^ssRqjASGSF|0$3_i_M(P)gfSr zH5D;WrnoF^2&sMB!BXUr_+5rL~=`>zwS=mO9 zEBof+66NPL#Mz7FxKO<&u#*N9v+4)h$O>MT@fC)|L^Iz?1}Y`TDvipMO&bzXqMvH* zP2g=fmAGgu6$7#0U_=yqh>}ZF6%bqzOe;f1&+KqW&yv8E?OUwUckg6*RX#pa?<&hI zNJC1rm01Px!1^(tRu4G9OZ;P;amnawH9mr{HzQgp%VyL18Nk|Bsva_aIfVt1#OcEV zEFU74D{f|lQZx;U2ArPt9nNct>b1Fb+moRNe-iT6oDBdgXXa*-+*9s&q>;Xtab_tC zCiil#N|EY{Fiaf}uFq88kbUmGwcdSpb|`byGyQl~yn2iq(nvz9!&b>^o|pVd#y6FO zcG8GCEgt-onv{gnL3(^em9644sdQS{RBMitu)<?;-)ZIf$`krJCg^Ss$P*$6^!fF9ha6Yy*Zo@s|W^98f z$~!QK&qO(+>prS63EKxRlMZiT8RdZr4kgfM&y<*;XrB&|dBdRB#M}e)iZK~TV!FaCS%y-$ zd5q@gE37nzVMCICbi>blL|qLo9C_%#{yDU6wjs=B}EETSqw3VD=x80Y?U@wKziC^ ziL=?GP6B|5W|UFqYs=d+r7?t7?%F1esKC6Z)sgh`gLgFBWYc*yXDtKW-Jg4e!2$N7DHjIfKsD>kp+z1@VwB{4MJ$3r?j z!a@4){rcZdY98y6#w-Y{6k8(yP#P2Pk8U9atb-l#Q5xf#un55v+71z;wnM2h#lsOs z7^{wx$sVLUr<+!(^I?wLA%Z4_I=Umix=F=op{qsVNlf+?YTWV>aXp5TJdQFx$(=HU z;{je-7{FcNi4z&h!kK3sJ{Q2o!m4T+*9;m3^b`xLc_Mdvr?&hP7W}>qLFYDk8n64;6RdKX8cj16XPA#qLXpU5_h_o)C*2 zjLPPa4>(7l>f!*>;?SKYZZ~wLYYi@EXQGz2siwHNRmmiBo?YvtI33} zAD$R12s`gPU8*`)v|(vo4;$>t!vXC(%!jA-*O&0c>k^`N9+Im@f43+&CokT}h$M;> z_oJO??Ld1d2yiF9igX-MjP@`kzzqwE3W}&J8lE$1&vB0QKB@^r90$?Y~x$|LeSS!tqRN2EPpJop`hY}1CXvpePR%1~j% zdp?Nf?8+u%_M*Zr4MNDqzyMR8xO$^;z(>N`Wr2`KKOP;#y5{^$5)$zsG8BH7+tND0 zpPubgo-hz7D0^!w!k$)qM`GTJOj+}i*?|N0DxFY+aABaJ1PQFq8b%31U52GnJS;J< zK&p5qMMLV-)UNXGY{r!3+53Sfx}C>E&YWJjp`v3#xy%KL{p%yFkE6m}FC&V`J%r=$0*}!-2bzhx$4l z)RfX_ORJeO85-J6A_EMP6~kN=M$XlD!QOVjf27eV5H;d5onHkA1h;Z#9|xmXOQ&`g zsF_OWm=w91*Yb!|H)WIA<^ypV)nPK^mO+Rirb%wD@}MoRrsNsA+v)hRwQh43P`l|$b)8?;u^fr;tR)+I;+y~m0A(<|qN=mu*TFmi4$ zUOl53b_6{kCps6-dEy3mKpFFOQXCqMX06czB+wzRP5!cY8XD&HYW-Tz``Wh2&aBrl z?3K*i?KQf!28E^TG)!T5yH)qzdQMnJ$mAzo2)$f-jR|pd!)nCCBkO_s-7@2Zgz8UZ zWB?7z+`7qEO3M0QC0Y~+LC5=8QMD+q%pZ+JvHUjB0Ww>4h!fqVtq{#CJ43*OIi>Cj zcSft1(*~rT{SeON4yeDK&_;-vHv?Tx8zS4R_obd5e(jy96P*pQ{zjJv&?O}NUIbjw zv;ckTIuskrbZ8;2i&69ROE&77+@dq7HFK#)PY`m+|CFB0rGdq8uY5QeZJs<&wRHj9?-Z|OaUt5kMB)Ht zSm@c17FE*thgWh6PPG*h80Z(x%Lt#-G|XDPMJyH4x&TV0mVO4lbTTY!DBMY?ZBkCrC2D{xdx~q;g&eNcDRDF2a zC=UThqo9& zO3MV)61`{#!0iQ8{LH8&WPIeYk?Ndc51*81peH(gPdY7vx~IA>I(=|4ov zHn7$RpAbJ}wIVVALRWcYw~maBDg=+%uL}8}Pj@l^kRr&DsTuQ}%K$49WcP|&YsjXAUCA<)y9oO6WqW3^rD z>+#m%mWLC|*{+buz!Pr2tal%j-oQ&kwNy{8N;3wpOfR%Ty3 z(#QQ6r&$!_A-Rut#^VrdGFdK%78JsJaaY~q$Yl(@v(o*wFXL*)KN+oHxFi&>!o=H zMy?1mzr4!@M;J~fV6hbR6pz+o$YvBu9O4CUJidI}Ih_zb!MV>jxh!wPV%p&nE*V3z z!G97(qF>-h>K(7tQtVoAI^e|AE|J2gGi3wQ($9gFeHCDv!!+|aWFhpKA6CLXG>5gE zt$M_gvT~Jm%O=1cqjVUL%xad3v0R(4Kuo_n`2{Qb@`2)Rh$ILTNUj7Ahu{d`n&61RCDTuG z((+L^5*$UXjH7d!5$0r%?h4ia3-M{H91`Vd3^8$W#@D6r6T5AxbC}MLm3wg1?-IxA zHyC$pd(fypzJr;)bw_li)$D1{xwfA;c5%1>`Pw zw;~R)vMqYu_ZQA6l^&MdXNFCjy3vzJUkhBksvcm*p1(f>x!pEwK%-W#b>kJv=z*&s z3@Wy-=^rd(<^Nb27odndF+mU(S`A?oiGtE0xQqq=(}#d7$`~c^?ikxKk$Fzd=epZq z46iUj6`7NtNp^3Pb_aVNSAjTDP_}SG@f!7JuS-C4w&rt#U)x@<&(Hj?+i0k;GCgrS{Vr}LK13*w_YhkQ9(ELHUsB|Y$JstCjoY<$6p9ZZ zB7&Noh-Y3y_@5Jv*5(%*!g=3gljIF57?esN0iZ<1oL|0hy6Nz);GtpR%ih17{GeC? zg&#P#Q5+z1?=r(?VJONG{szQC1w%`9s9Kdcr4a>e2|4W&Kh=19;>|@B$E-l3d7dfm zuZ6yvh&iGgsW`C$tOeSL;}E!t@+o;1^HA&nH#8>NhX$8YfHTQcw7dmLkyumBdqf2D z6cS z;PEyhBEBZmjLmIWg0o}lQNB0Rh!$p{2{lZ_!$&1wBohfJ;4V2LQi{|hsGvk`1#6ts z_zg!gjEjp}PLDSnV=+Uq2ds=jDak=hA7S_4g$CvNZKqKmvTr;xSOl;Dk!Nec<9jjh z_=QQ_I9gy}!Dk_G^IoEvWvPH4-Bd-AR@L?DgQ8;vZDaQyFiz;`ZVMbapRwjbBAr(V zD$1@~;5jX85%T7+zxi-Y)-cQh;M&8;;{z)y-c(ZU(@L$OMpL}9)V0AFznQQfzoHH3 z@qsypbrG?^Yjfdj@#RW&@=uC7h-!GzI9D%a9a$a+YLo!G(<_9J7(S-{8OXMU`PXw0iSR)jEi|H0@8Ry?jk8xyK_NI+F~_TNdijov;$9x?AT0WEprXAEk2^hj{Q2|msqdXz)YBAa-~iy|~z zg!1x#YbV;NtGfa{?t86XztiaUn!S1xzyR~mUZVTunkrlSiw9y8vQJ7VA!>igr)=NM ztN(*MdpC;ykCYp;GFH5pI?N*9ZkF&7+v=xQ`fBaQ`RL%>7!STQlSC4tkx_Z!c@buQ zq%HmA%;f%u2E89N5PXa-Do0S{c{7Lko$JH7% zex<0G^jlzLmgSfg#(i@2n$EO``${t*cQ86+;j^|=oa|1;l+X3+U&>M z{6m0d`W>90lNJmNg-8WnuBu|wZ0XAbKMLJea$gd+Tm-%52Oj3w>tsYSH{{6B>UpKc zs@_&r&M;7bbyl4LL9Z@OF4;(kE>Ep@Xu~r`w1n(Zcp}FWNfdLEtTodOXi0d1z#9^I z7o3^vv(Ei*Ic@}z0*GO4{xT4X15sd5k}mx-m(9xfVF)$!rU@SHseR5;RPdPL zk$q?Fs%`4EBk#!dDrlLz21B zeYlLUwEHCiFuD93Xq7z_vv7e2ot%Uxr`^K^=~#{7u^1D9SV;aXBts60W*tW{*lsS= zSZ99`D$B4$iJsf8!^kYp<%CBCMX8Y$hYa1k_?aCmV?Ea?8LiHnS$13X+ERfbEO# z7zM{uIQHA_h|*L*5Yv>Y>qRin21cfHkyFg{FYm5QvqG9Wf(!UC!+XK$CFQ{ZeTx~T z@UU!oXx z>AHNNW8vhAE5NWPvg9?w7Hu+ zFFun+vV#B*mY?Sb@A%bBK9EQ&aas6et(V zm(#q3d?bYen#F_|mdlUbkIQ%}&q)Lg>~}}dtd>a#i$RFaM*u1osT|1WdNG(C>}o~6 z1Rx~F&=5x^c6E@_E-$@%5x})L$F9JrMbu<43xbkdy?MMcmMXd6-=c6nx{?H2d!6@( zQ7#Fz zb-#4`$Qb|U<w&{DFv?X33WK}|SW9GnWGfeTL0UZ7;6B!7BzL^i%b4_66D zBRc@$Z)zg8q?>Hf5igiiLaK_64ZBZOCUkCN0R@`_X+x?goKnw|TAsmv5ZX#SX^CN- z3J5z1q;M^-5)hbcP+_b^plh7efz^Wqip}sS(RCI64q^zsK<$)gwF;zZ7lc<86{!py zyE-qZWcEDyj)t1!w4R)w6E8t|BmRmXpt^w%Cs?~niBriHfV`E7_(sN50N4~E<~ak0 z$JtjwS5Ik)#_}|ge-RJ+Az?~p0db5?m0(*SLba(OoFqS$g7^pz3^i8dzf?3Y9}pF5 z&_Qzaykg4AV3OD`eNMti>xzXTUZYHkNpxAPx4$blNI1u(E^Fw=KGPHE+1W5{7%@%^ zkHePBM)KP|N1D)n7ya~M`ry~71}!IpB^6%E@|dMiNC0Vv^AA3PE3pE zFf9jGj=;bio-(KC-TNM6@Fjwf2bv`eHQ_SSg1?l$U8TAiZ)VS2&T*k~!xp zr7rGJR>pf}CVrOPstOU74?mY5x2Nc67(<+`l-6V071f%&+7IN9hZnF{LgG?^Kv)Up ze2R2A#jclc&Yl5HCAmxS30bD$n7AwQZk(g@>G@!e{!?-tO;vdzq26eJne8QXkphCR zF#TLKrsye2Z~L?7TNSXxbc2P}|GI)`9hV}mnr7m&CJZj=Z#r+*Fm zm66FjidYJa=7%mtM)O0LLZkViGuUW0kUNueCnHex+aK^=(^~>%E~EC=46p*p2*fN1 zqsneB8rmr1K>8(_UH|k6p)VRGT%NVv=GBBq=BA51=D{wLVFRLkjLnx)d?h+HSI|mO5bhmI8EH z!AEtRG)XD65}@1q5hgR+H|PW-vy|Ow#1Paz35n)o<%mIHt&FKJk9e|93Pl;#y)y-X zJmP#?I>-o3M#Ncw3b!+Hhq&tZ0KlPEWf=jO3Y~=j`A`>&Qr8?n3pZ0OgNS$2U3ZIk zDo#@>c96;VG*o)uM4qbJxTMhxRrgeiM}GH+LFOEq3c(8_X9m;`8<;pqrVGp3h4xgc5s?Rgc7CJ|IZc~!Mj z%j`ch#f-$1J)y0~eh6)iNO`gL9m16CD~KO9%HL}bEA>g=nI&htzM6)p~+qlR|{7eGD@|-wg_r>Eh9&j!@5sa)L6g{>NE3Ls-Z&8YJTngI9o{H<^<&hO%Yk zAedY}c=Ts^GVbA1t^E1X5=;X9i=E2TB=#HEVGQ#j;7{4#2{=;^)%<~m=kfGhyh(ZE zw`7hLV!ogsmgSEXVMc7)Jw-#B{;~WTyjsiL#+}DD`xI)m)vG{I|JEl6blye z{={p>%^Qntsn7?>fAY!}`Q3}v8&tl!_$qnpgB~r+0`wXM zUql|5Dv*MFe|?2+d-r+9(S|aL-m_>cyIszlnXgTpy!qg&3|&AuNRo+ma9W}i7M=9^ zOtr-&`CQE0$THbe`Aew-FJzeMeQh1IK`>)s=D{}k||&5%}~b2b{V3^vl>}(i=k4$cu>>^ zH6zIr-oiycIslI^lu%MW?~c(HqqkM-JQSG&#lkZ&Xb*thH&<0@eigyHNBJ2H5mnzJ zCn;hqtDK(r(nN!-c$98&=&)KSKon~KqmbquF!AxSD;e{dw2Nt=l;fj)Ai_0vD}6^H zm{IEPosC_j10^QYM^%3kIP-%X-$&gPSNa>s66N2u#E#D?n zUIg^wTZ>VXVlLuVeRXzfkp%V+_XJRxpJ;nc2b7lo0D%k0aE8TGoXt1JH^feAb@4Mw zbyUDbhz$z-i-i;*i^s)LTCVFXX|$~D=4{(73e@b}AV4XLdCf__l}wj$3wN^lS>n@j zw~EKGJI|TIrFfDVnC#(}QIiS=NAHP*w=0k&!gIEoZ=X({N8!GUeYil|6vxw-2+y}V zP9d)1a#{H~-^!^JBH?r*jD3e`p5x%C4Iis#jkdDYG$L@K`to9cLbT9b?9?}p$m>oA zx*!|*1czQhN`GcRb?@xz{(}z&SIIIhpsuCTL9@vk2ttQHX}JsAbWYA7y|xsc1srisP|1+9kb`vMrL0wgC-;=6^&p^_K%|H1?l{Zb&K9J5LH?26C5>$!6j=P}S-rYTHy4a7 zcrBW=R4kZgGTwnEq37mgT`K*I4Cspgg+!z3gI&Ug>B4Aw37+N-v_)nfpfZ0uAs_LbEy6I{R#CDQoh z)Vp{v=LRMhj6PsjFBu(nW{6@md2N*#&OjO*?~!asv$wC42~O!l57%Cf45B5LUVC4okW+&ql|`0FqzIW7a)(y z8g$-VyiJA9k6xfdt)7GFmFdI`O(`W*OSB2Yk>eB+QIz16Kt)uZD;BLrKuxg`I71XC zSAY$KA&M-Rpic%X2RsF_J&I#849BbtHr>4OUgYTtKfaktOxEBCnNawH; zcgqzX-xZKNLSP#Pm6a|=CyVqJrr9!>K0-CgHIufO@6TX#+OBfu$W}2L*};itCcSZ@ zD6jP}E!wcrhwGSGGVU{7j7Z{XV*uPEzl&EV^mQ}WkuZ(HBH zp2R0^VbjUS^M!5{xw$l`(|U4qXnxs08EN1eM!6|q9HHlzpx-;H?kBSx9VLPaCCOY` zXoMzNr`I6#uCAF;T!hc*uxojPH$8ZDQ!*&VgAew9(s~M7+=Wt|{NpqJl($9+V@B&UtLhoRd=c5UxG8{l|BtB6Lr(pNT zZ`<1r;KZGbhM`R5%a4`36!zXs$Rv2qXJ0exc+WFMJQS0Bi_sY#D>tdP4IBvoBri{0 z4)4qhfOyb@kG5DVx#xu$XO{%19-~DUa{w9qt(QQ=ox>aV7``780iJ3qbEX;2AO$SW zsQq}7^WiT;2Xrr$D#Cgp>T#UW}0N-*(l+OJko&R5|?fTdqp=!QB2s~8)h*cFvezs zGZMs7g;bVYRd~{lb7~S!5Fh-nQ7fv&Mz77n)byBI2Wsz`DX&G^OB|qNk!oCC7;$Wg1u>QijT2gKf%--s{+_mkYT(+5 zLPZz{ob|I~pJPwE4IVk%k`?VMVJZX}EaHE$6@D>&O8~Hp^oTdf^<>LwFf&1#np zSfJc&*TdxeGM$PlPZ8Va2e_3#2WLq1qtZz@K}6J@dG8cY>*~90b$xJ|#L9~@j-<1(AxeS}T1s7j?>+uVVuv`AnD_LU#3Eh@ z@ic|_kjd|U3tZMJP4$m_{1M0OuJJ(%o5^*D6gFDlVYm9Z2o&9qt*@Iu_TrZ) zkb_1^v8!lSV#~}^#bJ}JE5iP=C?O~lWkzN$41kH2N}xcb>x^<_g@8V)OcZg%RHX-Q z6SB!dNS4>iXY?*I?xxUEp3k*QJHMFGWj`yz}+dAZbQQRXiY0kPCvKt)JMl|&RoFQj=cX=%r$3ku{BGh-fPettpB zmMKu}`+WSp?yu%KT680#b1(pDll`VC`{jO`4gl2Gm7>=hghwEIl?$bsgIEROXlSJ*xiImVO4 zhdczCsK~stIIaU0yr{A*i_FmoA7tMNjjcbk43y*=z#W767R4Y>AvP+Se+bFLCfWk6PE=RN&Srur!E8(@wH%P3)^)B_04YFec#GK*CC&;JB{OeTAB z?x{IYyl|TqEKH4sYOo}UAF{}(alW!{#L0ay$QzQcM325^{>-6r^gl* z>5;t8PzT$mC#SSI|1_aDqy@HDWt+44Zgr6O&_y3OSnMNN^a0b)b9FP2hmu!D7TDQk8oW1lz+g(6`@KLF-V0aPFzlL zcs!7OAXq|6)ValAFVyE&h!~|WaFsfff01B6SKO! zCVeqdrwN)TJj$r|p+?{RK46doFRq@UK&Mhs0W=`Hk)&31j3LqUvsmv6v}R#jCB9~F)glioU89JHur7F4h1(Y-Y{uNs8>2;xrw_nf`-J2rHscw~ljxQL z-W1TllEUiMPj2N|(Y<0$E5l2nPvLx3xFsF@8u=$8)bTJ`SM>4WJ+W1C zDbRx@@-cw~wyG+%(x6A@MS)QE8wBDt7B%54T7?+;p7JYxA;DUScat~qi zUI0OWz%oua?;$mQnZl<=ko2&c$=pm1uvYFa_bLi43TgRXq~&rSQ?Pc5Qf8)V5`UUO zk*z{<3m4LyI#A&*r?cEo_60#m?ByWQmt-==x*;BQ!saka@h_5V?jy^-ak1RZyek+~ zm*pC!R^A7UEPf$JO-!zVbc};D!Y{;IFyff3hW~MhAT`X301zOFE`3Q0^noA9YULFV zsLMhfX2h77)&7ZKJ5eDf6ztjC2wuz!QMte^SA$w8OOGKg zJ@8Su-4zF0nXj_rlr3zkQW0#Ec&h9?!cDC2L^d*7Ek#)R0v_qEqZK}qsC}c|oD%zs z0RWK+u{^i2lJ2WlfXPF9OaYS2`;hz)p;ky$*l*3UGQEWb&d?pZILG~?de-DQv3c-#E z6B03r*Q zfHPn38xxSOXDqN}R}f81uZjd~*{@2Zadh*E-7wv)u z9>j^Ex}g!j*gvDhNq^nL>+?W>*z++kkm4_TeW+0H6|OK{!k4pacH)w%#pP5E&~Q5{ z)M$NodTiBKvs23WK>X$hJ55qBI59VQ4OA0CLcAU9vt#dYo!fj|ADv|Ll zprd9Tn3RS@qq*EnL5oJQcsp$t%|Us|_sAhUI*MBgLd(Py#3_=gP?nD7D#{06mw*K@ zy0)K_bj4@fKX)oPYO+ppTzfc*x{_U&W_~tJ&bGdiRHGv=hz3c7k9*E_2oeT=mwtRs z#@bW<4fRn7NS3DL(FljdDkQ9KKRR0@7<9dE-&RU8S8()}5Hj4eCeR&kY$3zF)aVH5 z<_oM4me|QHXa8;uSH%3WC$x%LCW;GJ&JhYd%K$e)^z^&!-F2WVn`ix*z$&}(Cbl*W zYfvD~cis>^b7R@NL_Zd%I)D-cvDPXW)@3nS+>X;1-D*)=Bdi?}9JyRkHRmLObWalo z<9Ytb&LEfyDs`vu!ob1|LoXnvnh$<<~G2%p{R%7-;JSnR;gZYGVEsOJ+T zD>N|E$_|sHoqkbZ<_srO-xvktWts?+Hd_RnH~OO=&_xE#C-&dIF_D;bId{|z)4)*| zR)vXE83PGV$+cJw`7uK0pNRi*kr~6@c{3{iV%$|$-?0xWjg~)$>x#ef`&y3JHm^@< zoL~*6JSiqESs2>J&)8e zgbA?7y(i~#%dLq+V8aP4{>M@|ZIY-YGwk^|Du9}$g~6C<7DOdxO>ui)1>5h?gxckp zBb48FiuEsUZNhJS6ak4!G$zRyjdyZfnjDQvLAdGVaf%s&t)zuHdacm0Z_hKKW9)c7aTwv4!WP=H(n z&|?CDDe$9BiS%Zlu!EC72Pc=3gxNV9yam-@9ut~>r#W9_Fl}yayQQwLy(5*$_m3q$ zZEit*Y5&~gW5qsn05DTbUW-C}E-O}CVDnUqj|CY;z)ZAF_LmE8dNZ3Gk=My&K=>i* zXy9oOhoZDCl1&X`1C5XUfVCSES5s4#7?;L>mxI#~NN2;xuxDCY#K-x6L`mb*Z}J zd<3n@E7%Q+k455;-AU%R9?fcU#K;gk1_|&HyonJ@9l~Tk6b?G0W0ZAk5LsCb32~gG z(c;$!bpC@#m<@BBC>Nt5Q61;yFoKmXv4$X{^yYnt zOEfMpND^6cE~#?KBkzwyhYRWtcyE+`Z^7YiA7HJsf?}IpCj8Sv+&@-qXkz7f5cgcl z(hW8yXu^JBjnxn)gnAX0m*&$-iKsxPc82A3g`Hbq%}trLa}iK``t+=Sq-4_jN96n} zp444o3YNewci1;?pttD2I_R})qgrd&91M@!t$LHrYwcRAHLMN0Zy+#3$))H-bT zTg^tZ-9A1Zwuar>q&6CkJ41dx?jAQA6r!#T`>jE(IjWDF?aruCuQ#Y!-E8z~<4(Qa z=Fg4#aNO*6=;}6XA5+kp8;u%`@$sZH8n>F=_Mpc9x^!%5wOZqLuio$TWVP<3*$N6k zCjdc@zy@R*U+R+?mVc>7c;O?J|NP)nqih(4HKKNAGXqqz-f$#L^*!n6^3!KBevlr|VpUm_Bv#<=yi{z`l za$j(hN;-m*rZmHfURp5!yq8u%TFGzb!ql@r>?|nm%a>Ir!vu-h>MI}o5K9Jz$crEY zll+f%3(ZLt#)8nWoo=Ef#^47D5-f6rL%3Ho%xyn;rS%-LS%gUxe1=az*cNKC1hk>n zL)BD!LzGcwrXzSc=CKqK&rkSnfNhAtJP+-DGVp%Q)jj724JpB2Z*=`2%!+Dfw!8@jbs^==*TvmzOUNk2bcx zs~l5Vpk!pd3N`9NiEKoz4O*90(zRe6G6JrwfqBdb7z&8_?rd&2W~;^yBHxmLdV<_R2#(Phbm} z#m`k8l}zu{UVj7YVQ2Tr({I0f_WZ^E_XmeZuU`M~<4->ih9kc3}fV%uV z&z@#8V~wnJB(do&s~_Ph#B94~0fl<+kKSqWmMmS)r$Grre`Q2ii zdA^tK!OY~_EdOYtdm43eUK}E@sgk?*Cbuk=EN}YKw zb!I360i`I+Ym+r5gCJ5vFO{9A>}{YGfKan6KtZ47P+Bp-BM%@4IoKQir80o{hOV{+ z3Q>2NyT{{@W3Px(NQww3cNN%YQT9c!ebCXQ_29#q;+%#Ef9*t_X{+ahPvO_hu^Oil z(OUKrv;!otolG+pKK+Uf-CNU#iCtCXna<$lM0KIr$=V_E4){y@HbMa7%n(Y$VJ%)` zHU##`%k7=bS5L4Tu3|>bNOukB{>eE~fb~>+g3AZR5_2F4cP$7J;ZaC$QECwu0)a9m zx-u=;nh5Wd*T^VLHsmR_W86)a_Dtd(EAASp9)eYI z@XzM?63kUZrWY$JVLv=YsaX-ka8B*RISkC6Lg%7*45oSID9dsB^U6{FImEqDSav8V zP$lFn25vq007tkgP89lze|ukbAn*FHn%^w_@GU|hc1Uo_P*mzHG?_KhopF@QPCy$7 z&u54|Nu}^0t#IQ7d%Cs=p1dm~n21mI4D-CqKu_`ux=~>U^!@#VFv8?t!vs_we^a@M z3CUZVFAr8fuCW`rKvIdcjPc7Z;`L`f_{Re`bT}cbjO4PFq_E&BY77uEAw%C|trXO3 zAi>J%F+CuF`<&^{;xk?E*r5g>igQ>h5xR>%O~s6Y?C_;3IA8>T683{oW%)v+l?6LWdg9K`8kF&A&WS zI$nfNN`TMF_N};gJR7?p3?Ua|X|pVmrgy6!pVuV{D0f;1$_Oh1-9rN`(Ld;w6fHO4 z9y31g09vie@ke8MT)SI;VD?vx(*5Q6#*e>{xv}-?;9%#)(JzNb2Rj?j4`=sDj^f!Y zXgcj{$%&%c8mf`N;nR2DtlYRJN!G4$3+0OV1|7}l^g8#J-4GoOMc6jqASE8`DJNBe z^<%FbGL_ZsONhnI%4+3b`)}=E`%kykYi?|Bbi0ktMsusxX}7mGTDzOOTeY2fz1G|4 z?QYk*n{-0l==9pK*ZuxhtGiw6?e1>YYul~OUh5eCxG`xQPwIp2aevsGOuCa{YtS9l zj{B2(r!gE&n$32%Gi=t|nCzqButT@RUK8rOT|aKOn;jmYwY61iZ#8Q>wT*V8Q{SpJ zdcAt1(`s+Pa_{iJjYh3k?_gPP@75aqPIs%m*=TNVcN^`&sMBnZdxJr9&~Hw`Yp4y=4c1an}gbMYXBGD;v4(Dk)EW#xx;hq?Dn^}Ha9o6+U<>6 zr_pb3?ew~}O`1tI`po9`W@CG6r_tM{OXO~&S8s3DJG;F)eI&aZJN?c^W3$ulZq>T= zT4x7(zT4l~*n-?|?J(cFwN}4Nk^bFwug`t?_RdzL*RA*4wffG^a;=*Y2{W3y(B@x1 z`qw_c{>#7k`TuM8_W$f`Zfxu@b)Ah}_F%2Kxw*UDXz%p4wrkB!i;ncSe|+iH9lNsC z*p=*2B#>1&NP0-+NCI~sOdGSvk{Go(SWCik4ke=BP^AMGH5L_BjGzz%yb;@ln26!c zFRXIboW{AI*iNqLT=Yg(+3`&9ej#mQCB~KUx(S|e1^W-VGz&9kd@!cBsbsz9wiTW*7EiIIRg-)Ydz%Z(tF{AJ?%RCcuR~my?rbGeh^n4suXsY;3 znaVYn;D-JS#hfvVW<#NdmJ&pPx1UZ)0I`U>0$o|)8us8&2ATVmP8p|F&D3wc3U5wN z-mEMBC2R)Iih$k5jgL(?!sabup~n^CbwYY?9=M!YA!;>TJkk;!z7#)THYh+qL={a2 z6&w|UV;&|3to7Mbg}BGhvB^-9+J?+1>PD_7*d+ z*A1K$6LHfl-9g)71;LJ(?YBC}<$Al;Y4*GNrCZ|{gmRsRz3qOh)@pZY_S>zu5c{tJqx0dZY7{Zs=TP=K0b)ZG!f1^0bVS@T6&f|Ud45ciM8#$h*fiu_4WF^& zBv0QgKQJU35tBrj1sL#L)gJ(tgA*mvX=@urP)eGeBNjQbN&-PpT89gyjJ5hROPI$H zIj=ieVik}pV6A8ZrIK7ipO|m! z&#bydXkQxpSARI0a6}Ry7`KbxtcAS**83mSAD3JGVmaqU3x`Xw7F&nFl?_W;2QnRg8V+ z#4sJA?B9@I&%eHTkQv9n|6ZxS;CNU5_~R}!Ik%Gkc#tCX<#Tt-5esuQvU_d|zoE7- zwjQJ|J6X1b`U9uUEQbulEyc8F&?Xrp-0*2#)aMGWGRMA`4wK8;_rT&STn#QVJ#XvbPjm_>hK7)jRRFR z*0hDnNG6CD&jBlAK^Oq-u!p>}2^#lwBV=!fg?XKBd6PVv(`3P37JcO%7U%z1DMc0YMxh`wd>8FVNT5pY}h zrYx)7zhM3lsEf23zsmG`vaHgyv4>1YSgUclb}31u2O^6P(P3Yv{-6MiNY~f_&Zxms zri3J>U`dL=h;|WVJ$_oJq~vaX@CC6lBKO&X7HdW#l{VED*g&)CnOLjC%eA!aGN!q_ zp@J1e0IKOnD6z}N=$I|01yMuPxFxRV;3POH%X zCj*6HYoH$pS!{Ot_qtoNR_k@Z!mT=Uc1?E*Ig(SjGKX< zSSbeApmLI=04;UM!+){mJm|D6(NZ1S7zVM#l9I}IxmK7m1%&pA4<4qwIng3^M2d~Q z`pD6sMKaBK>B6c4kEqjPhA;a7&ufscZ;Lluw`i zl?j+uPAwB>VkN{8=dTixWXQ0~nRqRr&4BdT<4R=}SUe@!kMQcrNF{@%O2MMOdka3u z_p!)g$}0=d71?{)9P-Jve+gAwpLxk83j2yE z+}YYs6?EBg9zK?~ks@LF1$t%e1rEtW)bj5zh0ka$s_Z*zLRtZvLt+B_SG!XDx{Y2d ze%rdnBsRk&{_T%{VbAL!fs6*mRJ%{lYU!-YI`C$zTD<@McUy<`{aDle))^>B)8Jci z7+e5YJ%LJ zmX>)ziWw>?)&X`Vl^icp$c+ZkmlwD3R8~_^xqXodwz(*aKZnu))nZDru#5SN%?^H> zNoxR^*J+G8$L(={((etA`;C5MjAQ1wcigIvhvP=CKd865qe*`}Xx8gZQX^`^-l$d^ zbZW!;Xi^_{C!|7*yMtDfpGW=LWKf&5j~($@V%pyf6cVZv*d&D+1Svr-Y?Wy}zdT<3 zGP6FYc4ze*QiP5IoY%e#P!lxy$AiJ3*BuQSjp3v>thJln-h`*=)+gk8)CS{jtHYBu zhn)u5A>ICvOpX3=w^g6idX09gF=*n9t2K@r?J-_7Kvrke9JE{QNwe2&fZhf}{9w&G z4VJr;MpGWS7KG%a*6s`^&EsBUT<_O=^>KgHp`I(OCAlPmX@Ik1oJ!n8UNu}`{T`0B z#)RSH25Bs#9?_xA$*3`y99y)+?m2}Z;nIpow*ROcSu;YiAr-7YLCvu*6z~49LY%x% zFgc>gP*<7+c6>g+HYIIJl(MohuRFR_23KTPIYa5iRkYQHK$5_MDU3sDauG+bBH-VP z-Gq(Pj>Ikvmry|0aH)txxez|H3>kM8alest0r+E5>d(&yzhb{A>S&C*co-5DS8vwl zjm)?&5LXs`lJ9;Q^O9GQomveqZ(Yw(%Tf?7sx%BDj+qhbpw|~c%;S4qJgEmkB?f~P z*Z%vy!<1h5mdFJn|NW6bSFogn%#4WU5@vlv93xK^tN8e9D(_dsHxs{ZpVLU`5r0!- zL$!W^5#?p#=Yzx#3~%vwFq*t+3M;UZ9Cy=vtH~%2OyJ6N?cT3beDVL<3#rc`#65;x z>Z5@e_f9fwV=^&$9c^joXe!GAf*pBi*4__iuoeNlGP!GbdgTuON(R9PngvWn*~E!Oc02Bs-|K zI{3kB4cr}gRQM6EbpvmGw_j`3aDrg}br2;az;*lGW}g%{q6;uOam4gny+*%@2d04! zrcsv-4W?`p zr%k)V&%Hjv4)+cAFE%k2Fb|5oijCSL2%-7FGMA^Ug0lp~p-C=?A~>`&=oCSeCK*RC zD-RF~nVNuZ&~Hb85;NWY_+wRHV*0`K&oAlwK04F28pV{A*P9@j&M)__&-q(4HXqiu$`(;y3m_~}qst)5aL+ax!(8+BA!Z*a`^7`DdE@o<2qAGRmmE?TYI z?l*b_rHn@e6%QK6$AjLOK$KQ*NCsuE-5GE<&_Wm8*sPBllQ!9wof<{_+XRsGJN4eA zJ_0!iPYfFML2byxwQ7^epfMg0bu#St70`0r9QKAS;xZV2T(1%E(&jXX+L(;GlRiN% z^-jAns*#vE9M*@&HMo{;b9~(EHOGxnvvrKZZxIGFZgqz3TJxCwUhi>O`ketuBm;s~ zYWOKfy+NB~&c=vHmEoAQP4Y-vtvvAaD%~2PIhP2bhs3EOCob*Wx?H`W`v1!*>3}xlt%x=!o-ngm0ilW*= zF(JwBjK$;z+4B4DM+sK<&&}}0ZS|jAS9O9v{)W| zPtG5i%M-v^nZ**pcSLqn*o28hPFkm+zNM0~>y`j&97(K&WeFZ;QdB#=4zjMxc7f08 zKxQGnfRLop_WKBtW}kFjq!{_UZJ03RV6(>7k>qN1NDpGKAYYoSGmdFc7E%eZ*>3k0 z7X@twj%yR~!wN!}akqM_SL0w1hE#9V2^fN^>#|O*CP7K}Ql{N#H?_{Bf_K|sdqh|rLxzwhHUt`yiR?3LcBaYLhLP=dyDUBPSx4qI zdpK2ks7#^^*mHdzNZX5u1wMv0W1^u)nCX89v#n*}ZVIxVN5d9#y}%gqQh)}TbhNy- zhnwVIntq#?1SLIaPrmj*L6()(tID4_bhCKwlLJ2%mQkQEX1OfYuN4`=lNQ??! zu1H^8zmvi(De6C#C|^Cq(KTj_+Xov{d2$^AAhG7<->hn#o5&5b5|`MM3AKs_bAvKW z9rv;MQS$^_fNXZy#ws7NYR_5#i?A1b>a`-ep6`DJ*Vq0s|L4Do6a_)!BH;yRKlSz3 zeE*|I)KH`$7^%T>3(DK^8LXPb^v5@!FR5ofnJ87_k=|yVq1DRv%gT$FN0puJy`$=b z2eF8|zG6QVbpPXz2M=K9WiGBh_~J|Kx-a?H={f&oD^|X|^Gg^QL91=5ZW4(?#EyO9ZX(P6H5|}eHkZnf=>@~hN<}7o zahGg8edQK2w*>duMoO0H>?7X|`@YbY;E>#C8(971(qsCGihEAaqMdJF>a@r*F_670 zJ`X-~H!(6VZn9H$*HJ0HVxg3=li}^eivz(L7vce7B3QqRR6r^HQ!eHIFUs6rN#tg7 z0~X{B#D-^|En7XIGDV{qzaFz#3Qj8u_VSlxOYR77kzBW3o{#*S+QP8975-CNkpDiz zM_-joX#I}l|AQXCFfsqavlOvF1zEJ7z3ke0eSsae>~U_DLbn{lSy`l^;q?8tilXAQ z{wwlm;U386aL(AsmlCz{uZr&1A=x;%5z<%xSLN3!%KqObxz#AsA;iCZx?Iqel-J!D z<-Zd*K8FFlOM-h+J)uLXh)H{G9`;~Pb(Y;KE!7`?JO&FXf-2<6Mh%;dxC<_^ktF6$ zA6DKOLQ+;`0f$a2f33XxOXbvHkh4URv7V|JRknfCIY#+NabS)4^(X;RND;Tihtz79 zZsS+JAbFKJ_tqz1fd9O!Xa)O78V8s06E^+N9sf*apOTk}d)t)GQkQ~~!Z~?_Q`{f8hMMC=eA>K1!4&d2Q6I*_)n)S+}ATR!zM%XV>b7G{R;_2clx7v)te^8ro==*~Oz z#tZMW%GYBp%$cNEegyUgw}siH$P0&&liVg9S^~4A0+jmxWb$@$xeD_+zv%)287Y9&iu7WY%=S+M1R1v%4aAh@#&p-wz9=f0)B;mKRHCwAC#t`A+;HAD&c3 zusNpYD0o<@p-E;eN_M2S^V_Ai*B5rLZz|?T9k04~@GT!hJ*X;v)d9rRu7tZ`(quQZ z8)%ixz{{rS?{EKsoy#AXm5hhAwaA9$TnZx#dubM)8=W#YH}OEDet3ow$kw7~TFI6o zxEo5O&(eF&ZihlPeN-jS`?(%?Cf?S7Kb*rY&y>x{yh^)MTHg1G{Ar8_M?U<%Xnnr8 z7$zolNUbvDiS)K<`!J=Ml$cupz2XIUp$K@@%Kg3e4^xoF|DTCe|9d^+4t=6ncfL~k zV^xFx{`epBbCHyquelaIGp%MdCPi6i87ubj7uiB&6MrAiL-~dM+e=IQzkcgn;)Z?W zE5$GWe_SjbjPQd0CicEKqNdC5x5swyST>YPUY%^5rK@A_s+Sy+srzFFn0^u>1M z(reM4WIepeUBGw7bKvi0Pyr}8P8iP4TE?W#yVCv3*B<zc)_KpnAIHOj7|=zqXJLK8ZJ28vT~Xwarxu| z1(i>g?bhu1Fr;}l)pOs&+^?-Exm`0iUDdsEl5j@Cls+YZwyytd?mXFhQBfzjqn$%F z9ISk|^OIe9@O*D?>&KHl${c*RdGh`C^|Q0@H};zEw@)UYo3A&2`{8V}@vPbZ_SLJ_ z)u&%4uXj4{KVNTuc>Da(^^~ncm#|{ATZR>*-?dx}!-)(;S z?z^k)`sI^P@1C@t{dzVU4~DyE{gaz#KM%%@;o;}$hu0ua@aHElFD6$Hnm@m9-E4QB|2XRYdU5pZ^7C&;-|yYL9v^={JQ#Jpe*Wt9 zzIFfapx0E;MD#kLA5QC$#)-c-X1_TIp3c7qOr00|NVL1MG}NmMUZv*aep zR`0!cCr%Y(OHQ*$IoT+tNJ)-UHf@vaCi}l^LS=A1Kq?p*NVB2?+B z!Z!!vmacG8pvO>CnD5hOx8!H5yR>?>vCLpDv3BKlhn$uwPoCNl>2Z4_z8Yh#CtBWY z$!n|2$qzNx6vsjib3vm$$y-p@*&XdFMGppIfpTMxUK1|Q$NNi)qCK7F9z$7GaZYwo zr%oG*;#K02Kx26nolWnEp8x2iK*mv8Otb_Q#sT0^_O-0Ul?Zptw(xRovYHPF6ip%)HDXe>b$nxcpzIt{ZW_HqYHQ1BGH9wKdBwvxI6uRXiHzOg>o-C5L_)ZSB<(;C$`TEh`b zlQ&S>RAJ7c{s`6@s*U!b$z}69imU8Rg%x-br#QdNUtaC1FDR?9xQp`~1)jDfueHL{ z7SYtz;q^wo=De0pcU57xyF5Qu8mRJ`gT=);@p_f9qB9nWZq0rmxLJvhYPqy!~D|$BoBYgL9Qhc;o43t(=`MycnX>qejH7?9wdIX%=X+ocKvE zrC+eTU$v^tXl1}1Z*0AlRnt) zvDO$PJ-V*iI#+2$Q)w`+FEhq$t-AdGxAH@sS@>}Xx4KKG?9!nQ+GlmZqY`+-44!+) z(%>~YcxK9lm+y!=6jk7-?oB<}O*O^Fcwug(T^ESk%41dbsyb7TFH&9aQM+ndi#zP9 zw*RL(;BBPhWH8bRnk>-;dJVpFW-x1vSr(Vs;WFUiD?9*2UEsj?Qlr7rI!jfc#T_sd zRK<<@hN^IRTO_;4-eSq?uJ*W_t4mw*jjqoX|Nnc|NZF-bpkJURpLy+h`L24S!{ew8 zxeIbUmE~c3B&;t8y6Ownx}uu;`Z8;k*HT#%jC{^#bJ!cfLrhuX%V1gf3;=(X`*b|X zb$exAm#b21ZI0Il>MR|;HdEN_t8Huwwv@FL7@cvWP48_liqzy*etyKBxyIRg#G`>c z)&;$dB^^!O+PpwhTaLe~FjQVxnydAeXx(+idF48dU1!NQM^wII%l}$gzvI(^AMvX- z{kN4syG_O6KzDUzu*@AS@m4nG8e2;IrG?R`r?JEr z(bjf5txa|RYq8XzEc}{G@Y7<+Z$sSbEY-zwboQL$cAu{$+u+VKx7CE&a}2KR)^NGg z))6c$jt0Aon*WR6pgW5WBcJJ}?3li!vZACh(A5z#)dyn5T?Jlkf!5PftY{4_~H2<*dsSk1*^rclr%}w!ec~4ug(_-l9Dk;x(>kH~s*(HYhyqMPCT3D^p zI+}|BlMz zE~n8c7F5t4Zt18hG&%xaO+{mctIlZ)bTxH%HwU6QF{d*Wtm!Uoj^ZaIRKCwOXrxg5 zh%8Q_e=AcvvQUjxg*AAMjlQ+h*i%wb+>vW;u*A%bs`7%M#Z^|>6tbF{qn4JEy5i4I z!ca#Re!8qxP2b`*TB!H2{;Bu7RFM{=xiRXk%E}3HaA*@_n_5!TN?{Z@oZhA zx5wVq<5n3R*7p3|E_Jc>^ULRd^iSP0Qhza$mE~4k9JHR&o>)gggS((SQc&Wk(->Mx zi{nvyJk(KKt%^GRwbu5}FQfm_KYcstQ~x6kC~GTs`gJuCx3#jaz-%aw zuMF4fi|wYoc$urdw6v|EqNX*syCU%Ud5HHTh@V=b=bb(i&+@g6%pFnta6`~rug~f3 zGPjtFh4xrWb4$0QQ=^LL!}SJdq}{8vw&;v?9hQ#IPsnhKPmMc2I*njFts^tMAU~(H zTN|&zrME2>4)mDYBRQVtZf9L}OVnSL9qTAD*2PL~wXsga=eh$wliTBV#9Gzj+cP8G zAeJhgXw}f;j(F%3mvgJhgrB9sqw(TM;}0}>t3CGmQYVhz*_|D_XvEy*?$H?R4RL*G zeRgw4ywcp^@mo}%?|*zj9?xUBT+QlGv;+V2pXnL1OY5^3Y79A*)g9haV`GOqZ1PqV z>olfFowWy#I_BjSI@)?P&eG3M{Qvo3v;S%kossZ@K7dw}gCE=Gstu-ao37Z`P*~z{+nuh4f}vlY>{AnL>q1=ClH9r$ih zvx}Nx7+GJg?s!psTYjx0T$SIR=dX(DtGumUjoI~v>|os0RhQe{QeRgP)2s5I4e)2Y zi3NZm{!F(Nw&jPa3#%&YYuckuQ%o1vxpny!^%0#n&{I%t>uK})OQJn_?V74*-SQcK zaYtCV`t-6bu_=MsjarOH0Z2wt8%sGcwL?+9J5vBIMuDH;`(O`_Os=D`e%gCmPPM8 zKv{U0H_Ph8J9wNP`VN5Dn)A&*mDN^M+paPD!`_bSsL51RpXcc=bF_H7j5<$glP30C$hBXSXu^4o5G}HS=t1a zmdw)hEX~Z)ma#N7OPj}1X0a56i&%=4rOad}e!)(B#7+#dV-MM}pRr@Z?7(-~f$y*b zcbIfKlPcJ#rEJt}mc|)RWn9Vl^Nf#Tj5Dd0NhM4=n(@UfF_p0tmZD)&q)VA}DwAe1 z>0BmFV$u}G?`}IZM_peuY-ybgXzJFWK`+m2M_x*k&@B8xx-uLe>@xDK9 z;(dSG!u$TZnfLwY3f}i0%X!~lR`R}&dU@aAYToy774Q4mTHZIjhW9;wo%cO@jrR@h z;(Z^#!TWxWIy~9U`(Iwqf4XBMlWI7ZrE}T%=Xi3$d@h$sAafxG$YL%}n8M|9q{)*Y zvmrX3Xfg3bs~R$uCoUWXnFN{16Bi+E5zsJ(Cz_Nz(L9eQYNU`f$O4|IodA(RG(1uF z0wjwk>c>Hr^2FKDpDN*r8Oc2Hh3Swv5R~%*=ZP=EZVckj&E|(;>5Xf?*1TK@xd_S<4gj6Co3L!UE_mK-%1e5X9%EK*sX~RTjj^6K14C#_@#N zG6--Md}Nv+(94|66JAW>36qo%@Nw`nVHpJRlmwnIDvc*dNAU#79G<{65IIj;vIL@q z%!j1#q-D!^(qaWqvQC4{g_t2$o@7dbOolwqlgzUr7KolF&6YxD@uZAV5Dr1wBsEWZ z;YFVGBJw7T<4L13c~aVF2o_!1RGyR~<4MU&Au67vfUeBMlM3wh)p5k?`bn=uV!( zlc!`sVEe)X2=;{+Ch+8OV|nuU84#55+$0G6kJUkzApQbR#vDtQYa#HLFdc$&WXTYe zDTBTYx-#T*4nY}Q4N>uAhCJ*c$;9m-TMxsW1 zK4dI}?8ZRSA>$#>L$Lj#-b{kJVs&6EhCml>WIO}u9D+0n_FoCro!apN1UeF||E16I z#Kjpv>>E?CH!Q{4T)Gf47Hb1*ZyDC}QpV+(*k2}MPgp#Y%O@vuxyH&9GO(^@EBMQQ z`8{V?J1liNWEx}^Bol(Vr=squXj|%R2-=y7_MvYX`c`ROz!k}6u3+Q1Vq7X$ELg}D z*4aEQ`30UfSabsEQh}(;80<}&(OjN} zJxGU@k~SZE)Oaq(9+EJDaal6f^+F5cGkH>K2A5A5%@d|zea>5iv`JjHAPa4Kk<0je zo@_C5nHqbiWImT=p?&GdQ_sQt$GjM2hR+2&f!5hP?3*SHm#4tTY}7@EzR@YTe2El$ z@FeWJ&vE$-%%Rz-*mtnMnXp$UF5>b9^ZA-TeayG~=g*l^$CO5n z)!|^ zuls_MZ~lUUZ+ZB8`1}*!{P55G<^TL0U-io$U>A@v{Zyu1#H83FreoPo#qys9oQBKF zcm-E3!=)etTl@3LT$wQ*TL8LOH625OZk&j%M*0GmPoKn-blCE+q?FSaamA9^Trm-s zkHwh63o%U-=W+S0$y}K-fh$Lk;)>a6T%p3{#DM8KO^?kJOFbRi+}ycbsd$kq<|n{b zhpCLMZH$&Hu?;8cF@#bHSE@06rsEPP!?u}`$(5F+TscO<73$|PoY;OQVk^vqFE#AU z2ChuYgg?kKTpDMfE!Ykdm*7%57WKAZDk&#$`B>P?G1aAb1)qyFXM@$ zuuaRSU<*#fGME7$Xy5!9(8u(i0Q;q=Bc@Z*IMf}}SNYuYT#4;kF=i@POu;37@kE}q z08?=G3#gZZD^ioVVk|D1^KdL!jJ70CGj-^rSzMuk@3{t) zhi!Ngd`(J&&OEN1FoP>KV^9t*G4rqlu!SnD@MpkfJuQJN>GC~E%9YPAgn!g^!5FSo zjfX#M)fwoYsbf$d4Oe2?D<)uDnUBl=C^fbcT*4OM5@n`yosK6>S-_QAIogEfkL^yb zQDF&V*-ge$os!6t=ELujRFt;}<>3;Pf%2xJ9~O+}N(1K1L@ifLpU4%sOe>@rsBb3v z!om|LVhoMw=ULd!RjA8?WcWf~8m4o_%;#~`fL;pHreHjAWKpW%Q<03izJPwgr*gjrZ$`#mN3X zE=`jc^Q4)$L@UwH*p8H%*<3kl30F+TJY9bTiX-1r)PFXP0%KD!_i<#Jgk!>sW4SVO3i=+~ z>fFhwBgR#2K%b)@Ccy79_+O~z%7i4Y94Ci=%wG-KH4&Er8MaXw>M|8;hmIFGRw<`U zfGyfT741WxCTcJ*mtc#-mMWhzA6xl!l#TwLn$8s|i?OYv567!8k1?h*(a%Y^bWdJ_ zc@KZ;1k4SLD~^ZC>6l-W#$$eC9!;Lal{y?($Ds{M^eG)ZN8wn4b(EAv#~qA=67|*M z2&2Y0%|JPNjCl&y3XX3ITv8OH#&Nk3^M4}7cmj^48u;TAvDR>TQ(-?z#&{)T9phLd z$9^DJVGGC6HhDri+KD!1p&zF&gkaof&frPZw;Ie>EzJWf)(yt+#SF-ET#5Ci%)-1` zfPG+rjw=^q+?Gz|Np1#>DT zg)7p4X=o3QR0>XGJ%KCI(T*|bqtWQkaTu4mSi>kUaVqwSsaS^=?3=0BN7FDSIQAqa zOvJoL97m|c=W$7#i@8FVNE7xTCFbxP*iXYTYYf_|#u0A*M4tRSj)C*hMzs-h3Ydw0 zUWQ90_Ku`w)6oZ5%L?>)GUi+g`X&W^!f{NL-j9~Pjk2u^;4>q=nu^O z`H6^QAIY*}F4BI3^o8h~MVOb%u-^4ExzdDv#Dr@A_5x)h=8+7Nfj%9>A<&&*;fi^f z`)c%;0dpx6a|+iF#Vm~RqS07C82hE@8=Vz`eC>P)=7n}L<}~^aw=@dnZ1gGmH6e>D zGO*80LBCJHC3znDY4$XpI1{%P<`nD&=+_in10-@>2XL6etyZEOa~6AcB932)a-?Iu zBxc}Rfjv(?Ps`<5m{*y&zMyQmW(N8>oy!ea7q~@{C*w8@#~XPf#sIf#DGAtDRXCF3 z_CStfhkX3=e0|@?kS9FFG8!U%WD#UMWHH15nGMN;%!Dk1EP>30sQJCfY@Uj`rK;wkKdq2OkYzk| zZYocmGm}YQVA45s4o{mgji+I7(hQ?`nh}#>Hs@&yoL^HX@liTBT%>?QR7{SFrNa4y z49Fy&Is^B9^QZ9C1ydo@dCDAY#xrqxw`zFmC<9MTMaN7>XU)gJ=+KEc>!&Ce@=;i< zxRvH9W6%lM6jCzK`7a_L8+V#!DNoLVEXHBSf{Ulmfp7WWaZTl<{?-0{9JJ67ZXnTs|B4ZArec z`wo!o?f}WI4@mmol@y8mcY&1u9+2|y0xAEVq+Iy_o}@zPeIH1AKLC>64}p~NBOvL2 zAgL3213=Py03^K+ft3GaiCv`sMB)&74}qljGa%`G1f+~XAn88>QhSCZF43OH5|6NZ z0wlYqK(hN7NcumQG>iOCfRz6WAm#rONcq2#vmG-11BuRe5d-B zVxAC|fm40U!3itClYy1sgjJGi;kQ=OA+Qdd{MLgLHh`1gMsPyAq(fMEPLKp*A0J|kkqJ2G* zxWG7gBGUg6obW5)RNsFBC;Vsh>m=Y_^ef>$luLL9V!Y=J+Md`sX*l3{^^STE#f80&@bG3GJh6U<}6r>HOW=f|io;m@TX z3%gIGKNt85=@p^(OSWC$udp7-?$_{3_5B_E68;|Zm+JRN%wNJkNxmu4|1232`0uC} z>HP=lMfev zpUso}L7+cCbsKa_7)Ju+1Kl9amo4_@E zr@(dmRe|gI>jF3Mw*+qDhXiis#{}ZfFaozi59^8_M?T>ReomyHqN&knk@id=g5+JxtDjQ4r_!9(f z0fC9KiGrudUJ!bzGJFJv^ikl1FXH1ULaWRu@+*O4SA|m^`KgiB3*I1GDEQw&pUV4^ zELYh5y{wbQTh=8L<1UNIa7zgOHGHB^_>K&>i@^6~xFrUD51jmeADr+9s5hm5fN}}% z%lbw71KEJU58;pWehhzvKat^M3*f)V@Ua*0r)USpPxcY&MK}mf>5sq(hwxV|!eJRc zVgNptJrVe^?5V(?%W(UK^iO1E0)K)2AwR!F`v`vpPWitEC;V4%?6~rQ7)E9a46OY)GGA?4a#pTZzKJ?!27^=lWocM5=n9)a4E0^*Z?d|-kyy7W1 zN``)NU-GvFeixk5-%Tkr%G)VF0)92+TLQlg`~dtrz;}Rs_@DB>n_7?x|Ea~P zHi0GJC?~Zvbs)75_yBkh_+$J}{3qZ)1^&zEnWGm-B%^0dN|qZqh=5izY1=xMb2&fnS)kOknn;9D%vmFJ?+4>9ju*N+mh8?$epX zDUgFt2bX~pCV*>!a&W>#$+u~Krz<3n1uAi_Bl{$r>j;y<$u0$)kj{N%N9R7mH1OHL z(cpw*z_WnQffJ6EKF6_c(#PSJpKv@ll{W#Lkj{amN9RC7ItOZibPgn(#OBcYNT1B+ z3Y;P-5cNuzcm>iq5c4&CDy}z#)3BdXy)&_&64E)4>P_cB!kOThr|Gl631@>-z2|@v z&IQMKrOyK=q;nzFgU*G7S(1CA-U}qZ5~#*?liH!db(2sFPUYyp3H9LAPX=&8BhG)6 zZo>JG(41}(^|qwrFD2ks^a5}~8#t9y2u@f8PURGX6PDomLhUNW^@XquocgUCoUlS#%4u9H zrDX!Ez)7zfoUlexDX>-&7FY*P^{59Yr1K{soj(cf;8d?BaKbO9H;I1vyYw##{1Wo1 zo_~*gLOOqv9i2Z39pGf=1SfP!#knrsE&Za%_ej4i&?^LOPGm0MdDsFal2VrW2en3Ql@m;Dj-$U-V12 zRNObF_ecYxU*pmif&VC}r*m@pS0r5m{|TJx@z3Cd{|Dz?>i^|9?-H&6r+)7RCtL|m z&2u^mJzzJW%`GM><BqqdPo(b^^*x!sPv9whL`nU1 z8Xr#*o&hI6XTb^2fs>!};Di^z$k=i34Z`idOrjw z{1G@Z(mwzvyr2HAs7HVLdjbcfdxf6|(tQFy1SdZ~1}FRpIQjV(aKfL0lb?s+gg*nH z4*Uq5a1iT=@DbJ#;Sf044TBRtmYxyiJdvIi_!OMV`52t==isFG2{_>|z>$&uOK`$p zflmki8l3Q7G4ILlH<+h{zXhlC-+>eU9-RFA0i5vPz@eD_M{vSF;XFK6BFT^d#{uyH z29hNi41e_}QZ{$UY|{TVO6Y+2w%~=Hq^f^b3KcUxXOx7iWmiMKemk zNv{-~unhM@q+ban{VK#rzdEBzU=29w)q)e&fm6Ne!3i61Uq*KJ3^9*0z6d0}F99k4 zA8?;V{=W<)JqKds-#(S1{vA?^VoW!q+g53182cC-997 zmB3vY^9AnC$P&0GV}ZaoG2==9EsO)evfx*+kCEL~AlY35(s*76lHE;wEl*ZFCI-vFol zZ)JQ-@NZ+EBKz-P{~+uGlK#6HBlG4xAkDkGK(f1sc}3;F52W(Hhfg5L?)%`B{{cAR zee4IM*AFDU0U+r;$oQ+kp8(14zW_=9ro=JH)V|;Hy8?d)PJaH7@dv^G4f_h| z{}Jnv@XtWf|Bq=~xkVzG_QtgB0(VW@A@KCH_XWN;?S}&IPW!&VdzqXtQ_mStzhbvP9sQGaUk*nPmb)c=C_zS|v*bwq?2n zhBG|^+cP@^c4kHdMl-tvc4x)}_GHEdF38iDIF*9u&pxnJPP z%%cKNWgZiFI`f3UGnroz_%QRI1pX{@o4}7UMSo=uW}X-PJf1Y_!;3t`v1pY!( zqIq2+(UfY+1eR+m1XgOQ1XgQm1lDTm1lDUB1U72y0-H2n6!>?VFA4m6%|8hIvc@40 zUuqWU(Rc;=G=722nl^!9;2S8vUDF|W1W3G76BWD*NIa(L7Q6>YJg)gi!M_3|{!f|$ z!FOo(2z*m>Lf}cwDS@XoX9S+roD+Cnb3x!m%_V`CHCF^))m#&JU2{X=P0cNVw>57I z{Ho?_0^iYmL*O?x-xBz3&36Re(cBaGK9K75Jdm$`~x8I`mT>6is$bOP05ZDW_>&t4_K24Ly9YvW)y?gsEI@FwsU@b>tt=+oyw=ayAHRbQ{P=B)!`x5sqe0U9Fc0JZ3)_sR;)6JP?w;mIB$M;Ef2nfr{iz7 zN+aC;&D;E=bB7>@rG9BZ+98cedtki=vKF!daul)>vQZk8cFW#fNAB-llP*d?vG1;s z{pipKy|Vrz0~cij>kxdnmSP(QF3KMs-1+d}O~5N7@ahQc9)W!$uzv(jjKCQIhxa`^ z47ybid2 z;^FnzM_`});jP|>x32&;jli}Mcx423jllAUw=Y5E+{0TiCqTn)pMQ9Jxsm`0x0fT~ z!brk}X9>^Jw+kn?caOln5jZ>oCq`f^3SjS_XYXHR@84$MTfx59%f7dPeeVGK`eCV4 z>Xv%gxA#bW(q?IkG$d_h-#H)+OFN}ec4sTQvyI((o!!~R?(AmY+{o_iV0X?)yV%|H z?Cu42_aeKuhTU7s?yX?&-(q*ROI_^FPWJV)QZKvn7Q3^L-8sbW9A$Tou{+0E-yU}7 z6zfC!IdFY8;$zIB52t!I53Sl>q0w@DgjeOp=IHrBVD z-Mz{p5q9?^yL*b=J-(SA;7?xJrbpMYu+UYel$M zg!@FeUxWulcu<6gM0i+)M<~1{^lu6MTSEVq(7z@0ZwdWdLjTr?{@J_NWOvU|aFXnA zU%q>dA%f}rUN78Tq?{`hoTluzscKW-efizxB3wb?d%f)LRz!A)#2xQa;tonYi^#fn zmrK74KR4mx-g*i)3qL4E{?YRD_@^8Jgh;rAe@Gy}KQ?U|TegfXo5rRsOZl4`B2tai zAT>%&QnS<|wMtdeCDJ+g;!a0|ed7pgZIiaMNQiZY*uC}a>xbC=t?d3bc7Hp&|1!I` zTxjUwHYU_{&`;ueu>5h<1gGtwtsR zS#uZbYL<01Q?#3PHz#P2p_hNO?gaiRM*txbPU9aE2=I?-HB75zS{>8snbyFxMy53} zt(j>pOlxI2jckrqGZ%rD0v!c<3Jeq&DKJrBrocjh6@gAOH|1|dBEps|N%-i*o_DXZ zJ15wkTkJb;vpdVB3uIFVdtayE4f$a2y20KJfD3~w*CovP*{bDpDeM*DN)fIW;TjRH z72$djZWQ4r5pEXY77=b0;WiO&NBHqs^7-@L*C^b0kitDTDLk@{!m~RNe$soA!kw!q ze3LwUa`q^N*DfOb#Y*z<=qhPGx=xyp zu2MaRcI^@=RLaomQzD((HMIH!#jow5_)9Ag4)3P=JYGTR!)K}7;oVe+r)#M#L%ZLi zlvfW?xc4}PyUG9KgSQb5ZGDO2>#reva(*Ah4++m3$j_r22M`WzqgD@{I!w8{DCN;j zD)-3+>eZo_sD_UZi5lLd5}&N4Ql6~6Fqi4HOs8WyJ<}PO&d78orZY30h3TwJuVH#E z)9aXC&-4bSH_AUbd-dZBd*$e&PxidV^d_b^GrfiBt<0cd1}!t_m_g4B24*lagNYf; z%wS;#D>G_jTJ(WTM}eLK0|iD3OcaVk$FWl;nNPj@wW~hiJ?lOP4F!rT)7t7fb}Q>fEHW;Y#3a*8Csj4HDTozQN>kh zpN@3ze|Z`i`Bf={E4PZ`(aY$Al{;v>F^Hm1;0l}?3*U%Q5igJE(L{MRVi;+fI0uBE zb#U?um5;{s9)U8P>=c^lxRtMwyWY2jCOO3vy9I?e#5it8>@`>nu3R;ehK@itQZ735 zDq^pT*xM*?k7yV=n0jTmFj@zHyU-6v*dw}bJz_{e$5SOnVi#ch=CdI^Z;9@}SW{QLh0%fz!LweZHtoaQget+vzz9Ospm_%Om^2_% zyO9{BVGUt9QW5Y)^AD=<1#%3z=#m{ULM~#kMF&$Z{O?5t0MrqKz2^~u_L&h6GR@=O zYceebItug@7$`7OV4}cGfrSDq0_+tcBpd7%A|$H>Etw@~$u2=lh6!4-Owf{Pf>zk- zgso24>V&OM*y_lZxgE?AWo=z7>|*W^YmUl?u3Z>jw^cs;+Nq)Ko8&_Wj|`tW0JeGf z{EZas+(S3FJi7S?wrv)6uvP~PIamw+Ia$cbd`?*lel3%Qy{y&CLO#~wWBxb`1(`d@ zT7t|QVyz(-3NcrRwIHHnA$>yVqjftYauMnhI~;DJice9;!V%UQVW9{Mcd^zk7V2Ux zsB4V1##kuET4K!E&Rj0$a?4#XM0svhqlft&%pYdWt*oVmwREyzhy`0&u$zVbEZo5& z_}9f^&V(-5gc2MSV)K6W5H@cFdI}5_7%4DOV5Y!AffWI5-V~AzZQc};6$V6vWQPF} zAz5NTL?~=^!d542b;4FBY<0p`Cv0`XRwrzA!d542^}<$9w(NVG*qy`d&PmqyChJ?v zzWK83*9SMAmi>DFz6}(tlKuL?mYuR+A6ma2!G*1|Umv;gGV^+wx0!i^EYd0a(ZwHK zrr;0-CuBdmJwi{(?!W%QMcMuHA6#Mg_p|#u*!^AX{%&@E54(Sq-9Ik7f9(DW3VP-D zk9~0S{)!RkmEGU^!4(RwQgBmte;WncDR`NJ9Te=O;1vp9qu_N4-k@L?1-mJDlY+ez z?4#fS1qUfOOu-Qfj#7ZKW%rL$u=9g!RNC9*1;IfIwxY%Z=h(mvHgKCgSk4Bnvw^qS zz%};ZAbW6_Jy^vatYip$Fo1i^

      VQl*8NpPudgl!)!GpzLU6BN^vT|Q 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

      pVi>OJ{zYsOd}{35P*ZJ8 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Ú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

      6sDw2#gO^JvpXBZE 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%0DmEcz?g=pFp$vfrR%(8cQ!e2Ecngz#CyfBn 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

      scdLbWqgYUYlAKH1?{1%wYN$_ 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%0AP( zx@<2kGbXPr+n34t(z1O~x$#1!HI}hCt`Fh2keFO3f??l%PLiXn42 zYPSmcT)(MhGu&?oP7Bgm>w5T|qV?DCKh%jf*~Y?|<*N*E*#QCn`=FQJqbY9(OaVfA zA4~a4;19rH^d89ns+$?-h$0q4VxQIl^Sj2-UZ^(TRjaS6weRZB{QlT+$e(0{|FPD% z%OBw@dYRwoK4cV!&CN2u@jYF0knydU-y!{(9|*4bPQd>@?4`@MDIW;T07AN)O?f5o z81UcF<&6RM53FZ;m*va!-zfW=A20QnH20yquQva+qOY#l4|YUOjai?1L_#Wl?nPF0 z%({oEIC;1HLgf2{S1Ki04NDCSn}QDJnoTTvH_Q8Wf-)_vRC0rJz9OAx7U3`ZGQOsR z6kVo&)JvBmC?5~}7zpX|fRr~8uLT&4E~VD~^2^18^1VJQ{CgE;ZsH`Xy~U>XZngQ@ zvi^^<{dfmKWz}kr@%cnK`%p*h;f{GvE8h2L*}hBhzK6^9gTnJ3DBFLL^L_G5DnXxiPB9|N8OLb`T*O#X4;BtVXVd~YCKcO0DWeU-3x z1%zE@YM)h`&x`37#_WG~U^AjteGqn0Ec;|f?5U1IwBA8i9B)hMBY5NW50cfqI3F_ zUOIPB9u15KLOM^Sd=zjzFc_Ve|DpeS@A3imb&P9&o7Y3=#rmUgJ=vpf)V0%xHXFM> z-w}JE%b99ILogb zAKfz)UK^-ycX07b%HnSr{j?XaI?9uQX@DF9`_II)`{T9tt9U7tdN;A;;0CY7ptQrQ z9kC4^^Iq-n{@oX)GALEaRF48)P(oJcngL2XpyGiCiLB&sP@30+Quj=S&r0gq?blS( z!ghL$YyWFI-Tzg5{B3Q}PM1oa(^_eO{yd0q{wm`ZRp*YC8c30dkx$ zM)BQE)7ANe*Za5kim%pZ$D?qomq=nWjzYpc%@=AvrE9+%+H6%U!YmY1msBH{R*RQZ zy)&z}OJpf4fw0d|p<|TnPlUU6WCQ~{RGx`i0ecPnY5l$(ryJM^F>A!)rTkmqOMx#|c-pAF#MEr@e`L^=7TtL1=@K1WdgBk(jJM>X*0 zTf3{GOLbEJdHK1ouH&W!^a*CXcRb#8FNnf~Cy0_{*P_=(mMrWv^1D}rkrrZy8LSSNE@~h8XB*G^08e92`iv5Sx6hyQQNE=Ss?QY7fvI=VUXO*VDvkD2* z^iy>fKuyfuTc8V*(Bignl5pKM-&6GN)}lT7saced1%3z^K6N$o$CMWV1LOFu3G4$x zd1iIku?yxOch~~4gdIAnPri#$M;H{LR}ha0Qbwnm+GlTNtb*$}HviMueCH^pvG`nTtbheagP z5E-*4kvdT}?J{;A zHkJZSC>&}NS?iE^T_C+hj`96qT!3R*wTVWSCCvpeUhJVmo^m_z)KO|2YzW4~h`2H4MHEi4VQIH=DFyem9T zqr4cn2nhSlrIhai!g#^qdD%&-eqnu%nsbz}=IMvfImY_77`N%#ZAm`hM%#zg`QaZWw52%|N@lCYOwf3s3aznq~y&upTOJ zrLT4Nlb{<3OhfePDeZU0f!f3-q)aky!+&LMMex3bJUi^4mr@=dN0$o-9rBuH{+4UE z0kh@@e0w)_9+>x_I&6noGv_c>4ILFsAPP96V zYRUMX`Msf|b|$=qkz1%Ac9OnOcTVya>M6~eu*?{-)EKK-6CTctcqlVgs+sWvGh+3r z*Xm`t(1v1?n%jJtKt8*%+M1yLtEpFLSM>_z_km47NXO48Cv5o8fO>zGj(zI6%iOs~ zABSd~s?P3PRUB0;aaIW{SZ2C!2rEebT2(=x67!Bx^d)XqPdopL@^68=fsnq>Qr-ka z97W%O?LGC4{`7r+wz7u_`(Jg~w~v~0cyHs^EYuH{Djy=$Eo$Dj%Z!$#M*bY5k{!R) zFqRqiQe%i_ZMz(Mh17M?{En5^-0?R>jq9WKbid)mu}HtSwTI~oYv<;^`K z+K0fv`6292VqZRL)U27u&Keb>3J02d%rSH4_)ZgRg7>WM^PZ=FY-`W(j{ocPo@4il zXbXW-U|$&8d-Z?M5kDCGEsT@73ZJe>R0CcAxOMM{whFi(2=Q4>`FY^|m7N;>Ijzf5{4sFwPFk*=2(C zD5#*KPpMGY4G1UN^(OgY0*moR1~Fe&{Xo&98vXyFUdoUa?3owmtM@GDJz@LbOZj2o zNg(7C&ryCE*Z{~eupfl|+5eG`#b4pWLBHE!<{ZE48HsdPN>3LwZ^V^`b%oKYStFjX ztjDcZO~d<3A1N(x(t>+xdKL&mYg!R0P@@>F9fE)wsInbZyny;xR z3V_~}L)+jDGqcm{f~QTs(uiGQq^>j$yh3={M7% zc3Al}_(`-Up?+LZ|Nmp|JK*D}uD$2pDLXq`C9R~Dtg^CXNpAAG%Y89M*nmNFhbn_* z?BLjn3)ocQ7%*J{LYx3b;H9{K*a?aZ!i zS%Tf~_lZkyj5!QV0M^CP)l<_ix$PoC`4E_lw;E(WP`@e=Os24(Yc z!18z~_MgDfBjdM&C{qGbt47%PyQTR+D*kb}HwTm*|AEV$_@rwQ|17R+grtjHwWxTS zWyO=+Ams#xYA=3{@av%8ft23OkY5`K8V_PeHb2?<>gIj+2Uq#u{j@6E6cqb|r;w!< zY^N2s(~|8payzBl=~AAt7Hkg^@u5{(@NdDAdocIMe{Ya(C+K%R?SUZAX```WLqPPw z^W4SYZochoF14lAZ-l3bnAl;mF{vw|3f*cU=PNl zCM-iuhzoHHNIsjx{@k{MhplS=1|Yi57kb!+_!}kW{_MFQ;`#HSPqOUd1L{HS_lx#N z$cnx=wmTr?&W;(?gJW^e1f+cc~#E(Y@*Z&MWKMwSc{O<2? z@cAb!(<#At0C`iRR^~dSN9zSbAHBeefg zL5+x}*nU;((zQa-?KHZbI^J60wlEPNsHFCt;pknM@Mqi|X0^h#q0{aQ^ID+>OLwgU z)e7fi)(T;)<#hNI1Xe4wUMS@5hCDef2QmW=$oS)hu3pC@JPULdNa^(sgm;171`S28 zzdw*(#l#Q(v9lYo{fn$@%Xs@O)OrM0uHW;wN>snMM2PxsBGqq?M7|$kGntG#BlOV- z8`L-Mj?f(uOvt=1LLX%3huD* ze(Yt4sdDgUjsW>3Ri*3e=*1#^mK3?|)jEVbL05s4{%%D0-#`z8*s&sO|IDq=iSo-I z;?HXbvJ*T;P*KO}*cilGr7u8c*QqZ4fY+@ zdUWQxF34!kBW}%yEs(rK=(Pu!s=U91@VlS^kkad@V!yT!bOMMS+5BbO0m0ST{<5?K z7OgvaCHq`N>THzvZZ~I+zMY1Z84%)m@&b_?d!y-(Dp31{X!!Lga-3nk9i`7k*|+(8 z??-8WG&RD(#}k4TRUbxqO)v+g+mBg`=zmP-#0o4IMhBI$60Ro5fGL#$gQNlj*KBHB z2y}tUcpaAt{p^I?NnA`eooC=)3UnBV9S4$!Kg6FY2TEtwJ;JSQQ&`!r z7hp|~aXYCMzwDO$L`z+Hb7E(+eeQ51E)(*0ApXJp+pF=M*%cMCfBc~BYI;Al44VQS zjp>FxK@#xWB>n*6$0a}Z*MBi=zaIGf(^fLhuFXQuCGo-axE9Z^1P!_W065~)H5pw9 zY$pp@$Bjo};a!@XljyeuAN|0{Y5OTZ!O|n+PnG4^PRsZ-ho-e{5pwJRjwSFp+dJ7iU#+D=<}RX@*T+okR)CK;c?@IO!-eh-^7vd>}I4;3>j z@0QqUj}`N}Jxq3Fe-a}~63p>?n*-a+R-uO;$fxx13xwYX{U=E2 z!LG#E3}`%PD0(>UK<$FcAJRVMOJL3sYB+Q|J)GO8q8s4QJ;m5mn}0{chwo_Ue<_Y2 z8|;pq_E#Zx-9BH^kh$QxwAhF8Tri)_P9wtiPh2JB?S>pm-k%}-D(KfBCGTE@3#$AY zc8(m9yjuxrE5iYxuCOhJFq9VDPS>@_nxG7Erwg~RRgLH=l++ARhA}r*aJ7JO)p~BXKqYCn@jk zub=-0JiiOHXOrw7lJh;P5W*fV`x?_wZdH*&#c-wB0>5sSv%a_r5%zFX- z&o_pHk4YPWdBemdPar9I`CxPn`Hi3|5!=*CXwhKruu(XMg}Tz z{!1nO&q_AUU;k?*y`qYBH`9Mq($Cqm|E;8*RXAT(WnNKLb$J!HibZ!b?_QSHG3#Uu3kqV zoB|yQVn?=Kx5@A7ideC~`GNYKPh7oj>GF0lRiHF^I7Z(u7NhSAw^N&Y3+MBG(S^5E zVf)crt0LQ~PPHm-7s@EaJQKF_1l$C^_K=Ukr?(D{k_4+Sj)spsk12s|RTIINGnufx z+k~9m;9uq26aQpsr-PP)RQvEGp1%#smT%)#qTbri{2|pH!B!l^`Q*_e`PZ+H6)O!+ zq*LV1Qk~xud^C=A`A8wW7<4R1@o^%;+dy%-&y|{AwBx&CKB?ftGrvf3fvJmk6PQJp zvt7)b*QjQI*kT9_l;gAFa3X9h%w&J@9V~p)mQgV^0@%5P%_)qawYLM75y2>)U0@pp z?Cgly*r#CV0`g(E_Y>W95`Etn^6X{2LeK2@^PBi|6zCryCC`LYF}DGftyeW)Za;cG zZ{<47#gs?utpcZQoQrcl!mHk;*gx0B*^GPt26|^rW;?TW&H?l$P%s_%aA<8Ll%`d3 zWwGjyl`;c+AL5Kp%|SgO{`KZc>>jy<&BevhFZtRFOjUkf1V6FyeytRwFcK2CA93bh&iO0Xuj8UPRdv*5{_YZOS~@NsdAazZfOtT`eBgDCyyY^ zXzwafUWS%W_~Z(wOf&G`hp8W^UnQQF%tyNMo@G%Oq(b{8UI*|J^4?(SH@tGN=o=lF zKGMEgiKvv=gBz_0t z?vVI5A^d&N?I4BUjqn4Y({9Qv-$TJy-*Y#jDRAK|(u_qeFQtkX1aPFbi}ImO8CpK- z8CLlavy2!{o5WcGoZPoV?jTmD#Occyjx6%s5~q1;p5&2PsaN83=L_eU4cu1impJw` zw_eU&Jt;w0Mz}-dw+`S8rQRA|errAVoYtl5R{$m2AdJ_vNm^_^lC)%739JOQv^{~X*2pp9Ua5=@|O+5UTQ zaYNp{}lk1hH!6!34`>JI6c5g@H=1CkMQ7ly$Bh1x5P`#%)MN$ z_W(Oo;%vp}Pl(32pg-=8A<3aDAF2bALi2i31@93I8Ae4=KY=+$yLvlNAv5k$Kq`AN*h zoL0%=VEnB3XxQ>IBe4Z_Hjlkm$q&4Q#2c)99^5~4^Ox5k2&pI&b;A#r+vlk0NNyug%|BY{ zI6wFK!1dmc4vnS)yCwv>loky`>$iUWu~{I0>0Ia#f!(kbW6| z2a4@?|d^T0YHA z*M0lRvl+_tV|yjuM&Kp5W^(1nDs=;IKmKgL#2v_^oL;|H+ac1sZBhR8>h*6E60gsL zmm9m&)vMRfO-a1e5&28U{rS6X5_czXhhp~(-QRWP^!mM>60h;dT>HH)o_8HapTye+ zyxg{fS$MK@X+YxHN9Eej&BDv_cT@L?^3mzR9n8NRy1%;*E;nbpCEft=I%T~x7~atR z+5O_RD8E*_U&y&)asJAQ*S}3jyxktW+}MMzoXnU`Nu1QtZa&R*edG0a+az8O@bXpe zncv$fapK3ga^=SFb@k`8#T) z@wVj`FYP~T4~l$hAMe)Bxvno6SVH1-04HDh((6yBBwj!8@?}SO{pvP}*Lp(!XwyVvka|dzgXl>vULO2Y ziH81CiHGlq3`w8E^*g6!x}Dm9#2Wx!LbiW{*(*aIUl8pA!}GeG(T9aT+fL4#eB9kk zN}OH!!|}SATC2osUgF9%m>$1Gx_RA9twZAN0A8NbZGUd2)+KQhUvtaDVC}+i{Y>N+ z?q>E#oUOpwDD!1*##Ph#((7Jo+7Cs(+zY&+)SF)-{k+4dT0-KjI3+*+CG^PglzZ7B z@pgOg2J`cV>sPvX!V2t@cneR>k6)RI=em{29+8f{z|B*+@Vb>+tHev5=Hd-j9)><{ zn$D-(=IoF-+km6;XO8O^uUn~gNj&@Xyp?l4skTSrbO1-ml}o=8`GmWbeG+GP{&4uD z+5w4^IwL>+B;-l^1gu(2JtFdZ5AZrN8;@rqFi4>k6yP?>yvmZ z&K{Z`zXYDwZPW%N-frM2edfb&oIFWX!X1x^^0si9i(q0%0?@OfHe*MN?iM!++w>%71PY=^?WO8!9v0vi!0w)iCBg4t?8y-I(FuY-o zM`q!v|cHwP>4U!s1=@Edz2 zUh3Sum2>Vl_Dh@{z)^DL&~Ie=6T^{Di2N8`l{XyjHzp*`M&Pu`e4oQ{NG6Z#3?Tjv ziMI!M9TM**tgrm?>n=0=Mi)=|jlB|Y$v1|UFNSIFF+5&@^h=yx;N&S^WcZERPLV&7 ztMiHH`i%*R*PT~9H>;#1UUW@9<#YYUHi_2>yoAh`Ij$EuSf|9<103ZK42JV1@?(bI z*e&svbmUEs+;8laIK9BhlUx~oW52{pesgGYeF;5g_>J06M0xAZA6|yvn2>nUwXQz% z;Wti^dA(cWb$ak}?>A1-l1~af?g367>d7g}U2K&&t?S(KJed74On-ync-=&;L*n%U zFF$gL*{od>r*VD0a5CIPtw-W*^WY7p$6?xW&|`+1sP#!adqcj`Ez?aLka!z`Hq)ZlTsA@j5+tgV`m+ z^a~-UuqFE>&K}^XdNQ~5Nrqdf4M@BtoAOn@xm&13e=71xFL0DxIrIymKj9W8B~If7 z`NH9Dq1GyKx`5Lr^L-BeLdfIV`YifxiKktd7r!u#r)H-PNW2c<4W-^6ru_&!QGrB% zCi2B@;N&M?WV(e(iMQ~gJmR4!w@RFzeByYrNQcBrT%1R_Tz63Gl6YOfOUV46+xk#| z^+=q(z{yWO%y0*_K8d&Dl6>h=%t9TIIDNp$k6anOLz8RxYXQh37hqy%INd zMc&FqhQrt|@p?RXIkb1f6>L04rAhZkq^6p zHin^n3c-jZwbsZZB&?3H-C zfR~WvAjkD02kVzO$!qhLA2S`t7i9hiUY_g(?l>kSj(uI;n?}Bzbl_#s^m($g~?qaKX!QV2J_Q~=@+_qavZTs;`IZsQ`VJ(;SJL- z%*1ouLTy0eF1a~h63UX zzL!Tmy6&JhAn|qsFCp`PZtFt<7JXIZ`_%XIl@BxB!KB3N0bYLW12K-+Dskes=1Z;& zcTnq)cw2!t6uE|9o-^D*txMwV%^O~ZJE-+YycM?%O}>NMbt_k|Z(qB7>DleoxZjkGli@aL0}>D4;~G-B4O=eZHfhnkyJhm+CQFjo3tK@7r!%C ze$#>RJZ_T~eO>4k-#5umImmRIw4}t-e&FJLH9H|oPT2+DDsff-N9E6))+d>6lhz^e zb^|Xj)rX2i&@^S5@#oHRC}4zaw~m_4vCYvCr|ky z)4bQZBp&wV&riM(=DpS-!WLRblr-kb^HU`i3=0z+o~(^aq+|$b+wj# zYJ67u;b6~Lbcqe9cqUJpl{hnT>Xg&jMYH?k;o?SY)j z!#%f78Gl>u=TJpODrQ_pA~!e(jN*$Im^gl#IU(@wdtR z`_;yw()@cy7c{L);_L!Whs616`&G0`TO6cY#@~hbhth8| zjQo}1Y4%E-y}-$FKI0x{zl?v$k8>_Z=D^W=qP+A1XDD(ELthyKMhS`2_;}87GCa$a z#OWF$&cXeQb*olpjS;cxu}$La1x|w9z%f|+c<^x|FOJv45OH@(ycJIjO@G6ZOO6pS zq;84Rmk%6|$I&Zsns>VL45q(f$>Z@j`Xvtb6Uu!$?a$-*r6^C)pA4$6Y7#U3!ilTfx+ZC_&mC7 zd6efNbk#5Mc6#sz^9v3>9<(o>8Vh2Gsof%9G(MFpKV<)S$`k39c-w%N5F+QUe)4!C zy%I-z+Qs>5?YT!Tm_hwA{x-y~@?XyC39l#eE0I3CfHM@kVOZr>j`gr)NJt#)hmn@& ztN9}yeaW#NhLe&w+wy@U$9fn}o5az6mMj0nBadsIYCRHX1#mhTFpjV0pX`I9rpAfL ze=YLEZr}|iKOEdH^5A(YhJ?gPJ(Gw0;PF^e5@$!AaFoZ=CUK&@`H@FuiB5^LF;6(k zW9gPSSTCNgM{`!cDG=niUWv2t=XuC)9?zv;;$S^IID7JeZIwXW0Yv+>T}p=R3SB~t|!IN)GQj2LsNYccb5nE!q+YBO3*bRh5G@X ze+GJb)i()C=RJ$Xx$Ew%@1=WDYYdb6b-!gYY%^;6sX=ubphnRYf^Ub{(3P}`eMB5b z*9Risv_9|3zrS@~6HfJMvq9PN4`p2Nti)Ms)~s?z^EM{Za|{v}Ud%@D@ZHhh$ok*I z#~*PQw50KKw0Pguu^J(v_5qi*$7U#yfS^C&#oNg#wKp&D1tiRK2#u$z*Z&2+! zxZVa*eB6pKqilVs@v?K)G&PP%^RRBy>a&{`Z&=^H(bd8?65{UCj>N^In~qv@_PLr< zpc(k@Ln8G^KK20P|0N$Mu3p7B(fTC*iWl8__$q{N1l!I_sT_lWbI)Vf=jRj0n zBLekW^tU2^>;+bWLu;Dir{X1-pD_qe24(Z}&PtI_4$M#MhV_!Aw>TGmYE#GLoW#Hh zjFK>o(MpNkD*4$8EXB`#2tNvX9HjJv^-&^)pNRE$6J% z)eqQViW;ePNq*wH_T^_b?kRqbK=^o2Ha|nw4_Mm6xv(rBb^KgE1<+3^oT1%iH>q<-dVdpT!O>geelgv4PQ8YTIPekk%$ z>Sb3?imzq3r}$cn@P(jkzJ{zPu(pLVWIK#}RKWQuQu(OJ%}0`-K47W#l=)kK!S!E3 zil1+f_iNXKlwMRjpso*`k7VQBLrb*VK=SC2xC>v|7x!G;`|7xduaU^z47E$iiMUge zhrb|P@v2{24AR9t^VZk=TFV=L?R$NGerMpV^}OBN^4@v;y!B;qo$y`AuOGbhe16WB z|G4(0%e0kin%KEz!>Uyp9ocU_r+;XYe)CSsPsi}TFB$yw=Qux|^r4Bmm!9D}8?!2G zY7ooTeYQQtj9aIiJZVY8$wkMR)_vrV+4Fx*ePiu8hb)+X{LKPEA3Sd|`!X z?Ppf>hLJY)Z+85D_uE}f#x+f-(Js{%7*hNHe4$m3-8W5lEhV=5g{6A#C&XfQs)G-lGc!$VR3dkOP%tL!t& z{-GfS9)I!TX|u&EEV8OO7x@F>m>!ECURtgvzHa-{{{jeA z`gEUe7r-o;M1%PGT)o1M(s2|~`E8?Gw~RvSBVj#)IWL7lU%(#@7sO&dVu#|mM-9|Q zmL0GSpI&4v4BMfJh{M#&j8Z*r*t!8SK@+SvG4u*2>ezvhZs3=paCss94;Sr}K%5v$B<^o8(iBL)c!P!-57 zf%Z$Sl2CEnjll?|e_x5;v#S~G_dpK?^pF*X=1QWpmd1*K;Mo4jxN0gj9VckhD32`& zefbUBXBn1m**>Ntgfo!whPtix`l^G20kN*gbLVgt!mkBYs zzqdTnFl~6H@#+%sfO989577)guq&kpe-v3Dg1B8h1noc)SK|W_C#?l34`o^i`}|xB zHcvgB1pT^$$Q$UPbOxR3PXvQB zR8V1z2-p=iWizzw%8(wf3(=`8JSwDz!R7qAn7xTs(8y#u#crrKM$}a!6loaQXyF{3 zY)vU>C~RB+yvS5*nn_*8*FEqa;9+%=3n|@441AkUG z!Ae@7pk+_BQv7$*qhowg78*4tQnwh-7yx5o;+XhU>nQ%tq0uqpDtKs7w631V|2EMr z@TBlg^N>$n%dOo#21vJE>_2V54rnz)bD>>&ERgzg}Ld&!)wWJaP0=W+UkK+?Vl z51RDA0(%7l=NP6h;P`*Q-Zu3>IO?Y>rl;`ovQE-KCz2V6)J7?f(r~?XFPYVyao10a zEq1r9fliXI#)(5?Ex36Xep3`E@!uk&E)Nt}Z6hbTEtMgMNIIvXfgi6H}P9`kcW^B0yI3zjM%mht&dTt z$1NBag+3qB)~==z^f_3xgy=|BL$5O8)FE;F(nK88uJc(jv{k4Rb)RLA#Qm6zpW2pq z7PgBmdwSRxKr!TTRPs1#)96+>DW+2qhv~PRphwa&Vxe~Ma-B?b zO~Wy?uC=DEeoL4JnB~E=R82#u%q;5SQJb}HCTr0%-t*!)D3FXhhw%Z)gW#=QncCEy;$o#uf7UyVQse3!sfkQ!$|I%mxKkP$ zBF=u}prN=^#xx>i^yD6vLrQ|7bPhvaaY#U~XBJ%WB*-`(?Ip9}0yI?b8x7Q4V_UB*v5O6m2}-b30hO@ajW!`xVwz6GG-%LQ1Y1pa zSSWHE5l!-$^cd5E-XlneDQJWfI?97n3Yvrb;8+nl#uwL1XaXi<6+tdXst1r_BT0nR zp;(AJC}GZAD@;e@T{KUm(TPN?*c-$juxeGnidfN7kZHWn?l1Ny(8yLefe3Y`TkK&F z#Nn(mL^py*b_61#&Y}D{qKpO^J608*hwyu9#qoP}w}i7=?>M+qjbBypUxoQ|FlLQn zFi%P&ytKM5wH>B3RQ%6aJ|%XcG2qgth1|)$ZG*htZ_#PT-_M zH0njCluRmaC_$rM@CXf#4208dI@&yW^!pqhj{eH^+eafj1JnXi?K#HBv}-`$1F<8! z-}JT%WWS+|H&`Xw`E37j+0yk(dG|Uk?RbK$AsvOFg=<(hRSkR&6Q049RQsb@^GSew z957!nd@mXfT|(y>MaCjlW!KPBWO6n^KW6#O0ElIJ1GGS%+5IZfAG?{*d8js0tW&mz z5@N#UMD#ckej)b&mpP_y z4Vu6TJ6^Vsw)l8k6+ua@M~S}(=OvbH#%`W?Q|GpFhN(j^FKH zAB|&{wWFu9eeLKb(Jz^;FwYBYaSH3XEN#2^OwtxOli6|i6YY6l{oyB3rzLWDU?EFK zbi%`5K%b%RFAti5YLV2Z(mIyP^|XydP^%!wkG7ypXUL)YfhK?8*XDu_1u1!tMR+-A z4Tv2FlXuII@Hrsds1wAXy~Gft#Vb9hEzW|q8VkXL5yQ)sP__e|C| zmzFmg67u##4kfQj-`d}}@(wqBw+%^Nbj}?_UcB*+uYN4jb4+AxV4O-Otyl8B4Ll}z z3TWEQ-}<#9LFa;0I<5cEua*3}U%L#%j%`Vi@2>rh@FzY$N1SC8+HH}IJiiaZ)_F@; zZD=2i?{(*{>=^7h8-*F{IkI*0V9!~;Z)Pryc@4e8B;DpqC3o=dvPq~B(F($K zJxu0oGMiAh&^dG_Z3xc$jvl!MCc`L${F5|ZL(Sk8LgOS96+f?<=$zr)#3HzvB+v9O zvwle0X{d+P-)myaaAn>Z4S^ku@l$?lLJIT01%mo%b{4n!~mPL`HtRs!%te4r#uaL&$&7)fu znFqEAnc``@2ha^umr&bmx&_&@eV*e_wn?-Hcj0%u-MK!WBszy{2s3w@nY3hx7 z6#aEUTEi-hh)&9l!suwzCNaEHj^D8EEB4#@GL8t^5m@G?0W)&3C%$T!Pb|KeO;`sP zyhXo_4kR;%cN2x^6pIwmA~Z3!QH<`b1M_o81}`rDSkL`34_{L}_r3hqptEU|l&Q=J z8Ka|iL8b^-@OPBn!NYH}m#6FHbPB4v z0RE2BEt*7=HUTfPyEQx{UT(*`w-S^ZbR7}&Z}{~8BGx)s!z1C?9N~M6IuZZGU}NAj z8eSKg7hM~vFEk3OV(W^gmaL^Cp`C@L_2?XP(3#X!)mT|oMJvk^gf`afA$5(ln@Rn; zQBxb&HcYjPh*MZX9OCGpau6}$@LQF#CQIQKt9#l$a_g}Neur^p(6|5K)?+On`?bxV z__crgFWKHSW!7V@+cN91Wt$IFkMWv~wXX-N$I>sbdS<^ZQpOwmt;5rA9H1^sKNocw zzx0ewHjYWZfC$jW5AuSv0tR{Gpkm;K!KL6eHmh*ID=OU2$9OB;i2W1lLyr+Dv;To^ zSxQL(4AU0d+275-5Y){N8vGG^HDHh7KSAO29f9j0ek$&xgUF7^_bj}(Nxo+ujzJtdKf#elW~w%{}X zi5anX9FO$-|IPU_&f)xKXgF`__I*VAqdn;pn|y5BFZd!a`eGZy=Yv-&TgvtGsPilh zK4x2w+htdoV|G#NB|7yLYP^iKC(DLjfbiExoJEXpsxjj|1xQp)eE7pIrm($T8 z(toOG5M`$oKxD;@FQLz~#x|~|=5@68w=^6NQ>12}5&W@Z?R277`p(=*jVD;@Jxa}$ z#@`M4q!WDGFn1d*?;6f)>b<{MFp+L^-+03?-!WSL+kpNbjRmhPr&pI7*Ok+*^1#1J zp#2xA`DDzvp`6}W9(W=~pN<8diqW6NjGM~oE#=NLG5T!G_)a<9RvvgRMqi8>-z}%# zFAuyFGhd6fyb(iMJj^1sc%&90{kR0O_jn?GEN1SEA!-IAB7G`m0zgFiOw0s;i1fLb zxhvN4Ld>~8Gs?G1kSgEzMES#*`J-3>5kIb?6w!+)Mf4&{ME`uO<>xWyp3EqJ%DCL( ziSmJ%*%J#O;zw1KB6<;}h+agA=zC)=zbcsj1)2W=dZ^zHZy}f2mBp1FJI^ZX( zEom3!jraoC9BGRVc1aDNb%lGxG-1(M!lH>;L9-zk3It&zH6X2-eOFBj3SrGeN=;Zt zB#Nhg)_E8YjTmiI1cQMv-W?;~9YG7_yXb7mdY2DQ0lC65O`BOp${v*5R2SL>jGI`w zJlp7u(_?s=h}%AC4O%wMvIga^xpj(PAH(DXF-fL#lpriiJrDt!mFC;R6}w}Dnm`8Z z%~3(16~mrooP!rvN()yJkPXUyo7r*)dpk&ATMi*^Zsj7r62mSpE;HDGC(f2$fqP1( z2F|r>8&)%X+;h3D$a-T$_8XqGo(v7?Xj+S*m(!u$sovZ0093iWg?kES5&?l<>)cYp5&X%$_ppHDCJ{Gx)M@3}e$^LZF@ zIS_-O5Gcy=>Z!m<;7)|y^*rg|G3@Wj0e)jYV7MMaME?o3#-bw@Bep)nE~Y2@9jDlD zTBW9GwU|zDY=DHvg#6(nLL|B&Vg^ewoYNBc3n`2gJZQvfDWP?xW~{J?#+DSB@T<&N zpeRz_fcxtz&GN!BvwR7t02C;TB-s76wQv-x&BPK=0Vq%%sps#HHtP#Vne|IR1)#vF z@#7lCn&WE6wl|HWXHGDZ#S{EZ;qhiu%XnwfNV%Q{-0 zz*rG#)N>>YUnBlaUE?V@}Z{#18ll)i6Hl zBc-5X3?KRQ@d#n^GKN8zZ_LhUPlG-aqU+QsN7-`FdBMgg3({|5yh6TV8AZHY`Y;yl zBN+EYj8*B-%=9l<+#*IX>m`Xe*)K3*n&XJO6VksNix9&TG1l+%CVO6tIKvu-LFR+$ zMkEAdJ}v~n2obefNHf33hF7AXYE%*9ah?ULBuUTvmURTFNWXg&p0nP8Y5YC+{@Kib z@0cd?Y4lUS*2r$)7>n=}P%}uS^Dzi70cH0WuaNV~v)x!W8}_`Vn8c1b3`X))%&;ub z9;M&ZP6$KA4x3MIVi*u(fQ7{Np=*GR*-R%5B5;PL4M@Ir08{bRi}3THmqCiJj}iVK zP&QwwZ|pz+rJ1^yfFJznB!!r6WP~Hsh`<-dzY-F%e3*b!X<}$e17CAU1@g|}Eci8~ z!{JOv-P48M7XG*B*I@TfM|cHj6-e>df$+tkK3Oi*Serds*uf%pbuGvEejZ<^MICU7JT#pLyhnJ4dE3(x3qIXjE@-RS^o?7?Ek_2 zwL&jy-ur>(e>RRu&$J%hl%9%7L(ypw5-rv=%)dgO9fyEn(<*{H;^>t8Yy_4{w>uEt z0eS?)`nSQ4*^BVYpgs^g;#u{dnkUO2;?LfX4m9rK;nSUhO+(2P@?5p%G~Pp#chh3c zXzU{aj5HPM&Kr!~1ZGN^On?MThKZWihz>UgQyZit15%FEUtKxQLAV3738duMitx8V z+d%9%m>j_ajxX#h2OBd9C1HuK5Ng%Rg6BoESKgi4PQ zB0WZU<>-@g>;!*#%ja^!F_S+zQ|K-AcUNyLA1}l8I*`)a7KE<@-3;2F-ceD*wo|jQ*5i5;NVN}L2;U0Iwx3k{wQkMY^-agO zFI{`~3hhVqW}~+#euWgLXUfa zq4a3~)2|hPN}&2rmX@+Z{?@Tu;!@@oYB|m4LLUZPA%FRJBZdk1S(t zx=Ch8YJYU(@FY&t(x6;o}gr5OD2U7SiA^Z*~ae($*q!V97n8iZJ@oN|htF?~^ z_OE3u#G#Hx#YPNM+F)U{&J}uS{M^mIlM$W+nh#QZ9EUA-^L(M7lgqFQ-~X4SJDBV}kx%Om~C&YcK^G<5+~E8_Gm?I_7EPuX}CaY8>lk zXJ?U~b+9C>k$^Dxk^4bx_P;pV<_Z4yfVYIa_Zh2lN0)@%K8y{{hP8Z`&4+e%GyBzJ9@)^H+nl zF7gz)fne_HGFB*e(r2l*5M7FdmNXWHXc&{W7GZ81=DtCTrrm5s%!rt6#FW1nW#bS` zhKnN!=5jW{FeU~&#;M{;(|QgOe5bx}^?EeIOF*ZC6yFyi{B2M+-%rc=MLb`uXkUul z$W_`+KIcVtC*4l9RW(+jHIg>4nUJ>W_rZl7NvG<5uox-kTAYJm3kca)pQ$+gSg4k# zcHexN{@_9B_cMfj|3Y00QhZh+dxc8{HG&!COQ1Uf!6p83x;NP3erfoh;V7On-20k@4f%c(qP;ZYl{Bjb^q z6AJ{t+rW$B_g;h_20aQ={QeB#S3%i&Rel)fcis6*JC0kr`W*0D)OyA-HrU*xJ&q1z zA7;i^h?0(V#bgRJ$GwRoMF5)XmV6{MCtd%HM|dviP>|x|GlUm{?`*xTc*K)0m#t}C zdEOdUVmfJ$@h?I;>Gk%%@T;A)Kd3#6in)RoV+N&m8;n`MqZ2iMMw3iQdE*3{#i z!)KzWDlo<=HqGXs88suQKSr2U=6KUT&9F<%VieVSbCelqVyQK1UIJ*xoBCXiYWh;u zRVde`^bk4|oP~@~%q~SQ4@=xRXllPt@aG`{R$4%dK?0kkpsvRRbe?gK6#1YVmnt9p5aC|X3m~O`f;wazXdnGQ=+XZ- zH>^DS+;jnZjov{>H@Qcav+o$%0OpD$sqR>TavF9pH3pMgN1*a;C~`_nzZq`8JOQ&5 z6TU0hq*qoHBeaf=u|`g2S};by)tE$1KxHuvwMipZi&dfD(vN8dqj9eS*XVZ=wcec+ zcQ42E8&M6yE?F$(+=}OF{??5Me-E@Bq~yFG;h%uA<;*CbLd2quHM~~74xYVUiN07g zEUYY6^0L@~vd5c^O7s{_l-3dIGs#C3cN8CXnXa+*?IS^o4|b1{Y9F%CqMlf~aY1{> z`W49EmD=+3wRMfQ~N&${8<8x}Q$srUmCCd9={GhSehpen->(7wgjtaa{sZ^0Iq+ zAKk~kQF3!W()JD8U}h%`Xx*6aDUOuHS%El}9djYVTR>YqIM*Wl9Zoba=1Fl8{V2Hk6A`Dx4i1^2&VpaHI z;Gdw~Wt<>jM-VJsW{gZ13OGjSc?IHD_Wy+lZw6ffQutRRd@Cqh{)Ojz%5hqLnbBL1 z;R*hA?SA9y!i1}Y4df#zaLSCEER(!L@-YC6gy1Zl-lpa9F{Jbs7Phb_S(3k#PHwGJ z;w(X&D!o@Dya{xP2j^P|-weu@*S_B)Zzc}U<87z#kNB)|FU_&P2bD z&jw~UPDkOvk!ThA-vca_{$C&rV?qmql>Unl9tXXuA#kLAxNjHVffV7@-gvoF*fTI-5V3WQI^FHd$f8U%%vUE3mWk$94~YL&_f+ z{4sm#w+8YBKU$9!dKf^Qs($+%Vcm8#A4ut;0O15EyWYvHXV))1YZWspQj6v>qhgu% zidjjg!S>}=1gmpmsAkJVCLD=PLU3Oky^@cOz)9J1o0c-aOD(u`}QSB`(T=dbAh9B!wM;axV7g=LK+nBY636PFI6vFlbG+60JqYw?& z@?>FC>@ijXr?6a48i!!r4!YIQ+91X5Lc54i;&`FIBwQ4gkLDtLI_NBr;`JBHV!Rg*dOl84EM(;fFwvf|Q>75dIw~JD+Cw6>Hb5Uy9X~FgwZL$fc~I*hVoOyM`^6#Y%71 z0YEX(5;3OGLVG-Q*rY~g)R|;D=n%XxS`^!72yK$}$r8a|a{zgQGYlUY;U%EcL5jai z5dJP`YnDH`ZKEe2WcZV3;^P!&gV(m_$e97{N%{w(mDJE;qns3Ck}dR(@#z9A`sLXe zS83O>2Kxe)(I!#|jh9d~WFq7Cc)TF&i}N+X_W*cOdewuDRsbpiDZXbQd>km7?~Ha> z`I(C4PAuBIlys7>LB~(hZmKm3SF=*OnsYp^=6KiDWYY&u0kL&g<8dCLti*3KSF@F0 zB~KB2?*LCq-+x$QYER+17o_<95aG{3*?c!Y?9sRKGX>vI(wnGuG+azLmE6TNOw$Ly zqg1(=!p5J1tiYDv903klp9Jf7NV}T9RZ4C>Rq)x0A1VE=KzKc96G-uSHNp>pvey%3 z=r_a9R7y^rIgg|^lX(tQ{4J_|y@obgO;{OHN2~qJLglTCP1q7Q3|gTh(#En<8{>aA zycaCD7diPTJURhmn>8x_{!fG#MfT-;=U$I~rJtub?xdgT z+}XR_$DF+<=??$GaBYPlgEXzX+b&0yv;EV>)r4r;I5Tpv>v-F zgjgZLniA}4h2NTi1ak>0r^JCc%hZz`+4M~cWjcJtx`|Q){j#1_Hb?7rVg<~b*q>>j z37{nC1kh~I9MDmqiJ(e~Rf{|{1y@z53k}qT&8Q36e4+93EFHj~>sUB_IZr4pdX`9+ zZs=U)ryn8w0_YWxN*6ndbOB}OrxUh&?3T3ur&6YyNGEU`cLJZJR~p)l`#OQxLCG{4 zB2FRdeW#(=iJL`m0^?Xii{)C-E!@BwT5XLS%d~@bwglE^5k_>!!U8=KYBs`VXgoW^ z1mbR?5oMh>Xn)G79;#sL3-)mi&v$)8R=p;c2|et9jLL5L8Nx4tUIi&Vyn*n0Amx{+ zb4Ixm{pYZv*EO-qb|N$3r^0@-&<~o@?k6c&?na3);3qM3O>2|*jp$NT_=g~T6sQ%X z@J~SaY>>iL=Xgf{C-1)(R$7{cqPEjv(pqQwz{Dlm>*Nv`v{n_2S@dT5#|RVZ6n5fA zzvO2puoOS9A^a|AH;C~Q!#MBz2>%|GZO>-(OE=;pOWcFRzF{!qX%Pk)?PNrAmTSgx ztSvL5q?};WoqA)8E_eKCZI|_2p_8tU+Yw$1x)7wsW40iC9q48dI}XGLe~3S~&GqEh z48DYGdjfjetYdtwU~c-uwDuu7Ml+^=qSyXOAH(=7CX)rD3mK!+VNu{VJNhNRd%%aX zH~$ymnZL5MIUuDktH{wJpab#A?M)9~!u&5vwal|q5uvI&!NC-+s@CN~Pi=@(rPBt4 zCkM66gB1C@z$guZrwAC*qG*7>zwT)zxbe7}Y8hoC=#_Q!Yc zwV8ZJGxL?pw;W4zX5CLm-bcr3#;mu<$T!&ldc6?_lZH86q~}pAJ!hfY3XjlFB>8Mb z|Fg|G(6r?UuLE5KQhZ*H@b^J?g4mI*-{xmB`K&u2pS)k3b>F57z^sSq^oOuRnlbAh zWBT0&`WqC>7|?=YZm3dwoM3%Csn=2~gnsQ3SHD#VH-M5L#rF(^7l0Ol_Q!X2zGyxm z-@J=N*sn?8oZy86uX++*KoHvbnO>5%irI1t@uzCDbNP^wENXKa&J&Kncyu^;#{t$KfM^lsv@<*Mla2*pWR?CA<8z4I+=H2#vdsHX%R$mW=xiX>#);W^<7y zQpRqKr=v{-X3=r%1+DArLjT*qM|L@S1osrb!!1Ya2jiC&C1cjFjp@H)g@zxAa|IuX zGPhjJK=^Rbu^`3AsR*A3x*Wug?0j(1)uMjn5AkQ~V0`eRQJTDgpw1jK!AT+?9QrWb zN*gV+7h%18U;p_4{ma}qm??~dWtxF8>w4asF3bZ2t9h%3bd~r^ z5H}d($JY`5C~F_wb+~uQQ1Mk`yFfO!99lHD2#)5^-w<;5Ax>3a9JN{3KE?IlKum5N zdcz^Mc1Fv-`_C%7XeIl){OYBvCM^HPdfDb5k8IPvZ1K_#QFA;^Bib}H`QnI5+=ZBX zk&yS!MR*hF5|F~(jPMJ&J88Qr9qF^=bN{uFb5WKOppC%;-sCOCFsTV?cyWHZW1$i;hwBPnC1VZ8rT2 zxgLAi;IUC!0`IQGDk)(?8Qj5On-Kd)7mhQ>UP}zj4Py#efu7$I_$}KZI>84Nv5Z?l+xezf&9Ol+8r-X`>i(qrIF71FZ^)^THetlB81rDmz2>$E_R z!YU%Ps3aJKX9sbFmsw#1;Sh^(4JHM%*(z*953V_Qq0AF4#Z+w!jw5;#tC`W$$>-E! zn+*6>tf#_^Kpp&v6Lw0Ew6HFyq_C_2oqmPoe59ZlIfWGJO$P4};OR6PLuRF@jj(eO zehy3XNN1$K0Lw=TV=RpdOPk^)BnbPG9erzse%q>GPx3pO_AtU5s~zp0gs4Ap+q|yU z(Pq>`zYXGd;~p1!t^29SS5ro%HL!6sHmVLj2vSdoIMSOZU0+x_Id-acbeuKQcV8{g=3S zUc}$dpZsxOuu}fu4=5gBMu2^>?^{>zd+Qn?vpn`EQWVAXcRMz+h^?9s1WA-@Cv{|H{j{zTLv7a)AuqYW|N5`x#v;y}%LC6;n0*!C zQ!J`{uEKn=LN2O&slt4vLN2O&wZeST{k7R!!G8B_#le4txbLe7KOZ#2@>7%iZ!owy zge!{0sDE{gvcO{`{yH&={ZA13GzmRLXfFvoL#!8r#uE-(oBC3a&acq0tp=X`}>I?|9QQWgb^JS5NVo7n7+uyv5jKw*qv`^E2ZS#jpr$+%wSOSZ|m?z7!Qv7Y0nd9cT8Q!}Npa zSX9e3Si#=&8zweKDQql_S<%8|1oF$+_kB8+{SFixO6VOv5@w zUugkS5@$99<+);t*oPn7gHga6{CcF^UD!=JL&(uQxeqMlu@acgdF3MD_choi*A9eX zK`@Qmq(i<_A%R8%=mab?_5}>AHvMvEtdrFP!0`cx4G6;>Ec9UwG2gyv0ygJafEsx@ zmI7m+Rv)!bKy5$PH`=j~x)#<^fpjczAZ$4&&RDjTFoV_%vH?b;_ctNDIiCNHjTxxl zu`To>Ahtv*%HptKYFf2qIo_EpVocvnlJ_vSLuT>YCH!`bY$oWYK8gkdvyCa3P=QT5 zV};RB65GdaCdILMl#C_8$W$Y)mszFJa+qF)G*~)294Ia*2^0jdgJuBF)>%_Y4P;w| z3D7r?V2H>F^`KQBufdO|(vs?pxSB)i@Y)A-WU%IZ%+b*PM6iGoQ%Ir0kr?|Rm=Zt2 zcdA{8mzJRKy+DwKu6b(-r~ni&e?fxs)zGQo0?hL)z!u;qf!G-oEWn!104NG#VMZ;1 zaA7$Bf~3Sk+LXpCu(G+7#zP=%70p(BmSExZO*P3-9P@p!LD6KX};`h}?RZ*o`)l&JQkz~HA+L>3!_P-luX5E={ z7oCZbxLJWD{!Z-kCu&HIAEZk%(WvvI?Mh*P_BT3OO5D;uN4R7(`lLb3f5&0Y7=!*e z&>J9j>|QPVZR9%3J-zapKh?C~ZxZ{&?_*}JUb#vcnY1)@8G)lS0rYzn_zmS=PYo6q znnf%xHnBVzix6f1@?8hsdiT^Ia0W zD`LDHv|bBhv4lzPj1;JAhg#2s;=4i?#<{Jx(PqTo3YjLxqFxTt-v@*5hiHGOWkk5p z_+^lyJ$@!=zY=uVyB~(^*Fsq_y&S@?c}%}yF@4~T=?@|LpII^W1ubw9+xJNVjt+a5?;DDDYmEe2W=wZ7 zovbsjU}~^s(l|^_v@oh>QB*8e0u9Cdj5}lSge~+&RK}^S*wye|6EQw&5VV`+*g`pG zR#;_N?zdcz6Wif;{c$JeuW-uXc`f%fj^I;|akQV&pXpk~nV8);7d7dL zqyTjk>ImjP`rv35V4p6rQZW0B2_bw1;RZ2JU<|5em!b%>2OZZ6ITGVsIg$vcK!<^p z9IFt%52V%+?v?YpyT2y<=XIOboxOC`s;0BobZly0eI6v}CAZRN2X~^6p9AUysrsY`;g3O|gV>Sk$gEFJlk+_IL;U&VTf)y(`Z&CO zy--I#d4+yRNIx0r`5WQk`TXyg54oDAo*q7<@Wk?yUZyA3o|HJf;tc(C^Ngt0MW#?v z6Rs<;$&B*Z(~K0B1lFSyz)$C5d)ZoFbb4(vQBzT&kHA>9(BTZ|u7v516O@ZH*CmQp zDQ~3{bb@{f?#`A^u#%8vtGfyPlwbmTf;pP3uuMhoLm{S2y-bZ-9SbSZwPO;|`_|ee z^tiD}^f#RWJ#Iz#4$z|@rN>VZo;ShKP6DxGm#l{y<$2sUGy7FP-<+w(!&aZSa_t&) zPgW1mx9FcK8Gy6FPYeExY}`u^hu#SE_KbdFt*_<`N4tf#P;xH`-%rRBr2I)T8~d`2 zML!HCl4IXB+i5b3V4#|y={kf%ZnXWTUh-p78?N~QQ^W++Dnf&7`L~T%D{&3Y(I(6! z!Gu3dkZ#h8qJ_Q?%ca=Bwg~+xSl^6^E==zgQmYXjnbAqnlRFI=u@L4^sd*Xit~(r> zCD80Mx=~Bm5~aQyg+6ydPaRxSn)WHeb`o=5KuVwAo#beDPjcM^s}gZxqQvqa}Qa)?68gPXD?cP=!%uAmTBon7&33gLi_4o`dI84 zN_y#d{&&_hQ1r7DZeEmpM&OYf5PKFbmVzdN&XM<0@;n>&5}-w(o74~3#VMd>Pztmb zFYAbC63#xH=iwfErww!#Xt9ip-Fu2^trHx7G|9W#OlGkNz85ed#lXi2>Z$p> z5&fw#3f+&!Li=mj!LYzwhq7N9DFVSRvu1Ei&mtccqyUCu8uZ2XNkM!u9 zm=}kBL6~&~XbNHM>umB}ER6Fm-T$F(^y|J4^)b{e$K;kcCiA_eNB^v2oyi!x0lrL? zU1`2a%^z9O4*_U?pV;3e<_AXfm&Pc=f0o^3-ayQEjObsCB(*QG*O-w0K4MO^F=x^Y zI=7hqt4#fB(|47bfb7KnIWey={g;`(&8F`%cJF$^HdgB)_?UqCg%Q2U1jy^eeihT) zg9YYoX7vBE_9lQ)l;{8Wyzd-4J9|yCyUFh6+D$@kLV$2z;SfO)qoCp)j&M|j6oTT_ zMg;_<7_GLnT1D%DN(*g0&|0O6ii(Pg7Ej`Bl?onJTCd;dnRjMqvk6xJ-~Yff^Uk}I zXP)Po_k7;xeV#2UF#7{S6Fk7_=oHo=Rz9#TJM`jua!V ziE8FicdFjERplMk^R^1!jKI}gzm}_As`+oV9DX|kH*@_DTn#6K0bgu8*WqTY674*% z4gmI|ka+Iqse%4JRwX43vKLhiYExyDN-{Ja zlS$ZN$O6P~Vap3ba$A$r=W;M$FcW`L!H*GyF@I=Y{8XPjqt3%s(Yz#)lS~1x>|f(UPRML{55229$bJo>EV0Ou1P$ zxx(zzQe{@osxhmNsq@w9e%7S=$I2?D(@L%=F=K=3L9)aSTKf}C<;Oh<5~k>)kM#P#l&b%O!ek?`@*nwASUJPglIPzVG^tAwIpPCbYENx$Ij~A!4wohHWXqFX3 z5F0IzgV*$C?COCmnY0Hsg#9oSj06$xK~WUU3lNIL;vKs#*^%%cWA&{x0f?|soV?yN z-6-hOhZxc%`}+?>dNJTCfYX0Y9%@K6!wl&<03CO27vKH!2SopQnkw#X6jFK9GHWK9 z?j+HFQs$MTA$c0Bo`{ z>OA=O2j;zl`8|HG`fFCWirT0F*uon}6GH~9d9cZjLy<_zMHN~UT}G?`^iDCw(8C_w z8GdlcLwb;|a@bNN;_0N4Cr45I`yf3MEhR0HktUG9>O}4906bHHXKG*tIt)gM5x78t zV-=cNB1%M#LLng#iqHtiMG?#>G-imXh?t7`@sGZX#b6HH`_!RArT9ob6WvG|pNdu&gCqo(D8%5Cy!usQ z;SK*VB;muL&1!~b`aI@`?h93znb??@kYPQmCA}ebqJ}G?JkYN;ppn7%&Ml1Mjdod4 zs^wt{qH1W>>d9!8MOi`B_sFgv_3fKP{V<2S_NIN19tIct6CN7RTX;y2(72&6-UjX8LblYy@K4KJS2GJ|Bq%O#F#;9K2odu@^Ktb^u*_x%3h44*(oKD38FIcV}N6 zK9($hj>rZ2zNdG7^F`DoC$E=^An^m1~_&VPJ6fd zN+CbzJqy|w&xD*h*itg2uYe)_GnmLoCN1c;D3#c$gO)uHDn^8nvkZSqX*@{9D#cGk zD+jM^mJGUVy7uCo&N}~lNPhwN3gFO{7->k=fNZ+5zvD8Su&vlnzJ;-^EVczNeTM&= zNyRCQKhVx_?AFE39|ObnxE@4#H9WMl3WP1kN28v|-lmTN9bwj75_Xw)3i)+_24~&) zI;8IeYy~)UK8^IJ0R09bFa26^-L|Q_{HU3=`ee65reb#rO59vPIZE74j!+maBt@MM z)DX-L-KoJ-=vuK|3xgqxWQqbtqc55qhahb13Q`P}oN+4fL}2f^C`OA|3a{QMjy#t( z&k(!fIJjBxHDi=3|5L_#q@Ut`8NlJ|JfvHZpKTA~*r7P(qN-;4g0owfwzbZ#u0LVX zg5}^MAMQ2sC9L$25sLW-@xGlI?;D0qQ1Bliy_50250L&B;D@~ruC>#zE0*qJ#q_#7 zNhy{Z?Dq{F?ba`ft9~5rPXIXlos9G!`+bjJ47;Dt_b~Bc12?k zmHpn%jQ2kA8%^4b`>h%8r96V{_c`~yymuO!@0klNPLtA;EJ1Tq5VXLT*dpqV<|kgdEiJ6TMsqOdMoxLJA7um_uBRvkKJc9d?M~A~- z_SHr!RZS4%(_Z)=zj#UOgk@*9fueqh{H%n-k-RYYQ?OS$kK2syw&^m*x$@ZZ2A67a z-w)u(gYpQn>2U6QdH=Nb#cget_*3vTld>t^Vz>Xjyzh7axA%=-yr_M_qGfpFd+E1H z4fgx=@h*Qa{!NuCa9;y(#{ZN@FdTVwIDBPaZ7!sdhnG9?oh}Q*rTt9t<{65HK15MM zmi+TDUAG0>X4BW1LEr6bH0ckx{}aHGKjjf*)8pLtBLC@2X10x=xol}G3V?yo))r$O z_WPs>ZaWu5Iv-F7aNbvk^mssIt>|wj+3RJEtGoBVRQ?;$#C5Xev=MhV{}q!uplQ(g z2z0WVQYe}_ittVGMz9);!7S|Ch?*ka2Z{;U!=W2ZZWZNX1KwF>3;BMe9|SxCaOnC6 z((eE^UDTbfp8e-E#G#)#XU>wzi(1%zC_9B8Qpc?jKf)4xTtu}o_k8tTb1?e*YvjGl$=OMic@Z;zkoJrq0q7SFXZ2GVS z=TI00h0U21HoFuGp*8(U$gvAFIC5kY;r9Tb0~|UFk?sq~rgNLUp5c_Isv1X*Gz!Ti z^8!$Lf%G1Hk@>LG7~A=1>Zm0GAkm9msd^@vW71@9x9RJ^yB+#&L7Mv6+i`X1dlc#C z0on8&{yURf*@X)hos~%=`rAve#;(D16jMd(pVyIPJ_wx-7iHk2WQ_Pn&}jjk zs_E2Dr%S9~3VsglKmSUVZjxbQkn}21Es6!-Ak-g$A~i`SCA8lO!|#xqQ`1Lo=1LSU zAVpa&OVpgJ&Qg&BI}aysaTHY&b_7|HD60zuf|w#;?p1)Tqp+xfjs*c8pad_%_}A-0 zJZ7%?@@3e{z!FHvOGNop5pNCdjO@I){kOxBM;>_z&+$kPpvs=&M*!(S=7pj;hv)hb zY#W|KOFaqR7p8q!B|*A`52Umw%8#b2YTNQs$!@t@e2;CAb%WhLJdX4mfVTn8_wY`} zJ{Exfx@aHv+WS;@KGVJ38asP7Jhfm^W2?NMZIRhl`Iq7{V2e!6*y}P}d-TI5TOGUT5=-^+#$67tK5y({rro{FYg3ImbN&?=5J&;YA_Mb**`P zelPqLLAfaS3lM+wZTlf|HAt3Ai5Wq7%QiuG2WVPuf3KZLzYO>Y;Pku0j)o2qa5;dE zO}B{gOzccifA&5qzFW)7!an%W=*!U15bQ+|4(Waa$jlx{$5et6X{pu?q{Jxe1WJ zQk+fBexvHw!>%IWg`NUA>^9ZESw;RWs^<<|eSAEcL>KwuzfqqkAgC`6}l5D zG_53aZ1t1`!LS<7f#w$k)3N=2A%AHKbgov8B;_Do2^b1+&eOiL#sfbEv!!TPv5|#c&ZUi7 z3e6atkD*D107-cNq3|h=Fb&Qw)4c0YAJ|GwS&Lev^N~?sA@Ad>P_!a%#lSx3ODbqo zk-}^|j}<^@q!S?{MzU!qZ@4KqJs$=G4zfdoHw;9XiFmCM2mOhHk2wogSq*qcK2~b{ zJmFJ#4Pv+^NEKkwixrC?EKWdg#{)u+4ad0c&KRWU0Tu$B`gc9jZvuvDqTCL(<7V#6 z>D~`a!~C#)p(U*c#U}X%OIn52xjf?>qrLOHd8aC^@}!g@5Fuiv^0A1l3U_5NXgSir zQkgOvYdw8@MQR^kp9I1{sH#^lBiYcr-SUbQWBHIyF2?+1J_8Rq_*3EXF&|;U3yo?o zSxeLy2%PKbhhKC3aG53=Y(JVltQ{GAwt6H~#MllGe~dl^FYuwg7T1Iq!ELGBm=6g# z&6w)8Q)eT+2CyFB$Y~SOF9Ndlh&vsBhW7kf$cY@`T9G5SvnSa@WIR%6om0-48m*_H z6@Y}`0MfvE9PA%--k=nDO9Q1IOA;!SWE4s>M>&UqTf@d%9 zL^L$~5(Oj(?DlNC;BV-$MtYrNBGRV;W&#}keungIfc^G98b?3y!Ed|wKWK-~or7X< z5R6$XM;BUWofeLE@K3l@Pk#JcIgbpCV#3BNu;M~pei5?*dXudWZJ2?|8%X1$_?eFM8o;)< z1^tIU64x2ecISsWl=j7EFPH_McC#z_vkdmS4H@U?vleG}$kO~2_LF!uD1iO*w8?UR zUw_k3ebv^tvIY&bZw1S@@MR&B8EqcGa)g52E)>L@3~ftTu2JHx6dXn|T81tiPE#=K zND%NSH4t=kK4SBEoNGT(i1bl_`2eRKJb?6?pa0aPqWU0t@An7x#|j3o*fwMjFNw$ zo>jSUI^bqllE`#(1{yDnZ%{yUHREI~)Q3VFgo-%@%ORfj^f)d>UJaVKMgO3cv z1s2cXTVvS;&7SjY!pd)=@81u;afV|aiIpPWqShk@{V4cToPxkNG6_Df;qFhay=C*eyAl(9J1vvHRJfyD%Y_s))PJ6K7vhMZAUN31L3@g8*j`g8b z{GLg#piKKXJX#Ua;6D<=yD3YI!D&NS5EIw{9KTpvQ|oDjPKHUKXqBPIu<85&G&skX zMBj8n(g5}$J9>odt5d$o46(ie6MeIiJP?FDpztK=F0}xCsFy{VawMDKihSK4@svH8KVWmtccJ{5u}( zko_`WDQl}_6ZvZq90m3$)Sr6TXso2gP+n1z!7>5I5(xdskATrUR$|yx(IAwWuUn8A55$!R6jujoEygXp*W1RJxgG0r* zc*SMi<+B9(XKQ>5XV{%^_5#PBQ*W@OaSo(W(@h$C)znMOe1VN1Y1~56xE_QTUMmN$ zBWc_yYd6Uz@^8(Q2AR!JTU?LrOEI|sZMB94RRVY&vqXmasKVxwLYIV7lj6D`6UZlu_?c_E8OAP7iL}Iq;(!)oo86*e%3kVoT*Ok@IZKtDE{0oN;flv zHlG|Bhr*!dok(ZBiq6KMgz8T~#SgV#QZ6Y@s)%!bIg1_ ziG87AR-$-Iu%Me#3&VZX8rXeYgb?V#(U4-EmU>mecUh%0ekVse6uw5$)+**N6m7j? zhVn45DfN~{OKG|`fKNb!P>R-z%!L(=83#$WnPeMf1+BR8C`4nYa5{4F2k$!De#zg71KH} z`tVqne+j2GqAY1gW1&OUo4 z)aIC|9)kqN5?#W3@C2;$Nic^E!}tPznQ=!7 z9ZV=-fR+=a*#peIP*#lGXf&b>L!B=%0x*6b0Q)UWB?55c0W``UhJovN3>PW`5p!6m zz|6x4?s68ukC$@NU`FKQ1@20V=Phk&mEj$G?cg^mEQ2|&m4 zH${El`;>j{-(9YIzeldi7Fm+TIQ3X-fO>#gmm{q6IO`m;&Sf-a-NP?tOT+ECOZE1L zIpkX|-OTDxS?a-3ARa~lG`+YVW=b($uUGJ-QpF3RW(ek{u;hXvt49-aRT}5ee4`PX zEtm{qWQ(9wmU$Q5lYJZD=Qo`;y z{d5@f+pe_9DLMQWpqN=U4zL7KedG`wz3N4nh^dsM;~#?FZJ;G-Wk}K!NOu9=1vvD2 zPKTcp!1A+1xp3%RzDC@4r*|^>WoaIXG1n--c)*E(Fy?Q2_>)}v0>*o}idR9C4NKP; z01+*)_rSSYRFca`nuztK-V+~nqJ14Fm?+1bMd8C?c2o(Y0?b$hL(O{yKN~@-(;hy9 z^mBk00ZzH6Jc3sNbYzduoO@d&(*CS+FTTt4*0b9dFPXXIy!2?v&WDY`;$@hz^asQJ zrA}U;!|720&yzZB`nKV{4t=!lTXhEffh%SsbIS9_$aCoZq2<|mj}<|~8i;o= z-*3{H8RLJXTL7&9=Y30&UIl2(8voZhaS&{M$G8QHpbiMPG{HqsE&PD);cJ=nhD>hE zF@aO+sCN~P%rzw<7eSq9jrb`mLDn^}qOye8@QR?T3-5IF#U~(5bR7izSh}DpUDP_e z-Eu9SL5j59e$S*9_dTSSJ`MLX0nU4VgkHL>l{~OOFTIEK(BI0A_Ptg)-kHrqZ}F<& zZ#&*W{RJH_A-xaqPR4sbMOvMSzTWo3>a+vSyuxV*Y<>9Rw)V-EsfIOmAn{+rq)vs_ zF?HU=i%FAIgu$E8ACX$t7XK->{Z+?ng02~OXR{znT7dL7iH|LB9dB!~&sG?#GYk*m?m~@?gv+rGRn(pl^>4)1Fqm|vrPOxSnv&a%=4}XP8_b4fnDBOU~rqZ3l=vc=- zKLZQII#ih$MI&NR7=u__HRp$QOac)<>aab}B9+MPvgzFoTAcE*59tp92LKMe-ym(y z?pYqP>me=CwW2}HZ<_`4u^N~j@8MhENJ35V2vk;awN^}H22-U&r)}AbF^l{okcHp} z^gHxU`-B`j@J`2`Xg$)`1MUGh?fbh(=gxuORRA565~3XJtQJ>ip11K;F`wD7y8Aru zT(SP1-v#yPKH5$;m9~wc3HEW&`J0gCq^Hak*0*`zch^^#`3ptV51p}xW}p?DJt zgwl6d@NKNg^Ea6GIx~^~GBy;Zr@aVv3@+hi8ik*NhBRR6Qhc}xA9&J!B*%c0n-6=ESGwhQ}PudCnZZ? zFw2LDdG{yNh80m@ug zP7O#;1I!1|QT20CAG7ra&9>g4E=x|ctbPa@6qs{BaWMIcw2%ftNTpaG=IPS3fu(+> znZMLvE4hJW^n1uCax078&iF>A-N4N2n075mNCqvWLGi+*yA1jP57w$;;IUVYK`rw^ zV*pI@Wb5xxbO%8ur3&<#t~O=&TS6XP;4@nu2a)HLn;$BVHd`JSX31l=-T&RgQio_e z5_mlytga+hSF`Bl3{C;Gi<$W|?IN2|OYGA2x9$2r&n?$iAbkViUVua2KBT_}_~wi6 zb-4aYV3nlytol!jxmJ7C$u4EqC$p4Zq5&9zPgdEjTw@ExE2{YqwLkR@XMmAbsJ-R~ z=b=!~(q@`xXs2h?d`$msg_j+V+EsWRm#y#`flt(%!fX3GLJq6JpVJOri}am@G2-oBV9L_?`t>RCO!9pR?5c zs(G(Em&1K?kRKUT5=TXk;S;p+W|KCiTd@@_AlBQgij5+yVc`+&D$S)4FxD=oX!)r1 zJC6HMse`E0lbzP@EJ&xSTLJERSIA`}_;uv+7o;Bnyb5sS@*UF2pBU0003ESQ4^y9q ziFR*FcKOJZ%XW5~SVf!sP+Bf$^pFc2LSrZ2Z`6}H99IWKFgubfc3=H!3R45k1C+JOJ}huNgoLL>;~W2@_7e&KUO{)ZTU>- zDW9}`$TK|ErI@dSZ+K%5@?3BpiuySz0^?f3=KP<6uK5d5PHj@pLwXh9dVoXM!$`jh z_z*zH|I+urwxWCeo;H73`y3JCu0!mVnEZ3+i#7E4V*7dOVa0q%spaYjP~HH_`$lVE z{oiN~(S~MxvoR>TVa%RHRSuBj75YLG@#$bRz$T+q&~i2o^!CVPC-7F)qeNM<*quTR{_qS(fA8`Cy1^G>F1Cb7ZT z!WJ9pe}vd*@J9w0@YjSGY6Ti}r<&LDMg(J6tftt1fPHfi+Ocj=;jw;#&qy{C0?TY4 zg}^%Z+w~uEaK_2BZq$YQLjXr!KXl#5wEK%ay_7Sur*hlEnr;J#Z{^fh+5CfStra~* z;=!O;Da7#jVHz1f&a|D(ME))s_o2D#{Fk76bz4umHz4oF(%oRw{dE@IONAX0X2z*b z+5Cl|?<1lQvm2!l^PIPczW15-0W*=m-=XhgL0{ERUHY7H+F;~4^!?az+ODi|W3@1{QjT6C^UGyzoorqqYn|CWBaA^=X-1D2K${f6hD)nLP>sE559}^rvPKA`@IGueH@?#K*zcTLLQDD$eCALKjL(CRzG;wf`yiqmaxcm z`%qC_yFvO(ptBmqpd}~W3qV`yC4)jQtVyiW3O)c% zMNPR8hBJM%D1O#d6EF}1dFu6qupqDPp9(oQEpzMLRHRP@ECo32!tapY26!AmhZA?? zaOG_CCEdq0;}^ow6Xe{%=F?h1#y# z$Jm+d$@)GMmbKY^A+>|uC(}>rscV^ey|5zrwFas?p|^$lsvZ zt$BAV5}H(JSdj=G+Wsy0+6KCv_TDLXk7w}pW6NE6mLIB#v*(l4@AsxI=jM7cNnYat z1K*P3F<$+Vsso-(A-`7wMk^E(197y9Vj&0k;6? zaMmrItFta+{fJYfr`=B50$L&KU`PI3N0lr>_cKU(#$R-UYTl%lU?c$(H2890L&z4b zh>sQ*C=V@^E&ma6G%s-FSc-Iiz+`|!=Q5;!1-KJn9rn6$w*Iu!?l&V@^Hi)SEm^qW zY|Cd~C%Y(nFg3hKtA0};^_gmZp$_8eCkDj*o&j;cZA7~a{!c^u&@lgHXdfFH?Yd)l zMOvs{3O5a<8hQ?;hWFCO6MxPB6>_P%(3Oi*zJ?&rk;{)QUn8^RLWZ%}Zm~I(`o?2+ zV3ULTl^@(5^n=@f`J*5D`DcFZbHDkeUpwS?3K!^W_)5^X6SO#bvKNv52oSo+rSD{< zuL5iV&@t(e?&Fl}<#J~J`g`P{^C=Q+cC#TZJn?iWJfa#sk`?k7UQCqw8Ko(*ZcLniX~ zgsef2r{aLA?l=7(nZ6H95N{27Xcf%T6JcHnGgy_34;7D*?=3LG-T-WO0*GoJk#mDk zIWdpN_Iv4tcabO`im526(DSr}+5#w~NvAXLnTUZ;17@W`d*Cw;xZ!^>J@DE6wUGDF zp9woWlI29CPXsIiIOXAHq#p;o2B2eSr;xW(PbS#w+q-Rf&&ete&19fxscP>L)ACc? zY5B2PVy=^R=aMo*-QqL1`o@x2Z#N;tOCi6Z+{uB+#=>bU1O~@@r%)zM!;eLU=|yj0ek8vUBvivruMvPBL5|qan$SY1f5ccTW9!L>V8^pV+!l)TtT_p1Yt9sw8+aO86w(mw%Q0H9-& zy$@pbV?s{OJThtPpXOxsTO=P0w9bT86x=|}r^Rp4cbzQl2^ZbsH#hm4#4MQlE^6B| zmk^5?-ddEQFb?@d1|vH;>wr^jx_$uql2(Q!eSx(966iAk4j<E1p% z^Fh=8&W&07ypBJchKn>GyjRQzXZ1E8tjX%$8q)K@ZzE{e{vAdG`9&BF1wwLl-P z{v(%~N75`mksEz1mp_}U?ann{$kq1biWy<#ld$*Wu==mC{$UuDQ{x!6HX*n(LQAWF z8DXs3j1arcvuA{T(lf#cW`x)tmf0}YpkXY{m=QK~pAlk%qb29&OMB{xPDh?2=O3#l zx+|;RPit*GOS(0h`Z8etH(;rWJ|hwBhlt|;%ng2+i#l>3S38(%BLDMT^pvDQk)#&* zbfW7)(2}GC4yPP^mqFhTEe8#DIrt!}9GtL-_E<|>6ZjIh#ql{e#ql{;hRyY1e9kp7 z(E4pYKId2Y(L?$C;+S?x%v>4MR>kbk`TMwcV_dx7^LAWo*w3lKg@?VLi8z9KC zOSQlM%ARzdiM$_6XQxePWKDN{fJNsy(q=*EmT#3FQMoFq$xeiaLTO@v+?*Di^h z$X^xDBot!-`u2xFlcQHxSHWH$&==s)c{k)h z72~C;522|NO5?d%-FH&jTadavVs4Jipf>*&;^g``da!Hb!RzAS7eW zce1Qomrax9^mdC2F&MIz8K`-r<(auzopn-b(1jeN%iQ|ljB7*4bL8-2$F=Wd%Rv|u zA1X*a5ixf~Fs^-^_+@P^lbz!jvj9d(hmXt zkwKrl8hbzh(*Sg|trz3iDc5&j@9atlzrHtT=~r6elkgl;Fl}Ymh=zNzP~nk*5Dm04 z)ptqhgTmB(QS*W5QCz(@0X{Y-psc$+5xq6Rw`%BWWt53I;a*J)rG=#i%Lk>>4-iP!7fM<>S zJ%=HEKHzr%I!3-B){6>fi>tF6{yGE01th<=>lUnaCe3G=Ij_BCXdv0l`DnT-^WBs+sP zI@(Z~UO%!USzvscv3}$(y3sn)F&ezlCM=7CaC+hGJV>(VI#QcY$T7Co9lus0Jqj=r z;M9vdk$wa46@ZSR*L5E+RQ*%jciR0#OO`)O+MP9%Y%vb9?}QxBJ3!&m@`N<21A{CD zGFcyVpHVpqKoeZdBSzsdYh$i z>LuM%oVqOET$>Li!pcI3=f4n7388;?h7V8KdS@Y^C7JW3aeqMAG^R0<>p6D)| ziS?MQiZwVrZtN_a!lj+#rA z?O1pW2>SI9@H^A%F(?vM8KcO--A9q|0~Qi;-vD_!?Y<-TTafo-<=$n>eRI}0jU28? z+emm@NO)UGc)y65zluS4SCTcysv-#Q(xPZb5nofJtt~QtQKYRevW0hNv3FCkdRwu6 zbFujBQZh%--Mro%|DK8TLcj_@nr@{32)GYG#{+XkJK^a0oU8RCPK{af$+q?-GiRf} zQns>nc7KIoMG%ee_^dLLC;d4YyfkjEierb|#bl}U1+ny5QS@LD|4)(j-y-vyBJJBE zlzK@z9{V;%ql;=nq<4%L#%HyS*z}Mq_={a(GYs1LAl(2M4sh&$D0uu2z&KP zVUTT;vE8O?1K#NzwJ&k$0o>Q)Y9DOV#phY$KIi=l7tES{CXC`{VpIA;=-$qRT(JiP zgZEZxFIS;a5&RzP1#fO=`dw^wZ+O$2Z!@vRRHCKJ#yiQyAvyH^#LZ(Jm-IsK($@BQ zOBOF{TbhZt+`@a%#=FtQk;eO=o5yzdhSxHZ&cs<|;k0BI7IHY`;z;AoztWY1-kThR zQE?{XItQ_7<85|vr175Z<}tH3ykvx%iM2tMk~Y4L?%$^IZFlonQ*ZceBi2lmjW(eT z4*xEWG~WEHT>iKACRef)YwcFFhC2K=IsCgg(s-A;d2DxY^t#5JnIw-S+|4%LO)ic! z-uLpHUFZ_q&?~)ZW5`UrRxxO?@k+l;^PI+8?&h(rhoRRoD$GPY0R*?%cxSjc(s(a) z^VrVA;3W~$rkG5;lYqCw#=F(Uk;eO+o5wcwDhJz`E)(e#@#Q*gy!zEWKe4KL9P zW2a2Sr`d?N+jz}uddi`}&13U>!%OsL;cc<;?zZvHcX6cYUFGJnj^4_HWki%oZJQ$o zsmsQ@-Nli{`?{OQlD*MO#y^>8+g0hH!~d^(^1pVIThF?BqmzthGVxIji->l%r5AiZ zbMsiNH+Hd&i44=1jcn(s+|LUh~&I`S0iEv8vwj zE?K;|Tf2C*gSf%QJKx2TrgxQ_#~OOYOU4qJ^los_N=-K2?JkZq-Z$MmHuSJ~NlTqE zNVra*Znp8pHuRK3qnpQ?d&4_tSz9K`jX>Gr@bCU@n$DGO9-DL+d;>BO-kfG%YIFE^ zaisA+m+zL>`Mu$t+oOO<9X3AmH$D08=jO4t!{Ey*Sa&&;b~^mKIMQ@p=H{{GhrtUY zf=mf)bMS6-_;+!n@xJBev5mdrbr%0KQSY=+Z?*Bpe%n(HL)<*Jtv9^r$FXRiiS!+Z z-t9KtHWx>l-mBa^w*4@8#Ugtq>Vp>Q-8SBxE{-(b_uV}9L2r0zpxoL`zMU8J4u;xjP)JSckLmcDOjw^xov=u}O!+ zYb~;6lDyMG-eBY1>*7e`r8$&+u$Er&(xO);PT2Q3{QoZfw`qJ6-8^=%*YdR#t2>$a zUP}w0+2P;Ck;Z$2o5z;-Mkmdiy4SP)4&oMve-}p@?;$sjtv(Fiwk*V-+lbq2ybag) zl*6%Z9_u^|-lg5?T_@Z1ti#5;+QpHk_ck|=Z9EL#W!>>!?cnXS@pid5(s;jf^VrVb z@Gi3!y)r-CW(V&^8}HB?ddlHMH;?V@4R4QXc9(-z+G^wNbaABV-Qwo4uEXLzCzIZ7 z4&v=L-Vay}- zY`hy>9BI6FyLqg$xB5mw4KuOsaIm7?wecQwaisAEZ*=9bw>P{C7GsSd6Y)+Lah_;* zC%HJ%c;~r!Y({T*#bQk+;$046)5g2e#gWGQH#d*9^p1Byx6$Zs2P@iL8}A_(M;dSb zO|Bfa_x9byVo4^wdmPLSHr{3zM;h;9H;=`7!z&gKGV#9V;BB(;ZgO#?@$Pi<*oNNZ zFqf3kgBvpuciD)WZM@R&(>$l~Cfz)Cs5iU|d*a=1<886=&Tw(0@t*7Ev2DG{p(omd zjvU%-yjxuyX}r(6d90x~yh6#EDTc2dyd5^)bdey`=?r=l@WO{gjNreJLgDA*u)V?~I16+cYih=7hw2psPvOdT;Hk4@my1Rr!fg7hxHs{ltH z`;q<(a0oz0wtqB7|7`t;Q)8ALds-f@D)2f>$Pf61tQlKYE{lm|w^{%*}fBvm5{TCy>7VsN@L;ohEw*c+} z(DA?MA9}d&Nnw#Jmqmj5;tcA&g8Hku@0T1QM7?R+hY{`L9opfp5_&nCZv8g5oL3@U zd!TlWIS&t+l>>{>-KG>zyJ$?YyPUOBT;2cd%IhY`&Snou_Tp z2}fTl0%KWcuUyL@ixi*78)YFB$fYSEC@6R->5(6t-sF99>M{0d!X+XV=^ zT7P;ts!oNUD~cv=>}8SyAOf-c37aWi0{>!hzXGpZN(k%Bx(5*jBe)_0Ad#DdPsei9 z1rHxGj&QWqebFQ=XV9=@!wWer7wpSFzmT=YDbRs+@n zocFB9@9+K&{G8jpKiQcQ>&!jNv(1n77OV8a0}|ZwX`cLc8Pjsi>4j~2dj|BNe7Wu^%`I;dAF&2*aUS^?J5MYWw z>acJWu`nGhz^$ndOeh>dXo;TPHXj>6pToy}NIwjC4&Z!;E~MWF><7^CzxZhR-tRym z&uB$_8T|bP%%R{UVQ~_Clm{Q<@}r2Yr_|ifg7>lDb|ycBFnb{1VAya_tc;@%5yU2F znX(&7#CMqS2bcb3NdF9Q8Ni{x6X{#6U1Q&X^H)XF{>Ab?hOb}#x>ILS zU5k}7z=wj^;c$$euCqkfL7SiEtu8-K`?&~t4nIyg`l0RT*6;rwb_hA8<_#8korMru z*dkX#JWo+Rc4pA?0n*2f^h(nKPQUUA^1c9Mw;w&n9hvQ(8#)bQtg)&b#v%PkKseE{ z)qek^Ke_$qwQCgV{6{qDB7pP$r#5+|y@2fZe^38OCL6R}%6d;jso-;K#(SPb`bEHA zfb*VLk=_s3v$%WzdG#gYzDNI=ehUvb*J3bOajZu&7D~!O+C_)xj$J|G}(o#S+A5HeSJ7fHFYX648r!TcfkIiM`yUowQ zf59`FbQ$1sfP?=v;Qk8mz(Vnz9Q*6eTe8MI-LPX{Xt`bfGw}ak=^r>CO}^A&-PNteo0xIZZ#DoUDzI=YZvs43@z-Snii*IZu2HBCygf=lAra?`O#S zvGjG?^j&y3`e+y@t$-(Kxo-x66&8V`(gc<}1a{f<>G!((HV{)ydK&ONz@cy4eb^&$ zKejLc=(sK`zT|~B3Hx#DN1R4Z6mhWHp^m6u)VdtQ%Q@rcFT>UtD`&yd2@B?76R>py zHQti;r6(idkqeKN@EMPid1^vlwy`g@Hez}59!vU)(Q4V-emR{rkES0um$7zD==WFLF zjoMs;H)~V0CT*0~ggEP59tqu-fCyd38N3!DA7vIgsHq1u`3ud*a}H?!e=+q_rf7vZ za-``Ujen#0_c5U3bz0L1b@T*v?htP?9HJwx$pmGTR-uiOhbJ{YN*i^7lBfN|xX3{C zg5$LO6wKgxPJ#ylTn*O1AN6Radf-eQ7Myqvv%LQN2rYkzswq4QxAnQTc&=`^r@Fsd zhbN2VI=E@&>LqN{#Y}mCX@fw(WlUYmCakgUZQjOe<6dOyUe*hLGYwu5Y&uI_Gyx$J zCdfcqZ}7S+nR+#w(ALN6drR|urTM%8)&A$Eu>ZzK0R2*)>{CtI=L=x32j%6-G2|nB zNI1+8OFpPH5un&RyqN{Q3w#I;Kyy^l7!y^xZzhq2-?+V{ZL`ZnC4Eg z&SlnL)mdqg{}@wJaHSje!ri)DX8pmv%wO(1lAbifp-9l<6WOD!zdGA`%~ZaiK;~VG&^N9XO(CH>5OOs>2scyCZ-UQDuj?!*T6MBF2isWk&mG?_V(34 z)rvDxl~%(@sT%n|^k@X`^63wtn#Hfkk68Gt;1!>qIm-I+V@^LF_Vp{pJ5QizfuTyC zVyALtR0Qd78m3M%FJ$eQcfa6K3Sc$NL1HV+f+-lV^}cHGmD zZUM9csDH;HUxf5(!1hJm$7NOL*yA#4KhB=nK6^ej39YD)L4X%k@)9Q9iohQ5%mKS~ zRUv&`4iD*}Fyc`JDT|MmE1hJkcpdZ{HeFqKXS1ETpXhl2dIEq$S1r=bfD7$-e|wW+ zys_bUd)z^EEnK|#Ecid6fI3$S=b}eh4h>qbKxd3&+4&Cv*M^F)ScuA{YLBz(G1%D?sEO68#Q{$+4o3R%dQ^7|9AM?$ zAd{oGqpf%jaelm!kMV;N3gJ%%U|`|#Du@ytFhX8b_*^|Fj`B)T=?X|#{rD=Gmm%!c zK#V&=-k%x;K1)g{m!pN8x*!8*f5C@HOAo^TAi$ARHPTIh>^OXmKWrhV_QeaVuYZ&H z`u(l1Un0K#HC(z*ODO~34pZ@#VzO9Eg%lB$3su7#@c0nHLb%36zcL8>YHC6JSg>fY zTvB(ZkbN!`TuHL)Ym z71n=IwWiKoL=MQi*fZSnko~-HlwG#ZD#Y(8(!*dQm**IX8jD+HI-lcrUSO@~FtBQ+c$TJN`hPL;6j?djLm1-y&V|cSBld`=xOF)9W{7 z%V(lhNZ@CGH~)k^%h_%|{8_6Zc#%t8o_?AiZEdA-CZ7mjb!8NrF9cTm@u7&!0A^Vj zJAOiXz9*s^o<86spCeE*J#ZqL?kNa|JDfhd)HzYm-3gjzIPEgh-vG)VcE_RjJdPL& zPZ-i;06IEu6Z4tE&7%F60`!_?P(i0Z`B zR_qIyBQmRM=x?j*7a>#R%$&9KBv>oWnR%YXOSfx}kA6sF+qEnBLmCyGrzl458yt04 z<_p;E82qsZ1N>-q3&-h=0{r+_S?bUSC}-yN-Ng0VIETh>kiJCc`Wmj6$~AhSK2l%7 z!nbktLbXA^lX*8YtTa`sVN9rAWBN+2`_%9-?!B4Ee#gDn^VpRB0C-qAG_e_0;>Gv|#Mx<|M zYD%uEK!Cj*L_m;rHKE6+VK|bbm_`gOv;GVB*;U+os{Ry1V6NTh3_YkL&L; z^({uo1!2x(gVkv5DaOhAY4SHr{gws4^aOwFkB^9!K~P`=*DvNa{_C0krA7Wi#FQfP zy}B{vI6S4_#Pu7wdOg=KbDlk!*j%E%j;N1;98aOf8|L)(qR6p}kbSqq_{sVzu3gIL zL)EB}6G6s5F_;MRY4dyjF*t%$VkVy!4B~1Y{aI7Z?$t~&SXZ84ohTgKrY52GXbPx@Vz5P4^-*vc4qbNBhVu&8A zH>;YAm{UVWyFV||PqIF}t{$ULQO5?34@~pS&=3y3j>}qYanBdbRXq)LJ+pPy4=o4! zy`#_R`D0L36Dwd+VDLynzmch{*<{% zXNm*~-_>kzj{Ee3Ouw!B(=c>bj*YrcJj{@`OT2g^?A8ms94?^kHYBsYUBZU;k~=pL z#2@&3`-Afv^xm?U*g`dX{@AXbC9h`kZA||yMwYs%V;Y)M!?7Bk(jlHdF%>QBGX2+J zl~>)yn-$d?*u-O~kQii6+r-0v;A*px<2wmG$^fg2Cch%4)(0Xl;AQeO7FDs%&+?5R zD)b*Pz?Btm-1r;wPE~%6Q1$up3?&%Cw9WN$FHO7_V!bUjDU_2ej+9~2v^QWOaC zn%o$d!wLf~586}u7425B76?YY3Gduk4g61IOrDS5gL;1Y_guIIji1b`3jN_3^mjCC z2G+Qd8;KUx8t2nnZCd786x14P1t}HA&ye8|I?sM+74yypokZ*D#_t97#m4#euh)0a zC^lx^tgqUYGKcxW{Rm`~VjnZg=LiL%vA1`3% zAZ%Y>Ii+pm>R)o<%L^X62dlFY;X2G~y+ztk=rlB43-f`2sCEZwI5geBT}~7+DbzXE za|68xb*!eJq2F^06H3P6Z6RxzqZFQ*NbsXbCb~59vYT0eyOTy zp1EXcs})7gu^6+)EI(bg7|yV09P*uFjYA$_4{1J(L;k5r9~%RBSkVKc%~0rsTr=kc zC^pW_eTc!YtEubp5eYMHB${A!W#*7*F$bj*1jP|I5M79rwuozkL7bu?2mUB@%k%|# z*dwecQ4i&r5jC8fr$?1MJQGJ~YRJ!15RT~Kr~}wuuCtV>hLS;=sw0dhk9z417CzGo zZWl5_5qd&=9;Gz{-gEb&U6KM~*M1IW8cWJ#YReF*Rk!1*pEyYM^UOaL7_FSh3mQ^j@X{o-n) zkm{}w-^&s|_His)hEP;DbBG+LjXo7kM*kelJ%dVAi+Bvq>y!aS3in4;|M(It0~r+O zkA>hYzCVg`NY!{Dx|c9-vd%sU8o&_u$pspX`F%(gV^~rzm*9-45(*Ojx<4F)D2TBz z4-R`L!Ki~w#J8U%_}xqV*u=hz^k;xW0Ege?)0iIujsnoJV|90ax82;G-_D~l^aFz5 zfuxbK^rfVj9SGKc&7}t^{sTt4-XXrBPyk>JV31EI{fy?-MyPy&DEQk5x|2jWj>jj+(jRgEXMi)m zc>w800P}4>dyf5&6Q|MoZnKxQFKwgk^sn)u(n~%+rrQBj8%(UK;D?MZ9Hwd3kvv&~|>Mfw2Xs@-lm8UK&x?QdLe3rKUi%F$Xy4`b&{*Z@l_k1c_m%W3m z%RP#9xmW!54{qIE!>r5Q;>j#m#4@N}u`%Ov$}pUV5Kw zmSEa_zg%&jtluw(aeu#j(u;B>Pg)p?lwwxP(a>l?ubJqxpBtCT`f9lx){oK8_{96= z9L>wu$?86NY>acg?@;rva`hpmH|lqC^;_;4jr)nXU(Gxr_2=YvFv>muX8jK_8MC89 zOht5Oje9QUqw$a*4FmVAvC^n*LXLEFqRV8ItN-sE}Y7nm^3W zv~rSwT267Arx_6oGo4LG} z#WZj)Th9hI%GwRqQ|+J@p!&$d$D+Fw~2;4aWV7jC=T4 z3QYD)(3G*Cb38RzJT+zP!Hm0+^;{h_@*a#|Au}I{g76-(XdhiNN*!&CN=(f`M71DB zNO6>r`aSfw_&CH}a|zVS_3v@~C2_aI68rH`Lk%K}W=|PqKF8D-Feb=(hI1nq#oOqV z@pz;2xCe#ckI*ULag`oF0F`epqoK5V2R+!&c`y(|`-P8!B?No}9`!8Jp!tpdwEq%) z2cm~(6TigxY3cGDBL`!E=t|aq71Ou&^3*E0+GEl4>v_%vHXbmiLkI(jy$g*Cuxy=E zXHoZ8>yr*sl_*rwzDJl4dEhaGe}u0@A10T?!#}L2itMNMIZq*0hIr~YXbY}j!yx1N zD5q;#ArVgBAF_k$MmGGuC$QEM-6?Ca*k4#Z9=w&uEbj17qkJcqA0V-)>siuFD%x-9 zYfS89CeZ0CQEm)>$*Vw+^9t6&E9J1(P^Om~`(*$1+`Ciu1Y=zB2cMSg zg#r(TB8Uml2yG|(#4PfZ^W}UlN=s15*#Tva{|T1!vB`cN3gqx1kttZz59l|C#vd@1 zCz<>N)1k$JmIg{)S=LeBRaU`rKQ|EyOjbWJ^-oRJ7r!Qyt9h>qv6Y!Pt_qERG^BTh z*0ae=cqD#98dlN4)DAiRoh-wYa2I@-Q9{0t@r7$; z&ssSkGrxuqHUW6w)1dKXQ0wlJ<4v^F7V-`=h%ZfZ-7gDEJ7p>GkOHRkVs2FEd>&Gfd=< z$q&a2#BwkT0>ygK;6g|oqv6@CT(6JT;unNyXIxt?AYgKDre z`;kaxT+xd?MM0p;#WfaFO@D1b%dhfO>MSN-q>QN3`6ypBRf6kaUqBrb@$mj3Q!UA* zyC|JKN+PdBF7>2{L_L2J2#(?D{=QhM0C@WYstc>FC-aK2W{rQa3-Ri4D^K81HHO6j zM94(MXr`C+vGG!lUTM9{dW+H!s!UmLuCUH}K`b_uL46t=#*=Xw!VFsZBMQo6LzBLA zZaszUDJU*XOv#p=VRqEyvK+{!vihs&@Qv6uc}nT8>{R$cFW5z z=LJ)a8{=s*OCXJsk)}C(G%p+DiS(Tl@`_yh86GFID&_G*d~So z;Fci0GHR6~y)u$6L7hw)SALfIzaOhQp)6ROQ*=5oM#z8%FQz%>(HQc3W1f6(dAu@) z!f2L9sJsSZ@f_UsIT5k5PR%Jz`U4G~esTjkf3D2TDQzh#ljoKyMP(?*fta43Q>>5k zjFrc!W9JmL0<%$EV!es3I_{hBOfpuTk2;cmuH53Sx3?A-#+6vvVcuG(=KFx{h~nYa zTgu7{%R=S#KR^K8YFh82tV&dJWl?#gtiFfbQ7ucUPYM=AvMS`c-4KhKo?Xk8bHsG| zOf1Q$v?#-MxN_6cw&?tq43_{OjdK~#LL}`j2Q4*C)O3^%&1mqfCh(c>t zgc#jv_O-l<-aUx<6vS5MdZ2$vtS*eTwPAAq>V*Bw@mYU!w0%F=zD}&rEu8t{zF`L1 z#$n+yyj!z>2{*1_PG;#EY$huSl+LowD;TTC&B@kzgsJn!F#Q-db3#U+M8&O)RpWLE z@JCDaK4JTf<0>jx9q>C8)>V|UekDbvXPBs%76QYJhUTX4P;Em4t-CT{qu&M+#iccP zZM5{LjP#ixVMaKNTvSj#8e9~Vnvtn!JSUb!2OG+I=Bd#=`JMzUOH#9AbN#LH`TD%* zeE+;SK25}ueJ7g*Q<(4hb++CJO$tPEJdgY|wxsr_vG($%Iqjo(Y+24Z;{lV#>(CVz z44T_ELXWfA;%=z!AAV$t@&}({KFIj&qpgRI%HxrXu{V{~;=F>DU&?Y;u+eJlqMV653?AJ?7yJ*3U~9;y>F`K+zo_*%sxD_MNp;B=`wcQs30#$s!ke+`ST zWB$uo9FoZ_v;)rRhu-wXT1@YM%`hdpJ)p$p6*Alqu0n5(LDq1+5PmIdJ@0x9=w&eE zM~q$X7G{=&DuRK)Nx8c?&to|`EH41lo(PLD9cn17g+p&Dv*|hY(B&2<3gWCV{d;_T zP!HV5ODj|UWT51T@`5r}k^Zr4Le0|_#%fld&a53@lg3zGS7TPIHAb~siY3$%jA|>q zsvmPYoMC?Bg-Xc#jHbsun4HL}r@vqIeXQkrVxE$G@2Nsxaqwm_zeoJkJZ3u78%>)Tock34@&SDT zLjXeo0|54Ne0z}A9M#w)!|NLh&S>dI)RMn|dRj1B5Mfc>JYko2+X)=)3>`%XPqIe33yFkth01o&w{ zvEJ~VD~j{mxs;A`QN_H61!lzkfCgX?(BrErljpGrz%ytHTq%qe&+89mC zUS0~GPq0v-Yb#Ap<}w$WhN*lDhWWB~5^sK|AfL+#GqZHXaoS+YYr9-ojt&Bb18MU1 z9qIfGBcRecw-)WK%ttao5{>BK*x-~~w_h#OyKYJ$>K!h7x+)hLrRG4}?z%NpT&OEu zs>wH*P_KQh9>q-39P@5B`PmGuZQ--0!G8n13fTO}H{wnyP;A#^+qu@Sh54C4sL{1c zSF-Pm*LJVUl*-Ig!r95fAu~(n-(G~dyN3k`W?)I?e6p9@XGjYf>a8>M4d|>U8~7R8 zY@E!agxV)8q_OSChVJvA$=dT=1O5Rp|IJQ0wel_O*xqJuxj!0Cz3Et^kA5nQU+p|+ z)=|RGIVlc^KWLMM6C0l68iF@xx8gA;lo$W-Q80E5(9iON|CulOH1D4g@oN3-Wn#ix`Jr#;2fvli?94Z%Qs^8oJ<0e?%xm3}$3^683v zWs-jkN-NzAOMvD*-UdQhs>SlT!uJug%&NYyk6$pHW8RpEhu>-J_|CtTPCVN|=|0kl zcTc*xer(mzMUN8a zu&^xKVtJPEni3hWkJmHOlCpP$yq-Zz#@Iw^NB3 zt*gunV=U>_%2~>p%p6<8^v~nl*01Fn@LPb}0Gs|j;Ew~v<2LI@rqeg;C98=UfWIJw zv<*d=*A9q6$nnkX%Of9j;CH~1i67+~o+ z8vFua)rF>ioD}+rocCrye>r{8$+HFge2K|N^JV7R5$A&Z^zSI= zLl>FB-Mnuwz^P?`^9OmqaCVWoWTcWgFX|^*ny7UZbqrtYStgD7%Gz03!*-UxCcYnY z=$JfEuiD{f8q#|!v{-uY0e=|y6%f+vJp=wBa79R`7q0JG`{nFGX1z}HhlaqOxMsl^}i zK2yHzXWl{YSHYJ7s{mWR>%o5xZ2v~cC*k`0i{ZZSn$9tcaax3JAjL9slt_nIEPx$I*6 z=1bcfM+eTEa+HHYhXrFT3YZ>6orWzY|IL5t94C(fUjVEI>^$;%@TY*c0Cg1allIDk zrd&djo!N!<6FN@g3dj1q9?Ec<8r~#6H4*M7-l?`$&g*lPK1c3^v*szEd4!c%7_?%Al91pwckQsNg}K#b{RPu)V{86eknx z8hsNYVON;1ozQFNcOQcP4fr3x=1V#ES;~hi*Tbr zbpE%>7^nYnt8W$wld;=G=601q1(=`REz0Hn($5|$JMOo<#8hNy$o!aiQ)t!qX`^IJU79Fkd<{5M3@x#n4R0cVb?>Z ze%~Q~wj6eYe+q~XJIg^mYvF!BKpp$4-;H58?AoJ#$DeTGe71!DzA6Sz-|;FQu=V?h z@Shf`XGHn|mGx(Yuddwd`c)M>qHCq%0!O7{JXBPv(6xT6$Jv)y3<$yX)S=O~*wC!r<7$YwpE0k}#T}@u|l|`#p zQUM3!h2#GeW2cHuo`1g=-QuNh_u!)~p6@{Hfyx-JPLD&B-UtUJmEOFN&Yh&+pdN6% z5B?e8e%wjtVDPEH96%k#bk4ri(7k@Fq4Taw3gob+6Gsp_tM#byE)`N6n{_Ei_?R3HJH@>+ z|1i2@%}PV%4~4=ecs)fL6Cq!G4JpW$Sej@~s~$7;vYmX`cK&;C)h<5dYU`!tZ}^P? zhXLx?P-Gux^Sdd`@2h*{7f%_RHD%R=H&oo{oqQOm5%wvTu0)+vGNiF?J-L z!HB&iRm;3gCQHAG;f(+Cp1DqYY{x6cVE=?OpUwNxvcH(pnSHi!X0x`g`QP+QlmE@+ z%j&-#2j3372-tSD1N=`waXojLFX?(6r#AbRrR&AqOGN-1u5sRu*2?{`n$hF2Qq^|M zh^Gf{$$afXhsIv+tttITxL z(ZkZw+(F0skdAGn(Vz(9uynlg|3!xumdpXuIgjoxeJ2l)b>#%m$Wuy>fMHTquU*oSzos` z&dOFbp2l80#*`>NF?O(zC0I1+CQ__p_2yYqZTy`?`G*PjqeP!SCcKHUN&dw2T>q6s z%^wqTV(chC?zW^3fO6%s9Ej-*Hh!p<2)CoBo5~PXJ$@{xkycA?bF=9|-3u3P_s^sQUHAF}6GwsHFAL_OwaA;UAsp ztGI{*xgQGH^bY`^1blh=%wUw8~GNnJH(o^DNO(Fhda|B`L1*} zlhzi%@{fAJ#~|Ll-?=gpXZRWx#SH0F4DHMoedc(FZ9xAN1@ zbo+o028IDP-($e10>$a=*}o{cu4J7O?Gue?Kh}Al5@=<_-_gbNwq?-QltKG5Vf~Ya z9Y5X;{uJ;WVCk6l&$x3oP&|Iz{ZliZ(fntZL<$Fxk4i04zNXJVagAX4XT;eOZ}d{h zgzKV7XSFR7^Oz{7{N5vE+X2BzXoB#mn-`NaV)4o({?BDTf=5lrx;OjY@JJ&fKYComg600Q;1m`V7IAL$`w%n)R}kW2JJ(gA9uK?GCEqNO&!`=~$UngT~^b;3$-uj#=znzqg z9Vh(-{O`c0fGxifpRv~?P&_Yx=eUCMTYUUlwMM4a$L><=V>NK`O9D@VbdZl?K$u5M zP~}pa%*zXAr1&O4ISaF^ZLk;$T(EPjcc|-RG zXtL{MH-W2m{}Zm3?%#mF2^7=4Aza7T^$y+PTIC5)-PbuQna2A|bq_4&3CuPne%x6V z%b_yJCJmhI*)SyctLvVnS$bU?0whtrY&8tI`sQq zLtXZ8ZcX;k#qX>S)2nn69r}2i-e8{D{QbM>EoV;^EdbXzcc`?shUu&;NasrMtAOtp zq@$iGu=yyycFmWOvCLBrAyG=Q*!)|3*PN>Y0M#@7w#X>C9e@@>$IbcF6wD$M_eZc#1{> z7PGT2nR1*7m)i8Kp5-K-*?vhqQ*d4AS!B~Gz8bD0&Q{^PxIQ{D!{)EBo|((=Y4{^<(WX7LVI!op`L)6U@FpcUvgJY~2>Zz0}(X!5PpA#%gtaSUR=eGzn zkCkqBt(NXL=JyWlT*D|6b^^vSQo7A06Vfu6NBb*eb ze>(WZz;^)4PxpgA59|cgvEg~cKbD{D{tel1e7a$8?MSOAG^MlEbOK+v(87gX#cz}! zsQtu~A81BmguWX_s=O>(c}2AH@@U-^%JcT;$>7RN?Dz7(pC_YtB@cR2CjX?@!92Ac z!)Sa37mGZ5&6h~MX?mmlrXVCyccJh0XFa46y<0W0Phfd^%k%&0_1-U@pz}$~k0i#eEi4%%XyM;u$e5OoDY2)} zKMOfcyddxiM2ZO1rRr#S-PF%JnoiNoa?y10kG{xJ^Kas4+84gT@=sP)?YT%Up_XzSPmaH`yeQsLk}i4r2Pxi(aE}R zNyRp#>m11}f*GI`N}o)TrrF=VPNmbn)09_Rypz6m@PmMffTeFf_zK`eKpn;OO$y_) zt_s`r)II1^t(bL`B@ns9*_@01D2se)*^vml${ z6ePm~%0@Yja=07mZwl#t2YPI0|2IWjBH{RerMm@uEHDF5$Cj^~`nL9tmhQHY?(80P zFS(@dp(BThihI^wtG=cre`q>n+6wn5UYYOhf8e(-ZyTaB@{8 zYL!&!OQ$8ID9GKxn$A_fH}�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�kK`)=6>I{K8#2yJlkzy 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 Xz! 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%0DSp)R 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 IfPB{mkPA8{6=Xh#68_GDR z@b%NcK8avWbn4=+*{|%Cd-d=V?6zl)NEjj8i@rcXU!1YgNemC@`MOyA+W1iIqA*0u%OXp^W&7I*C8J`lM z4wUu@kDY%6aS{}V!~6r>OR%nQxy-tFo;DvMYk_8MvHR%$a(cZGjJ_N&W=EONz(Vyj zhuY(ygZi)OPO#OLLv#oZNu)yXH2QjeGjdJM+`R6P9X0QrUzvYCcf3cl^5gUNU3nxV9iL%k?x#4NSQ%D;E22Q0{-fU$2C`WA|=G4*Tw&4hxLJ4&vBoF&Y6@acMmmT4@50uN#*pk zfEVwuGJ7AYnKUrtaVv|6PwsnVxQ%q^hEh*N+21~}iZ;Q@N+Bjb8)E)w8pf}L|I^Of zOQG<^hD z_fv|eqv+og5_e5Ww9`BKi>JPu_zs~5Aok9gy=8`Ls5d@OE;p4LT_lc+zh5)2pMU0z z-f=?zX@RXPUv~&IxGd9(DU^?vzx?tbB~J9SX;SImcT`aR{tU~`=*tRO2lccUl$rT2 zc7Nb~6J@+fhR-kWV!XHSbe(5rk$T59#6g7jZ1s29Q3gfNw=Ne$f!k?u_G84+Ywu^v zK71p-8n_6;=^G>(Z=Ay~yY)aI_H)#P_b3?0zXXDiM~Q>$^NPqeseKyqFo<{(Mz4vG zZa(@9r#G3B<^3DL0dIyB;C*$-0MyLfT~XYbVNht*UYWwnv=kM6|D+u8lRkMO<#y_M z#^qsF7W1&v?oB|kWwMXVIgZIFG#@xCozp+%tf>KyjXx59AU5=yf6j$!R94kY1>p(G z|6Q=%%h8$JH6~M4JHNKShSiZ^uthhyIbuMY!a|R=6;<=Pk`IxWTk_Ts+1zDKO}$Pl z|8FAg5f8n4VmX!q(|K2`d*fjzu1W{5^K$IMwI~Pb{ZGpD&%RB?am5pEV=ns}mHl5a zK13#4|LPaDT^U5#bzCb4iqZ}jN_13Qp^E@%^P&|L;Qwvhv{_7=Q?br|XBspCd()*q z;{{MYx1N#^J%;MCUY?X)V{Bcfm)!k>M(QG;NDq`S_}Z1_^+f>IN-pXWOc<>FJ!egk z!4DERib9L?qQQN2^_=4|7AxNCNIK>B&wF*+CAlw%A3~xuOT?F4h!pbEq7XNDz1iUc zq0Ns;Ulqgy3L#!bL@VyVQaGnnUQ^dONtZ6=5;uN?c*cFo{`%K_B=X4hFM1v#807Ku z_*U*{bcZDmXnt}`6l#f^{pOGr$PQj^KCCKv=j~NRa%e(ev^IZG9&Hpg&`yihh)Q7L zXWF+U6x6VMuzNbO2(JK@*g19ooT=eN^phR#sG9!_l)kNTw?7~)x$^sD(bp;GsUu>jTKEFC1Fo--DGOZ<_TIgVXG7AEhgbxRp-?T)vmJ&b;voQ6M9FCn=S z(7u?&a+)72ycPZ$xIE@Y&*Xzr*Ri@BQe)qq48IW6Oi*P2Q01NTj0R)0j{tDW?SiOr zFC^w)sC<4C13i}X#RPikM8D*l&l3gpSPVXehrWKLikI&@Q2<{0)EWo%qxqH(SzQBi zd)w+sKd)jC-0E>_znw}Z%8S%)K!?X}J z{QT9V=VZJ2tc2Izr?cfGM__(m-z(H_clP4!T-NJ4Qi)A;WcCb7fSL1avLikiwlB2s zc>MHIHmMcGL*v)6Gvc&Yps>1qHN!{p#ItufC?WuR!#nBvZcNrw^P>mx}3b&P>Fogg11>F5fn_iIV0J0YIG zIZpE+IDAGvHh`_bCf87o_KW%sYMUf~PACVLZhbLhn-jfntOCdwaPz+Y6-8X=zrL6a1|#`>5;acxD$IZi95agVm@%)UR6@)XXTpohan5QHC_<|ws% z%Kdl{Eq;~Eou4{N_>T5F9h1NL5|hdrD?X!3atM%9A zTup**fIE0X*m&^6{`sbFRs~XMc*DP7Zl_sM!^MTiWBQr5qfWJ{`haFrX*kw*(&Bm1 zU|M$^cJu)S;uAeGW+Y5Z)=lGZ<%rB6tYUqfT=EbRjY5_$Lk{D1BidL zcauZ`>yp`okphZ>-4TkCAN?A<;mL?mTwIhinwLDuvr;ik@bzRy7yG!kj8JKUu6PpkYbeir&=s>$*nTHP|kg@rru$^esw=Zf|T) zXaiw8HopBt|Ig4*ORFA&pQz8fgmx9a> zx_b)yyKFkxf8=9U@y-~Nc7J^6%WErM;^s4B4($h1oP7%K$SOVU@9jfZI@_LK0d&W& zJo%AD`n{h0ze-0xlhDD-(9M<&PnBgo4%$Rj-w2og<7a0<$hYn`by;?)_do8l$`7!y z8#bqf_ZjaA%tdmj9oMbBzr}Nly$oy}SoCfg>Lo1ETG?ye)jwZ}vC=s>*_gYxs6q@? z&atqoFFY>?eK__1M+mp6h;8zq~C>+F>O$%ZHL&j<<`K7@-?@C=h0+4JHm z4kyz`K!C-k1fBpsyK^L}e>d~O;$U^2#Vi%hx8f8h$ANKQEeE*)(0sn|#KJdg zH~|OP?-_X&E2(`HQF?xfa$?pBzj|DC(pUqb^@cMSCcFrpgMMB?`Zu|7x`*|J?fSh> zk(q}HYY-ICpF@`&ky-lt6BMR-UncOIlQovyb~+)AG>zK!_J$JlleJ#rDoX&HExuW!o(T3F*U4#QvPi{2Mi%=HJT19WQb>(PyO z;elQye<~BCwm&q7aMFjsu&6hf`f^-!JVBk-_Db)fd@k_A(l)_N>e}oQ?<_&RZbv;& zQp!Z10HfZd85gm538jVI#_2@dz`e*al#n{LM0ht8A__f${lg)9DfGVS$}Uayn+tFBxza#AMJ ztsTT*A5UBetYh`mwE$_p3%}{xCY+hGHjM2H*>9Z}(|@a;Du4Fy3r>5AH=$?&It#ku zOAjv0u?>ACGA=06B_L&`9+6d|dt@ywn3*!alHAGq3Xb6ZzI?Y_&{Fh-!=rpWtG<)H z-IqA7bS_XC@>huKDkJ=bG%6M~hP9gOEI$m2!EnwfK(~@R+6hMYc#ql(0cL)sm*qTG z*%uN`c@&{K)wv>bF1~?`@$u522 z%aea2LVE7~q`)B!npM@D>4p1COun&y##1z}!^@an8VwPcfhO9$8=v`#>&{_np%&Ok z5)`@F$q9Ma7}9Xi2h1YgHyvxQ!vn9m3DaxpK-@@+LfB>_?*NB zsm4dh#6SI{(e(CmZB-@yrH6`*!Ywg|{NnLwGHANw;>L{l?sDJ~RW$o24l2C8ekWcq zS*}Z!$s11I1hcw_($lV&Z>NYeIA%@y3>e`xj_jj1z^!vlQWkO_=!VB`KuBV{2v|3H z{v%KPcOtkQ0X$r~l7sTRiI3jmJE@vJ@9_KvH?c31@RnwXGp+=W7aGek?n(<&nGs(F zjD$lGvvfGFCLPqM@FQ~1y-|fg)B5q=FltUn7~Zn<@0P@T4s+DWgHyLqvjoC5`k^V? ziVXcRy=w9g8a$X!H`H%{M1aXp>T+Ac3Wm?27(JDboH zi8no8u@R>Hf@?BFW zcY?v3ZCxTf5{c~pZFd$^2FWAS>k8Zad2sFNQFil<3N7N>__wLKKN@t!ZnEe|V_V!A z?BULgxv{l;`Kr>rlN0U4-l4|@J8#apx4a%1$;yv3ASE?$+hwA3ov-9vWYr-?xggyFWQ%>eq@qWhtff z_E(zw>+@&-d)-3Y^#cZN;b!wtU*yB_9$gZ%{ctDT;mWjCfD~AhxUDPs!P35YQSMR27 z3rWK1;N8NdT~qt%^V-3TiXw=fKlJ=p1q_;ilE`Edh+yy~x6(hK5~GS!E}r6e@BgG% zgYN5qIX0gTICY;Jy*oB@A;>~=Pz{6%dj(q0+x)h9-4ckjnU0Q&6{46-x)jb zUtu86+6qQdt9!}3m)dE155ABKl|qirIH!j+NpBLV{Z*KYr9;9IQ}6a^{ds@-u>h#N zeb=TS?nq($;oh7KkzhZsh%i2O-bz=>rJ^8rXxSjoCoHCOL_F|H(!IgxSGHePz5;+b zZj;&m>!am0~xz^^f_QS>#s@Af}%^8H( zoBBI2@~i=pqX*};^(~Ll2}iui&-|!!v7|{qqK`Pu?uUHhgN#A_$J;{?8$QHGoZLMkFEXVL>sYR#`e;G7&bdYZjqR` zktzx&2QpPLFdfo|t1vsAGdb*iau@f~wPg4OXt^ zcuFp#(yHAaqk5*mQSeh$Tzc`l=W=e4N2!hhSo_x``E32RK{8h`6y_B~E7B>c~$~|L*>)9C0KG}J* z@<6=;t&N%Wv6n^e375xoJ~wB$jLf46laC)Cnp{PRc z`+do0Vyn1W(ryR9CaRp0uf*rgZS1DoXIw7;RC7eXFf1h}+ zlDWLBX>~D*@{pmyY^~4f9%v8dN_PB}xF;XZX3g(dpzr$DiC=m`{R%7bO1zzLoZo8U zh!qS9?C#&QieLdC-yX4}Q~oW#)n@leQLrt5%9vimPqYLXl9qNohfhHx)66|bwc(ZN zdt^-)eLjqhz{mAbN+9UMxY6FpDVaGdpvHmW?K+-xc9MLI`(Edjo7~a7AB%{kex00M zzxVdHxd4_1D0=Pg@}4Rsc@Yu!7&LM1ie$`HiAgF}eSYw@uTc0m1O49Y2o-r4wNcS{ zecih$w~#jokQE3D%R42#{&WQ3aP-$Vg(VPSz5sn}S*|oQGq3VnUe4{B_YgO7(m^1S z^29zaM2RBxqd+2%p90B8jW5tn z%qIpqCc9ctG`$dHF_ZYwGLw?T44i?XUe!?Z#2f<&b@*Gw;RVT`PZ$9){9b3)!>0U@ zUAov>x?RIOcC1B6VP+0JIhOC^1SD_w_QB{7T-T2< z&1f~P>%|YX{rk{+PAr5U+R;2Sp3H>skLG-8IEIt?akzb?{rg7zt|#ih&Hay}^H^7u z+oI?L(Eyd$Bq*pzQUvTtlpsMePk-j=-tSiZRdp2hUTe-VSTv~wHMt$68ilL~lo!vM zH$;01`Fj!S^?ztVe6-8$f`-;=e%G(g<_a+DzvfiQ)aA~g9!Tnp94=RSJ*R7hAL(#f z>C@Ocr!lNfd9nW>cX-febdo<8C>Jq+0Se%@IqL^+6`A$+KT+v#VDy*Yt!VP{{x9!w z;|O*k$Inh%xbU*l=MPiFN5SC^Y+>V>8r*lU4zGt>zpZ4&ay*KU!KvJ>sqxsY1+q3Oo5Db27FhHw*val~ zx{}!gv!N~X9I!9Q5LYF>HJ?2Y^AySxO<|gA^tf<>JaEQ9h$HfK`VF)^(MtX9Fr~G+ zwZ}U-zq~3YN9ko$(*3wUqOoXzic@Bb$!HrDV*QTao zpKpy4?@#L*`g627SAXU~sjIY)pP?*xfoQ0%K6?)}J<^0L@UjR)Ax-6Dx`yH^m))pg zvaG-P-y4_y;_-Mmw*w`G+Pgu1je{%)jZ<@mX7Du8bm3`ag@S)Li2f8U0_k;|CVQ3g z#peyQ;K#YHzj5EsojSD#jZ6n0)w$MB3%hY3a{Gqa z(*#uTVkMBHt}dyL_xuNqr6+x;LGA(mxIVUnM;)LJ85!IPPp290mh|WuNt zv&!`8ONTNGZ-V@FkZiOOmWD5hN2_?e zU$*PB!_1lx%WcEa;79YEJYCK`2Vpt}W0Rtkix0_9^(v(2=ptyvP?%)bUilT$ixNG7 z*4dAL7NgpZwE#kkayQ-&3@i&KT;r*js7~fK>`t?CbPcv-#CUh9=p*P z2nHKj>}ChM1p%(B2%ubT&7)p-p-jdK6y1mqUW{2Em$m{;xu!Zpn0HiZ0?_1LIw+5T`E5o8M@d`SB+;dxU^N5|sO9+2G+yQ0bamN}%oQJPx=1bY33?M)DwVf1I z7Yqj!=0fIY?dtC)`)eG{JFY%#WOC8oo(#Zkxq{W189Se+2`k}aB<*nEmXcyL7m=(I zA1pvjf9j$=yGqZ!R~4$ffH#???>Ufj`sjK>x&AhO^WHp6@wV3yoA8HU{#CZ%`8{i2 zE=Q$Fihx%{J^`*o<%Q_w?6JJ~LW^vfDD)Ae`Md6}2A*6yzi#%g9mW|(2b<(>p>Cl_!0{ASg zYYPZjZ{q3&h+%tmZACQ{y-sqvI(tq%X&r!cP|m9NI)2*lF=&sR+|f%mfeXYxinl76 zH;%LId&ztQlx30&GBF@_Y!$j!DOfbehlygL-^AUZi?{@Fyvu>Tl z;7X8SP|CK^U&%7|gqXq3D9|eXi9>I@T>8dH=c|wjfvsJS=LhpVdKU-ek)1sV5o=Y1(vnvM zb*1;1&tkvaUn34`tV0>~q>sK!jOwb0Ju;qdIBt2XPi6$!0WsL^Wa+MwyK77n)&H4oqx>xI;i$|*bk}GDFz8vIg-I_a_DJp$&IV?`^bD@zw|;)@w-`XjE(f% zyiN5A<9yJSKYb54TL^Dm#o#Iw@H<2n^0^GJC5XKsVqhE$gah(gxsU;^1*uy8R8y}Q zC>87}_8vO5IU4;$=L|3?n_v%zMi62^}_G zS{QM(!eimIFJ(nuJ*hukk}r6s4#moeEZGhT5XH|>UMUtSmtMR45Wyh4%EH40Z{taa z3p}Z~%iO&-l%;~B8Kg${nuj}K`&avjs8JhAFYH{}{`9E%9aT~4r&V%N_uQfI#j)wQ z(qNh9EX#Q}>zZ3v;&YhG%Gp-szMS>vqkvDB1u+%s`tGWqL}%Ns7+2xxf79SYeXT;8 zA?5B<;z&PS<6uekk4{aD?|}#UDVN8m(h(0DzgA{jZU08+)}fItNgq};2i$?&sr$Ez zl$BgbJD@JfZ2D!1T+fv_24@xYk-l98%U+RqWdy{e;k+3yi8-2cA+KKvEhxtB`B0^A z{hiEL0~DOs!vo4p$Kv1pj+2F}&x8ri2d++^Jclka@=AB6fb1sA%j%!Oct6??E2$mB zDDLVZfimTGj^m*dnbXI0jW7PPSE%U4Zr?r$bk>RL~Frx;mh|AQ14=@e8bKS_gU#o+S;$3y1s z6>UDgArhB-JK-JRW&3%?Zh)zzZ--42h7TwhfVm<=bDf2-D2ea!$;5!OD4|wVE`-`I z$G>Cj73|C16Q`ZRoOf}es;nD~H%Gx7z!udF98_z?K1H#-%;B8$_L=uQk;WT!!h(6B zufO+70(xK1d85@cUW0ufQ|?Q8r87)VFYPogr}ikl*P}gjsL$qvSDb%~tpS7kq^6H+ zKZJ;U*UvW!DD4C$FOC+3OENf%aDlyU{`wG&ez>Plj@@&7#fY;)I~||?u4sNwCpYyc zouujC=Sr28pG8OkkF|x#(%zV6po+6Xy7TJ8Q~dDL{j5Fm@|VQ$^`Hdkrl2{0?)s!`tYLJpfI>Hm-6nkLBKkGyk}alefXiqk6|`hvdZ2 zS`&KeIRbtm6(XXcOz(G>W3GV$w-dgXWOUwY$z*!Og_=^2%{Llc`c=2kwJ9f4E z!@ef|eN_IjZ8zhM>0nyzlK8bCqMLrh_`@Ws4#UAD4uiayQgX05Gu4!UqVM}Nfu5uM zb_|=@U(8_Tk~>%!21f8mkk^qy=;6+S4g{>Fv;zc&i`eY89(=QVT-WHeTfXzY%q{E8 zS@do|VB#a)Vctq#?XoLHt75kMhn@Vn{Bq&Ezp-G1cL+>RnqL{(ry4Ht_(%nLeI2IG z()5Vl)`7l$r;aKS&F>F0a0cyhM?RE1a2^A?&yu^JbXuDv8xo_@iSMX4N{~K)zVK|Z z3x^QeGWbnrf8;HZ!pXFa;bOKTVSL&j%{@LefXRF9%85^JDjJj+G=>JJm^$vX|kF2bWliB2livMWccIudK=+N-3P;I*-0qW?@xNLv*pBOj^VZ}uRAwX%RNsQ zH@)63lvs0q89W{_11HCuMI}yvEUm%XWYenk@C9I0yaA@Lj{(UqUdEG3HPGoqSl7I2 z+V=B!J5+-TTFG-}DfkNkqR7gD!1<36Q0MY2LK}R-{8(}^P1|D;-#*E6`R<+^>5J&l zmh+SA2YEO-rpxrVIQ@;J5~{d!lm|$zcDt9|9nO(jD=d@*$ic(LQ(#GzJ%rtfFu_LpmzhSIGKGhkGwSMgM5`+tlLs|+X*vD#%SP@ zE$z<6G5UmBnM^Nv_ZjvX0%J_ewDjY?)B5b;-G*vCe%JF|#LPDPDtBC%NoZO-mp_QF zq-A?eVx-Koop*c_u8Kj66L!&ZVckxHWiD=k@p}uV1gE7pQ#%?(bKf_O)i~ORlm7YS zk6G)YHLniCnp~3gm^_5Faog^Gq`b5rilN=gJGvI@WkQy*!jnV9wXZcHUeS{WA&auq zYIpRWu{}$@_z5C1I^ zP7hEvRiId>^L-=)_DD(gTQj_RaXcGqV8Q{ZmI}3;<#NZbaM|Eqxqn$a=!N(J3C|?7 zrpK+cEjV#T8VMn28?``+*%z$r_iXO2?F&sur-VQoU==hS5V1l%OmU0F)TsTtB`trv znVWD8um$`P$AN7p`dWWH1}h+{tE%5+jymcKgF!r3ZahQ9jt%NG>gGv1g*~zd%lKWY zYPMc!M~Z7Cz9*aj+P*Aam9??)(1h3Z^4nq4fK8)hdWP}cVv@gbKi4%{%yHU zk@j?}s#keH3qC)QyKiXVo8quQ?b^eXeCZL0VnvE2PVd_PzU^udqbV6E&MCv~JA8e| zNMR7$+YYV%8o#H>xOq|2ASz#Te-*PkXyvWHqB28z+Q~l|DC#!a%OnK=wfGCE9qdm@ zMTkx6f%ol3LsbGy9tl*UqC)@;#Wk$IMET+F_*s_!f=kK!EQ|k{zH5%TMKgC{cbje+ zM)BVr?V)QlfVntnPum$Xzmk$6+ZoJQC^p6464igxcOtX=HiP71*JL(Thq+cgg)8a# z?}+s-x?5u4Z`L^duG}jage{(!t-kCYgZo^HZ_9k|>-iiEDgVsdr(0nqZ)EywhmEX# zyZk&tiowUV!&aNif>}w^k*L`3k*_{_2vOPbcBKT&jBkP`-Liv5Gu#8t zlIA;8(KkI_W6Edgok?Om#(c$1j{BiKT+98TkTwewe`UlVYsaG%aFdIm)so9%HS8rj zNAH(oml&50_Rq74OrL_7HpVmH9W`iIfQ` zyQKW7bLlzg(m8s`oX5wf z&*8C54WvQCeXwu00|AS8Z|`-7h}Zhnu&CiO>HvuP&7_B~l)RZtx)%5r`4?<`$9SZD zEtW{hRY7^(Md>A1jTh?Wx904G-*fp6#biob4$jiI@_V^nussYs{oxHo+Bct$W)Z=$ zV(i5#OC|^+1a6cQ9UD7M1?b^k0`TdR!6EuSO25ji%K1Fcv~`;5Fmvnv+J0RGYJ7L@ zJzaPeM042-S$}IV54dO59vb$rqOAO9L`Bjcz2&sU_+;DJ(6>@JR1Pckl4h+{PUE)Y*B5Cm>Mb8?M%F*O|8)ghjsrs#b^K@ zu2v^ptDq)))h84gm0ebXiDG(7eYAbt zMdYwwyCK}Ov(Wg5_6dE)`<0QWQy8KaB0*FL7&;8>jN z2Eq8zU^eLUj-ay#je`oJipgq;7zBlN7=owA9ymQ+TUml>ez(jpO0o(0hIHY{n6dWtp{r#2bC)kATuP z{Id+675cIuI*kc2Q$+6Qb6wpDXOOe*Yt%ZtIsGslR_&>?rW5yH>0tG3scp^KDh%T#^`5b*k^;4hp#L}}z9GJNZMAPTUPdM;Q zitrZiG1!%GU!I&qXVMH_@0Qhuy}dxf{61m2IRx)DI+XB~ehRAgVlW!?JaAhAMN?b(zetzq6#9mR$qzc_ZkNNRZDPX&=u z%^r}owKq04knw?QDy=?|X{wy%t%9LGzAU5`guq&DCVWYr8Q5{^n2j+#T6kFdy7{_n8Lw-oAw()-3Nl9|G z@2=H%mBIXIEIpvcYrV7b`Eka}c}7?L=W0~*KRPOWwr@I9aOhp^Ah69db>2kxT894b zW;k-M)SHQxA)Cwe7zaAZzh7HK0~6h*$3Pu%e69$1zCpny% zuMR_YT~v=G-Z$F)Fq4n&*1^FDYx*@Zw*IJvqia9o(!^vj2)2&gSfxAODxvQ$^fLuj zO|qFKCHLk|B|m9h^1rF~A%k|>cEGB-Kr}5@F5?*s%#QUCw)N~A*|*PQIDW1V1cHjq zoo$mtYOMR!@=w!%`^ceYq#v*tI`B|?dzBkL=c^#(i_i4Xr7SploqW0&%dafqXM`c- zY0YU)5ifwO$}hGYh9~CMsT#%cTwld6BQYf6sp>MyE%tHTnBLg%-971jBObzbA7x&X z6N!@w=L<%<5cTZJqE8Hrc@-+h=L*3mPo zx1IAK7n9mAi_Pc;?j_sJ(tu(xV_u46S1`6r-aoPF{-nnVyv|Bc*;<2ApKR4xY&vM>2F7is`yP*Ht@f$H{CKi@TUk?`c z$uyqUMAtNw=Y<J?Xz>x58TymB`_J-SfqTB*~d$KSHT4a-HEednEgVu$04`N zc5HLFKQwKzKn{pKlfY#aQWSCf26rPpW8sqESK|@E>)dE>09mQ>j4hpPN#}0;>^|*t z05Dxl25btz>5-SDXAarY^rz_re!JJ1*Kb?MUh75A0?&Gb%SW57$TCH<Zor` zsGqHET262_FuLzy!1<_HagyQ#tMJ@C$c3PcEM8#Xhqq%=CUDF1Jh1&S8;|VZBHvP& za;dZh5h|m+&qTC(I5*LWPt~83jr|&w1q3}23`^<5CIkv^k;fZ!W9h|AS|-5d&MLD{ zuESMVM71T(bd;(K4hiSCoXXVvXy=D2>o2K^-F?qn_Zg)i&kB+Dq;>J4*ZX zKhQa5e2DFa9uy_*gzzGNgj`7u6N-g74|)gj+JsbTanI*Px7ROP#s$DG>Du1G`SWzX z$@6Y_oiRsq#!=7k%6gLpJI`6dX@j=xZ~U0B;W6dh34^`wj&-;>I~xdVa+C(Ky~BU%bMFvkU7s~wd$`4HP%NgtaT@DK*A0JDPe*4FtQ6LnDlvm}x|GYisDg4Y~+n(IWch5xw76vl1P^>hlaFCuwsdc4nR(^(Ox2*n40 z{I^;{giWg&LYcdLfmm^dk9GaS(CWV5w~r^KWH{l|t;W8ws`=Nr+@>Jfx9HLO0S{eX@` zCWPfJ;QXzI8{XTu0sNps=GPo6;fe#~co3Skr=F2y@{a0>9maMlejktm8=e67U5h)F=d|4bXmGumcz( za-W5V?A`{i9atU|5VePawdALFy=mhC(ThXfU#0^~ee5B+YE3zv6~fuS5Nd4C#dLpU z_n*raMwUtYir~_`XMua(e|7QELT?lr=<@-yV&{+Qu);8%7HmL3bXMT?c{fEjG4Z!8 zrXk*c#!|OS{6)kB? z#DYE41?gzMPp=Rb1q6Uf67#^_3mqLpXQc}-SQLkS)l+2EQhM(5lHTz0pSFpp8@ew= z^>tkp7LdU>WB{ecv#<30B0Q;}ACd0UwJC|7u!mhR&}==EXb!*y3*Hkwf^ok+_b-^F|k#RpA=C^)(scrpvma&$NDU-WhzQ{jc)B_usq}m`eg;H5oLh$9UVoNC#;#{?o2Gin|70l);ZW@{R>VBjOdnnYwZcn#4>mQpqT#dRuir&-0l13;G zAjo_qQgarIqtI}mN6W@{yNL8un@9fIY1TVW(~o_9vZGD2HJM!2pOQX$9ZO;zZGcg{ zNN{PAxrsk~F{c}>g3DGQ_F~PCO?+4-MCcMDfUV2#9?0WvykGWx^ zD*Ol!9O3X+xnz9#Iy~XqLz0oF54(?e#?Y2H-|b_Xb&mkyn5Cf7Pi5`$7R=XL1$;wQ zFsvF>jVqhWQblaiZy#w$@F~f8sOG!L_E{FW-J2F-XqclG;rj7(jq?V&G-4e~d5kj8$FQ!N_^4d4g z)w?xI%`D_+f1(Wc^s9?YCk520;0~-yp3buK4oK7nqMVRI;u7w;+ozOh;Aa6ID{tME z9MlF^wRv!X3Jr7pr41I1Oj~%!Q|eUqa+=++%y!@L)JhMftsV$gI;9fqhJn)S`kD-f z9TJJ($64N|1OL(+DKtKzQh$*)lM3SVNkG2kKQ{r|XFJ}wb}7~pMxHSKB8A!RGV38U z_k4Z~uZy6MuT|s=FxT?;zGwZ)Y*w<%H1#ZwKvjplDj)0DV|Q>N&F+s$E+RmKi>mcE8pAx* zS!csBLue?riMt;r`9(qP{q1@cd#f~KDkt=eF|-q6$?rCG*(tX7^_$H*nGatg#sh1FeBAI}!oc|ZLN%=5jKEDV!X(}Gq#Z5Ge&wBz z24GPy)8jz#s2e}dpBpAQiRs*zcE+}z$m?AzN_$`OPIBhBh~@s2Z1AB9`@y@nkQPG@ zaOys$RCs^-+Xwo?QskoQQD4?Tg1D1GZwGgB_xWPX31ks*de7ie0^6=choesj-`A{E z{&j=hs)^IXfJ!3fy`;TPnddiph@jra1$~x76Duoq5*dO1_+5t|#T0~{U{`1sY?|lKz*91Cre{o=4YEy=0zKzP08?ITI)s+s1iT!zZwMJ{el(0h5N z#cG6sRv*AEP2$vpJ*e?`CO1ZnN^ci88FU0jqN5M;1M1aTQZ$CyyJ7T>BX~KM;)-%= znan#s2xXVsXVlJrB4D<{csE{wGWsMv|JEpsm_k|fSMkk6?PJdk>0sU$87~_`f^5(Kxy5zjXors?V2y5$|d^84GiQT!{JTo z?)G_id+iQ;7`+~E%L|xPq20^FCiZV6jD5uVzS#*e0`^`P!9&^IiO&!1WG2rNdl-1- zbsvx8>3NGR3MxT#pU6nmDBtSUk0zB(i4q&y=i^0V&?E!VA>%;M0{+xhSd(LmEiHFH zQzwdD>$9%Hm4`F%bq;D4&nh%pdjq*n=Y9Hc=x1&(T6`2qgt5n&&P&WvIWCpiUo`nn zQzX^9C|z=Wty8g)fxUHI&(ZTsyv1NDk?x?9hfg;@lxb0aviscQNu?0B%9RnLzAW_n zq8IqYIq%T>aCUBkyC2*vfvJ1UJdQ2=ZT9mwfcNC9ck#6H_u!Lo2S@Vh@&$To{36HT zh(aEH$qK_SheL?F{8$Ln+q!~0b2)orv^zL)6QXokAoHGc*U4#A^8g+n$_&y%7ka~`MidBN*}i5sN+37-*iv)C8)ZA2mQF8{XSq( zaZ|YxuYjLhU!dD+#Rjk))Z!NRNxf~R`UvOM*B-(nbUU6z82>BakHVBQ$vm)9s09b# zt`Grlv zlTK9|J;j3{Lxan}(fplnO*Pr3FU-Fd-#8hC5`eILh5G?!aE&X~LS2WqDi=Hg(ds~m zG0tIPyl)fy!wa%+UKPwePVG1Oah-1rB5`RdEd~9sAIq8k5jW5AlAZ=xPHchkk(drM zH@o>}!$DcX`A{7YougB1<$V!_2=-ZY*J#9T`%*VD_kzPFh>nr`&qh*wv*(rfCgL5r zdiUs-nfu?Fg7HqSOHJQbC7&`hlb(c^)Ei`F9m&u^STi-X-(le#sm{S}Q;Fqf%8x}+ zg#MtO?wxFUPc;0|eyp?y?lLZ@PIK?X{-a={{PQ%^1I$x`#^1u*JH2;yMw!>;^!prN z;-U-D9U&KIRvpZXp5*;kV>EVuoco>n?K}#BHvTRn$?xGox|7}5+dXw{(|=g;%%{~P z`j%C~{2mX8uO_G>*%VHkD_%*5@E=RRe@{VYJ-HmL42%GE0r;!(NH+1Qx;-|=xA!mG ze`VAGE{Hblmqf33zH&kJ2yGNEP{Ps%8xmyDVCM$XIIn|pi6Ff(FMA&wP9iH@3$&Q1A!g=D6U`ooi#MlvTf5KrrO#}FpTiQ5b<#`Cw|(sh4c4>xsK z_2N|)0CM8iW(N=Vbl8@Tx$k!8cx$OfhBFa_arJKTZJiutfv9KJ+{2GJmO-Y&H06^l z%MVtlKb$YQ_9(rmM|0uX_meXs)CV`Hll@)QMbALVjp+(Vc{*2+kY2?-yQ$r28t&k0 z6s8(-b=P1|rQWV5zKI09+j-xt^kOpC;rTu&c+TAdUk7Cu3U=yq<@75D9@nA|r?kKo z@#n!q_q{f7Sb^{^k^pQBc?4Nf;eUoaKhkOv#QDt&Z@~H-)sRR@g9KTcqfX>UeQfPv zJ?~focEjSdmmWT>jnadlsd(Dy0h%(6*&Fi;c#epx0()*nfRs+ zJ~)!6H~-mM{_Gq>`Gsoj>8ii+#S9TJ*W(Qzf`vV8`|uI@fIshkDbE7}yn8u}6ofqD z6`w{rv=mt9&T&RMemQB)NF1+3 z5szib&yi2ihRU#`gG@Q~`@q6?y{VmWId}|!4To0m%k{dn29T3N zWz&Z_^vS;4^n%^Ca7+8!0V)y-w31!m17?LCPM(?$((+p+c_Hq4T>7TCakoQ|^0%G% z4orF=-4eOPLzR%9_h*CWP^upDr?EfT)l3L*1=r8DK;HdfTNj^w&(wW@B7o7wlaI-) zCOFo9rsK=`3tGb3kyqtyzoJYN z@AdwQBV~wgFKsojcDh_joR7<3MV`coU1II2R(Gm!<^yl6C1I}hpeK%!{^Sb@<;O=N zpD}l>CVoOkc9l&s>_hO^lLsrv?-5oRQ0xZ6{puPs$hm7^)QYZdcZiu`%adERY6)bu zY5YE@O^Tb21_9fJT?x`rIqMM4x6*zOGwA#n5_tF*C;~s0vP3FC z+Uhpy74ealPsjlhVaw}jkT3p;>5Az*S3kpa=iI@YV=U=wEWE@kEAK&EQ zk`2w5xL&cy9&EP+=K_ZS6fZq=PWtKU1>1QP&+3kh1x@Fj^d7!ve&A==830)Ul557_ zLMLwOy1DzZ+35&*UXr(=khR(z^G#d$xtt&8twJ0z9<3NYgf41%E4m9Vbu$8)69heT z%XS{^T`alDiQcIU`PDr6cUF#<@_DSc$GWH&lKp~&6M+lt8@NjSu4cS@4uN|{ruWpa zrquuD=Pypi^)+Ubw-w|-WsMHhX+)^+1uHCraJy+Y)=^{J7fBHdGrjh;O;wK7qLMncv-10tO#2un- zH>jVtdQTyx7qdM->aUI^FUe$)F-kj8I^F!3E* zdxQAL8|__WXda(zmU+GSI6|8aAX3XWf87l=BVJ$o5=eSS3?8Wa91oV~(xj=s?%nsc z!pjFFYH%xP^}A`~O6}2?H->bc!V9(~2etY!gOy=bzwfelF50iEKk$^CN&Sj%b5KNX z$y)@xZ3v^HtbZ`RX@v zuI=#ty~Py+U0eDiPE-=N2rKnN=A~ajy_C_tpaHPIzoXAxzco7TTiuP-GFHy10uGhW zJ_+qc8I>RV9WQL&w24%ZQS9rAsYTsyA}mkKrnfrvn#&uH*+<8rUC#%XQDlS@TAmjt zVaYZHug0es95ePg?Zd1N_J{FN?#hP`0JB1u7!CkMqh;lL=W;QDD_(!FH94D*Vqo{r ze+>lP?<(t&W1ny$I`b+?-sa6k_ZmX>rJ_7B#T|=GO6uzJqvi3Tx$he?H%5u*<*#;eCZb zO*Vy;9%&L-*))?Ecip$fp5=4*UCkV>yH@M?E6zm#il)JBLe{F;60r;0??ZkN{K{2` zeJ3yBIW5#}s$Ap$Boa+K2(5qOEiT^lHw#~Tp%5O6el99jW&qOQ%lq^N<433D-vuq< zSk8-2vpj~4+KL%tY!>If6U`imAg?W~K!Wq}Tg&B>9$P@`RV?y^>mK&+3VnxB=WZCk z<7}%qzfEEVztn}~YdQN`I~nZvGVgZ&(!NMK+h*bk=IMG+3}efYm{8!$_(1S=N{W+Z z?vPZEJ>dN#;wORvw4&xm%F9W585ihVW0<^$dSxDOf`9UFuA0!O5em$<2i6Y*ob8p> zb>8;w@-l>#MOBgVP6 z?|!evBF7@p@YYWYkZPpF@(1lu!HlU!L;7l-a3=6gC#6Jnpy}~$)MsDj#TNcz#<>$p z{+@xht|x~1PC9d|4rRg|4)Ciq!EwE`g3?_(fwLTHc|{4*m$WsDJNrP{Oi{bf85#Hk zS1eRcJkQA25YE3uRcY;Ae|e(8_qGK+RA}}mn#lPO$w4c<4{I(Q)^~?G)wR@8uZrlB zQ`bDb$VZTR0sSkB^LMaZjc;{?gYLz^&6UJA|95NFx9;b`+_t!C0Lz4v%qd_M;c-~M%ernz}jwJBYlvQr6_K_0|}F} z$GX2MCnPC<@=wCVJa^ecC}I5Y>Tx@{8Q;+liMel79EyrY55!F-ulZZH zz34k$JH7Osoh)|sosfZyGjB=#_AhMAGhCyc?s9dpk3ut}JN!Ea(RcGQO#jqGdfWjL zg!Kr(@~7x)*%MV^Qp_h%;vGq=9;9`Ad?r_z`Ec0%S3^}436)riyadaN=MFrEt0?eX zBXSfTm>-Uu3uCg}8~mRA=jX|3a-a1KCO+!5A|ji}J#8`ZNY(V}Kg73QXSe90sv>>p z`0<4Rwg^=c4?tW0 zD00A>qw2U}AK-0KbatA|f-(^I*Si#x$0za1MN{T)4$dO;em<;rpZd|LZu=t!mF)2h z2Ib-GrL70>5w{v%GKS)^f3~6J^|DA0KT)ze(&%v(xlD{(1)jB@!`Fj^$5F!Wy77Rp z3=z$u-%&K(r@fu8DAm1w-p|HK;Ld;E&%pPRxukpbXHWKG?@r5Qpy{cR z|J}|DM4cH>;Lft76p*xWZyZ~=X&a&S70^t5;@WZF@J*(`oUx=2hs1|XzK^RXm%kx< z5?mxS3^wNkK;5U``j$DSJWkhatHR4eb_O@4v4~aI#C(oHAn;>`LAC;#~t3lKtAr`oMK#n zwG)sn)C(UWj>;HfzscUk19uCpLMhEf3Z|Xo>0M-p`WKAH+tYXnQ4>K3>8X3tw*dEI zmBXh`_)qn4aKX7#&Ta;eh(mINFjXnVeGY(DocbB`z5N|cr3;Wb6HY=SBJdb|RlmO5 z(=;IoC+x=!fCfOk94F90SZDXc=a0P{eg28%UzryXAqZD!7~T)RA4RByI`>-ap5UT0 zv1H0`>3HZ4wp*hWwslIQY-a0HL3CO6YPT1!JD(l2Ujtb}t7a$>fJ$dB-I;MiVmJ+i zcYJF<*bdfP^|mgN!Gzp!zSh`|Wp7lcm)-tF=+jOqd#Y&OTjxbt7%w!&o;1e0RW-`_ zRkijfB9|GN`RuLwtGpicl`uE73(lzgV2e(URB|mz@56f_m%TgU(`zCKMY9IvZ7%wB zrzMs%lHt;Ssgr*CZX&~zDBso&Kvghw41Cr{pFMfKn3A|(t;9^5Fg?`%$JrSkDJ}18 zR^tyZo9>CG4Fyei>H|Ll5u?+9yQ}p%J1?!7y)b{5e(3lgE>q< z<_eiQ<$iW%x%y&m1Wh*|GwyPB3jXrbiB!yMvL0onJ5l8JjZil0%$9kVui@%75q3%9 zh=i%dfcG^MN{3xo6~J;MhRkKOj-oDLe09REh2~G#(pA8T{`Lgz&+LV6lmeKL1Q2|= z{|Go|4S-sEV{mYdc@R_L^#Yt|IU?DPpZXIYJJ)-um+3JHZy&%7z{Gx(WEc?%50bdA z^?myZqbbew55F}w&&_fizIa$dghO7hWb5M; z-%Mq9JMiW3RGa`MsHsslG%-r`oHsrbmO6xr$?%IJB@edJM3su;j0P&9yI4v&EI(&0 zbdO?C8+j-D{D)DJX2)p`Q1i*Yhxy_o5`M z(&PrAF%fr>jpp%NERXW$3JFg&Tg-I3Cz4g~-P^&S*c;FBP1^b76=CinNXudTEX}h_ zNCc0T^ilx$iI@AAT^``+Tu*u2(ljpT+|E+tq6iww5i5dh;VJ-R^Vn&>UccRHV!hp{ z!b6u-{=D2z;0+ zxE+i1eB_f%@=x&MX;rEyXd)M$*;%a&-&Nh4U*oosjF4fQd3-4VrdapFK1f4?CEw#w zpMz7sXb*p&p?bbo8q{fu*2o0FR&cfFmjNpdIO+R|A#(Q3grh}=$rJU#QLLvoTUz-M zaKn8nnW442O86;~0ErsaG+r-+35z!n8}FT#E2udRwHRx`fdJlbzjxmdg>mD4I%P+=#U9F;Gk3q_<&5h| z^Yp8Fh&;h@4hP<6DWQ>Ud|@~Qhz8@eeEqrDuA9MP2qVh2h`LHfsXvWrlpQ~=7uCc* zD!L2F^_ssr(P^0>f3O}Me94yFBGbm;4s=9}yr)`V4L~ zrV=3!%4Le#`#k?m?UO(gs{qN%^@4%iE7S94sXy#k7-C<>GO53c^XnEQyU;!`PT!h7 zg&AF%@|y+$eKvojM$bS8!sdMug`WhO!w|f`vIdCMB0}j$oZ|(UVwP{| z{8a)pA^csAj6yhv?J&;F)*m?5Zf1S{sC@O_W=qMbS1|K8(|Fw<HpL63`YqNY3P6l;l4o9I{#k*ZJd;iNtw3Smq?thU+EaI5*0O-VrO1dZBw)*sPbctzGT;q>Drhs$!!xSlV!M*sABeoBIdri*dX2k z+eF%aR64XuzbA^NTO}1@7jPLu}O$~MWqiv$tL&y8z zC|mt{Vd1fp>v0idq&7Wj7~l7^nr}NXfcNwR)fW1ez}WTxHH~ioV4G1B@HJ&lMDA0M zaQo2Se5oE6&@U_c$t~T!heq1dK~2>kx;tD`DJgpCd*f-;*ub{7pA*iYb&TRoh27l` z)UC%)$dMR7?Tp2*_nv>^Lu*5)F7g|zqO!JzIH)itQlRxo?%cC!> z$OtuXOeG~7HkFr^-*Cm!4%AVU>MWLWsHw&bSLK$};7>9>{PI>*PC_rqC3TK3$H;$O zvzrc)@dZTn^noheCQ(G2J_S@y%Y5epHvz<|?=hUNhh;iB=~gee<0s_XzY5k-?B4EW zubKQq)X1a`ouL+yH+?X{*;@Hh+5WHM)?7)J~;lgqNlXsGa+ifbCS@WqY{J_uD7`Cb(D) zAZ+EFyhw9#Lr|RK(cc$}NO`;g)_B?w^@WSU9;cmlYuH?qoy&SoUB8bm$XA#1S4`Zk z`}FvDhxd1Qf8h_GGUd|;2SaC2G}P^jdf+zi>i`*V4GS{r7QLJz^2>*4y6-ww=~~r#mZ3z1Vx%vBUBKiU)dh z>!x>#o|pd=6C5cg>DcNdVFnIX5{I~eN2mV%#+13bImv#z_H$8 zesk1=>Q#RH^OaHHUYl;LyV)rC(x2uMnKZjy#hl%NTLnE;1%qLX=SOom+@|V!_1`BK zl1A@+JJU_>RMmbcloz8t^D=Mf%KXx5jpMw^!-e?XKa6*5U!?PUYydaET)zQ}C-sAU zA{)VMJCAecBBSvGbkHnoY5B4Sc79=^h2PW1AA?W6sH%)`<<%`Mw@7%K%`u#^M5mHN zdK(=ah&Rn-U)F4YKQQ0;B$KyX;T+O;|lzba~^xh?OYEV2mGXCwN^MVqE_~s6Kd`7{(3X z8u@-Hu<^-auLvpU<=BCLuKh4>=D*#mp=$w!$ej#oc=xSD3Cd#C2OS#PyRTbp?LaozoP-P^sqS_)*(Y zcU@m#K9`*|dj!oVf-`J+c|mO8dBQ_D5#(uU8RdEFC)n+vJVToM*{iODVv@F#w@?d&||~59`(Jg*WN7j!tl9tGKXt z%OC%;NF?fbzTvt;_4GW!o}I-hq&L>=b>2O*WZKmMZ~)fbnlLRP~&^B_yfwy#^tavgqxr8 zH+@A5STtD{N+TLVB8TvFHa#FEvUe~mw{1eNci0Bi#D>Q-r>5E4b+2M@#)+;7Yh1`#iwLjUfc= z>EK*qC1CBUhM6t+p35IjT3BL6f+0M@4$;2L<9n=kJF&*wzY&&fU9@uzG}JzZu}< zbq`nphc;OR^6_DF(%?Rn+UxhR*`rJ=I&03j9=xjp53&X`AyZL}W1Wtb@m-Y+513Lq zUrw$S1l1Zb1F*d!^|HVRv8n)!UmYt{r*7lVxm=l@XNRSA*}VBr-?|d=&cgs=CKA;N z+QQR(2So3=714C0Hyj-+!>eDecP^U!)Xu-_;m!C0HEGXdQOsNFzAV7!Mhn$Pp0Z%y z;#lzr=c}RbSc_iW@gT0aFBN|4T#w{}j+`y14c>dR1mXnhS_`5e+HXSjE59a(=%~89 zt91MA`x451EUw=1cXtk5nUgd4?;2zZfa@m{J3g;|_&&YH{=MUwXt$pp6jazysXN^V z#nWe!GF)W8P|L4JPh5p9$%jh#-p6?Co~Dbq5XK<`k`rIA@FIXYUKE&=oN8!D%L9#1 z5BLoIOr8Yq(Gv${&XIm34{!;f|3LUO`1c;E&Z=(su&>PMR6v=iq2D=;j9$ z6~xi5H-RlOh!v!;op7gE0|BKbHMnNqGg(%x5Im0e8?`)E7|=LTz*w_V1b@aIXjD~Y zQS8H20#(;@dh>;#Rr{R{bD5JeAvf0&bJUxPFZ9#EBm-Z2co-J|-_OS&TBhhY6>`HZ zP-gmqQocV0f;t%?)HH5y9=U5Zk+TEuY@luYJv!(#$}#2rfRKtf!0nEmSN$r0A*J#8 zBAct%*!`ISKY@2n&}31}ZrzXZ<<_z(V9`TbI33#GNGLxW`7r1x{Vbi}fto+>Ydun{#UAD~KT9%QAVH)V{O5nBVeI8^nX~ zmd#lSyr13=-^f*%>=;lH16=s|cg(Av?x;a~pei^KeP3|HuNfg<7TE*p4?g)}iy^n) zixgZ+ifn}nxmNoKxt`omvqi}FIMgU&etG(oB)6BpzcBCG;mEViRflqSi<1lq+;V6H zX&-DKzmkf38GX0?G)KgZBdHVZc@J3CI>3vVqCTIMs#ETQ9WUYP@OV5cjqV^&Zmz<> z1fZ92Q;9~!HL^-cDa@G`?dkGo#H=Rw3pvrk4iXL8ccl6jf$iYrc)s8O!DI@Zr8;u7 z@dASB3L;Ru*cg+2$X@t|(pfi>F)3cnm{j4BI`)862o@O`gS%XfN6VnNu}Ag@>3STV z$HxQEt$E^q(2$R(&m_@DeFZ3_9T>sqdmTovJMej3VUjv_S;ZZpt$;q1d2fdG=O=$$ zJfLt3Q$omsXYKIDBYAfd_Y3`Ia=%dI`EnbNHtCfoEGfUXSdNtEHXyFf;m$imohL@- z6+hwU$FK%i=qxP*isLn$T~~~uI44&OQE){2#jrR+xdZ84adxfiODhnEMELc^eczzL z)C}~B;GPoS=zM2Zza*5d9}i@Y>t9}$|x2^xZq9>;Cc^G=I*0Muls>G0mr6o z!~>+d!lBjtS|-evilWxqF{omW>hzcgE{I z#0!<2k4`AJIc6^G;9Pdq9U(CFlbxd1hy1-w(`51MKIsxx6Mf>|WA(EhZFy#hj(YM~^F`S`}`Ad}Dw3ejsT@6@G{rR!#I(hl5sgjL0uOqh9rB7adArYt0PhO9{z6_`1 zb(6Q@Muj({Bh}*mZQd_rX&o4jGqm}Kx5V|kG`##bmU0o&z?*onBDRV!s0d&{E(TB= z3~kS0zxBdu8Sken(*tGjDsKNfPPEQgjDoh=cD10lUVUf(@4B7)xIOI18(WDD_Q zTY!Pfk<57aNgXT`8j=0oaX}*Cax%~#D_fy5)8t3wY-mF71{qJH;E4Is&t(Vt<6YG4 zfu%!jkj~u)5^sIBQNkzsD<2(S!oc&C*UU7{wYfeMecuiYa}5`&g5T?f4r^xVHDgr*TpT0>fWE*Ehh!17Uej zdL)6)S<=%k6KYDpFy<}ql=PK%rPSgD@q7_bQcCJ7138n;U#~;ZtAtcQbB`eU9Cw4@ z-_+r1E&LHI;%;SC6)bZd(5S>7LmgVh$m{jwLumv&Wl3Mcr< zer1&AS1^Z)haq|dOTlf-Z@;kECkRs!Rx+&8_7;vepPAUM7igD*6*+!>S+k@m*G59A^hvDp^{u{B!owXJFw^!b&I8D}m z%}fsa6w?{br(2?@coR<(O2BWV=Tk&)u}nq}To(4hTFjK2m_t;}uj=_n{#`$jI7+7v zH8ab}bvyCJNPAnHucb8*Rt6?-8YRmWN>FP*U3%KF!sM{5n?e*!phKN91ewKOxS8}1 zDen7{O!fB|Y!!By;&lv%yHgd|O$~cNJ&i?OQnGS#U_IRzb#og+9jz{LUQa5g zC5P4yEdTYxfltetQMx^NrJ@d3z(!=n1DNrupcAITFl3a+}m*)Hs#nLC+->d8s>7x zdY@Xa&$x?Rgo#%&lFzFCBlpMa>-Lo(0!pa_kwD`m{0v%p?Xir@7XioJ^ir$#xa!)) ze_R7SxFcH@C#)T0qWSY;u1{eKpX%X#lW)e2T~Efik?6!*=M{hF9mNY%ZY|H&b_I?7 z%CPGqhQx~NxHCok%IvHBLsVgzjI7;tXWoWmIG0c5gsl@c;UHV3*^xl2jDH0`Mo(-$ z*#Uzozm5aBv@iDGL*~aHPy6#`{<^yN5*qFPQu28oCf~ zXmN{(d=NnJ2u}ekyqlqSD#@JcQx=;WSOn*nLb~U}A;K~|Em2?3>j-oLl*anY z4aE2veJfHglI)u{qhS+cCfsD2i7AmmzaQvnVYwEVi0ljWW!MjFF5yTI7q>%2;TLEx z%@{$b&A8J@MP_NG@O{70rW~@T(DJJMgLUul46O)PkM|ozR&>mi)fDq{9l38}KhgwO zYUlG^2ZS{}Zd{o4I{3AMd=WorZGeG^P#afR`{w~0JW7O^Nt_q{zDQNqK1%ln#~x-T2Ku9r~6s9f%_{*`?_`XcD9!8J67yI}jQKD(4lzZ#(sv{3{y+7aQ z2iZEn!=_iBX#4X*9v!ONgY)|^Y>VE1DUqO5gp@Mhb@Y-~?nF89Hch*SA=Pf@ZO!jL zG>Id;O4!9T9{bC@yQ5QNOe}VA`_r+_R`WM9;Yp8q9mr>f-RIlBRoK;QkaiqzJW+ui zz&mX07pRVGZsx*Zdx4*BiuJmv5U09Xn4w<3n5skV6o%b!I=nCNG?Gsu{Tk;ib@Y$w zKS%Z#&toR;v0$S;E%6Q`MKSV$h^sxAQIY>WUto~}QFJ9!elWXD+V#k}O$Kf%xH(f{ zVIAznp}vEI5>xZ`rYOn!%Gplmdpi(-JuKo*W43#U&sSD6JNA>~0KF{2jl#qhPiPDP zHl=O-Z^PYYpKg&}IYEWV#+r!k-eS_K)`q{v+50aTIG+reoGLygu;~SwWc^LAQhfg) z8iy!+dHn#SD|y>%>d?yk^EVS-#$#>Ds|A6z&EyT6K@LFdZzeW%H1$v};5f+@<(1=b z<{6_@TvI@!>%|g+jUfPx#qZL2b>bC=(rIg$?&ez4dPCzS+BSlC+y zMR~g2D-gg7t`7O}w9VG2xxD&{szi=D`EUfu*P>lR z8*Jd{^B%lo7~XfY2DaDv6Q6ah4lmZ{_gpIV1{9{g->puFOFC|7{2{sSUvg)nMS!EQ zt!KUbhA!)4-OT&MbyEX|KmYLL3C)A5*=_fnIIEr{_ezhW3}SL87l!ds{d@$ag@Jv= z$*0HsK4=&+(r$4P&nI7P{Yb)m4C$|jcbm6pbJ(Spr#5mCC=-V_7@`?+*G$f zUPGqgwI457m64-5XXCo<3Gw`N_3aqvVAsXB%>H}7zqp2rKkr=G+TWalT4^S}!{8)s zSYoI;nPI#QGGL53yEg$o!6qyswS@KQFKg0;geu1!#$P|tw9s88ss5b(NKo$gPx^pU z{T0h#l(96ov4pW}OyRDRYdmL-GCY^yz~ryjNrHLy+tj4i%~_QU3-`7(DMkaS(UUjw7(S*Q46W{t zWi7RV`Dpeve8#lPImcU}gkf&pp|_VoE5! zwq&$tKjm&eQ&i5NYUcz#FE0>BsHiubgWvuDa1pw&5gek&FUbe|mSi1}+8 zyKN4a@Uw1oy@mbX1{w1aI#(nmV#;z?u*81Ntc=u{ZjXUCl&M9#L}d`G!48rcHQ#+Nz-P~~(n_(#_4_-p`zSZZf zh4%^o#8BIyR9-#{ZJO6cLGbOjtE!>oIawjPRv-xK9e4H5=(BpYT$iNewHKdER^j$FfA z7LBgT^LIsyWZ8dxGk?mDj&(rTFe?ze4(P;`Mg96#UEJv*__K}6-z@#S)upXojIFtQ z;5UdQaXKGe^=22-X!K8*Wlf3Ke@q$J-}B@>b_IOYH&A?Y9%+UX;Gm)PYGehExaw8+ z4I+Umhpwg9@=7-gkQyLbcP)wqQsJ0asNU(5r7}v|Wv|UMkps8tE*PUQm*?8V2j?l=)SD zCNSW<@oM^xs&wIw_d8Dh8N!x=Fq^C|L16qOH1qsBiK=p7Z+mGXa?PPG^5GNJX(r6? z`FNyJ!~L0Q9fTKx=!gWfMno65 zp6=|-_!ibhm2C2!A$z5uS?%u<}AG6{2T2bMd! zmPhuB^xHt##`0$NS-5~8x!g6ZJ1J?p5vx;?0r%GB=hk<1JdxWVD&1EcI=R}A$-F!f z>t1O<+NiI8I+IUa1W?@uS66c1reri7p3pCK-p#)u7=HWy{X+Qq+Q4PWrGctqI(;Wd zfb!((*B@qj*Z7ri+U)zyF%_zIiXTGe9N#`ka}vT1ab`TdKWX6Q7lM{n8(^-6T!tSW z?Vx0IGDZQm1TyGcJjWHKrKM7RkmPLCA znU;}$D4mbQDK|Bf|U$pj4;w(KECwl8XNZE#y4aW_c#9; z78P~>6_Vur_7YDZ#xNjV{2s#FG0d9tx}*yqJC91Kv2O;~b6XhxIIQQ0!wN8qsr#P2 zKAm`9@nbm;&qE@Bw#M$Bm4MXnb9V-V?G;JW7cs7xdz2gd+@hGMo1B_M_5n&IkrS%! zDk}r9q<@OIL_hO4d}_PY9s3U20m z`beNf9dzWizx{XkX8t0Ivu!(Ej+%XZzbax?gDFmY@w5w0&y7o108=uJ{iMh1uogwh z2<0u?zjKddaURl5f@UAtS<}9P)E*V8DWl)`qcvfruEAiBX1FHS2OJBBL%8o`CCHnZ zwDUO@_GzuO;--*;P-I#xdTc=&rMuw8;^i{qPJL>BZalM|tEvrJH^z}yB|itT(&yg0 z;skTaKh0MNl)Z!_rbePi31hA&ajn#PnYpp^Q%h5X?SRPYkRcou*VQx zCi(JteE|oI%lZ@=hFs0RmvGrN@{{pSh9cog0rLSo=K>#!iwf~F`WoeW@p)^^oPpy+ zz^|LxUrYC1k>4(r@6No790gB=LOtvHIUtyHe!+VE{0a~24!X_q6T>ALL2BMIsu|2j z_8bg|IAB|M%#TB6U@iI0qT4$nU)U(CK+@`$l?sL3^GhCf$2Nxeu|~=!bAG2n5rKR8 z$|&Y;2c4T0Xp7Eyno}L^CsVcgA2bIe?zxu=V!=F`j?0dOZM69W*DxcGMkkung%dp+ zWJP^CukE3dPW$ig-5qv2hk7d*?^Nwv{^W}QmdE%ZQRa>gh6WNA6p(Mv7U9@R)rgkS zl>GF{^$PsMm7so_wYwpZxL!8n0R3e<=ROZs{JACR;Q(*Q{-U!W1CBIhsPh>e*N5*I z(v8MOpo*yF^F5K{NX5!SjmZfT8K+rbnMz0cHk90jQ@A<(vwL-33htqFT9z%&9;YqMBpA%+YSC-}H z=4Y3*;AzlcL8_=<1O9bD(q_u|T$>~H{ChhoQq#@uSkdM&iTd(gKDih8%STI)(q%vM z-ec`TuP=}u-&+mMUD2dFUd8&otB3DJ0B@i$hzu#*$VLfop+>&g?b!J9oisVFlkf4Y zJLTtj5Vix|-0Inx(#wzSEJh38hfg=sZlmVv255jR&kJsXI$E`lg{kG!&|CnvzFbSR zwVOe1ZqH-dN$vr)Lqk+8YY%GPsC5@( z&j}?u*I1|VvCH2jh4PMwu*Ca|3O?gqBkG1ux?5SW&q9ujyL{}^MHBF*L1~7nev-kw zTO&<(EHFLj7j3~{7)C1eNw(kb?%UE9yi=Qs$r#-W`UV+MHj;gQ_U7|lp{5`Gkn1)- zU?+3&_4F2r@kokNN8xqd9@)2kJMCzu#i58jtinW~@5Oh8T%okg>eu`J@XQoGtozBKuWOctRnFbzQJ`^qmydkZlo zvp$em(DVd=-_xLl=7=YybIo>2J#9Y|HS&s-68KGvkV{}kNU+xx_7{zp@^YJ7n>xko zZ2)!dN&v~8m@<4Ci*8YOVy$s;e5`T2RH)iy%l#AD)LFUt4Vt?seP&Df7-`bb-AF;X zx-4Z!iAUq-YH3U7IPyDQGR8yml)C)$-ZQ~n&34cGGvU+v?)mvzyEX=`M050R^Y$sp z7pvIYXK!EfVn2e`@old80Yp9SqDYX#>c%X{N^$x`R=8Ja_V)G+p%ER=$|+ec5yrT7 zm?3(fxa7{xrGTXo?z!unaWqkwRy}@oM3hrZ=|hn|DOlS)^Uk6yWp^Q1WVS&|TOLnW z+~(Rq@kXP$$=`WTMP%W zO_suqs-s_CvdDHn-$dY2D?b!HNu0Kw0}m?Z@hLxP?v^(N)nU+340G47>sp{y4D`yGPH6d&qO- zQIoUY54&&VFFtWTjE~$q@}Uw|1vC-M^10{ol&xw%qDjZC2YBV%yg#j9Q4lc;8f$KALgYSi>7hSa> z#+EQJjlz8o**JWmCK;Ju%@c_GR2<3sO&9l?`=bfQ#*7M?wTtC|?_K*B)70pvD39z^ zf3E9GI|?Al8R0Az=ro1G9E|sN#y7{Yq}_A*yzcqlB+bL##v4(+kPd}L*BxY4WmSKb z)zp9McY~mj5iA>zw|%^(namPzp=w<}MR=12=O`RhFsrSuS&zP7C$RNRKN|n%U^)HpVA{Bzxb7j#^dR>1v zAEE#S9hNeO3^qNv$FYq$G820_m5|t@>HN> z*dDdWh{=2MeHPGu9ZSO2Sr8(%eW4*pamb|XL9|%*k_DLQ8W3|lTjV3-S9*3>Zv}VL z?Jb1~hKBXj_`OC$#DpNVr_zzBOSIfB91%T}?|PKn3J*FMRD}Xngcx<+?XZT+co;e zvL;ek(G&+c7k|S2gdNgWANbR$z-@&*UVaqM`$f;iOJ{tZ%?{i|XnXTzYkk9dkJN2F z#z>4XY~e5j`hug5k_zYym$LvT&I`wyR310zBJOugjp<#f-y@Z^CDTT(7PvopvR3at zeVyNDFFdGDzfLNbc!~Tmmp6;ivt_CFyI{$Zc5dUWYmWV9*Dn=?BYD2Ock0DvKKE@h zt@8x{v%X;@tQo&%Gh{}R9ep5GuHOWd_DkIMF3^RnjBxi?x6cO>!T0QH-KG1xyv|Z( zyKdcB+#2XJO6M2W6lL140e6k!*Z7_^SGwtHWvEXNP!3j;P`FrbUq?Q<**zV^`ZK&q zNUuO(JXdGx+~Hywulooz+kKW!vjp8-MFmQd{01z2Ftj{|_XpGI$AIqTbk(cR%e@{J z{9HahW`6zK+>y_GXOzEJLz?EY3q=;qpXvpGsQ37p?lYjS0##hg{WoOJ{NXz7xiJY_ zy$b7uU@`%oxV-bw8?!(8hx}ZlZXMZ{3$RPdKL=2hRPx7$7%7^vpb5QRhvprq&$&}3 zeMi(s3$2CzL6JeAVAuCn`LmxP^)z5F)BA9$m5)?r(oZZS@Aef&tIQh^F3E zwvVVXo)8;85|7DqzRVKUgtcg7I8R%4PRr-^=Ggwio(jZmgRAyqLZ~}WReIFCVw9i& zV2x39IR(ZA^LahF%k>d-@Me#G`kC*mNXGylVkT&WirR@fJ?|Y*at7%!Xu-4b@r!} zq|veXaI5XiDNbg=YLD{7dlwnQw|$xl5Eq1MIOtUcmvf_^_7?xEKm}N$Inj`uI0Oz# zpu_2H7>>kt+j{052VQ#3*H#j7^;|mes1nHUmO3;j)n%v4dW$K<9?waoLtbr%&O`pZ z7huRUJ0$~*u1^s>>>DZI5il3F_bceNZVh&7n!u-}2u5tC5FH&tVOZ^O( zkTt!0&u0Z+Iu;|Qr2$^*vE~}+$sfU;?e|$ZO^3BLK|;N5JO3HI8~%v+OQ7G?ciyv@ zj(xwo-zRAUqE8Jnz1KTRT&v*iv|ALO_BLkPw}*HMb}|PYNjQc^tD1!FhHIa^-Fz*N7kc#CA&OfD0>@!9VoVN%13gN@` zwGSt4c8;?hL`@-Qsg2T5OI;Unyq;7qf=tt?hqO5`aZm}oc&b9<7F`iHEYto=O;zcv zyPfnPOTtIbB$9TTm0=O6L>0J|8U4DG>RBGrHQ0NE`~0}nA(8H8cRc;>QVsl^>&9|3 z$q)9ylbwB^i8OTy;Ec9 zx%ruRdz`?Z=QHe~s~r(FlhKqBsL$;7BG?T?Or>?>4SFO|%7*@U!rv|vkoBUe$Z zgu7Nh4_(nrq_N|x&^=V-I3f7nc*l#aAV$lZySHd$3S1WBL%uZ(D&cls>&y$9bJs;T zWhwIgdpE~BZ?{{H@7lZr$3Q!SILZBi4#whg@5=ES{6^@Q_!m0JH5D(kju(O^J@@28 zVWrN97m}i$CdZvuUDe*BUpRR^7a>;crR8tBUtWqgAKJ3c-oTxu`yops<8(q7_2?yp z;v7oEE>^>7go+x-!@*1=6gPA#Qv@VW|`6P1Rtz}!7Y2k}*dSy73naGXE`NLEaGI^AUdg?Y_M zIqiSsZtA6J{CyNC*T>f>T9gc-3Kk*4>$Sr5Jle74V+LeEM+Sully7gmfG-p6rQ8rn zO7tuo*79{~eea3IjG3TOE>8irY0mjBF9(#0-}tx*?N#hwx?X~ zF*_5HKCywl7q?5Z^m`uekxbY@U_S zwVd_o9d{sdF4ewNNdt{w_(w&HR&8z(zsJkNS95O{ZO;;Gq{&cbgZRZ*(Izq;cA1T%L;<4m%>XaGkr9w?Fqm}8k?_1g4 z$}nU1_*}FAx}&+A&_=qei!t(E4^O>3=+k?6tUY76sDOwM#{1AMM#9)pjq$IQn&QE( zXT(IeoB|K3j5dbzcydR`Mj!3Whjw4er@j*l4C znZX@Rgyu;$eo>ZIccxF&>Jdn)y>1Pv;1}%0+ywt$Epo;gu(&-?22Qme?l-}S4~I72 zEuA=m(_YnbN=mWbi4W)cNi6y1!hIZ-41k4SbMr5#A1~n3yB^y4hexu8~TF9h3|wqi476ZZF9*1(9VZoSU~(AoqI~)>dJXXU40= z$Iy^9T!L_>$u9oZPspYB=iST|Vmd!iQt;1^Kt+I7&So0vwfKA6hXTdCU0OA2e1`+^71Tuc@u8b}R0h=6+?`!`U9^Z;l zJX{>Rvq-h|heXbX(}Z*7ucwbwb7~tE^f5Ov4*^hWd#t;?&|A!QfS*i$WDJM2-GQno zIV9kkH-OYQbK}0?-fOeqSD7bid0&{vwL7`k@1Fl?NpoQrurN;yq)UjzbcMUb=wa8N+GDS(cCb20f`I9DkQ0y|Td*+e+XGB- z#hb*ZA7UxZChf_#RqA}tbbqdtJG1Zw=~F#y5ZAb2=Ovj(U&YSn0N?iIcf&jyhZpK`7LZAY{%O|Mop#&Q@ zRhUagy+_}|7<^r3u?XLEsJm~ecudR!s|&1vqo*wG_UNpMjoQ-v-N)L#d~@raY{1<; zck8e!pc(R*tUugyFXlgKINwmgGd=USE}hRLL?fyKDox~UzP(!HoU1lJ73$Lt)Uk-uwfLt+vD!PJ-%I%*uloM9NnB@H3JY>l(nTQtSFr2`Mr9cmjm0|YmlyBcnjeQ~O8oS)R z=BLZUx?JB!?t8#*bASxeMhvU|^)j~b4K6Ja#+j}&A1FX1oh*yQ5Tq+ALWl72N%ijy zX$Io>EULrzkg7cvJ*9bJciIr5kbFeEOyFOod44hmIOyj4t$j`9?a#L!gTk2cJA z?LBX2Q&OKfz{s0FACW>a7gn#lw!f>#6W+w)oH5~RkhMGyQN)oqH;~G14`?hlw}sNy ziua^pAoz-#*9()bJZe-(rWVkSwT!4-%@03bBK)^G((L(J7Fbl0zoNl}dO75FkWfFB zFqrS1Sb&B?yq&jx&d$A~SiO*vcT)Y+aL7OR{&bgivJByQh#jz&%ta(=N)(U-BJO}f zg{MGS%JNPIfP;bg5=QNXv}vJ_m;T@%%!n^ot@fqDgN^W-Xv{^PHHJW}@Ov4k&uRk% zm4N;BQdyp)L_qT%;{k<5e0i8T#1qnmH`EAyIdxD^;k^s5gpxtOMSN5j7ZHM&ZvQCK z18c0E6_|c#3w~$cYb3hH!{UiS&IjLe<^v{fgbvt}&ZTBByRf|GWp6ZEAP*!Y3YK}f zS>8wY4p4Cu#*Cp=ibp0`U7|4IDeB>o-2sFWRZRU`uRmHqoNC{ie^+1WvqyC*d0hX@ z6#Yzl$rNJTkNiIWSeN*1L|W_n_>YXa`MT}P>DOLIx=NcZ{#nUg5e_vYX|qyHrvRJP zPItxy->b?oz7{plplhElWr%a3HuznSfDULNS1239)=T_Ec*^E(SN(#wcf0Q?o|bPJQL?FsiH?^Cqi<7#_{w%K{N9r3jPP=GP+ik6AU^u0tI&t zNp5!XE(%NfhZYZePrVa;+{;2>O%8Kd@2CgMk6$~{6gi9p)l@>g3y8y@8|!v7cG>Q8 z{+tV6-h?B#(ZCLwwskiRk4Pu~CL8>&xY~4LKNO#3?uD_U#sg*IQYE$MS4>NVS55c^ zcB~s zxq)$`l}pc8w=inS4$*kLi)r}bwdxE^^1?hn0O_Z(MD5k#CWz7QavJHAwz&3Ys>>r> z-k=~9)!D_V!^RC~_i^ zzO&rS@5|vZXi!~|voo)5z+a$Z7(^mpho5e=91;irC_0ZWWwkAe{vaBt( zp(IfO$?)rIRqKuM#tq-CQaEStwdTYQOyW+>+Dh1qeF_?dJ^4+x<=!DK!4`Jn?$nkT ziSG7zW6_V*B<}P3QDYDu(vn{z30)%}cr$&9Jsr8jJ~HI8svXU6M>qk#Te*k8mTabbyk3qYRqQNjO={c=Gi&_W$LnYP%=%P3 zZd%5pBjAUv?2(5GJf*Kn(gEZ zJCVMP3m+dJ*z`OQbwq5-y59GMJJ>PZU3QyH&U+d?>s9*gCe&rn$2Vn7po#%HK2w7R zVE05q?KD;VyFtOhgrq)qeWBPT1$Vf^LmmnwCbi!iPH)eWVpjGuw~IObtCW{9KJn); z#Gzt}P6d(mr**n6Oil)PQvfR+^TN{{j}w9t=IMsu9Jf!Tc#rAaiSbm*4DBC4r_KdE zmt(*b@AZ(scE{5mn{Rd59h2HQ(LGxV%qA3j&>TBXp@evnb+Q1;j^p09A^Qb0_v;1! zDv(}AQRG=R*rUd6E#l!ytSUlOeDIuu&k( z;hOIkvS|2z+20#Fz#+9-RMjYql>N6W;O@JBQy=V_QBDj_=BXr(7n5bK#UA%0;z;Eh zqT@8QUKl&_#NPZo&Rry>ds5~;CYWbEC$z7gbDt&izC<|a-AE2@xl&u9A05u}?eXo} z_dsipm|LzAPlRHH&*|rUkab#~QI*ApsrAJ%(_YA=r+E`14*OQ8cU5Se5r`XxS?=xi z`AQjRxRHFOaG>j4k$d&ersAn%hKU32;Kfk8Y1%)v6350t`UR6&oFL^;e+I+O+~MXV zs_L2cJQOh>mp`ZZg`{Pw_)nGA*DF~&y{-~vW9FR>|0(}5OjDfl$7NKz z3EQdk>-L{RhkCiW$5=x6IPGVf315QsNJO)ME+d-8cy z&%1d%z{2$Pik$$gWSlhvtzz~${Zd*f?C?j!A zI#A!pwMqU2ZVI!F1c|E?6cbYTx@Ehp)j!EU&A?D4ldA&uHr{0w7TU8YUKR%H{uVCU z6VTF@xN$fcn(Ol{>`gwV4pNT6w|#St{dsQfXb3-dh>GuY;rvSF;Z8%z9))0$oS@j< z@aZm2j1&kJ3W12sZ)`0)>0lpOL8&hJZ_qp&ye?`whuSMU^G`Ays%3G@DCphW-9vQ} zbh6VRp@V5tlXL;~#kEx7M;5cb7`jz{+|-63O!0ir0U%zID}maAN78+${L%svOkSTe zWODj~DD6(xyyD@g{b>nb$3szUq5g#%y3#r5Na+bj* zR-4D^s_fyH?*Tsl37#~CSuTGY9eP&*!I*>xt0t5}@}~aE0sF2^q$(CJP()w?Du${c zz8q`yxrIytaVE~k%uGcSlPdzp@%*!+gIaAi38aY^3s~cFeB;(|!LbcpX|X^@n$F+m zCk_!K_C-)v>^Ei^))}}S;rgG;%wD@P)~X9Je_NvMetxY|ZLypmm)NPVs+0PFis$qd zvS~6JOK9B6?lV$TiGawdB_KuHT0h&X*H0CZebrqYvCtwDjgv(wL-!u2TEOvXfzeGn z6m@C=Rv~#vhj8R1xBFsOK?fwBU!)32llk5KT!kj=+ z`AVoK$+z%MI>CiJEQ?O~6vjZM39UPcIDh}9*y3`|W->jeF)cr{9;P#~LixH(AiZXyBDkapOz-bZd9&1Wn>`b9dm5ywP)be-s6Y zFnoTK6tUrpspXdd=huG@&UYEYD(`9jtVMlG=_FI1UGa3HXQoOFzZU!aegby>1r|*j z_el2D@bA|2Jq@``TK&b)PWKgEMB;NeqD>bQoM`0ggDZ`lx`4G%y@~^}RBNwu{Ju8DVF1Fzw>Mf2ycJpYN271bi&8$GFfbR6 zaZe4g+3CH_a|1pB&l5?%Nxt1~(P|fK$XvO|h@qu(@@71)sw(Gjkm=?7#-oCJlDo)N zk_X*9u(MO9CoG0}ce~QU%9O-dGpF@|>;K3jESe@Zjd{!wL=^VqDOB{~o5eJ)XQJk( zSApuUL4lC`a903mTAE3v1UW^U2y! zvdn1t_&i=s4a)0|zwil4c$B#;?~T9R$fkr>5toIu#pvji9ENXHBiD4ri<^HoXq9b@ zwF6Z8CVBk%_vNJi5~-|sQC@~L+OG;rKH(;y88{D>vF1vFVzYk6pI9~GjQbY$oLd+F zA8y!pqAaXeY`LP|>hSHD>A-R)@$Jniz!JL!&2K|yX`fLz4h0-ODLd*KBlP{*`RlLc zi_z|&ygQ7y63X-kJUsBk8OL*9S_WVNE16Ff#KlQqta*U&> zUol|eS*&r*^_2IcNUJNFA5ku7)65EBr+Qsw^ZPNKxY|GgI<2159H zFtZqU4wWX7<^rF~Z@wPT*SS0n%a&`EuhRL}s7~Ff9?{@|_xha|r55JlZN=773vrnn zR;{R$lmBk}1I?kwvIIziU5mJ;XsTupR~!A0rM$IRF81bOVWHKOWB{rr5rDOaBRPbW zC)TY`8YMct_mg~FF)C>?Xb}b`vdZQ?w57BZ^fnqJV)nW3{3PfdCs2;_%mbXah9|t_$T7r*}Nki<=2FnX2GU7QckK@|E9d?vh#2a z!(IP)`-Mwx=ihLUT=Z~Z!hY;dS!fDklEw6-32!`GbzeWW7x9?r*Zla(_i&>4gu@50 z&Ye%g$s@lg&niFq0$a|UuOT9-!|U`7ZUwj#xWm%_WhDHVoC+gN?^<)-C{96W{t6dn z>_c$yM#q=AH zSBO&{04>tEcL}QzNO7?G`%A%n{e8QwN9`+5)1K1Ls8$}HF+-c**RVSyWu6cl-?+CH zsRJ>{+K)y~DEzXL}6blh%_^8N*u@wtnO46A-k-(8yHK1>O@<8EZRC;I!YOdk?9 zJ#MEFqoO?VKj$6m`}Z4xqrZNlCIw}Z!FUjnE0Y{2<5>j*3%HBt;Qa z+M3>+K8LTxYiC(|?o7nRmh*mEViUCqcq_{0kZCY$km7aLOJS7d?+KgCDl@Tm;*w-A zAT)?#di%8{QT5r1aJHHV^bfieX-#E#NoNji>Dxw|2e~IoKVfD zRSYX_`c1SbSCAVl9{k)vtDPzCZf9HTZY{7E=DoZkD`Q z$RH7*3P;eqxW-^%496ztl&D4*eu^s^2XHxa^X2Qh;^73%C(T@LxJT|o%jL%Rm*%4; zuqwKi;&)9a)v4`^k#Z$XI0uC>p6_|V(8~23ng_{wlEJM15U+f-@0s!`0^scF;ADzi zi1YJse%h%!=SZHW%Q$8{Op!7HH&H+5k7#2E^M0t7hAA~|SH1wA6`wb#86~VqzUgCP zidNX?AT6=t(qatj<9;pZ+`XYD?X{J|T|lp}uU;X2X1L5XV`2M3g^_cS3@$ zQYP&_CFeBO#@8gmxh^pBu{|>iAFtHec5m*fre53YOMvxJ0-(5{HS$3eOFD4qBPfsP z<_ySL$y0lGi1Z5lAfwTpB+(*!Hx7dix7!#NFzOhldbk}qCL=yb{akciY zSwi}LekmNq=apsfSH>Ud7#b%Njx*AK@*h6CVm$Q1Ky&;ZKfYMk!X>DvDDX39OO;Iw z1H@3LIVhQISTrqVEcP)T&|*-j9UWni(5jt9cb|58DDDOjU<5e<)E95#%wTDLyy>qG zwU$<9hWhcGtN;OIiVe%ndDoG_4>CcMVy4rNk%Jk7xG4+1IY4Q;k0<3^CjH5mO9Yu4 z`aqu3cFqs)M1^%{rBUg=Jknd+A0qn&yvs~dPF^dXBM0^Yr2R`jz7veZ0k4hERHB*@`x+nc|n`!Rb9;@{(iyc}_sAI%j#}gYCo&Yf1tZ25k^1t5wEbiZ77mDc zYNu#bx1fgO{7a~6h#vO~?1?JVMSK-nQf8>}A8)r0D9JrUSudP-3 zF}XJx>GM_w`&7%7=dZ*hR3u*a`agPgLB2A1-)4LZE{td9JRL8Qwp%7Qec@Lmz12&Z zSGp^um|(AR32$^D-LjXum+bG-X}XcE4Ndo>%j9E6uMhh@?UZvNc~*81P9P1vA&UdJ z;Dvm@c$*^au9iI-_fNLDDTV0Kz?1S{{i;Z7v5QDg+0 zy29(TbTSGh?4$qP$`IRnzAEObF<&(xb{u+^`!V2a{Friu4$B1R2tPVh;>FLfA~y|` z2E2#v23K~U%2Bd|5prk5Ao>21jougKF8tv7-T)+RWdL`D6OfSSVvP=`z;>c;a`>)E zaWCkw*QPP4#j@Q!-d+4h8JmO(_r&MgiAjK9_Vk+ImtfsSA(G?o1?XyUY;qHG2Wj$NnKJT>*qPu?m%C_1Ar2mk z&uyaK7A#vZtTbZGRn+GsCqRf`F%Y@!;mejbqw)=APmons!*hCO z`E*!ixLTQf4u3pqkj53olzD2p6OVEJ^)emupLEUL7^`fPZhyp;yFGX%J)h!-*dv`8 zsTLy7Y;x>_5cXtodKVnPyvNSSa_@Zazy&bzHCqR+Ich8*r612R-GlucZ=WA6NbTpD zlZ@#XL>oT@<-L1F4LTZc8XxcEK8C7&4TJmHXKD?{@fOB#J_~PMUfi_9&3X=4DxhTS zl>GAJub){Sem|mVpLenAFzZ#qr*hUWhZoo%j$Po$)KA)|{%bM$0Nu=R9)R2lUV?MB zsB-;i*M8NyTe0_E9UiHa1xTb#OIJh)ZygXUhzV=uz-YfNbDV)=jb@qx0)=i9j)3)l- z@$`n9qrT#}G{*S5-o-W?uY~dx8LM17_zjHbUd@yJzyf$5z$fq1sHikIK1ZXDY4V48 z!K%^%8-+F!hc%b6@f_h{?S6(+V&dzCJSY}Vz`12-+?UkOLqq>^jF#`}A>wbm%OZjF zhi@|hp49s=zD!DW8LS}j%<;|`SWoL#*_iqct;oU;Kh$=jP-|WJ{XNcQJu&dY4VBv# zv4UP`=q(iN^sgt?bs8aIvw3DW_HkE}{f@^78~f-dWaD^>9pR|dUplf}2Nj1QOzk6t z{G7|fu1&}==2U8xx6iNC%R6z4KD6{Sqs&F^rBOf&w%KcQ$>mr$R6rU26payCqQZgW z(pnYgQ96q#&+h)2Jmelb)KrO32j6GARrm7&!>`}|FkaryYH_X7P%!{1jyA7lWk&II zDRBz(39C6G(D<40m&YSZPa4)=O}nXATG91%(u}AG_2W2vp+1o9-|ANe`0q0?S z0tocm4{PLFhG@Xe#}!ev7h~+c3$Env5Ck8erLDgb7%WUDOn;?^*Q`mXCgd7-60Y4z zLwn3fVFyCCWpdhf1s({>ovAc1BN_?+a=xVq07HgW@Mry|dIIa7^43BR^lC(`G0zX8 z&86>Gl^np?a0~eI@pbPPm_Eugu_NjH0@2v(0EnyPis$AXgiQPpZSVoqW2RJ#WR z+zL3g1HM^MLs|^4N=)*=E~X4o%wq{H#oqnrUmJV=HB$z0yIare=a`n>?Y_z#DDj6J z)E=T+{b)dWEhE5FpUqf(UAIeoq|&68zFcHX=Oh1mG1;_(q;=u&5%p{EfshI3axx0? z7$c|KV@E3tTy%ST;i>w%UwmND>9d6${LTPa6M%}5Iqx#8m&aiDir?8jO0-PE9SPu# zasBjSU3{^0O{VEl2=r~(T@QF}Qg?^9i4skE*kaYZW-Di}{-db(U)CxI zwC2tZB7h<@Cds)2Tsu17=ey8&IZ&G9Flwej{GO2{IrgssTIi&bWl{3JNPms!IIp&^I72K+F##Hom z1&Qq&EIBe{c{u^tU|*b%MgGR|y+dcwC=0p(5e25~2OtdSq|QvcOQLr>n!8ox9Pg>J z$>Hs)c@OuV`KS(ts9936mI~BOuM=5J2R;IcI+g{h1-mzgyvl)fl|nxBMkRg^D6`0c zv@a1D3vG}?!vW{8mZVh95r5_9M)Ub$r`dgd0V#&F@{)}=?GO&|OGl`h*ll!CqTHXw zt9{2#@ui!|{`Pa7`g4DG)9-8tsXHwl|2{p&l`W+sd%oS0SuA&)NiGB}E&-5i)ny2- z7Y8Llj4s4qafS?pyO?oX+53U|)Vy??&B+$~=<_9x%V78K^kBM7_@3w!Xo>OzBjqy+ z&6j1wx|jvSi_X?r_30ij#uNU)Zu^9XCpH7AC+F+$GA(aB=a%oKx)D4nN|k5M|09Zro1&_7(N`)4IFcFVI3 zTRTYXpzPQ>C%kp&hPe^9TY3MuWI%@s2rV%LYRUA1IUTLoM_8D`S*0q9y993l8s#A- zvvR$JW%|jY*R@+M;XNcM51!jp2`=Gw)POa3=ASn5w&4B!Vn0gQOfUJd5$cYx4s_&b zPxj<{Kbq+(bS0!W%yAdIp29Bhqk-|r%+o`$_9 zB>d~sohfZH2&t0mTt^Kq*?8--_=a2)I5RIP^Y+j;u@7^ex?EID;y21QU*2gUY2rzw zi7OP!31F_Pj5-dslfb242QxMcv=y}g&to?1FOPRz0`KcS%EoSgf@7BBQV2`K^NE6i zg|`z}wY@~|{Y&S31|3ge;ceW@o~S(wt6TZE8o#ar!$|p(K2` zLs>LYa7k3sl6&s*ADWLmo@Uiu8{c>qtFs`0=j9NTPdFHYtzV3VM1`ANiqbt$AR@}w zy0K1s&_A^vAvZf=#o@i*Lh;j+6ut!Y1sv^ra|?t%oTCQwMV&XrZ}6P2&>DPeD$~XT zY1P*4>v+*=$VKaBQIUS8^J(dSIu=>J*6hivKm1DG-E*m*-|lBXQ4R!&1owkQjE2G= z>U-GhQvwW;f8gFm7%-+DeW@H$dfuxB%s{Y9Kk51J$~=%8+dF#)qnnPR&okgQ-gLEB zS2Kncqfg_CZ9MKxjGqt3Y6HcFw67m={~Zs2E`5hi{JwQqi2T;KvK*opObr#F@RPM z>jhKTAFTAQKEbbeE}x)ALU$GhkD+K*4zJ{wvXn`HStkX!laX_^a$9%W)t z0zD1fS*Z&W5sL(=k>*X9;CBOf4NE}lah)5ZI1`^HotUc;$4A z_Zyq}+xz<5M}`;=9DgCIQ(dvb_UJo$FOI@j(xs@!8e2$P!=2`B@Uh2SQ)1{J?a$tD zshTlbA-afxufxFYtD&GO<1ZxxRAZdXyaunGTA(i+$Pm!R2NDgJ(o@wzd845--?{Wf zd6IEfjF#>a5GQ3K0_3M+CM(?I+4=n?7dAamQJ&}LBYVe}J`BEAqdXd!z2-y%XaI5` zzidA6!Y%s=)u9CPQyc9dK3@3w_BE~nwbOHHZ$1H(@oYg-uM|jVry74NWPFB_T`ZK8 zcr$N~!^Ap^*Yj`wa`NT@l{EmLz1DWZ?jq7>-*{U0pBi3waidI#7xOt(Yg*sO1-D1Q zg6N_8gE3POTh_Jq0S?Q|uD*V;41Jc8{IwSl@Kj1&2Qi(d7q92rp}$vg#>AuF|t zh|h__UG`ufFeUB*+q^&L@0X28Bzi|4>CDq}iL(Octasaampd-8!VP+tmpyc$QvYtr z@;+~{aI0rUygJ(TnBL^X3_%n|maC>vRV zCm3U}MFGZd^F}VLt_{6JU(*o`nD{xpnvM~^)0T*(Vb*uAT_pC$kOW{Gh$+zZ6OBM( z*C73?ET5qxoWMj=kvc>&gY*>->YhBb>(zby!uvyc?w)Uz#A;yW+IavQ7bfFUidpNu z0!wO-wmfjU3$DW5xoiaY5^ak)86I%-Ao1{0(tAymqYl@EF1O+HQ}`6MDK_p zJ@VhpmF7czI~T2KN(@LNB|pt7L~)&%-nr6}-#;DRhG=m68|J2)pWd+r|B|$@1FD7c z1TnJw&^xiK_*g-GS*FX*#z@}TZNH!R@n^t-R@YS4pNW>QOa?`ak(7i{ZE^AT!u|_Z ze6#OJ8p=a|odd)u!eVzoAOX3yb)U2X7zK_KBKXOBNLHweiXX0E-e>V6 z(hutsqwl~zPwRc=i%h+JT1V0DR#=dEV=8C(~`Z0AwV6XC%&6`U^%VuxvCFvTo)$c*y{&t`RpcP)?EMeibA-1XQC%kD4Y{2qyQTJ#QGB zGg8_?Rf9FsmPyu_zt>A}S$;me>r*Vo5hci)-_PQ};T6f|$!!NRy=cc~YML$52PKBg z0w5!kn0VBI(t1MzKbWVK!WXKiT_JlRKcCGLkjTdZeyxz5!dEI`{Pa{UqK^6Y2$#)E zpvpZ(e!|O62|pgi*?>1c{Qj$mMp`m~UXGfN41539vS*orf@Ibn5PtxBEwT>-qj)_l zC`%_<*E-U34xB>({YaJ#H#YJl>$1=xf{M|XS-CFDty3xdkF*YvNp)&FCs{isrEe_a z3&VUAU*`{Y8{HL>2sF>#sJ7o%pN%@#4tozrk^GucpN6ZM+oVPjjuXe?>G8_<`ov+I zanCEqANk7J5Cs_pKFCj9i%Be`?h;vUd<|5`vAT%{rUT(S{;F?|bieSJlln`bvjY9o z+*2nvgh&+UEbz?k@NSt*`p>i#fv)glWs6_mY<b*GIZAaA=bT%h9;EVKkEn}N_ zvbPY}S@V|ZK1CT#n_7x9y5df43U{sdUFa$et3l(#|tVlOmupmd+PH~7`5q;IJKN&a9A@Qo) z4SVbH7l#+aqD=30JdBw3s4ccPRgG7)at2u~-hnr=(5My=$hW-WRgR6l);M;mn+7`W z*>id0kL|trfj84+$MTJnA%pD^M#R??p2ER_teZG+}UTn9|iYjds)`(;Dq+{%q+(U6oPal^=s@ ziqlg_MtRxCKH0uN$%eJ zVYmkpjNtC@sDej`mZ~Oj%EcJmq8v}HstA?HG&pBfm-jvf;U#z-h>whH^Fr@GYac>< z(Fb4d`F(5U#U?nend@^m4Xw)@|09Y*d7vh{KADAd$m|bgZ%cZ*kJV91^nB=^sY?qc&pt+m&z!o2rZe0#u_!zkAQfWSnlWc`?(Lw$B%A)Iy5^!bby(+ zl~L@bT~_9O!99-xb3^dOt~R8JbbabZQ_EmR00KOh=L|sK+yMD*Bg*+!C77n)&`JAn zq;jDrgc-w}uSiG@%4^`wcy#5lOZqJj&)00t4xdsTeZ4{_B1Bm@41gfZ=~*TVtPw z1Gjq(Z^goHl&q5P^MNWdWj^Z6E#S}X6CpYm+P}CN^O)>oo>TZ?K0bpKZBOp(?NIGJ zN^tGI0|x-Q^POjB%969{wLjCr;adrx3nl5wjoqID#san!y^{pg%} z4t2gc@6WpBq_ca!0h;FS#-;xqpDMA#!y>a0wnnKO#Edz-T-a!4y)gbEcnO(Y(ee#s zBt05X`YyP~;#O85aFP*WwaX}4cYTldE~T;?{4zSysvkJ$BizzX#r>6@-*PlvhPND) zD`v*@CL^lNV5zWUz{9?@h@0+of|vqQObzPbi9;f*E7)UBfgEp#MEL=1Ipc^mRD$y$spcnCBGB@tRtiP3w5XNZCg~@CzfzOX_MKJ+gH039UqTi)HHC;G> ze?})ovB-NsEWGIyf4MC#fG*J{rj@L#uY=@WkamGFuJi|ZKT_dB<5G!q_vhQi3oaH9 z64R--f*6c(c6NaaW-vZ(arW|LCX~$0EXGfYO?h!vwZjgEv(W`y8%B7^q?Dn)bVGfd z$DBUe7Akv)^E=qELnF;qN2^3Y22--WUGjRUw-_*7ORUEMIStR?KD9rB&zN3oNi zh&b8p%BhSl|Z7WIIK+=troHRtMlr<`i0N zw-5C`(V%e1+Tg+I;wzsSh1&)vPi^D5F3@T@Is9m6x02O+uC{CTnH(icEWm&JpKx84 z5)b|94!h(O&WhiM7JYF;q|kMkOe)hZ7^qGr9LEcaS^{xT{4MjvNA z>y`7Nf1u{qIxqgeZ&`z5TID;;<-Z=XxLo}kq!=~2HpGH}|ESyUjxV4gB`V#fXER`= zkf+BC5UF@=Z#;Qvc^x<>ssL#cc?I1W{di~D^FQ&7I|z@tp;U|2%Ad7Q;CIp>xfxdM z_m0ypeC$j#GW(Zh>0x^GNt$>T%cMScvSqX3>2%<)-k}>%)5J4hRA|wCBlD&sdzYTw z^!>xDM!Vln@7Gm-pRdtXU!!$QjwQb2?$vk<#>rF9*Yfwi>h?WRrK?;XKl+rj_eKuF zOd+)|^=7MRcxwkZVhO%_WvVHDXf`30zL}~s20(9hrn1Z^_vvZgHfX?n#wx~;x&_tN zemxHy9{@1E3V!Il4Kj}=<`!794S&%=0P(oOatVFIj~KGvfsv;@_re@(o~!;HK#DM1 zsmt03QwcSreQ((P2J6!*R#0jJU|Eiy_CoZPAp9(%lz3?e5X&CimzSWT%wLxU^Dh{RF2qo54Gn*e-74@QTmrc!R1KT$-x2H5to>5Wj7v}6T~Vk1^xSQ+ zpS(Q)3?azp0!rA}0-v3W!;Vg#&mL9IR2sZ!5q>9uQk8L;PlzeWwm-y~&B4_J0+3$u zNAb?w13trOPJe_U?5FuCac&>>#<^c_4SjmwzL%au#DDWihuGdxq=&jD4Uj^j{axnL zLBL30fL1z&$1=518k=7G6LOtD2qQ_5&RmW` z&sCZ=Dhl|5Pm#PjT8i;Vk27db9DcD~Lt8lB%@W5fdx@UK?A&PtgbM~#n1vs7L3lW2UEB1GC|fA zXT6DR2!Se&dff}G%eVk%43VGORaEM^d5=8(xkufd6GG~qd*$zTYufqv1K5J+1nc`d ze$VX_d;Bx@5 z-kAaoO^%ekeu%4M?5?7Ic_+;>y=;vN;>|}16^D6Z&VYyTH!vaERrNQ>z0}5aJx~vl`~dRF+p+sI z18^G}UHEIEjqMDK8kZjyw{&^ zFM2F61vncZO5?yt!|j+~Mvd|HjY}@T4RY$`t&qv8^?+4mnuk^}5ibi2*e2(tB zW$UV4e;vE2TV+YW0nkw}9nH+`l*wRnE~cHclzLs>xFGKvH$8LUJU9CzCmCtu1ID=r zPTrlv=~vd-v%igI3%)Q7Lj#VoGly@tL1xmy6qE3^<gH1ep7KEBM7Gll$?*+8F7>aGM=4_O7{iB_EvY zcq-{^X3kGH(FUZu<@&|JK-2i=>kp%Mdl!dxT~=pyh(b~Lxq+g0g3O9DY^68m#pS@T zD-vqzE~!E!^P5=s6r?9vmZMufk$SYM6}_V4F}+|AZqDWdpoylulpQIk+h4z_|P3v)UU@Y5#(Y zy?0t2WGt#&fCd^b0q3c)XPg}=lcMfZ@moGd5}WG_uko$Tc;N^vmWxLddgkR}pj?{l z;8hCw>GDg0Uc3(L=cBdb(Z?b&(oHUN3Q3W$BTme?My55X^7~9b`sj)MZnmcUnkUNGNC)8v|cQas`5rH%Reu-tU}7uTdZghpsYU(?sVoK=d+dInDT z0B$=!w!6N~7bEq7Hu1iMJy zg-(MYgSBaR1RMCRgp>!tf7MtV^S&2=t=7@pQG-i!SzFDFEEoiPwb1)2u*9vW4fL}Rr`SR2qt9SGzhr+Lx%N#vhxbuo-h`<6oF$-)9|gzZ*H&9geyF7#%!aK~rB2R2zOJhj`_Td&iTuf@;-dH0V`cF;)TY~ ztJ4qD5g0Ix1fg9R?h+lLt>J4`y(*_bw;ptHJp+8Zm%OX22T{z)FC}5g7aNnT#W}&KZ)h@ zmGkXMm#CTgJ!yppf|9hBOS|D@s_bFRqSnVu0+UDyNg|&1PcSb>M_1Q2h}gWkKVl<4 zM$xD%lhBX3u3-F(%Ol8tRAa&3(iqH5~u7F#~dyDUOexDW6PM$w`aBNL{QjYcN;Xdfrc*P zv>WC_kUn-zj$PW@S*sXVY~=k}COgsCDU zJ{msEe8@1mdRzbQ;Wbu(c@^9vYXBdQ)5=41S?_v4YO_!)m0sj*PHePEo_c|DE^=rO zjfyfjUQru$nRURESmJV6SLDZ6#26?|RXw`G4gTRw2gY@jjC%hnF{y|fn!0y|=((?* zd8Y<3;}p?_%IXG?H@w>FbVjw(AWqFeN%?%Yvm%FS>heBG>YFa;pMeS4ww zN%=Xx$i4BDCGkeL5scv94a zV|4Y^_;K8IpC2w~ubKn`F-xp8&)g^U?;W|G?__fqv;ARiLLna^V3=z%tle)7F(H;& zr1<476z?AK(b)MI!c3Vx=%@XP*Z}6pRZAF>owuEYcmU3CLSdZmfpU?2pl9jWYmM`A z_UC5{RN_$O&tqja9joAsa35;i0f5W*J*-yd^RF{@7Av1yfeFj@-Bzq>+Qvj?oS0l= zpt`TOobHfE_0JR4lqH=W@BU$Lqx*DkpuB-)4?vUZ#Z}53NejsIk}wKxL#n;*KPaew z8;40cGO}k;I8F;xD`$I<{ZO4p@es8Np|!D2c>ISBT5)%H-U$x^R>$uhd9%i454>cx zQl)q5un6ujur(U>^}uk|2uJ)<<&t-RC3<}2$B{)E*`xSfY{B;f8*Rk$H{90QPV&|r zw8;$S>f1qzO6o-8bE%exmx!*M@$!AL8Z_Q`;Z|WN(^(}DYzgJ&_rm~( zLA-phoxfKx(iS8&sBD>SHR7rguky~>M<2-+Iw%Oghxm z`D1_hCjdPfg4*`C;uRE!+HdO$vMliYZtAh(g0p*KV}X3_!6F?Mdo5JxkqLN$RKgyv zq6TCb_p>z>KyX-`=KYQi#pHC{PqiL5T_9zY+7Q0C2Fg3xifUNY@L_gJ!@ZUr@Vs-U z@{U&a`zP3tw~8e@oqEU1&)si6XonvZ)00H&9hE@wjQ{GoFFYQF>`gAJJ|?9tUtzz) ze$!i^o{0KDovZQydKOE!lBKN=gzG<&5tSqYc~%>TE;XEO=}Es*=McjN$q&zqy&tnV zC;F>ny*9;rCNK1x=S|&RWb;O12+=;~KHu1Zr~Ploeu@`^IYbi26zTY*yp()qQQ8eS7Uz zpi)q)Yk5x2Au4=Ek)Upqu<5bcCgX?O2;)pHNCXure@IcvQ5e?B7oE4{`*MA}4_k3N z%cCPv6_KY4lNJ5jY3cL(Cl(Y^x~}&y8Om4h*Ct~fZV^gRGm{;zW~Ay;wf6Wv(XZqr ztUxu|I^0CCYcIrI#-(e_wzDi9t~w|wI8P$UADka}rlK=(^d>Lg_sPaf9hLM&wD2~& zJqbE9qYs#|;cR$tok~EQ-$R!%uH8#Y*YaUnTla%E&;n?TTw*ImtE6{?_$Su_gHNwY?2mLk>uZA@=V0`|TsY7;gLXclJF74u=8$WA@qzJ6G;rH`CYiuW8n zcZ!JLv;Z#M3d(Ur5TL`o+o9!W0R4=mmRpQc(sE1}`8Yk$rr5bbQ{#|&D)}{mDU#I7 zh@iK_*KDOEsPErOB_uf_fAAj^T< zFqlwLlw(h7vfqi9t?qkS%6ITb(U~l%s%=s9gJ@7lAx!}Rr4&KLo=7DKA~k${&TQR? z8*$&ulSg6iwdNcnAe;kGs6Dcg>9#qw!&U9q#nP(gq3gDOtL}N&jLA2zGN{T|3_E+S zF*z8PZXrBC&^X|{)_W0UJ=RMU7B8mW#?7^}Q3|}ipO*qou}SGBi>3JJxNq+x9SnhW z@A}6FdW7x7lqrKg?zS6p#{ZIC!SyFB;?E-NOh*`zKH0)D}!8WsT~byJ=i|7Je785e_Jy1OLeDDa66~vs0-uu1!8xQOg4XNtG z%Km`g1UhA>&o`MKNfr^eWdpSwUayPd zn%+rrMU&~*`&ilMJxWBo3{be~SxK?Kd&mJ`N9BRO9FFsASnn=^*DvvgKak!@59{~s zia6OPtOKMwH$V6zzS31G5fDfc7Wq}nvGZu!3DoktsuijLj!YvmifH)7=@;jA!Sx`IlR`5q(PYOnns<-%DXZ{bMetUyxI zD8vk4Z$BG8i36j@Pvjvq?sveh?DDNr=GCsCp4@E>$irwNdj&qt1QJ;58ID8#|HSrK z<-YFmo=f|n;*Y-u#nG>EA?`clw>pv6KKYBjWBuQ5-cl23rQuQymaGokkoVtLJG!_Y z$F6z5D^nSQ>*w#aEDI_esKnPGQRdMUn!TRexc=6=K*H~wAD`B~T%F7}%pvVvfb#NT zhwKJQdeg3Z?{QlbQe!8{Yh@tvqE%K#ZicoK>5<((dS9jquYlEr+L|MOJ<;3=_0}v1 zzgnT7+UDo>r~83BX9P8VobA)EUPta@HlO+(i=1ly^p0A z5x1aPlcdhv_WNA0pumKRbuQ@P zAJUR@0MbVhtr!7OrR@_^7SvENh;7r||KP%*xy8+mC$3OkR?UxcT5)n4P+Wbykh?ze zvndwd#_b=#kT4=4TU)w|T89L0f|pNd(FtK>O~Ho?FtMq7&jy?F_>JFf9emvp6BK(4 zm!dsu!UvLdsqmFwtW|8)-4h4b-byVZlJE5cax}eWLWQ-RWFjyh2(gQ>kMasb&X5GP ziFQ*ZZQj$7A7iA-UG?ZaZJ)qXPwlrptRHwmd^2ftM%T1Wn zQ8c4tNYRpg_dL=LH~P1CseJjR{i+fE$nX=sb+W{@C=L2tN{|iHJ5USPWL9MQb_V9c zG!F;s1r+!V0i@Gi&ttOI@fgVho9xF9v*8)zowz+zop`;pC*ttd_|S|}8M+?-^`olK zE@SrhG)R~1jW4%86qJIRKCb*_EPEMiJk2{`a0_?(2UWc2@6-j3sXyHVPm!L~d>$p} zsLFzqry;fce#cI`i01PlnZe&hQMe1D{fpUm;>t#Ic_f!Wsk%ja33_MDu;k&z$)7QJ zZa~OT4P50I(&F`V! zI#ZO9V&+}Pc;?je&Tox7pTkmaAA0w_i{<>L2`gY#n)?(7{{FaZT~sZbz4;c!p0Jt5 ztyFoPfAc+>aqKv(w=Tr+;C1efB^04#=bz0iH#Y*8_e?9-9cv?6{n=L*F+b}W zr~UnsM-8tg@=AF#S#MkY*aP3fyGQHVS<3GTPil|tLl0>ExHX0sU{uAw^VksaapkiC zLI1d{t|iHEop}ei`M+1Hx<#NIT54e7%B$|D*R_;?SVQ)xtds;6mHc_d+$Pn06D{%K zil|-tyS-B^%6qsboJ&uKfXpfE_lyjL#tY3VqvY_ru!W~2tx{dT*oAYNa^pe z&uDia5D)FQ4EE(2C6`~dJPj^wsS4_g=Xx7roB&R{I}!q^epWL2?&zHuBGk4lbv$rO zCGO?Pc8t)Ce+K@fcbW#DJ?Bw>P;1_4E>JJ)n9>0X?HWTzvEBV^Pw{+R{+HyotFpK5 zsg2wTv-lEN!tB*b=J8~zD>{`wWOi3oe@It$*AY^yb4)ummQsGe_K@lKA$+yFQHqP< zId{7+Ps-I(dQLQ^G)9&Ot|~kfCX)zYE#mod`xt@(Ecx(Bq6u?%Cf;M3gGTqn&y3To z<@h9%= zg3064(C`*o0nKIFjH7?0g1oplS#_uf>}5j{D3J$aSc>!RgWQf&&Hctt>Pt`zy*}!| zMbJm6iJOhfG2judTY#>G^z`ku9hu?>1@liY=}Y2(na-S4Ooa&ozn-ut38b0lz*a*N8l8j6Kl{7qLMkV z&wJ1g4ie-I=sWsK#=Qb-9w{dAQ+sAq>lI#7S(WvcYZaYl)M8(P{l;g+K ze_3|`bn}1g%XB~Q=70P;Hl9Kdi9V|g(DUl0?=@?C@QVrw^wd8{?QFS|(iGPgF!biY zixrlHI_nB;LCrY*pGIPdaCuOY5iP;_=CH zy-y*q^F}|7QvJSitIi#D5e0)Btd%ptO`piYOL3+@hf62e=7BfP+V%9mu+0)pK>x!s$)flNbMa`*^y+ zf44{-Us_ifU#rpNNZD3fVW=8dVUOm25pPhlf9%(l%Dg z%S8t}7Be!@`Cg^=cvJ|+rzjT1rX=cK7a@42_fj-3?Wph9_m@I4#gF@=e-qIy-;{j4 zuB|GClN%ldOo=)fFl!mkINo9>qF*?RUf&3&NfD7G*qMdkd!bu1yQ=4Zyf2cY8%+_1 z`{m#6%ObZKHtaZJ!xP~nx=dZZCx;u8>KRz8%SQ_;kapJ_v(4ev7edw>Jwjd z55E!;j0{w87quH>T@S^4K{MGG-UAXOrtDXsgy=&&B@nq#*M!5IySg z-bLF@Ppl|1-$34a{K$&*gB5huW+nSBG{tkd0g)wk*Y6nm)}`&ix~o12oygbsLh_oA zVQP3%+y;>}ZWXg$PV35K%1ha-{LX#x>J3eBgAd$+aJ>LMtEk@#_GzPj9Ke?k<2O%> zkkN3&=-tdvp~u?C*~{zfaJT~Ml?(O;eS1S>+C6ZqYUJL>PCw$(GLnWKQHb*OR`^$`Hl ze`7EgTgP8;D97~-%+7DW7DIcEqV{#TY<6{$i?;>-cn$YyJB{<}{SFD3?`O7n4_Q$s z^c$nF$06vpLRNiJs!W6E6v1p=e4CGv^BCeCC}2>?>u9c^6p02Vd2~EkiG{$)dy?P9 zSO7@q{o*V!=%jjEPoL9m6ZD}B?}m@67k7z%2XB{9&ATSSBu0VsSNDQGS`HgoUq^eN z$}2g2!{_*^0xQ7*i4p%9SsirHT8aWuh4R{>waP2m!oBCw;bqSt{Hox9xzFGGhB06D zhbBZ34>^Yh$Suw-v=m2<+c}71o_~j!Lb*V1d|0+qfyt(FhaG>eE?T&(}oPF5+45gL!yBVhWiCDs4-=V=^&9I;% zPYDoM_PT{7@}K$ZEZ&IYO%rLL4cRhCDk1kdbr-V9(DJn@yyQ{%?hYx5E;C+?%&D*U zSwI-i#rMlJr!t%8tC$OYKHK1d%t7jXyW{Il9`bmuZWrnkF8eKfA-yIWjFqzc+Dg60 z`$%0Y&tZUsggWB;nK-&T5vHz>-UK7ZPQNI8LwvwGZ_YT1BHMJn-MiB=@51G-B@W~D^G{r)rm}9$aC#9j(!(kto_$mX7;1Y!sy{U^+_TBE9^AX`5r56U12;Gp`a9$p-9LvCe%-xp~ z)Fnf4fU~5_Lx!{Q?f0}3b}hPfzyDmk+^@)iYp^*O_KtGUZa-iz0=EVA8?)n@I!|=q z3{RI0eiFSs}2Q&ytJ(9RKtl;ZmTOkZc3aaK^jw-I|$ zJwN$E`aM-h$B61i^3CA-)LDB|35J`FuOW|HJXt-0jH6XrMk{Ra{!CdzwE5 zp`$t)we5|gFhRiG!)W{FiumH(C}X=AqqTqQgm?+4ODFA??XrYfbZ%Gi5bY!d14nNgT0SAZ)i=n|Hgtd=X*$G|LQSMuvIz<^t)SLUw!WAT)s z&EoE#%hmpjmY;ui{R>qPvZd1T2JWG5>+l{k z_p%O$B|U%74ZyA2Ol=s-JBff}I%2EI5oG<}6Kytz!GJlZ-UDZ!en9Js#F@o(yUD+q z_fq6JTnccZH`YK!rnlo;G7;meNsGzci8!=xG3*I!lFt%3auKC}04NyOp;2rl_E|;k1R!bD#wh(wPQ_VCxj*Xp)8T>%NP;x>i z!{{-9Ri3}bw`9-|gCM-|F7%Pr7t!Q+IrRF8_LGw!ullq*T}MLtfOtPC6&o};X?`E* zDu#O{m!1!KANQ^)bKOi|*p4u7yi(x)y?gY6}Li(vqsTnD|<=x<1H8qaWZ z92dx<_iE*&3|B;{IchV>TxAF&xa+3A03G97-^h|4q%61qFtrgMW3m6M+FVthTOA!=}AKoh2gmpv$=6bfC|^hctcoe-Dr{p7oz2_dRqe-7V<4^C%p z-4pIp4Nf$X5=-a~XT8l)1XTNG<4dcP;@Ws02fXnR-^ zM#znSlt4UeTNIWRsz6{2sYCS~gVXiItU*N(pxy@C?QD?K5db-1ChWIxJ|Ln3Roidy zc=G8<@9A`yVEA}r`ILC?Q`LV?eZOc87x~LFV1&^v2sEy5S5JeCK_T#jqo%@ za1pRrYJ8{b0hQ0}u>FAe_4exZaDTTZq9#C>=HpcK0J4o$6_!(Dp6j?_SuTHclxVi9 zW-6Tq$+-mb28d4T>Fq|4C1359n2YrOJ9Mv&zsw-5f6lIVes4wrCcL~B-tM&5$H6{% z&9QUSUA7rj-FR?*;Q~i%?d1*|x(*c_i}-lkD5TmWrCX?Rna#R`mEXP*ZccQJx)S^1W?V8)n%=)SM%VC1;Ia|b zudYkd#P1t`Dm+#WWWk!v)vW-M2O@<@Q4vn`Tlm86>1O0KaIhjmy4TUPjvLb?z@--Z z=asx3l&S@nka-OCpgh>6_}ct*0BnWD9-=r-G^Jjywp6o*3r|F4-;OUZXhP(WD2nsG ztaC+EP@;qtn6D^Y_nPP*Z3uVOKzSqwQJ6b%%h)qljtx5rzmpk#ZxQ16QG>SrQ$D_@ z5@{U`S;FRZdNt+FmC{aR_vY2i&toPz%Ie*i(<)q)yF**)x01x8y1jMpqi`x0NCj8c z^id>OR38)>_=(9!=Ty6izt=Fh3djw6u~th)-!aK8=ccdTPh?zj9Ssh(=Wn%ePTB+H zyfkfOmrMBRcB1>ORE6zT>((yu&<3^W#>I>q2kl=_?AeiOl#2c-{wBmX_&lKyz&Zeu z#|}6$z|Qf+`N;fd>`6M1mZ&&ZH=sgx7w#%f?RagIUb~;))aT88>&dx2F3CdMA^t4X zsuFlKByz01KM~Sd;vGXyxv{du(zmtZh*+%D72}W9`b(qEGAGOWas<_I z>fI{+HT?4yqg*WPBVbxv*l_kTzMk99_)uTxct~9j)D9&*dRvIj%sI`2Z{_RO*N4`0 zXTQ@J;Y@8NW0pM!A;#Ytu)Xv*`#Mq0Habu6o6|5%rCV3j)0djJ!ASX`UgdbPr z^s?=-Ma!4(yWDHv(?KP^@2o=Fps7U)1j^mDmbvUkTr!8m8`|ee*?v>U98VJJIM+!z zMC*;;+|!2w>?u<{-WHib3$P%O$V;Yu4FQLTvx^V|{$J>?Oam^z{2$~UG~DqwhPSkF z9wjC+^EvmJ9@si3%@5;Uuj9B`MRi)a)Z};90%GE;DeZMjwwF%OU#)1`Uo>5 zrM$D?n{jCZNmz;#wxU`&#Fr<&1Pps3`;`$e{aV8tTD>L$N+GGmz{PaTe5tqLxm8Vn zybAXp63y8;g!z&^^-=Q7#q#d68}0>KH=}#Y@o&BF+PkLif(6FtP}N{QbD$?Syca|k zx?f749O-n@nckVU+t|}VNa=Azy7=dVsuj=LzKOYCGepFSL&^31MJd;@D(Xo-ALkjj z>u0DtgVbLgJfzO?G4aY{kMBPH>X~@H89V2Gsaw`w--(Q-0@k`-+dozAON=Ph?_y25 za>wKK{-F;~2n1%7$e?Kn8<5_D)#hM;t#_ak6mv})zt6jV@30F2k!D$&Z?7yi93f5t zu=Xy)a<9j+Z?^yqx!?bEooq);R$d6!zVzL2f+{F6$}$JnT4qY_sbP(cR4|0+Tp5~2 zhdh0ZZ;X6_Vs6pFm=Z8cqv=xSPx%+f3s>>9WM?kqy(V=De$J_RGT;7qdX0@Zd=J%d zx%&+L!RIGu^5ye9J|5g6=8%e#OJ{5Qlo92u|^}$m}^+nWgbgD>)9e)E(&r(Fu&_Un^SDr#3QLJE0)8*N`q+ zUmKWoplM)MbJXMq`zB`w$iQ8pNF{`|?v>S>#y%r>yh~z?(>a6u&Er*$KMUJ&w_gnQ zd5alAJwgd`Mytoe#j|3=MUpP*r73+jkfCC*b81Qsqbk-1*aak{s)w~4!vV$0Ck)6A zR5388$-SiS_z)h6+D_ow1fR0cd)DW9ZJ(9uY% z4S&JZm}=zL($I6Tv^SZs6x#sDa_OV}(KA10UhxKv2yDHRMsr|GgfApjDzDYajoLyULlFBnW=J+z$%waXf$3U6VPPwJ(i?DB2 zGF|3=R(UvW1SA$UonEpby@we!qYMz)|+BeTYJgtqpGSbxt+^>d-kTK6ePed zNr;pCtFU&DJbNE~j(QldadQaAe3ACN`~0XJE4)YKOESPCJY^EFA|YQ-R>7@+h2=%v z4`$XTQcrZmuQa0aOx4l#f)4gU|56V6a=T}_#J@)wkIOLM=wS4988g`7msf=~OKmS& zN%=ieXrKiszjXLuFYG&$itD0?+J+WZb5mVi$MJ^U#fL?psZN>gJTx5U$DM7)04i{* zr5|I?FYb!WeblwrwTqu9s$N)h!^}0>sYw@Ev*MHdcjR8NISA^06Z!q??HdnieC}_> z^BsQ;+`6(~xQLEBo-^axfe~RZ;S*YAHDXv8b(^;i-wH5nAVGbkWfyg+v3Qptc=oNF zXZfXn^8-sZ#b!3bZ&k=OY8v@%OcYE4fzRcWOx%T_t0BdFliBn>3{890jF8Ro3v*fN z9xLKlE^rn?sLsk&Es-v1Y8rwoH`Zqk!PXKWB?!LNtL?H=Lzq!j0nu8~w3ZwUf90v* z>;KrR&}Q)mM}Vt*hrkT`!9~FYiI?H_8>w@~f%N(GjGN6##>%Vat-JMF_YA*Q;r%+P z1}V#w&V1^ffV`W|%QCyY`h$?=s1x%O+KGWf2l}~`NRB;T)T>Wz+++B*SA`%8C95XG zD94oUYo2w1cg&tyQCMV3u2k$6^OyrzkWCY{Xa*#?mZN&y`8!D%E#|$?8 zAfA%G5itszrRe2^KNl-kSl(jI0u}p}kM0?RC*TL>Wd4jrgpWM14ldqay&RUzJHOt1 z`NL`t_r!Pb!Gxuh)%QYYazt7tTtVadH6pOI6_Nrr?dHpOCSg+BxI8Pz0cOkWWP1-uDtXe;n z=cG0)U%f8xR#?~!L>ia~)@r^~iC^xGT^OkDD_7#@P)gn^F~$QP=+yFf)BG%w_(LpR zk$xHpb+qG=GXNH2GXAEZ3aQt)01TwcW{dR}z*@?1H{sW3^no#u#8#anZH%$AXfB(4qeAzX}l`2jf5 zbgOuznQfrlotBTM;4nA*wE*eBWZpj#9doU7f=w^1^SnpWAylsW663E#)ZG(8qz3IC zP=k6hc0tJPh_|fV+v2|1qckgq)X2)EZkDJqvoGHvZuxdP>}b0BkKDiZ&*dJ_aMVcB z4FtINGm0L&3vR}Z+9(qvM3>7XL=RMh0+9}o0pG7*xnO~?t@u7U=Jg2QU~TI7BuJ9R z2)L7UW?9Gsh#Q{Y++Xx>(mounh??jwLY@hU%3_-9o;UY)!VH88^Q$&U^FbiX3| z*V4Mb3Ve4Yj`#AHbJckxWrY?p3n zyV3JyW^gDi8}!Ii^QYO$Kn8mAJe9nMsM6D&MVZ=ePz<9o>Q9xVNiSARP^WNP3umJr)nM3dg>P^F{ ziiy9J!EWopxYQ2i*7I6B#(^m?HVBR4ztI# zy77hck%w+%U1{$dXw6daeKhyOQ8ruvY%7s}!&LUp1_qoK}GaCkMML;3^Hi-wef4i#)<1(4T${@rZQe((E{QYbGDa%-^y|CrrTe`N)R>7NQReQ{ZYTkxn|yqH!K-wb_@sUc2rJU( zaTg=JGY52VS~57%I_eFJE++!{sOyfZ+(7V1*W2SWH?9W<`Bq#BA^_Q2*jHQ!PPqAi zaq4B1vhw9ftB-DvDM0 z{O7;^lNi{EdfCakl>my&7WqUF^^=x5E1(M$-?V7i61~IA8Y|Opx4JfDnya_+_?MawgT_&6i6~mabddRa0_K}ZYeFy%wG*4!Ewpd?<V0cPu;H=G~7{S(dvfHVi~eEWMM0 zMly+a`077TIF~`D&gy7nt|S(eX6J3lHtp?;a_i2AD-R4!e}Z~2^VtMy zB0MXn_uz_hyiJ7^*4WupZxuSV;=MiWCgY!|oPx2zwg*G|9&%TdhN{rK`f-99{i@xn zoA3lF_;f|mNYlRM3A3hC%X}_|aiQ#IkbBUSUW1@2TGcRw+I^kLI<>z#jE*(x$4(-3 zf;+n_69$yt}v8qT)Hw3&i#kFJy4>#<-0SxA9{b z8kI;KXZWO^3)fSmpIE>hfTVII;++1TzHEJd>y;3R)5q=lY|YdkQ%bnH&B zXmOMKmOXDVpp3+peO|A*h`Beqw8=mlEfCVUENe+2S#4bk9}M^U`4w&2ud$zuF>F*P#kf%3CG?!U-r;gTT}KKc9VfuQ0^h@o=pb*jk!rz zX2<=$KKqyfnD8Y|i1TzpaQM{VDtq%|0RRhLwVo>O%SqL=24#bmUeuo})E}Z4r^@x{ z@xekt@PL*bc9G)2yCEycZausi$sKzL%I zTDgkUSaoP|q=^D&I{>RC9s`cJ>S^}dzb2gu_ZzMnI|MS;6$pEDh0A-*VgdLMGZkj} zxW$#bXT0%M87G5-W&Y*tcty-_2q`7FPDRJ1I)PY{weK)x-tuNiFqh7f4V~0+=sOO3 zlK;Rc3hr?aS{u7o2u<% zCv_oTtwMy;%b1sQw4^=EGpKlpc9gi$HHI7etG@8PFPf*K-w;kbKuKI@X82Xjq#GTr z>eFMM+D1}r!w;2%ha5U!@j#=cqZ(TpBxwB^J@jZYSomfBMp5E;Jd}gStERY5Z z3}5A-Io5L&aQr&@!+WBlbaLjzoQ>&yI=@AV3yn4Mt^Kqf-QSM-^2WQy(A*BbR)P5$ zZ0e&!EAfwI%oT@2`buO-#_arc{`k?IqmM*`{gm9sns-70MTMraKZjbK!+2HhOx#=N~s+lwhyw%UQTCgXe86_HW?x-~zx~T#eU+9vSI$KzQA0Tl(>i z_N0G-hyk{!BYGr);oe5yA9VABh=kSQbUa~hZC(=!7rG*xVU_XrAvyPg(`GxjA&Nxj}X>e-9O z@+E^dh%qn!O;<{}w%Uq!N~g&;HlCR6qZxyBxPLaXPAjF5dIc{9 z;bhMQMYZG*%C+`uCPY`7-8rdrZE6NkG)IM}B|8)!nCNHTIg63o9+c)3hJ-wF!NdkP z>WhSHv?=PagJW)Y@V-t%N!>NGBfhD?jvV?`>TBtYtwO3l@1=Wn`6BKUlA(5N)CC`) zK&L#$#CCU9#uY|GR9mrwvWF&CRWti)3pYTj)%Fuzkwh+`Wlr}DB1rpiPrgQIXXG@4 ztXQz9qBq3e#xUDH56&mx-_ddxP6}kppJhXVLfBoWr9Gh*XZO)J{=GDDsLqvn|J5!G zO&8yRoNk^HQ_jlbvjU#^D6DC}&o}+;6(33!k)3d&?B1Qj|>hQP^{yw-<7I(ogN4FC+OiiaS5U1K{hkH#8HxtCh4GWC}-;byMK_m2FfW z<2^fKI`h50lJ0nIQT97L3CH)h+4>_xlccu5+kT+zwt4bI z;NHHtXl6Zih|BZPR*DS|O#`oi+bsr6LkMB$%l=Ev0eQJA!39X9%kESzzq^MNq2l4r zIj^{FzA$f7lb5#4sEh9mLfh3g7Qbxr-Xk+gYjVBN=Mn>g;NSn#nKDF%eRF9soD;W~ z6M(n-3N8#pW|#McK;lXq7EQ?Oq~8i~8p|ErUz$%yM22p|g9c zNB-Hq_onUY6r#eSeWD&W3QyAL#Najdec5xOR7|Sy#>Kvx;bWcev~4Jwc&RGV=oO!v zf0?XCD!=SoTTPh{!~bL#49@JlPq;mn2>iW(St?YZkb8rvoNXtm{@Iu%aW;@7ad5g> zuLs2$?8uA}KX13#+77OCyH<3%gk;VuAMJ6;5sGPe%)gXEMARATKW*n8Cs=8n3m*OD zrA~a|bGWwt565_!xm6H(Zja|U+_MB1Y1apD z%#Yq0UMjbfHLN0Q^EY5OqFMM*u5k!%f|bz=$1VMYiwy#N)xfwz`QZKuq*9bLgdjF*lRygT(p+qOXlX#@fbfwuX zIbw9odFuLL=2+*#+d=3k21WM^>l4~xS2Ec_;M!_yBp9Oime*klMD=HVrElq#UjVt) zJX+^x`)uebuyMo{yA|{yr}T*GdefoElU|9QKah-yoy;$n!>Qwu^O08vB2dZ>+Wr08 z5u!oASi&{@d_JJbYGQiwq zkLxpN&^=?4^gvOq;b4i2Tku1;TH@ZAgFadH!KaNp3$#;BrNU*$-|agmL429dqxrMYal0|iU%W859))2@Ee+87xVt9n$^L-;1h z?=L&2?>o$-bpLA)us&+(N2yIG%(wF`6`g(pgSLTN2g97zfW|P(A?zVu68IEMEs$h!@A!t#E@ZmX$4L2EtT8(?LSX3vT3{m zzR4CBKT(P9WP$~>OI(F_3?1LoO3ramv)}z_dL__{{z?vd{upxeA&hHqFB31jE`4g( z8f)&}wfo&rhZ&He&SQQ?1V^wgSj3+Ma4xkN^YhLk%VTy3+nbq`a}VCO(j|~NiuP5$ z3ht-+A*fLTtMZ8I&A{9Fp>C6K@iXB8fKYPD!-ef5DAIAif9m^glxr7(iHfL2AoD~V z&x8Y>()eq+ZVFSpI%xR-7Ul;E%5f1=vB5+f6Ap{lfpHIm_CMmgW`~`*bt&*S`&`(% z+#8-|2b3pLR&>e}>T>5hE38`;YYC)q#q0HxPe_^gy!ZlBm$^>LiQyjeqx#las}se- ztLSXNpw=6hXLZWPtKR)%QGR|`eVs@QR`q?Ra4~yIY7ZL2J@^#znxok% zu)2Py3$_19L|ZdC9(euQz^qryeB-?Vl-MWsh^!OeAESgjv)ne29HK#(+K!J@SS6(A zm^9ht){Y_LJyg`j=gg$@3rexKa(U#ejV$$i@G-F`%{zF3D4Cy2|D*2_re@=Z2-xig zgPQ)p&vbvio>jY~K3ab1zMAF-%y~96wev%Tt}0g;PgrZM^d&;=+WEw?^RM@BomOl; zi8b`p`O9&p)!&%}?g^Z8!{Cg6FW=|8ZqRrrzT?oO%fC2vziw50Ta$)8Mas_4;YC-O zmdchM2_fEAF@inc?G*gU3w>eEmZsp+jZ|ps<23B#NMsDY{8K}Sr12AVZ)%Lp$^3xe zo0i8TAC<;kJ)ayQ>05AMq^o3#zg9J)Ro0dp%j=)}@~C4!)H`_lu;(s6ZwCYbR2C2! zF~roq18d^@7N+n!(rxO$+Jur{f3iTU>0PBfn-sU4LY8`*~F54&1!VA@j(_MB6 zarjx_Shts+!2o)E4W}ke+~#p%0vrFF5C_e9iPqoej+@>$1LO1`_M1k&nrXN^0p3D123=^L{ME>rP+GgPHwiA?j!rj8 zgR8v6=(kC)+#C5|yLr)LCo8)0rQ*Poy=0@Ro~z1}aMNEpVmc=|sOBlg(d80FYPA3$ zydY?Q3(zrZUH$@O+OdDR2aSkOIn(6>y1G<)1VNVjA!(f=|3+Ch>YIlHqrNnr1zHJe z>k$ufs`#VmOcE4Cq9A%879cZA1rY@S6%pJqBQt_br?04OFS@#GNHhPBcrVe>!roJ% z>J<~VTw?T-C{?+zNNI)Oj}2<=5h_X)gn7Z9%`BA$LYNFiyg&{U#s5yLay4pETdi{?_q-%!2GKi_5H z-IN`t=jR7A6FAcQILQcohD(utQ;Ed2z50-DX@!??xlMa+TWWsK%s_o;VE<+7Q{Zj1 z+CL9;;;vhKD%jWeb6mc6yqKFb;Pya=9ss+ixd~Gwy5>s7_RXnKD3QJH)VGtB)}6tj zQ9Ut6>eS5qU@DQ9B>GQoiDqLUYY}uk`|9Z)OvP1YevYXj@5aYfqwUxc(=i<6w7)LJ zdm_%#2iy}|Ad-g|y|bTtO8w#-2d;{WGP_Riw{InLExifl`cyh0bU@$&;>cW^3-8)L zedl88Exu;ZG)PGcFxPwQ@%yu@Z5P0#`|Cu4Xm-N`KUpYIW(B!_=iSpdeD;^X#IShX zq+K@EEPYYPZttt_lFrqxAXtGZ4FCDXZ#_yUNp?~?yXs!3c}=%4SjPT##X|&#x)w(nNUBlZn*A&zaU9$)QmXGu;p#V+;39tX@$79qM?q1@RUfRd z@?re6^Av`aS!_vx&C5H0-M8x~m{lv9aHrP6EdQ8X3*55rJz*N=7vNZb+}|W@FMPX@ z532CG9suCMYTuZy4@3EYD&`(H##TFRNi@jsr0^+<2z!e6%4cQ{ZFWyawO5B6WjruY zCE3Ki{&vK*0od=9{1=u|u;6{9PLtVuLLb*8-t&l5xzO-ugTpqBdWVT$3iuziL8Pp0 z26?Knje!j40b(PpR^{Ft_cYnpZLQS@lgn}Ov8H7(P3lUrHv;bRb?)-7CUB)Zy(Nzt zze3T-`7@)ZQ^yoPOMy2_y2`g(V6l6ww5(-`h}`G=elzxKcQm^gI{J8TPa%ARU}?Ti z=839SquE{2LRRTDX=*2;O`wNHMhnO%u)3fir}KAH6xVCX*_kx_!HU~H%&XS)#qfHs zu8%AG`n;`F`)PUZK@(4q-c8*Rcz!((s+cY#dQujZys;ap|@>{Vf>3hHjm9Up&LB75fYT!$}}M0(m(wWl$r)%M{&_gYWT#J zPJ4&7>=5oJQ@p#i%ejWSl@VVKK_TvD5Q^FhKmvGh=^>O1w6vG@^16a=-91x%+VdQI zZuF(lda!!i7il}+k1Oo~a9U0HlSwS|Jj&#p&Jz^v?E=>#K5a zUOCE7IFIzuPaF=pX&3F*3C^lKg`{VPG5vV}_oy#&92v65ruV7>J__ILvqIh?@wim~ z{$ZkOX=CUP9g=xdK|BjD(#h-oye=gf@+ACa58pC*Yd$di0n*R@04Hy~Q3*iG$A19}yV@5eo<;LAc#4;P z_zNDos1UHK-5*|~14(EfbBk!EgFY>fs88m`mGY4&lg*}($G<$r$z&c63Trd^Vjyxj zTF&EiUUv0WQq%Ad>+&YK#D{Ak`Q^pYm0NP8lf7st71y*S=q;Q zYFNE**Pd37t2Ny^&j*uAhP1&@cG2N0V9!>_C2D%MH(!$#0KLn=S-7tI_n0>i_uM(} z&l>#k*?O{#ul{Ru@yV@x?(m|OS?OJ|1#W_LCqJ+!gQc-^#_K6tcf}dm(H(C7r@iNK zH1i2>_1&}e#*UwpjJh(N5wn4}QL^8i_i+5IuJf!wdq!)QeYejC1{!OCD&~&>1|%_- zq4KCU0zke#+1OMf)SVRX&w=5BE<#L17S`+9>mXBNSlbUci%Q)qv3mV|O_b^FXsNEA z_k8q2>_6>Sjo<^;LRP*zoC9h*T`wf(_}C?Xc7nSeP3QYqk9^u^OoGt)q*|ZX?X$L@ z6Ej{LbEhW0C1?{ofrPd8XFZS4p`IA{Ezis3rcdFg#?M%9bPJ|jR%>^T6cs`|qns#X zAu%T2fR64(1l1;ZIpTndQcyp!sVARj>tX3Zx{7#n1QT=#WuPc}a62kT*aTyR2ir=% zwgdvB=>t?-S9u4^-C>UJso3>*=nC$sF#?c!o}_E_m2N*cLDw=JpG%;8*TemF>@oM4 zT%~uDF`t*X9!|f-zA(IfbDvH@9I<_2&WRw)=T$M2OkE?V zRUOyNE$d9>tAP`9dT)$qOKEs`DJouOuKyx&1A*N41wPFpB)_~a z`vugruTpnz>fRYbTHzaBKYskHE|=VYd^G;-+;gND2d(7+jM{agQFoLja^`UM>`=?2 zdvqsMXTE8zsfOy;p_kCmnXH(T+*GsrbD^Xmaa@CP!HgzwF(6{!Fc{eErqk7%zVM%| zB7){9*=(bIjGt)0r%J5OU3Da>JTMP}TDMBP*ylcFe7`nTmVr3c)tC+Cl}}lL5J2;zH{R2L7E#*la|&-FCp05VvP= zf4Sg%7f;RWh^LKsmcQrclKgzE%O8kKKF>U-aJ&6G8c#zc#KNYy&(k9U*8J?m&qriw z?Fk%QE!t_*A$-idb4c<#4P1Fdu@y&rH(voTNaK>}c|HNI$ra;KOw_o}QrL4}xeBJ| zu~oW+?79O+h@VkjO47Ksxs8Ufmmi)Uhf2&T`>b@N+zEvqlk@F&D#tivpIyh~ z$KRe2Gt}AF9wTq<-I&)Ma1K!c1{H0I|k+(BeQ@v|pe%W5glhhHLN5uCw|KD;zcvSM0IUZby zZpYK(@z}l8%$VQYVH*~`5oy~3vQ5wEd%pM~@0aS{m$>8*KLjM2^GlV$^dj!0vkpU#yN7VBp=PJ4LkpxXfpuqw}oLS4QX zW`DKCgK=zmD^66uA6)uiJltb5UQ!!K(mq1WF#v1tEI7O87rh(hAjLwo@A!ru$Y#FI zbgq9-G;87Iyv0V5dH? z{;ht7*lY3&d_?~`q;1Bfgt9Lu($Cpi_2kPXtK^ygE*(6CqIE2u4aK1%u3XC6ADSHg z_NO%8pA$TE*ErsN?S(KU!ZLoh{Z6=M#{*#P7%b1vNb+{QAj#kfBj!?)rto?xj%;P9 znfm~_Ocxic*?X`GN+i~g>v^K*-og;ngmBgLeF^y{dZ^1O@fdz-&U0BLJz!Y2+fV-~ zV!4IRbjFnoaDY4G?@ ze!4rm#I8-emLJ1aYgH+8QZs^2HKf@$UM1%+u%_u5f>lHo`O)q7gQk8}9w5YP25hQq zckL5`qZzW_ZXvSDrHfy5+YLWAHa13MGGi6?V>B8RW4Q67F@rQy(M!yt}8y zLAt$(*n6E&`={c!c=ui=BsPSkjXRg2^oJ6kYRD7k5d^4TJ+7Z`A2Xd+t*7c%!MC^8 zG*%ZgH?S#Z6CHbP$8>UvOPvl%dxf1V^&v`n?4BeJLh*Vbmgs@Sh{<`*=V2wl?HPFf!<-fIaqQ;u%oq3HB#>!kB&UZ`Vo@FtcHqHr_|2n z6Kpqk6WDhfll!q4C1bIQ$oy&NsliE*ijK~kx#I_OU+Q)|3;g1wo;2!U;>wZTtolJ< z+HQLwt*NZ}im){3&VS-jtg&PeFpS%!Ok->yt1cK_=fR@xP#d@jpc?n-nDg0 zPK9-KN&tzkW*c7^FKn+L>ssM~T2dG3;*et>Jb|k=*?S*Nap8Er&9oP|M0RZW{fS9V zTHzF!rEq9qD`AxvC=V>>KZ)Gno|vY6Z@Z&9O!-)TF2^^@993g#yw!UN6fm!c^j_bU z+@Or);fw7v@r%2x-cl-?4F3KM%#L+}z?NLjwRmeDbC~UZ`&_)7^-Gkz&tB1cOAPT0 z09arq-IQ9Vy!!s(Z+Em8HL?|oki}W`0<~G<-aF{!or@K6HIoqxam5?6sFK5z%^rsN zAm>H|PUH7+Z{?4$`xL>Bj&e`ePk3cG8QO-u6POnJKekzJW_>%lbFQ-v2ywyPiF0%E zTA`k*V*imT%(NfJgYkjp_6+QXm9x0|=$ByEUi*(T2oaPLO`nl-wY!i^{k+L$`Pfa$ zHJD|pv5Y*Ms4LzPTwzhsSSlB0jb>Pj#4)@M<^yX9xDm^G|9TAq3JyWh?T|r{NQBg? zJ0YE1?l{W!Q63vs_o+f4JBs8ZALaic|37H#O zAl}NvIM$w|fp=nuO+ zuBEn|L-#5@^tC(HU+pv?(B-Hv$^DwWhjdwjyF|FqR3Y#`VGSCIeJnm%^kZY}_DsTE zKXO)6P+I?oZmF;&HB_@K>N!t&R$oKV`TWtnY~HY2|}(P8~zS_jcXivp-_cI$CM@?FcB>jwy}?EINoV$ z#EaTqmU~x3WHwc`c6D%e7>{J{#qXU297j=8QI7~9$)e(aL!ti=-g^-#{p0QhimGE{ z%&Q*dmPX|=sHi&*aq^T=L4zv$w|pNay_J*>ry%&cH&f4k?R!_9#nW_O_CI5!k7DV{ z>G8^z5fVXxciSrxRIa6Fa;+=6E>JL?-)5^Ly~6#jJqC@Y&}QM8uzGt)rcs-*S#@GdNXdI zLdPmhaP#w`%x8SkGVJg;nfVsCH!pp`$kA;)eyVq%H9oBi%lu;|JrdgYbLpE{n0R|- z;b25K9s%%f%htY3H!Z5h?etu9>K4;^&B6Zn`_GN~gBHTg0#r<&%f4((6F;3l>W23{ z7{dK!H1~;hiSFP8zWvf)%$fMT&-CvJ!$Z(aSKYf4__&+ge6#LfURDdBDvbDd3=SUk zqq@$#g`;(o_=lT=Jr%Hc~Ni;n#vh#V^Gp{iP zqa5Be*pbEYed2en_5LXgt$Yo6MpA9)MT4AeZ-yr$tL35S)8R$p4et3wXJRA9 zul7(p!Fm-X(RGAi2Mbk7ZFT=-PyNMgSLQ4nbPeF^9$SPJI$j$!fXo==ZPyDJGUx`my$M;)-Ko&9~F zctB4C;aQZ2e}o}zkHtQcW>|_IW<=5~a3cVCUEd~87Qm{YFRNT%bjibWgGxpG;9qB| z5nBrlo5h#)56xb6<^!ekRGHDVcDB5GDf3khA9yn{dbg_dcbDqgZ^@{Z7I;IGCGw36 zlJCO2dW4y2-VVz(lco4A&79zNw1&Iwl>I=%dUp&24{|6yR+`9cQ)xcObaGFv=5W^j z|9Y+((h}!<5jC5d-yUcpzrI+--T*g%JYYHsdS;60-koK{<3$e^@`;qj4=Wuvke>;N1{L&RJ%bM(cp=+sA5V#9#&~I=+kDhv9;Jya23#z@=9WB4Gxcb2`7f@R zFi)oGTA^G=b3oJQ;`IGM93{-V|-fNE&42}@i1 zeeql`M+IpN``XZ`wExyUAV^sF-$pg!$EWBUfav6$cf7|@NB{}7Ws@?HiWHri-p7Yc zGK-C;g2T4R!m}rY1_bu)k)F20)(gv7=8dcMif?cB{zATV$bQ)o)BR9MqR*WqHfC=) zk>%UAp#+e^Q;@PiP#1oWHY8Mlx*${@$MJ7y-k9t!n=+?8zDaxBYwt*dhqO1F(oJrb zmq1y%dMHqWyAR-}JGm5}pR6pphHdPO$RDQ6&~87b1E$1$;o4Y&K~A1;UiLu`=aFc; zOOUj}?tNa7BFt0%P2;1TSQqXj=cuuQ)}sy2U24T#qcWt^|I%Ew5?T&mI&Qe@QOtT9hJCuPQaGIRD zWQ#2h?K*TnvIpYeUzDV|P)n(o>nU?UH2&+w;vt|{pnNo@vmXdBL=WO6KLmI3yG~v5 zwI0uZua9Ndx)gt&G{C_~L-(&?I6ZD8p0W4i81;4I!f@QzJ8mwAaT#<+5HtJGcej`O zl+%t29$fPncG~wl-_HNBta%uyq{{OfQUyY9-`&j}yxrp}K2vS}-1zxO-=*=xkh0<_ zj<;q`XTsGKJs2zXD7%SymWtUc>Zfph=D&;m`-m$_qZ$x-T(AoQW$G@$lb~QEx6@91 z^fkD$)RvLs<47x$zeft;v+P$YH!b-Qet^+~WPE=;-|UYS-lkIQzcxru_b@mUvqR!I zQQySj)v}}@nDZ<_@ypEp_b$@YeGlN*@r~R=^xp8<#J<#zGqz-pu=hw~-WoIfAZNdI zYdj7hjo=Epj)YRx02G1pemy;?$oHQzGW$u}`2~vz0BxKJwjNUH{ND0*t%g^^nja0+ zSP(u6v{caMUaeEFzs2H8K%;I;(GHGE(L_aK4)c!p55ggMEUk80w3m}L`%J&8;4vbv zEA~6WP&SZuOy`jfdHV@MQa}ceM0~!<=L{5Mpu{u(ex2rgb|S?|P8gU*#Pbb1FaxPn z^PV*`gxc%jb(u~jgLAK~a`Ww-ehC+t8Tb}-sShT?%=0KCra|*xgurUgp3^hcYWtEy zA^!ATm8wH%M>DTSnx+EU13e-U!sp%}b0NT)ylbCo5-JzT>&;`J&uYMI$@L`!_R6#QA@OZYsdqPRvn3Vd18<2>Ut zrThJYqelPKNVI+#Ltb`Ia1x!xJ~7RfetYuu`Ms%pt%+Y}YG0SwJNG+1BPXxnjd-Pz znstN+^*d`S70KLEzK&Zt5=$>5 zs)d~7M^{k4F^*Jnz-bHxn{$u+PtnmV=m)YS6baynJ+&_^8-z9##_#d68_JEbl{60@$O#m{_ zu5?%$;DBubUOU$38!;tWG?aJ$n$ws4C*y@JhXc3%e#)bORgQ&j&FSS%2CmTkE)bDg zZs?q2Ga88L$ViZ!5^vtMzwF<*T!Txn^IZrC`St;g*W+N>t8q0dh~M=B)>MH=Td#1n zTkZ!UDR}wk!`L?FsoLJNtYgg|>E8ez4{XDCE>y1pQc7shJg8B>bf9*Mj#i?Zzwr7O zv8?`PBE-JZ*LIzB{}miCql5vhq%3cZfIrkJ@Zs2#Q2ZXBakoFE+r}x&*F!N_lV~vB z)xA9;_^vDm=gZ ziZ$ffZ@~uWO^!~1-Bf-B86HG^AZq^b;z* z$2*9L&tZBJtDXciumIIbOf;XAQ{bxK*UJyCxEHc8m9>+pU=Qg26d2jvwcmFyIWL3s zUihcXkP2F3leq5c^S4dU^Vdkc3-<%$1?ND^HmBREu1}~iAlpGKHB4Ugj&XRn4Mr=IGD@da&`<6%zZ^%efhXDF75l2kFjWauwdim5Q)S!J z-fhNnM>DH_0EBAR7kSIE{l=%aXDT$TItX#!0Q=rbRnNNWVStu}DAO5*_wOb}kO;bF z$N#cdRT<&ZHFGYGvncPJb#GB17m59XYHBLwjo~CZd;3wnaDou&Zcp5ApYRwtJo^&k zoQIx`gmbwsYkRvJIS_Nbs>@J%N#`)3l-KeZx{U8)Ap0X1HB86J#mX_#!y;^AA2EgA z!&cFXANi7TCVd_CWoSwZTJa_zOzvc%77k7A;Ve-1gADl6>9txUYuK*MAe&D`82R7g z>2nLIT`GO=AL0MM>{F7Tr+P+5Z(|`Q&>uoJOUp!B1?sGqClBGg#iuU=jGf89_3gV1 zuNKoqiok;3w8n*ZNawum};(nm* z%(xqXEPPgI{*>$o`ay$&lnoipjC}A#{d!Z@#Gl_cgU=objBuR)`Qm!R#m=WA?#FNM zG9@ohuSnJgSxGKBYKTfrQZ^ZZ7RCx$0EFgN#35x`CFdMosvnobFu--17YT@^tP7f} zP!N1ZjD2Y=ubnHQe^lSJ_jH+$>C<4S({r0WM*49JgFPNtb^5KIxp8mOIU-{bSqR_B z=lA29^z@S2)-b+`?b~DwqGI3g{;IR z31w4his$L`+v8;(oQQ&xub1S2h0G^Xu`m!j8+?B~xL)qe zc0yX>)Xu`S*-PQ?qI0&$hdaz=J-2497)nRX+NEPNzgFPecqJUZ;SZ>d)9yBgd(Z9Z z<(8BS`zzAxz1z$vK7g=Gx(CYbClST;s8IFiyPr18TC&@OGr3 z*s9{d@%!xD9Y=n2wvfHouehPIO?=%a+mjq-Wt{_J(BI!-WABYAzf}zku8G4RmT;Y-#-{VaHYNsQV`w9nQj1QAl z#&9D3*-uU#6z1E6*TYW1b}wTQox*Sv`DM(YUboZsnK^LDNYo+iH$k?;hXz)OHQF0C zv+sFquaDl2=n}k?gH^Q7&E5_aF~{0XbPiu292cwj#Xijeb8PfSOL)IwZ|ZSqBMJ;j zwOj!vSzea8#Ebs4*JHs{^@OLc@F2%s#DnR#mr4#JKi1#pyKQXlbQ;Bz5`xCIUS50R z7c$T8-V7y@at0d-hWf>ZDzAtX-ptE)Xr5eEU*1zKoX=!kV`?z6di+J;2q5?O>tubG z@>l?q_7q=MRE1Ek_wXlqUhr}sjN>v@*G!Af{0IVN5ar>Y*VdZ-2)6DVw@&K2wSn9; z;bRQX&+ z&9<(_mb9a!Oo z@7+oM8B$}MRrRXJ7y2^R0WwqucUM-S?^@dP*Uwo*tKYKC$H?=G-_~K58yQ?h&!@IK zkCS?2R=9;*LSI;wiCiU8>EfhY#-7Q~>|DI9N3##P#2d9ndb!2-iwW&I{9s0-FELx` zlwZVhhwT_k+nfb(i9jJB5OkQVhVWMk>h(C0du+aUn_M{;7cBI(QBrpcycN;CWqPr` zreS4&dv-l`8kGXi(xM;?4`!YNS;K7{vN~rZ2Qy`nR@dam09^qQd*P72mxS-q;saRa zLwqzKht!kR!kl~&D566*og3Dy6nC5Pm4244vj^u^f+xHq8{*q{u5uL~LRG~3BTa}G z#yD_SEP2b!aX4g|xi}V2-|Buk^-1?etF}UT*#I!hye0E@zMsJdT=)AD@kyCK6vq|M zqZx`a_Ic`+bD@Q=fGjqkI`lr?b=+%-C$*mLw2#j4mwbMx1UBT8|J}>BGjjTfRHW@J zY4f5(ZagZbHqeoV!YLA<%NAyBXmf|F60cUdEXTom`z;2g8Vd{%V^dS+(2Sx=24s}{ zV9NeLvQb0e|gSpE~S9C zP`Ol&&wDN#%7j_WeCrr#pM0jZzT6*KU(CY2NT54Az_eP4R|B72k1UV(Px4>}S&qA} zZN?tfSKDnOry;DrmUXp8E)#a=<3P2~URF(rxVtxX(SEWM3Fp4%L1lAK2fFFsCjnyh z{XGF97(MaRa%jK%dvp|Nyl7786sC!!0yQXlY+xQBJpXGVudva*pKnZvE)Vyqp33$ToIWOO8*TjIAO@ymPE2I)6a=ljZ6;zc_@4*G!Q zFr9ct-;-I&oW9J7wLw|Fc+$xoWn8!fR6V}z)S|m1HRn%te)InIcLuAO-t8fcJFj5Az7Hi! zo3|C54CR5Q$m`zOtanvzLE2Ve@_muWg~M85yGJqZnQ>3^Y5JaXB8E>`ED9o(;$C^L zZUp~eD?b~_p{-umKgBCaWEJK)Eb?Mn1hn7~`@aL?LnbQ)cs9-%6B${(k2$ut_6S!) z@agK~L4-P#N$pr(Ft=kB$*Pj*TrsCTL2LB)+E<3B_NAs?k?%v++z@^rMBM753A%p8 z$DJA7a3)e3(u>db%h39R`lsF&9tG}O{K?|e)BZ@U`XoN9E*C!|G1L}?a06U!?gTg3 z(~BOK#lPi2O-Wn+Y!n$-1oFNINaqB%elmw@-U!x8QA;oitZ&9ggvvUkjO4E80kgKL z=-&+EEY^zB@P(_gSZ4{I%aS{G$~!_%C<-1_CrY`Wm+Xz>GVO|SzKKw)<|p_sjl^}w ztA(+4s@!|&SpKVv;?Ea^+}Gvu;VlNEDq)O(89&0P5`9CWe0LwnEV>n7FaDKEH>F77 zWVQt2K(o^OIv7RpJ^<#zP~+~sXRqWq94h%aQI&J5PstAi9}%Yy);15m&_WEW?RHahMhE}>%jtnaY|)y^@^U_U6iSjse|hg%?hT0!uH{vCM;Rb_ zv9FG5x&t1+YDih6hr%HByk!>Oe)cfeEtkH%g_=$-14mzk&xS(JFJUOSLYnkq+~XQQ zQk8=PqsH+iQ~F`#FBzUdPFfJ|9m!B_y_35gB=PTV4CNW(<5YFN1@wh9b)ute9FQVV z($?*t&tWOYw}wKb-+ZDlW~eINuabgLp!_@0=rpkQn5sU5P z?pTj~-k5mke;s^+OkrD)`8I(|`POmWU0c#-@x~<6LwIc#)-3V8&H(u2vG6--m+X@@ zpfdapDpNVFeK)QL4lj{m04lFKM>AVXh=&Io>@Wx*U6v&Y2Ob9Uo_*U#KapoOva7=S)@;kYGy;lI(jjzma04%RE|IE|w) zRS_is%wAt2uTC)%(kk@ngls&;-avOS}udt@d5Y>y-oWG>-7 zy?yE3&$PoAiZOE`0hIb-TMlV{jIbvFdQ<2#D2OhX+laiiSv}1B6}j)go}P#JG=VjL zX;+vw8PXDP+nFclq{Rj4Z@aoDej7_;=wSt?ysc!yw*M7<-&=fXj2sQZ`@6qL3-4b<^HPF`H<)VZ&&pi|h@f>+}Ap zLmR0*k|y${vN%mA{8;gkdipM+Gr$TGBz`NAn_*kHtC_a4Bh&ibbk{R! zu`Z6xSpJ&4I6)bh9o&e?zqzg>SkJ@oZcm=aw`kKp^E0oATzLT~YsYP`AhoiAp9MVK zEs$)RpiT1@{h~e7aO5XI5o}QJxB>8BV97g%sT0J`<)ThxWMYKxIuG2(3r2UY#!P5T z79YWcn(m)|e>?s#kQGVLO@;rsR^0OUM5d`b^K#-SBgIN-56Mo;u1-8yVC2~QOC#Rj z8{Kt-w{k=SbIA`!D#&`Y7d-3~dj>%q?)PtX`kz#_?9m9*m49DQWMkMYG??bNpKk=p zTmF3bGL0~(raRiV3&|FG@(44%E&w^E@4OZsm$(fg0r4y%Y!zoOuR@ppWMp>y2n*#C zy1ZzV$m;1lb5B;S&O-Q!zU7ld6E}w^aG}iEQO=wd?&=@j5s85r2=e>x^}e9TxYkGZ zVh2PBv`t+Q$vV^#C4M77sE0TU^gYEr@;*a)dZ=#$a_mzfxZrTPhf1ACrEM=t@%jDM z1=ALMOa8mbr+2n2!xgUtc>~Jz0SdkhI6q;-Y=;fpK%Z|rI@BMJR&l2$r5=KH(9RfY zgA_w!YsBT?p)E*6Acy`~3F|yhQp_ljgk>RXiv6R`2`g76$I$8smM*i*+rjjw znqpoy;W0-=+*)b?e||#^q`z8sc@_#>A2dw6#hGJy0UL<)D0onxx9^i}VzR2a$C=i6 ze|K;z2*uu4{mqVvQYmYE(HY3Z?lie~Ooo_FwNa-x;x3&1d5hSyV!W--ZznqLCGTfG z@ol$qtnR2!^3}hkHz6^uS(7$&b=eX(vd`<@E2J|=!hHK=J6OS)d@7@(r{C3w$50sV zFFfpcGsa+KretE=VMe#f^gj|bWokCWd05=OD$g=?e|m!(_V_~I;&BfM49K%PIxP!5 zD`60xz3ssR*IskT++xB#f=wfac|G~hkAjt_IT7_d7>bJBpu}lMMVt0}Bq1i1C0>kA zL~V+s5_!8`TVs2`y7z-DGK9fwe|ah{ixRNT91Exctw!5R@^g7E({vZqc@|P+;bCbf zNd6RDe!zj1ksIvtfty(odBlwoAawqUU&Co~@gNJx5})iRN!;cg#N}AFKX9Rwy%%2g zI>AfGOff~q$>Cbn(t2+br*HN@8Bm^+&#Fkwwpm4Gi-N}BPFN9vP+Ix}>djo={z7h7bf(zrL6}~cven%LHAx=cn&hKJY!DBq-EMSl@#;52@0t#ys}O}MaqYy*Z`!*} z(ZuSm{g|ogo)n882!C>@Iw&?&vA#3@mb`0l1HC?-{m__y;656M8B#K%mwLr1uZ%K# z{h8yr+wt2hUu+_`J?y5V5_IPm>T2OR;@=3HZiDpAyXFkMAogqL(U3RQ;PcKzo$-v# z!zQZOvE+Ag)lKB%h{72y?yb?_UVybb810CjZ?v8tvAT#vL_Wuzd@}$bz0xN9)qAUe zfw!D@w6{M?5|x&ebkartjVtM%ElrX+H+rB0o^kSBOMs*2VQ|-u;mNZ^@^U=y=1lFS z^?iWXGsl?qYl$oQy#0GMh2Xfo_fEywO#~(aJ1cPX7K56 z0uNaP7M6kM!s7hvPSWA>rA~=y1~|>=a8HqsFG@xdEm+gKS3iAer6)u3g?Y5+9U4m6 zZ$Ya$U<|DFb>;Oa2TX5uBZ~`K&}K}8%(lGStf3wG*MqVPa2O=y*sh1jCWP-GEa*7fg1%5#}Q} zU0$%vGQt&xp4dAs^pXdFp2&IM6}~1%lhZ`NRBb>#!03(AtV2Dw?L|I_V3#??$KE|e z@cvFw>z=>|pMz^u_K{pXK!UeJ!AdyPOv z=zVA56)0Zo!#OMTSTqhVVr-Wh37k`bDfalYX-~!0IfB0p+m8Un>|^+z?)?>!6}xGT z{%)OL+r?xp`+hq(i%_4`861cgLO|QI#B>SAoSG)aVH0SM?;RQ&6{9Lz;LKeBJAdt` z*^A%qQ(YHFJ9G2JRsHwcxNPXSzvl3{boA5K*L^3BD$)Elhla_vJ^*1Rpyp%cG`8dUYKY;_Lg{&gFR_(9j8+K)E^>k@bVbQq;3UF1}>3i*R}^7W%wxY&y(QQ-rDWeXIeJ3;gFq?rY@74hfZ zy@6bk`J>E8yPFZCg10yUF5f38;)dist6xE=eQpP*^sc^r#a27Vi zPcOtt3!sv$2VEr}r1O2-n{e>ZH@fx4C&;)q!KS#yVOvN0@^)rY#|N}nQ|{a*KMl!| zk0CAeszfNAvs00n*fM)auTfxXZxK{$!x;;5_S0e0v3a^Y-`FW`*&YY{f2W`IqRAe- zDM5X67~k}oCpL$~32vTYasW`_ED&l{Doic7t)A5TVTumQ{*LASZD8VqaI3{F*Q|A` z9xDc<8c`k1FEr?S7{NO)OuNXh;kzs19hz|D4xjw?toa0UKB~s(0$p%FwX1jDI@Zs7 zvT*Uc9-TNzOX}-)`_bi%LA=Fk$IKhDdut6 zr!ihjgH6G^DMr%#kn7qe%ov0%5k@%sHtA6{P*fNC>r=OccGF$9v*+c><)D_j?Mg{g zyzQda174Ruk!MvREn}umtj4;SSMJrY+}-Y}clnWuQB{sO)LB3S7&k+rWbiV_p-(Fb z)=jRViV_G$HFqf#5bxi1g*o8LIv?hHS*8)4G)PLGbga;2)v;r*>^S3atI@^fKill4 z(<2uZRe?4$#q9$HRhh^CViMznXT4Rn8gFc!rU>x>~E>=9Je3Rl20%#cE&tdRTwe5U3S6#nuLsX&w@mywedN&tm zdk`qLSJn|+u=eLUZ~j96a`mUU04|-QveGI@sV9liRYqWDf~b$*aoCYLz!j5VjGm*? z6pA{pg&Lrzy7=GVq6~&#gj4&apJ5KjPudh52K|4 zvEx}uf^n?ab;RlBESKQh*J`t8ltdqnTy!)9#3tQZc^u#O7r9=A+ZC4qFDn&GY$_e0 zY$bf=)Ay!eRA&&K+PTN(i&P0}Dzb@8C$@8n@b5x{y90w)$#cK_Y3$Q1g*GZ5`Uz=0=v1;-$zG* z=Xyt_b^l$`_4%D-)Gi3LZa^WoGvat8lM?M22e}qEY_Eg^)Q*46NYS`!e&j~fl9bHp zSV6gt^1RT2^QW4*t5~;7|I2e7jN=$RgR`+>#IS!OfABr%8Ku?YrEr-UmebE2;J>#- z38*zyaW+3m+jti)%K_=lvM0#Z?ahiS1AsB-neeOwT2e6J2r563{4d<8Qna!^z*Ijx zzH@%l@KBzhC1Cd1V~oAUnk&R)&>-?|4929F2>485$HvYrOA zT0_Za?LN|ph72_FOqXw5i%R%!-?f*$d)2t@tdJCUVjkt%n*iIRv41rqVj@lq3%2e( z0UrSkyTyAx)8hkb<}n6RBAOU=5Yz7KVg6&Vh|7lZJ~1mAZ?2cb<}9{dL)qNVVgs|% zT|4H`cqHwOIi_t^?WKoQE)m&lyN5d(%5)Zi=t_VZ(HXK?`MwnQ$F7Vp9DgK_y5QT9 zflY-a{N)^8vyekedeW1*zQjHw?|KhZ_$$B7#jD(%vAS+9m@VkS4i)jU!qvO_HW>W@ zxjpt8jX(%mepTL|)OO4nTqxCRRk^7X&z3amD2lmhhfq+{44XzWW#%%y-yXyGhr=c9aj#eh*j zkIIr}4LkIkcwMgb3EQu)`4uH5cN_XR3m$WT=Tw{zkF?t1a1-E%8GUFFctM81IyNeq zXK5H(qh2ozqU^#Z5D?#J4^b~&4IIh+qTO5h_4i*YMih@nR0ZaXz<4@Z zj-76ggVU^_q!ST|RbjevF>jYo;XJ0_eoe9!D6JAO!TRvL-7PiIE?@=bJnCXT_;jk{-j7AEyu!kySxiJxg6D2AzbN)gY%Az6b;{@T#*CF%|> zvyWhkyEQ6%HpolLD~$cz<14I-DRNtfjRe&Ec7A$G?@?*#okrP4r@Rr~1kj->u&*Ja zU7L5?jD>KbWVJC(RDWQ+0lG%b^81Sn^(@Ld{=(euHlT&bZHY($NU}Y`@+u?lwsbNw zdZXOD*N*z$kv<||+Uy>m)0N4rvsAFIdbMg!ci}A`KR@w)`a!*&(Yd?s zJLs&Lz4bJvX)TEV@OAUSqOnQr{iO&CN9Ck_J`2RHev@&#yvp>L@i=>QJ~I25(Y z`n#8zlbT(UH~SP3-V_)VMDCVgGD?<)og> zxXJI?FE==2!T&3VX4<17?2`Oy7)^pxHhOv0h#ACX22oVD<3Lt8^vzm3)9!Z9A;Up9 zN`b8QLR#_RRp-?H98pb|&h4#W9uGDpRa~@s9*ADa{e4s*gVp=KUa_M-J?ZS!-#=Z+A~%KZfa(o#YfDODo@Y&0V^qte$Lcd7D93*H?^>vz_2s+8y^v zOx%HYPM+G5!5(ejg!}1WL*T&mKR}HHEpGpx{11A~KQYGZuSa`&n~7Il7m+_7tn-5* z9WT1y4y`~{>74E4D}z^lN?lXmC-2pfg9x>DUN0pk-xyccyrGQ*>cua+i(2cQa@v2H0NEY0b1|$ z@8>2w9j3eVsdZgj<@(8~jv*coZ1!pWvF(F%m%Kt{#Gfb0E*D)mZv6?aGw*LFHOFX} z-m72!6w8_Tyt5ebpWY8{0A2{moX7RUUYR<6R#(%`WUphyK_IWhPs;XTIgNzl`S%?O z^g~?uaFE<>Zs#jP@0}#iU7Yh{I6ac5Sr+|p&+aRMH(Y*3KCmZ;)RAR?S$ZORc(Wop zD$I7vXYMSbQA;Tx)SYptCV<|fzD}lP`?BWAN?t4Q2iOw0)5e}-4Q}v~4!*&8eZ8|s zFPQ$>XL8&^p7jzjd2yrjty#VXzkA#kWrYp!dx(Dr*7-=R=kzYPrl-$|(of#IAKM&9 z*zs+}8%_1A)(f-aHi})irJ-WdWwfUJJGL7zaD@I7e{giA8ht72JzX9z4t%MXTgPk} zlvd4yf>gDp-`J6AJv`QVKWSLs2O>&iu@#H_w7))45K*@fD(~`+ zl@`7{Yx}m@x1jBHawYcBP{KPVul4?M#10NZiLy{ezq%3jeWw)H7gkzRh>yzd19w^m zY0K^Bhf6MmvU<89#3!eT{791O-TO6+qs0E=&G()x92hL>h79?U`CXK4jr>?$ABVTT z-DH&qTtdfFubzHS6r=9b{@!zZsXxJ|V*xcfbGk#GEzC|h=2vBqPkPViW$(Qurt?Fb zrfF6Eso`{=VI>nfkF_lO04!#EM(59Y3OO6v@MxsyYVU))d$Cw=&Oz;ec5Ju1f*IHG zwpo&;5aw-x{$;10>)q?ubDg^;(pYXaru^6{zUaM#uYlALM&-AsirJsP_@ga1epGqb zuj-@JCI^fEy>{R&)Y_QyINcb}CmcV`Y(acfJIW#U$#Z$;ghx7ha9IyBc`aeQA}jV% zZs-X5M?5KaOXW_w^7W`e0&7hs^OT2vZ;_XNA%~~G3V3sk{&B@^H3zDl($w^#45Gq@ zzxRyE)Nv+B7_-9LVN->6i%NkX^$&-eEeHl+>IZ<3?(RAiMDI41fL5-?NtER7cHO33 zv~5Q>`jiVQZnl0dGi*^$y;0dRB5IufIr9XE>Jla}kw?VSK~GAJ5Ad6KaR1bzANG|tC&Lt^<{ zPGp=Paa|iZ%8s)OeZ1fK=&E2iw#)5%dqF&G>dbUF$gXf8VA`r8nuQi@Ggx-F;_+i*#Cb&hY`A@DArEIXs z6KL(UTa*fjEo$N3bcx!4<47Gyf04*_2+aI4v=y0*r%;=7f0pxyptQ`3+>y=if_w?jC&9_;`hsB}L9OHAbHX+0 z(vF;*3sO-pp#PAgGMt>-u{mo9qCiKS>?~oBj9x;GXXsC-{xA*LGSd;~J)I+2Vel?+ zXbgorXFA}lCBByMWg~ric zm1cLt39-(xZ}^kPxwv0}@^C>WxSX}%;OyV_csvPw08c@E+vi9hZN#BCv-E-Ne^Hkn zxNQk*ugNb;^E+`!l`?A0n|D0>eC;>&?*j~}1xdhcSstc4f)e(6RE3QFzM7N*HkM-E zccQ>3m6Zq%A_g>dy zj>-!fh$!(nk-*68$6|hf{{wrsa}Tpi%ZAJ)&nE6b5T_$P)ws7$U$z>l`GDyO{Y?4$ zD-{OPNEE5zH7CjW-D*sV&eNXu7qx^C5;n~=nccQiI zQ`Oj=+%CE844Gpi?54+$2_NJ(@_zmbsO9$+agp#rgc<4J$~a#ReXM>+bJJ0ool^q? z5%TK>`L($IoNOr6(^$PGLO)cd)3G#bUTZ*)0mP{pGof4E7&m&7WO}!~Qd50yAItEF z1zuILzaelPc!De_$T?>lPj}5RX;wHw=k*C0yuJir+UCVLY+7eRVNb-tLO0dL$2baumj< z$ID`Np57iYv6~z3#r4$Y0%@K2C`%E?ISb9kL#3A~57!m926@d2gq<&G1U9f5-}vcy zK}t=ZqsJY?1*wcPfHK^kk^ptoi%nDA%axG9lR%*GW;-k9y%h*G!c8H$BTF(skr+CC zzdw+|4{zOURm^RX9O-#c>(e##4h-KMv8v7w3)z5%nuNMJ&>x?7d=C(bVST5_jqcfv z24@`cku^J?yDMR!ZPigth0UiXhsQf_ZJ&Mx>HrD+8B7~5_iI7$0}le9(`yH*h9_$h zR)Xxi&~(@~s|GN*^XB2n=2XICG80rOI_Jdj>0DW@hT`M(m^Ca(QC~gy9Iw|>w}B8@ zv4zblw5s{AvYRxG3;>YwjB5+j@ce^%(zxIGwY`Z(oHCDP#pO$NU^H|h2Io3jpL6cs z*v!DYasgz(dBIfB1jt|W*!AcQ{ln39oWy>sQQsEhY!uc;|E|!b*>dUHtU(Qb{^-QIg>)^ z2gaQqF$F_|qFHbnUywvLy>e3QbGxS|%~_wx9_8n?*uf>oAP9dzR+Z9ld}0mywt(zZnUxBb>uk)=i|md3 z6H-MmC4c;`BF8zp1wGj^23{4XTXJ{9SZQMO!S2?+L{F-k*QfW1<8ePh&yGA9ca+&@ zcRqMK@GP*D_Y?k=p3PfNY{%t!?_#}MyzVhcN8NA@CUP&m7&~?(P2cPjj*}um!r*5l zE#i^ZrO8eGqE2&rYOHm>$W>@9fXEk)xSMeK2jW68El&#lvvitGu|TWD+xU|~iy@eO z^)A?#Zj?>xGB!N?NRP+8M;-fM{VI{q4|3m5^#>QS^0CqAR8aNvM;cd0QWVa^H|Wfo zJK1ODg!+uJ;{EWPoifV;F=?m-_@k*}0{8TFfOinv#B=NLjv$RrJLqhMHZ60 zc&qh3CH$mAvDnezQo^OZ>jZ|Y#j`{vL_LaK_fw8Mt!BF9s4a^$nC4}D=4ohN3;9f0 zcU=3VGZLwZ-r1|tnj$C27Q)PIpX+A~P0sbLhY^Y)FzF4Tl%P7_ITWhF!%F4mpH7N| z!<*WtXUlXkGLO)rwdk%)%^GcO55Qw2;w2zIorh5NkX4HJ%_AY{(Kz(l0X8o^AGaE0GxM zuU*7{3lWK<@(Rf?*It_Vn)CSM=-L#?kg!a0xl6n!|AJTB-zU)4XVhEjZQkw0eEVJ$ z-oL)56-Q>G0xRPL>?A4NFH8 zKZ7SVsFk<$eu9DDpm!{%R?~=jFGaeT*sa`BlG7)k`dS&FUct83r(YD8RnI(;9Z^U_ zB`xYw)aztd_h`7$UD~#N+#Wt1a;3wwr@{(L?+UICy35|9MJURa7h!b6?Dd;4l{4FI9x8X%;pPD3s!=JVG6aDtNnWuy^Xl6s3taDP$UG|sp*f9sWzIG6jGf#=Q*c7?Z><^{om77`66(Il%5RQGhdaVPej zbZw?Fb}f{nc$0r8hQO#p_G%2O(3t6NJ-Zy=nbdU<7j8N^18%sBint}rJJ5eOF1gQLpEEM;oN*vM)qCl9MseDQ|K^fle zJ7(T*lo$qU>xnjfp#$I=)}kQ&I2NA4@pYxAxBHSm?r-w+i>;-Hv?7mW(H(6Qfv2#b zXrtsV)KMIg-?t8K@c~E{Kk6}rxREcMAUGahb~Lxnqy1!m$1Q-n6t6Fx9E_Ij8P;~g zUwLq_@8T79Vj6z(Y^NiR!+Iips@%%08g1u;EX%@b(y`Q_IJu10L9CVLH6O|U`Vs;R zBrmUacFkT-YhPV9Vm-=yetz}*s(lv%^lkG<<^0#PRjDnW`DtW={9)1i^9`&uI1!zg zJB`6>6|~`F9OWoH2gzm>8@yrE1>s~x;(y^6Ni%cXV4S>iL{kS`yzD<-#o^{CMK2vO zYmvCCJHHA^cbEE+!C(402IW+Vk&I&N#9i`2Bz8V_e8{@s#U7^Z!F{j@vLfjzzZ)5z(7V4MbpyAvgv7({R-EN zaRz#WO484ZjRthiYHLS$b^v);P!&b`Iepq}5pRvbqf5r_P2JTc0EGftXw&v|j?Uie z?E8Ly6XU@(SY{`73PYR`jfhhgp-$2VkE`0}s}SrnAYlnv6!sA-e$xl>*w9v;pJn4r zVe?EL!&AN>fXYwjp1iWh$29;MNM(Fy79OFEUPv9Mll#v)Sxi?V!dg=BLZ}wfV0oyT z@a$!M=_#hmjgF)7w=xwx553!)zvV*kt+DiE7;kAf+Y#Dt4Cs^-7`=t9QL8l9MR75| z{)1~bSl>kCHlLW!>>$y}sSNC}2VsTD_KLX&YnxL5$*WI2@4rxa4rZCS(d7&^GJ}0C z+F}O~M4mj|eaoqA(Oxc1#eHh@(?}om4;zV}`yFOiemyvUu%=I~?~SE;ryyP8vtw;9 zq^=?`$U#@`D)kg!0>~e5t~^omzAmFcw7ti0QE*Q7zVodYrPfyXXhQ_xYi+ZlzPiOK z08gW?tC}9wi{V!!VdTNg5c|(Y=&U+Zo+CgFdfvp*V}-Ndzq+qb>AZF1w^Z^U6V`u+ z=XW{4sZ2aeK^y@NzWg$r`968mgclR>c$A#)r{#EBqpSP^kKh|3`Z5qQ@x?#QBvKY$ z19lkH((VTN6zRR@5+a6_!bn022oX`<`HT3T7l;YktgX}as0J9Id7CX8^RMk!e&Zn++u!$~yN_ll$sm@F=R zOx`^}=ZQFHmN&-w34vS#(VyN~`+$=fPrd3gw;m)R|6EFe`3-q0XNNqIhWt2x)ahpN zXMF9hf_N9gerJT=W zDa3=rF~cmdy^*r&d7f?i7M+$yNR<-IqJ&+EhJ?Z$3`Z6_01jPn4_cd@zRnO>D8TTHxUliMiO5 z?3#ZQWrgS)V|K6cV(NWrJh;%VR}?8yB)4&61*UU-8Iqq~kUjLUewH&+czc-0+{8T? zHo|53hQ+LnTWr>%S6|)fPIb7~l{wZwhk&ES)|K9(w*b&@z@xbH3&B|+6A2Dd?mR- zcgcDdy*T6!!_l2AQK7dnrSZtHH`qtM+Md|;<0)#GvwQb(kX%iGIYfQvqa z54nh(b~L3r_v!w@z{LinEqq^SX`c-!e*^H3*NAP-_OFFBMdN$0H(;+#x6sXp3`G<~ zD6L#BUyr2HHrhI=iHFu{qHh!Y#ix3|V!bUMBkOJ%3x9%^f{peUARcAQ-JrIdXZpP> z+tVlK4#^yiI>RIYk!Kzp?1DPTNA`>7D%X1S9m*mxN_~nA33eWi(Z?JMKL0?wY-VF) z_|HA690ePK-rQXjzdMCM!#I_ecX)emT4Je=^;8TKCV_uqd%)w24Wgz$eJv+D=u{k2 zNOxW$4`j&0<6&=X%prOz@Ir2tk;K%JH3+t5(VDdqJh1HEw7kCft<8$U8~_=ZK3Ao@ z99c;EoZoRmbd^AWW2^JT5rI zs2)StV(VDuj7uSAMhe5!zsp+ETAKV;SZ02}B6c%xXQcMg&Q!5-W9lNJv{f5Jj`wC1 z9`9nqS&^>g_eRri^~?Y`MEQ;4(T7@0LUKun&%2*LFERB<!ZRHSAxl@3?9%1Cf;*C7F9@-vRf!v2H>4< zu2Hho!8H%I!}Wsi45s~WWT1-dXV~6r2gcytVV#F)-V*2Lq6>bRP#Zqwl$>rCFLbvr?de`%C zq3r!@dnUnQ!rlgVq&% z0BdpnYVxEuiS34G*&)EG(F0WFLy{~{My!A?$hz9?+#jC_G!Z5<#a(^5?xzviALW_b z2VPmF))GQ%aM}bc`>7uB}$AUIWwDHYDmE@04GE2EKku zgJjfqCzbkYX{%pXLqq}$5y`Bt&13RG#74)ZHJ6mHgz3u1{HX7b$MB{l;}R5?L*R7& z6=yjEbLanQ28l;>ut$H=31No4D7=g;hWw-7WUw+c(LyZuM3^&QMhDq5hnR2$N` zsN~Bi19VP@nMY|I;IB2X2-vY5e~v5YznMj6RHN`jbsi!221@s5)|cNinm))|<5Xr} zjUG#o6yppr52$&XGHn>ReR~}_4Z5l^El;=5+&=RH@hOwl)Bt!f4v7jYMDwx|LxnZ< z$kdbkrucF5l}otJzvg6~t7uQ(>Pq_HHpF%^YNreyY*bzIswy1nk9G2#m$Y{%e6@7x zw@%B~*(nFeO3p^jYix{MP+ZQ3D*L>-J$HA6Ryib%81Qqi#}aHqOjDF_?Vc+trcakM z-psy>MAaS@q~G~QH3#e+K0t$fx#@5MrLegO8Jd-g{wQt^@00+m2nDPcWE$(=OH=Ky z*-dJXtKgajP}Uz`yov0UHFZQlmbeodxw}yQ{_@`6h-6r+Iz8l@GL(;bymc7$e^|5V z%9m-*-$#Bw?zo5fOreYL-tgv{6&??J(L0sDk&Jffsd<~*cT!@NtHWW4e}fy3q0xWR zwe;pSJ78`Wj^!jGd6+pXbyD5x#ps~s0MXT^j3k=M6dDRD)iTn4sv9!T@2}frk5Dga zTUdFpJhAOiKoL)7<>%K_P`zG~!XsPmSy%5_DF|Ws(Ye!((`5_6Fn201cdk!iEaA-d zH()fOEwo3l@wczzAz!aW58oMuyL!vcO-Ql3dJ9zGv)fHsx62AuI9+|e1u%G&jN8D_ zxX@TQfqkKb@3dgp$hTe09#pX-+CX9%bHTG^qCIuRauJkCbGy*u+TlN^N7}R0y*GRX z0w(bKB3;`Lh4K)%;W2dTH4!l-9S3>nfsmix3mqvpl1%>>k+Zn^cOl2*L~6d4x_e4q zo_sK~rif)V0#B81nf!VMjHiFgr2vd!iN@Cp%?4_#0A~#Dpjp9iSn!TPAW>(2s_p|5 zXPGEbxj&rVpArdkzt`pPdk}7v)<99S9cJacYx?Blo)Z+iRTe*^83e|RwaR>i?GG=T zXJ=zjpB?Sj5z+H+Ln_{lg)OV|?e2hv)bN=03FxD&=_7vp%@a#M-JlXvjqWln#is>8 z_!TQh0{|pkDKIUpu|H&AV?|%Bk`HA=otGX%d-p*QpetI*(HT(Qtk?jqYub<#V-OTh zp=woqEE=SwFBU~v)uz>_qIegCNu8K|#lMDm=@wfZ7Ui?Ov`BJc3xA)V%1p7xF~TWJ zI@}{XFw=uQvnC2EJ=f?R;Xc5K&fv9g+ufJpBbj{2$Mk0Gls7wep~tBEaV$?jsB03l zNA4}V{8*`uQoW32s;INf(dIpSgWVqG%fLAsxa?flVkGHle_21h^-;Hc4>KP&1D-hw z$M*fP!jo15uD&RiVCPT-X7Q^a;HjXbpy<`tsmIc84F+4L?%jC7ICI|vy{87ScM;9v zDpjAfln@)WVZJ^uWp_w;21_+$7&hc*>&d`-ie2 z+3x8cKK%vF#{azi{EUG|`1Z}=s#E*5JgZIyvKohh7?a-Nk$z`;0M78`?;Vtv$%qRd zZDS(LW*=4Z&V{4uQ>!Ftzb)fSvg_6mQi!U_4aHFs1 z>Sj;eUz zKOHHYZ1<;^Eq*dMS5?vp{7*TIn#`Mtq(s4nys6Lrdf%HMII z>jP!>*8NZkudH$B6jpnI?o5+yv*cx%YO&Oo&Ozurw z?mAxs5gw&2P#;c8~&Kj1zLx;pzePn)O~(jogiE4e`~hdD^JDCrQ1-c}hE+6X2(HpEC17 z^tRpiTc=;j6WSd@mdtWo_(^Jg9ES5e`h5;m$03jaJ>2PZkP8jg@q@2MLx z8TY29d_yt}@!Nf|R*$6@ae4JV_>JEOqL@9_f63eK(DX_pl(J9nxY!^2Z5i1lGmTFT z9E0m@b0_X+LE*n|6K=zwvz>QWJXycX+_)@zIidBTtWclAZX7(4-a?_HJdZj(OZw;b z)XymK=XL-Dbx@V>F$${9yb*QImY<=Fg& z$W|ocuwzsC<?yo#lu~3K)>m7;vv2~^(k|P! z$L!}MZdWk+^kk{ZAZ7pr{L-pTFA6%_!GsuYTs{r-ZPK)y?-=}=djG>Nvk2`w zIC`J=vT$C)$X(yOqiaA_qA*9UI@C&tQ~Ko2O>`o`I7{I393giuEK!khv1bJd244Mw zCym1mxBZJ(q+Lw7hx`6Lx$3^d>j9vUi%_ms&r9%Msb#AWvyG7MZ+Cth=nSaO!d6L# z+}e5)g0H+Ez<0U98*2T=2#8}XbGI*JKM*kV7wY}${@ZW0bT_xZV9a*;j~L4%QE3m%%ykjZDlM z`6;`{?}-Tk^=}f}t2}XAsPW4bzv_gP;$Fz*RrlOq#eCn4DxU#C_hK!QJeo^WdECu@J!f zeoaT~(ofh5!wz|3hSjWwVzRf#!!*96t)~a2=bPT&aL%HkH^XHmD&3oy90E`5N~f@1 zLpAJl#@gQ`fN^NR6JL)YGp42%faDwdA1j;A?%>d`4m582D8Bc&>NUTXDG{ z@XkBU_`?n7?z(25w=Iuh(tUS7q4eQcB3~AVTkYgG79@##V*KUtI6c|A-;I55vG1!SSyx|HoY}uAj)L=;g?K!%m;eY)__iLt(T98- z>4^Q5Dt+l(i%kGc-0*Z+`&aTTj<_+v(27ykH~-9tazChheE|d!Veh=r3jQkS;E8Gj zBP~Yxv|-L*O{YBNzOFF8^WMCkcjs03DWZ29m0wLbFlID)qb`YVcDl(cc0DC|C*7*4 zA5+kK5sc)V*RI$ae_^TnILu48voVJJ&8@(3vZ%!`X#IS%2=Hq_vLpt_6z?ipKVKAb_k{~3NXWF~wbG8v z%XQ3@!9Jw-%R8j%H1#rVV>0T$*q#HH=MJ*PUWS?i=dF|0L9+kkj5j92s%>S)Dx3AP#UhY;kd?S3Ln}+ zj0r=_(EUQccRf|IJ8#a3K;%H+9o4Xyw|*8xRlHh97$+{n8%8qkC-Z!re`8O(%)&gs z!G&RIxh@`Thl*?^SfP8=-c%iI39u3gl8)@j`hYDiun#|fWv~tPzF;4z?{WBAIIE44 z>fkjJACt|0d>)PQtg`wkYV}S&hHt2ixafSI>VXxh-I?YgZElw0apg{5FjKM!S1=WT zZg6Lny|k_d#&wvi%bk7S`1s%6lkm7fr0dd%_X$5euwQVAd827dL`98=+5VtUW7Xb( zP#q-Hfy)CJ;-(v}O3zFjhtSW-+St8wFQ&K2Kbh_$bD2noO=$OT_v%Y$FzVLDnxY;ND#5 z%SycP_=Apy(TzRULlADSd+p@5ly0gQC2h8e8amAi=(deM|6LKX*b?z z$kDi%NIr*X3ARCrn6dvV`Zns5;iG6%t)Fck_B-Y*xc9Bz-%>|~S#1fs{7!t7JA#Xx zCl`7r-}AFE;DWK&0MX@7t1Ayw7>#< zq(NOd3LEZq+=)h(W7MfqJjVsp$$_eVtyw3lA2BEetC;SitHPPyX9HI{vwMwib~e$*JA+ z_8WuDg)tohlcxVXe}v){4<_%ox7S(n@`FD-G)`8%{0(=^YUe6X+02c1vs$M6a; zfP#H3sa%hFR&4#;oW$e@KZSQee%lY1(yBpTAE`Ufv#xvmrZ~LHz;rkKSu9Q@dm(@ZrhUiKXx@c-g8pJ#jnStgH+HSpJYuC<;BqJt_(056@uY6S`A`630ZN z@5m*ancKf#4OYXwSFNQ!h7tZJewQ{{HQQe09K8*8Q{OH?pP#0V9LH%>`bho$=G&gN zt{Kc*S&Bnq#=XBB88`-CIz2?YlxmR%u()!Dw;grz&QX_V&rP*?A~Zl(POgY`9qnWeLz2U-Z$5}THQPyJ zT<{}cMKS|yI3T$SXJcAB=v*|BVc&Rou-zR+lB&J(uA@>4e-A?li2IpJ5Cfgs?7 zv0!n7?|y`M4vrK%-PakVK<_PIj_=@*?}`Y$FY6qAGeEAs$!HW`L8qeM4K*dw((vVnCn>D(~mq14;-UgxDKLv`ke~Hie3v6sXDZ&ZN(M zbG)NkEVSa~A-`8L$jyt+l<-L)>ye-oTUu<0XZ35(SvdzYbi2oiaFrgp9tcmR;l9ts za6@z?X@2ecWFr*U6SI~$lBo9%yL?`VEE*Z4f$$d2+eCC#&puU0{6K#L2CWikZU^`t z;^dJl%TIMse=n{0jh@6UIbL9On`?9IR8(n)B|}s0gU48YdyD=%EUO>y`#bzs4p`wR z1UR)M3nOlBt z^Y6Erv1hlVLyvo%m_`*fI-jAT(LS7}K(8k5)%Chmp9Ou*OpRAdHsu@j9T+^&+ZI+0 z=KMSI3EAxs9x}yK%Wdpi+*s8Yq_)~!RN*Rf9c0yVZplm~C$00*9#(k2BK*1Mbym2@ zqQvc#mjjr|?MuCH$8S_oN11vlXT&q+Q!yXxBof~EFzGZGJwG^+k?Ja8F}5JZ1wBw6{b9e$)cN1noi-D z=_UL)8(bUb_(eGk6X@cRb;Lpg{la89{lk};;VAp|cK&|T`}Nt2tg1GrxaIUc!iVZJ zpS2}FmEE`T-^!;`Zt0_VZb<)Q-QwC%kQ<}Gs>`Nqu?Asb=tmdtH{44!QOgB5A&VfH ztPhcI(%usvK8`tn^!fzf(j$Lw)DCh8&th>_j}t|w4rh_2OwJ$KG;qY=QRL8W8v(jT zxP67&ZK|ZBM2zc8wJAEv9k>#t{y2_=5FO4E>m0z|oY?oh4W7oH9-`{=deepaN70!r zE2?Et^n-Yyk@k^BK&3r`sBiR$(nurC*XPWLii(OGQF${@D(t=1oMX^R=*6Dx`mtRd zFBb#Ll=PuNM8x%KU3wV{XVjZdo%UkJnVjO=$AT3`B+ARBTWk@^JD4ixLh&Z+9IFGX zjgO&)fff?2$0K<^p8|WsP9ot#6ZJbS(aBGxbJ?{CL9EcA7|h}NGg2d`4k?!N&X*Dsc=u=hbuJ1FF_&f6S!-m zp!U}Y?(W65&nO$iWKX4u=~UOC|J`}iX0NUJh~cb3Xd`ANY{5Uv^&lJdPUWhP%W3dh zp18PLZ|bw$YWCgs51m>iV>p)w7-Vlz+YpSJJ${3j-ybd&=65Z#I%-(B!}nSIS*g8- z7D2W$9y8F{@G;n32p}Rfp?uCCC=kEd94|B2+P@zXj8Wz4O9s~t`LlFe#&tb=WUuk8 zr5;pSCdq)8~eG-4;n-9GtQgi8L2}GULVgWA;^4tov|#9N*l0?{f3#{hkZY z7r*>FRs#LDsykf85#UG>2-jFOG`-+~B2#0#8W;H%O+DZXwcQH&nIPUal2Pqlwwc%K zrwruooT65=ZRrri;OOYi0|*ie9*~SB+~cHS0v(X1su7g|w^?e=lTnE0OtcI449R6# zCEjcr$NqH9$6sNd#>Hx>kRF(YwcijxHKF^+y~G1vt?4X4Q3QznrZ>0~vH$9>Bx{1| z6Ml2RFHtwZn4~w*$#~d`l)EK729F5YP^Yh4t$1jjobbl6pqk^dlf4bd1 z8mVDz6k@!}eqVan`&Z{ICvYDCZJKex-|a57{6LF}Djl(RzPhG6UiIMEfeJUHj@PWe z%P+gckRz1@)7Hd(9+arxki|<_JeM{3d}^YYErP>( zN4n+U<>c$`9joNSz5MyOD46|^GI1=eOo?t-#a4`TUGsAW6qTUD{mt@CS?ptutcJ^^ z3Cd{sTbvgDa@PomlO58UDhc8;(b@uQdyu3!X*}b|*KyWkunivM87HDu@XM>ZV0Y4w zY&@osu2#aA?Z5K@P;nH9+zq9i5N4I4PqQF4b`(>lmwljv|5;am$Z4vn`CmcvDzm?b z-dhK2ZrWDFqoFTImXU8KR~jyqpkLxa*bGePbDx-Ao?mxyeB((l9Ur(tnut7xy*qiBw^`32tb=kDgO-oEl5<*qJ|2zE`TbUQMLK@()lG-Z$ONM?sU;oO_CK=*N%T`r!6mv~NIIOUw@H`Z6YF`<%OJf4 zN|ss@uQt99vpw|Daltn+u24l_pDs#gRsPhjMEVI-HM6hry`YoV%Ri@rKTYFD4OrmuORA_os)U@|;+EWn{S8mWZXKU?|`O7Y?qFyE{O(ciO1H3_eo(v;gpi7dJDN7fY0dL$Xe>7{y-q@9xgE%6q;Z zAT5NafQX(uPoLqy;WL%)ir?=T4R0ArSht4g3+O<#I~6x#%WXJruymGKOjBrbI|}nz zGRQyN&MjSoE&#OHqyv=n~ys&`X)jv|e`+77_mcGrASg`2L zDIr~X7c;wU4D~cMk0Z4Km<4vea)&m61NjeM3{qA3uEk_5R=*oc@ycrM1wyGv4;;Y* z=7+2rO&CG=`1ZVSANqi;4IODg^K?7!10Wtd1IOzTI?{~Nk+R9R>Y=gehoR)%t66k_ zw)Q`A@r3l(iPH$iP;U!B%v#n=r1{`^Sdn3Ai*tc9sC{Byf8t|5+tc*{ znu}@-(4{$3;8dS0jB76<*{&?&QP<35pI9vuf%XHBNx4M6V=~YAFXA4=?E7hjWBc~2 zanu%V5<@NH-rVEDhae;RsrN5qNCvU3B8yxVofXgbLf<%l>&|Z@al)JvgVgnVMu771 zeVD@I$($}c4eLVAZ0BI%2qitzB2m3Qe*h4^%uNFxCcp>u?e_TDmy)=UzXK{RSAmGB zfe|oLex=oveI!9G&!+XTbPGG{{zF{g@4hLv*jzgP`U|^hkgq*`K*Z}wK!9Gem7(2} zk4J=oh~aD;Jw&QJ&LehZa)IIFi~Pa8nys6j-NwuJ21)#N1u*b!T7a+~&hi=1zEMrH zJHvXzTcLl$`g%3MBSM@5%OvekV%>bJC`)h$pEX}_20a4XC|Ta-*5VD&9{{AJ1f0Yf z`soe7L-^q>Zc#BUsAErEjUk?a=ZCiTfSE47B(JxxjE(D8o9HelW)HuH;60FNHR1eW z#$)Qv=MzS!Yq7$;JKDn_n&f(oN3UI22cZ!ju(s~coY~(ZgZuDZXJ=suwdgD1{KoE^ zzOpAOc`^F=S5H>cw||)3eF-Q0>HIpvS#=v^KipnIOWx=|#8+vHUpA?`pY0X4-6)KL zx0LKkCTNsXXJvw|9^Rn(8@hwP-72yy$0u324WMmMtyQ7<*-d|&)NrTsSrdxhU&K_! zV4C5m8Jiz5I_@l+2pxa6W$(WRq_ce^RnwPa=NOx=mMTsTXo-SvQ)<0IMJI>8nxV!Sh z1nP(N>o^gskS?v^N_Z~Ml0csLrI^_T^mYXaL;v@;ntS@>T~kNZ>Ve%s+6J^VE>>X5m#Wmw7Q=?yNe%PZ#E8>lu(Rk#VM)m1i+iH`I0ffBE-~WlMB3$yy68_Aolm)XtjSDIy3O?&`~Q0u9hlWx znrMx+z(A(<+uNE3!6Vzyw8L4@$45 zTKG-QBa66x%G{|AG(5!`J(bCvcUya52s?j#-)A6pOuP?H2F$7{cWWy#H`Y6c#<*`7)v^Rq#0`~ME^I7P2x5$TUE3A#=PtrVg{zyo^o1{E zH1_CF3ArqIZwu+5T2>8Npu7hl2q+_1xPaX9uh;W`3UhD>6x=SFGrC6XI1@>nUUW%V zqjLz~g;TSi%QI{3AH`wnmKsgV%=tAmjE};%!u#9)Syc_OVS%d2EGi*)oQAy(Y39w6x4uh}oC z2ldcTnNV$zv0(gEU)Rg+qcz|tbe>CJ5l87gF1)0xDY0!LC(1V! z%j;z}wgwW7(5vphW&AGoVff2R2Jr^!_22O^8cA>^XaA*&pMgVXBp4^9vd>yl(FCP6 z7Xr!@`wnXW{Q;iNHct1c+xkkGIW1PVGY8%=d6Rz)uI1%e^8rWSpX_#%v*5{jtMcUz zH+2sy9@;%5pME`{_5t84AXU$fyTMQPtv)(8&PRZ)k`Dc9b|khKo4c>gdg zxA6h%`=`^xx!SJF&Ib|y9<(e1`fZ~uFPt1&lO0HzTw8CJwS+@Kbe%G(^NIZQ7Q|9i z$Z^NBvp9xNS>MxKlGx-WnNRm+=7ZC_?rzHc5bjNS5CjNQewfOD$nb>#^b|SW__r44 zP+*=m;fvU>n)>zGr=;RSPG$iaj|CU{stA*K9jGA0dgi$-wxiEeYUDquQ;vbQxnXcP zt9|w1TclUM*&`)&ggx%$UJz;SEIvq=MUvz>DIsbfW454!6gu3h;4 zdY!2RU?&=Vc2DHugh2eI`8!9gog^<9HlsOrc_sg<(4nYpJ)}E;e8LyJ8ObqBePr;M zl0G&Ns6lwVTd$oM zargs)%>J$4VbuPN8aHbUGVhAAp6tQ>MOCjemP<>&=eOm?TiJRgy+xIv3>EpbUD&Yi z(3R9xyEM)zZYm;f#qW9VN|!i- zuIOi6IpG=YsnfUZjsQS{w713S6%fR$o0q7|a(y+qJ)0X5p~i{$5v@aTjRO#t1>t|h z>3xm^PgChXVqrzr4#2|S(d7nrVuNLdok#gnw4W5*jF{)!-3Kpg2MdIqX6kF2E|$oL zAi6uJWmQZ6|H$im=H3m11_^H&UnGfA?b|#kT5w}}3doZ3GCZC!l2-!qRh%5i27w56 z-%0~D0XY=l8J!TZ*s~NJPyFUZ=kV=q<}Him@CT`Gf=Mw*?Ci{J7fKac5H#!KPdHyB-RI*m=yiTOU!xJ`K{)`kOa zs6#XE<&T!693=1Zn28^}J4z3EOrq-reewMQqOn8^lNUM9f9p}G(8mv+jm=h%gfWY% z{iZW%2PjN*)gyjEd^3l3>fLO&yQ%N2D85()gqXmU*z}_51d!}WxTN=6{#Zm>4H!h8 zTt!eL8eSXBE93rsieG3FVqAqEk{0t}`eRYH-v4~FSzV_mmkOieV1&|uzb!-+q#yNZ zuoWXrGG3J_lM3#zvNrnYUfU6_V!uup3Fhz~v1qb!s zTo-np?@BWK{^v*`$4Gi1PU-|0f+vqK=yD)e`~ZWt1_&XD&Pt_y#>e}Po2OD{_{|-; z_WEVr!2bhW?=l{)<>d<{q^MB_eWy5&K0?L_UFQ4pbWqv>SV?t`&h>^d=!a5->3Q}{ zhB(Tc??%~`-D^k_XAZ+#K;`>HbE zszmd*Faw1qp!6ZK^UN07b|w%D^Ep|R@_9d_Dt?cjj&r`k@bTtfL3U(C%*x1~gSa5f z`q9BSofawnduz>Wc!_@Z@X`Mj@3(|DPGuAFRn_5f@y}mXQV+L3^2%dOco^<_F6$G4 zx~>h)uX(v74k>^J=aIIt`YPo#7W%)g95<8MmMfUK@MuSMn~ZGh|udNG3h3S&c#n8OP^{D`MJ1?*7=rdVMtmaaqokJEp1Q^10^8v z1f^H>sgEra+H9dTxG#g>yWP#TM^7Y52`!VTES$wy83hid?ukpGcWss&=9+Xx>>HE* z<)-xH(OeHYgt;@!}qe>E3@1wC=o zN82I@fob)$M_$rb`o6gV9NSO_%wAA)eGsSScQ+RyzQxXfFX~`ECpQ<~3i~d$xV@Jr z^S#;s1!}XP__yWSv@+1f?0L4PFI>~iD(tTTRQBH;gA*rXPcMOMMmN~*A0&k$d@9a@ z?!85G$`m7+Tte;<58QPM1fUa|x{Z)9B;!2KYW^d~*%XTw{T zIZOVZ;r&(dzzcU#DxdzvEviG3!y2U zYB~1XFoNC&04+n*5)2ey#pFu4e7-O)d!R>C-_NLU2{TQ|JR1K;{r#%u`>_bDjDxiA z`G{BMP_0_bL5=eTtQW82@Mw}M$chrH{v8&Xk3TJ5Hj8jD6V{mjkdv~6C*sXB7kG%Q zs5hODU(@)`TL_kpS&q1oGDs6aowv)`!d1^!5iTfHRP#^Q>XVl>MMJf4?$nxo#RVc6 z=Br(cuc*Id4I^g#U;;_mB2U2%MDUnpFI?rV9wHWc&QFiU>4z7;8(d#@ZeFjvSbI;{ zl2s?~=)>6}YJ#+X_L|EmeInIwV*@LNmMxh_|K&^y&(djlVq}ARkvTgaPu^kU2G-6p z?XTNIu20p{?(p!t{bVfujP_G@=x|MHJjpOf;_B^wX=Qs6o+1%sT7Dwh!DF3&EFYcp z-eyF%atgV$Jhr#=5|Nd+|J{Fb)BvV6qH1CNR(382@vP`Xifh7!Ud?Ube+vB>V;xoN zS2hI&Qg*eHep=_}Sb-2dRTFuYdvGC?CfWZ82HCqknXhhquf5xw{jg^Ho#*Z*T>q+z zZ;LsxO2wakV^gqCzsrU(-l!X&rWP>Md|;k8JVgn5w8kl4%b+CLnmoi^(MZ{x{StCHsu=@UQL2nn?jH;V*mD`Aw2fO8@;;fbzZ>X zgXOe1@?J1>gIu(0UHRV|N=GR|Wsd`SHjG=N9uXfC5DxLxSpl#PtI%ltbjzPQ<~(Dc zzK1SQv}oBcX?)j z8aMv*QW`gTUdMj@=ONj&Dx!ApIO(yoT9b^VH zO7{*7bW#4YdaPBZSiL*sq5h25GHLa<8X$SMIpa?YEAIIABPj0v^8CpbmFGplXyQ#& zzi@Tn@_XkzrhPs`x(iOx_H(u8>Bw9g{^b0oKxQ(GWZylv;K3i^O6^xteZ80C0FY!& zM1P`l=ogi0dz>2U=q(7}S+|($Mgl^Kkni^BSi6Zzx~vi59UBQrIey&8(~6;1mYz{e zDj~kj)%lO~pS@ed=!kL*lPb9;c~6d$4|`PKD)KH2oerLnK(vMEF-?rRgZk5MQ0cHs zy^o)Io{qP}cbXN%-bUxsyHIu<2>-%9!v|_FIiw$rNYGv$!OWv90!c?NeBs;x1E&($ zCy+7bgZ~#xMyil;A90;Aewcvp`l|JM@W=!ZBOz$j;wl?TYVo{jDohl#Eg&(maaPsskxw`*|4C0z5Xqfx%{og7{9A$RfUJ z*;fdc;z=zx`7l+ll>12U4GRgo4PFSoi^`Yb9@oE9qY4n(qps&JiR|m5q1CUO_&}Qe zUVq?(yCok-hYapTL{CBZmZz zm0uhkcRKN2|J)VDemt=r!bCZgn?$)}8wxNcp_p%_7?4Zer?Y?kLru5GcLBOIg@xJr z_1%#~siy8PiA#J5SnWa~I*z$4%2moWC`xc&EH3tk2(QlzRK{hbQ){fQjif%4@;ntjz(PDvqO=a%K*b9*T z-JZ04N_J!6tRt)ZG2J_4?zca*oAU9$YY0Jk3Ne;xg*x)UVmuRPOY44~o7yCWD^~rp zi2M&8XT_yU&*#m9>6Y?M(iPUW_?c-UiQE2P_j_&el-e*o8}7?ipjHGjyt$7>;fv6~ z^p8HcXy^2k^&$tsfcI`!7ZscyT{gMO-o01eY?w8NL#LLR`pGp`yV+esKyyIZEzo=) zw@rQ?B~6cK(S;&v?q?qC5u-Xa)r!%o^lEP$UD}#hw_jQ1f8R}`BRof(2ie?~ON9De zv`NK>CN6s~H78c;A6Y8Cf;#L@9Qua)@&juc#*64kN}>6l5=A3O7a#T0NzQipe_P{$ z=!G<|(SR}x5&GZX@LL0-N0X?o|BO6W6jP*EVjLAid43~PE`g?{|0G-`MTPlWf1aKp zJk?!U)&hCDIlix`3Y)I9y*~0@cZa9{80iFQ;YFuyz%yE>kWC`uWheL(qb|R$S1VcD zQ2Zo_dLASb_Ge2K5) z1!6&Rab`n^Tge%N4j=`i&r@x5>m!}iOZrSEwUxZ0ri1Y|ogOR;484~r(`VHCs}4&q z@D@YQ{W?x$&m4*mRgKqD?4~Sw^*_$CeDrEd=+mrqxO>$**Pq;{6RXD14zsM{x$=GV z{4!J!2C~=rN?^o=R3-M>=l%B%nH3!?XuS_}}c^C{^S(L?a$SZ^&7k zmsi6M@jWB)A)@tMy@zi`OkR%n4DUDba79}B{r;VQQM&|zKpn~@ubA`iAzEMP2TgV- zi!P$f1|`=alkFjj_aBxoxi+14K@@Z6#AwRT;D3+594TgXL$Yi0=ywNt4w5prXXY|> z{6NrLfa*@tky=n}p-RaaoW3~qZ>Q$N6s0#oHaxN!W{o<(8)cZH?J@=MPJ&xeB_^>p*3Gm(RcCgy#r{}R59~9-hIkF z=SOH=7g4ha>2+x88o3D_i^ik;`f+aM6%cQmY5}q&`R5*we!~=&1GNRh2l?@GWirTl z-=okQH+XHiBcV;TX)$&>87zyaietQYg{d)4Zpo6)ZTQ3x$28lyk9UX1Xk7atiD0{j zQM0(xT-f4FW^4QCoZ8x{x+3JpGy1O5e;2kP(Ah`|~p(CS+Jz zr;eYA;7SV$o`d3`^_F4g(u6d%6B!Bu_aNf{1F1+7%ZNV@umk-##_!s`2+;xYp0_5$ zMHP`oOGH5+%^g&ZC|WJ!ZOfbk4dchav)Un1PCZDVg^vIww|V20$W6T~SxefU zRln3W8xwIZ(tl^pDNToFIToPxwIqNx!DFm1wL&wn~`+J3sEB$p~_l|UX(1hbEkFB z?wndOS7z~T2f&X`MK-mUU~bg4)`0vUtv2x)(T?4GSp>IRR8%Zj$-xBh&WhUi!7UI^ zPJg?wbNIaFAStlW7Ecns!%H@n9o-BPJeODVRGYuk;pdv7ZbILFOC||AQuxhzKsq_fqZLLBI<6axv5M3uOJUA7=eo^Za%9FjBc77v?A!{*=gWKKy>x zgHir$0nO64#@OvV9fBWzvm3i5Be|?Yl)mYmk#6`!>FJ z2yIT5Zy9(H=PCWwPrw>E{dU294`im>!6{nxz{NRV_OBai?3z;pJ`tsu< z{kr;Yjy5(HP$Kny6qi#3^d|hF3UgVQ>j=JJWj{8oBgb#t`Ln8hk0+`$!Qp+2-;{GZ zB_mWzfcGi|aeVi77M5qm%uzMG?r@`rv!4y^K+Du>?lHr;ORTs_G%;C5#c8c}I~XPk-w0TU1VL zx97zK#qeG^rB4o*k`EX2n2X*jq9I+6Oj3&3mHZ*j`=H)~7MV2qSpL(kj0-%^Y;6!^ zP-PGCcnSHZ{9riw{E zQ*>^y3pFF5zL{x1V+^I?AN8&`(d&6Bq^G3y;8TOkz!e(((m!L7mtaL2Csg^`77@L^ zdy);rNY(U~D}Oe}A|axLCvdFJkM!yDLL9s}?xJ$yBoTm7=>tRe3dx4aAC%;8`W(Sx z4BPIPi5bu*f?VHQF8++-;WghpL6sX$&*3^Yxsjwz1sii?PLV)#v6hIr>qv7D8xv2M}o=&WliS+11{tZ zO4YDAN>f1xz|JDj-F-h?%x6LQpZ@wFF{_m`(!Lex_4h_p48t;+%@!v|eMlc(jJI8n zZ~gD-ypGy_i?Vf3yW?Q#*+yp8i)^Xm+XUD%Ql7y5YCAiBsW*4)qWknaU`+}eyL$p| zF)R4|dWlz~OD<@KXQ$w+o_8ISNM^hyS$yrY^oALev!2l3-q2raMQzP?eB>GOSnZCs zC3gLievKMoAQ`Y8Q$@iQh}>2uladI)ciXxe)_=C?QLQI1{`V%L@(Ct_V*ps8Bho+B9A|8Q@3VY=( zuw2HMc)<;nj7JLEodIKd+5=VsU$)E@W>Ai&%K35n`r+>9gLyd|uu&YH`C`{c&eu;v zr4v6def$pTq@AecvU2Jp&GWZ>dGF^lx@1Pc5rXeKMFuD2Z@;@|OaE%rF^w6?ESFD# zJ6O-;l~}yV!a`YZ+|nnZiEv?216$YWjoXn6y&v^+6u&PO8-17tvAl5Qbn0#f4pWw) zeHCEp>7BT{tt`&B==o!{N2HCxhSKQ_6r1w4(1=1=NBG|z+|FIoy*o}99=^^n`RfnQ zWLh1Gpz7aZ1-7vJ_twvbROhFZn%By}6|8Y)KA+h=8`{iF(sDuokA=spCE29-q<>e5 zT&Sj)nf4V76KU*yc1w0Gy&X@xduiL_Js63*>{+Z_lH}i_i1O(w`|?pHW2hD{hpRPH zlMr3QFuruJ(*{1VYg3b4hT-4w?~AAqRJEb}GTUG>7+3ks@M$Ngk46aAW12axwwOio`LnEF;2XBo3THtCkkjxExm6O& zI$a!7kgu+!Si@!Rc~o$3t;d%n)t?GKeR%K-rjlMIxyHw5Tl`Z58};m;zapihM=v~N zmT&WU92&jF=;Pb6TWT87pj^i@;DxPVQqOOk8}uSKcs*i;K=MJ?5sK~snqbCPk0-Eg z#O~!10gf->@ahoN89fV^eWHKCqX;Ixa|e*`0IpxvlG)lZx^LH3)@b-_7-SI%oWz(OtM%P%Z<*aL~z7<>Wwpb4PmTTx`T}v;(H;^>`*1k z1Ye?XSRu>cTC=(0Fp2!6tZ&&Vg*;Y}w8InWY~YsFyz2X}8TGd(`_oQnKlk&K&kgN_ z9boCKzXO-X!D5UqB;oqZ@5Y#tk8 zgML3$!|rWSKSZAPOA#vC^!o@H^FJ|{`=+XN$<{%kJ}8Uh0N#SFHsi)*nipu+6RT4LaARw<%KS4p$6hN zA(ZzI`x@$7p5=6!AN09H*mVMx!UbhSnUgZG-+YS-OeQ_IXVfiUc}dq5{_Wm~Vesg} z(+wF4R!iprE17q91&lFyAJ0$igS_T~dxM(I!)|Cf5jD2!Rnc?!PmHnmTdi#~w$b5v zQzLSSx0oU+BLS}U<;WiaMD;~sDHlF5$`0P;nNO|LlpwH#XAWJx<1l@7f8FD$q<}P} z$0feQ29(T_dnz8H%i_mSoU1m$k(b<>04vt`c7NbIA{dIn#Z0x_IW!|1O zTU+5=O$4t_&(sJm;eroly;>d~LDu#M{7?2x_K=nq^v^D{a~0+LlNreBl&9G5x5td8?*#WTr1rT94tJOm zDNv_HFPL9qs7N@hlBc>W0?KoYAL&pIt%uM@u zO~_*V2r}QFS02)@L$qUYk%uJhM1YtUa$zBm9VM&MNTPH}Ov$wsm+nV=J?h3V7a~rz z$tUFh1dWK0B|`vXb*gALqH|v%z9B;mbpzRkDDUz1PM6DeTBM3`x+6a$(hWpfNq6h1 z_!j&t?rZ!>@}K-^Z}5@!x7#;^GuPbEOMb-4K@VAg3W)2#d40e6_sc7E9`+$(nKglk zjZ-NInzK~v$-@iiHRBK<+5siFa(kA+NxuNy7T_aTd5~#yJ~Si}CyzyU1vU8_;6C%z z?X_yB%wmbxoZkbi?+%E3_!e=Z2J!Le0p&QYXCwW2moGMAKD3zcH&wBVq|v!&Tujyk z%!{fiXTLxDpLLn#+d_wg5&Ex{|MQw_-T2(=$PNqAbU#twru}f#(q9#KN9E8|gwA^& zLTBms@ACPmg%4BRZn&?T>cI0G$B+hC{&a2p?6A&%gyTMdnYd8Q$9r2Mk!P@nv`ArW z3$_S4_CRNj)E|tc|GjVXt7g1Jsd8%m8+3EKXZTUUR_^p21g}mm2SjqGs8r6$QCY?F znpefMzK#`edxcFKyK?B?!g5z^B>{`}o!?Gq`%g6T_%p5rBTahI>tJKFVe!oeLn@C&;!&f zw)>x8dM2N}2Xzhz$(3m~>DKq?QVvbQy37N0*(o_a_@BgU$#7J@&W%(euNUA3m+I-v zvu(AhDY!7VtAaIMCAbgXlsf3|!imDG)As&|q+~>x8qe5SOs(Tm=gME8ImxIN=Oe_t z>b(NM$9UV*aLLMyhd@%;s%mE+IaLmTvd0?8H?QK%GcEW_+|M{ru~91G5N)`CElT13 zso7VZNDBpYm5 zcuLFHb2v^;7mUI_kH$Shq4MgW!AsDBFO9-#YUJvkh|m@Nek#?1j0N>aeF|_dq+78z zl+4!mxn72%v~UAaZ)Xey6M%`vqp*Bqf4Bo&3lovHn;2cmpYB|3iJE|TpIeevO~*}Q zwy$;FwS=AZ_v5dF!uKMo!QNi44~&X2eWI`D6;0}ge_ki6Cvt@Ug+uU8R$Ot)@# z?g+XTq_IVZySGanUueyU=4E2-@^=6&H&D15WZZ*`2m{>5aeVT`8FWl2?$mn#B5AN6 z%&jx++N^s9B6TnIj~Dksw<#7fW)N*CUE_P+ijkJv;{B$7mKJ#OB$n$PIcPmt*8r^Z ztMW9uUfs*odReDj9(3l2jhMYK&dnd;3dNjsr(cQ{ZA-Ll34YbQ-R_58ib|==kI!z6 z|8Crry{-uP?39iF8IF(D=pILAYbVca9ewjNBXRxcQ^&*LJ*FKWFZGv+U{2pZt`LjyKCn=LcZ)JinBFw4GH){O(ED0a3r=UA3qEevP)ULYiONM!3rhWYmjV4=6i`@|IYX#;8 z9!lWc`ur*p3PIB+YRYHrLr%o|f?^Vw2pCxK%2X8cOa}RFs{= zISlekB{k25u4qBX6FOv^4X=+qDv`&HLni>Yqy2>m)E-$IhP&sSXf?K^t5dQ69f78K zvsh3WgT*w!&~T&fr>J`Nm&0ZGK82&yzGxW)KIaS;%ol_2@!ds-zqtA)$1tJ&+krhu zee^pgp|4@RduaHtCfu(5`mVy6V`Eb? zxWit8r_VX4jb6I;ulkCaX*#Ut?)z@r&o&ho_&12Fb(FcDE0l2jU4A-L;o;ZAmiqoj z1#_|*N1Pizk7#GOQ{@k(J9Asgo)4cpB`^$_r+|fY@py8CZt|bRG$42QV`R7aIU}G* zP7c_~^LbytJFfiUaWi7+z>#jQJNt68-21yA9MGsaB_G)H=|8zRZ# zZ)$sWqCO-ot)dk%goU*Sd*}Y#!}5*b{n#VB8}EPaUWrI-*^&7`+#AI}9h~ORQCmLB z9T8)rKT--E%|_y$S;Jus5>77)^9qLn3cSXnC&lUuo<3s)*pK@Vu4E}hJiQ6;X1%2c zc{rkAnL|hx2Fg`?7gbf<&rjRvPA^KqAq;n#_7r6XA?*mj=O$(YC2RwHcIDw3q<6_^ zWxdAtsj%5hH5E1hMNy}_Yn9&YUweJS#-a+Gx{=0*v?^k`vG0zkPZTBrvBczV)?IF5 z5wb(FZ`W6ceYkGc2Q|Xqw|PmUji#lHXxJgIA2%T1g?;I|#jVS>457BUB^D)BA1*Heje%bg3bNdFM-r&~vBCujOHW#DqDwvxSR%uk{{#^HT+|-^#wlhB$}QsgEG}ikw2de(wLNb>l2ff<=g;rqh3|#c&PX+ZJDV{x$b7Hq~RZ zO~N5_4FK{?Du11nPB=KH>ruzMBk6@WZGyolisDM@wV$$l@`|xxXfU+zVk^=X`Sn2FJf6T{-66uNS}Lh{^f3Au8WhU>x&(Q zP}?9%=FWxH@_G74SYpwhk71b0CZ~2OC@k~`pT*o|2R0UxZrjcDZBkZpdOMFJU3m1u8{mRnFAfIS9S)HL0V;@W zUH&_|ikn;EO-JIWcW8VTPI^aT+?N>Fo5~IF+d1=6+8f!vfvf#R>0BTavk@8CSv;L9 zH$H9HyDI40UCKpeZ!r%hc+S39zo*iIXFFOzNNAW>bvm6XKqjeRko@USMpgDt403*$ zRL}!17qZ%p_YD1;FI^obKz@|Ve%vp|GU`uqVEoB`>_^x1n=H`wdFDTk&SXnbZHuBG zL<0n*Xi^9WDxiWuPmoGMDk;A{S7hsr`x^IVMkt)K_gZsuQ9a|V_kAlPr(C`2SI7cB zKC|ikG@}%Orzr2(_jR*q^`E|snAgizfr~q1fG^~8l!d}1ZpyO8eQ zy0mbY!(b?enQrx;{gDhYm`Pk^6?PLJ`yVJ3t4SJJ!_~4f3-yb^P4Ov z>b26ae_G0!Qj(*+d+PUA)(8J`%hS$J`=958-^b;K&`@;H8Ms)Liz?twFfWH;2u^30 zxL`+z@En#YcAc^&Ic*+L|rS{5|_yvsK zr!N2aAv8W^1^ySe*SLBV_zA9;11_BCgEe=AlzSW|AYhe{owkR47$%bTnox~ak0+JA zSGiN_%=IeXt{btaUzd4($fKsi=l7?+Z{FNdHpbOt$y{XxJ4f$781fpdN>B5xPZp-`q! z6!j+|URc8T0hfg2b@TG(`xLElhzU@vTJC_MJAD9~fJkwAuPGgP?MK z;R=STzZgH+4ZrJE;&YtW@jNoT{Hit@EGRpH{b`SBOB`1ae6CRU+{e;}>*J+nnL^ZkB|0YMKEa7ShZAlH+{Qi<*eDQKfXWy1ig^?^)&^EsHI6G4kjK?e7-IX z)*k+|8HwQhQW2zd<8kG0Jjc{8eFPxbeFg3b)ox_1*dsHZh#Fk181ruWR()95NnY+? zS!WH0vjG|?syOYc={CvHk7!R~y+p@%cznt`P&PPN!0D?o1FRROeD@MitVD${@()zi zFzXTEcY^sIUofc!(=A6^Gd?3m4!^j5X)o3DUXJ|tS*&{)h~yhzRdHv*lkDa+=xh0* zs9qFED0bX(uowxq&|?c2=ao76h!goQ5r827?s5xmfVd zrl$q3_vGX}*<$eizQ1A$#B6(BfGBnzY1HKe6IQ>}Gu>DFb;Z6FWc)lwA>UD%?HGI! zz1*iUk0WyzLq0w}18b+1Eko2jPt+g&MX^7)j#z-Nv%3k?X$&^x<67MyqSImvx|EMu zANAG$U8?FXEGNLp?IF`OmN72%77}zu2*VIX{gJkb(C|VLWFOocf_y z?Pl)2dOV78og zAjwhT9{E1=``hF8ge08d>eD=S1Kcc#|N6`BmBMoB zHP0@quMfmyb8<=CpnTX(K|f;V!w20lK>)aUq0*_}y7uwLRMklFT8P>ifycx0lO8ue zXyO%n{~WnmHy1?H%{ET&SfC6KpwLYP`j{ABLkVw?k0%4;(F#7j|5Jr9#iOrPlt|^< zk4*FQrQmV+?7lf*R}h%sWLyY)%87~lp<4`r-XdSMtX+7S7i{Et`;6*E_marr?Njfc zw~SM|BQ7sqki6%xn+nQqfO)i|ytn3o*&6mMY;q4o$!*OVsK@YfS1t0qw{YWS#WQkV z(8L>W;DGIJZX%))mFf-yn{j-o3eg`rvT!-~O9(bG+H<}a#oBFOxq#7L2?wi+qaR?m z$LszwC67(aGqo9$I&gHczNepHbWUcqoAF1GofDcnkdqGsqdYGw7nQ$9#vt+m;u!Kc zb)6N&mg`4~|LCV{(4CDbI({1zS&2>OPG7O-);tBM#u`bM$=OT^Bdk zgqr)x6T54v--FX8f3ZJAvjZZ6edc|Nhiv?2;qH5(^mb54?K|^c$X=u@_`u*A{xYe0 z>By1oKd2A;4S*pg>BVro?HZzuWwwRQNdw35v^m(7Tv4C65a#w~8|vXZC+(w+iSdKK zZ2hq9=kRE)*a=NhWcY9SRZ(LiOSRgTNuWv;YZW|@;|?EUr9D2KNk>nt&4+}wb;yc$}#S$K)pD#vkv z69gu&YZfy6bHxCC2dJZUrOGHocPljk@@JnnS;EYhPB_Cu(ZNpH{BD1T`S2i)ts2uT zN?6+|yw`3GuO7Q;41y&ez~KG;LwG66{hHY=!{r*6cIA_~azE6>rRw?#@I5251F4F4 z*)4-m0V4%ymh;96C&y?zHHmGtAu2{5T(66V-xw9Jb4UdXU8YkGtZ|Fki>%Xj*Vy= zfGbRElX>IRcY@`sRiy}Pi&qIB(?l~FVd$k{FvN>ReWI8Q-BJP;MA)O?;YfG-lGfVB z4B{0JS7_4+liDA7y&iu3iYCrWyo_B^yIzfr5f|BeJOj+v`vGJYwQu-51WNz-jPJmv z>}J@;{pdt9ylph?V5J6do7_)}Q(UR}{mh~we>wcbljMI2;h2&8N{G-*9jC=HbmY+< zjxQEi>uhJZq7$BajqI6`Yn;KfN!%+DNEn_Lo2Q+dnyxbG{OJh9Hlz?4O+5!F=a*Da zK05evlClJuYrK#(uE8vLi8@^1?aNe`oh2kMKYBzg)Yu|POu0_x4OSIMZ*}}L$;Ma&HwwWpgnzA<^E-bKx#=DPlI>cGs!(YvthY1n9nBmptL7?#uz54YI zk+6!;^O4HFtW1vF_E!j%=jInsBcttC$sQ;{HQQ3n_n@4~-xox5JXD74mF@x{NF*pP zKW=9)#C@N4=L4uTY*KSK2d_76wh=betkiZd%y^kRi<`}b_qGA}$1NIyRgwXtyeksY z##qs%KnDVD>|gW8oLqjXibqp8cuzfkT3^5_`v<>?g8NR4uP<}?I5<=?rxlB^Ma&ggX-D$|P-4 zqDPWS9XgBlJIyOV;4I-{ysAx3YHI$Vkv9>j1wCX=9;#h7r1k+8wv?c>8}|0gPC2L_ zxu>PyE`Bli?5^skEMYFY%U zhJFaO8ZGD_4#uK}x%b`4F9)18fTZ4!&^6PY9>^{4#ppo1t?0)5b{F{OtB|fd2XX0y z;PmViTrUF$3cp3-o$U&GPx^C5xwQN_hLgQK3LmkU?G`83b=3At-rStu;1pNGtkQ2n zwmnh}?Dun+#OrmAm_L3x$jp1#9=UR7fNykATg62dP4KjG1?MXLAtmz$HS2Rk*Mv{! zt)L<>MimFXgQ#D8O>FKse(yLFxj`r#iBvhT3Ny(x=kISX(^XsEA`>H$)VC0op-O*v z#LxRr%AkxUBYm8ApE;6qrkmhPqz)!wmCWJ35AIKO?LSB2yRg0R-14EY8)IqA zzB#M5xvKD~UjX-^T08^dtSe?QuDkE7w(s~BCfB`Yg1A!l^-E}f z*_=3-sM)h%fZjNEluZ@jz4Cp;oev?9oe%GI zINmXt?M`2YH!ESWD=C5P;`{f`R zxT zqA9kcjK;8rKQ}WudgDwiLTr+-Re1AOp%oDtri%@Qxma3m6*< z^Ktg}`#s#A=MJS>>z@3$3o}*gm9b1rPA^yO_7jhneVAgA9_w1XKO)MfzE_~Rgx}d| z9(Ur@?;7>?(>>ORNVU;Fe>apa2hw7s6`I$lF@Ds=p3BwGUtZ8b4U2iN^ipxpwM3+D zhmS3>Gva8Ewe52l@Vwac^Xcq=nhUSI-QM{&A>WI;{L^^fI;XgtmJ7?rneXUGi`#@R zg@`b@k8`cF&+Q8R!g0L3t0aDBlFh6(8zX+js1#3q1+D(7M?!cTR(q95;R_7w^O6%r zfDPG$_JGj;Alv|09H|AUb$AxfJ~VF-8hxdWQxRSnMaErw)$n70IF|mi5`{WSHH;oJ zf^;jvcoW`;x(kDUOqNF1#6*AIE*T3bbVqG^P8tm$`%3!^35h(OK?J&Tqm*{ia+5(X zZU-mnU?N57?Ezcv`l@;N?DVpG6VuS-_vEJ0{P&8dABvC?Txcsv z^+^XYd(aOqE<9CFn44owv`_jgITIhKcd%ZB(eIqI>w*<`6Z6f*V;FBL z-{aUus!KBRT&o@~Y>N&^=z!ziV=gn^dE5*bd@r#GMIm#a#pmXAYmdPGoWpmKV_x$q z_3Pa?sLNhnPkRKk+5~g!^QY_X!c&Le7*BzwNDco|GUdtgcI@d~cWwA;B17Q&6{F(W z5Wf_NADp}s9^EbNK8k!DRN7a62aAkZw}*zH^Rzrh;jnw1j1=Wk z%^g+oY1*;I`mRHMRr|n_1i#L|*n8Jv_GX6Z1q=EccelfDcfwy`fMNMjBA4Bz6P~yF zk%t%$7-{y4%jqpUM>({K`UBTTAdDIu0=f9gzH5e7k$XNb!$|7WU2@TvK|0Ip+Zc9* z+cZJEsL;Mtbl&c?$Ha@as}%^`;0Zrj1G_2_Rei1uXT6gXJeF&$KfcYU%n`?bYJq1# zNAz3tlY4ZaMuR4H-h<6sU)=NjddPrnb}W#r zy&azJhoqu?5@0F8TeBsc?oi%a2S)eAejfQlzz?L0`8r?O(x`dP?{iH z#-yVk8#@)b3x7UwUJ%qY;PAm+{DCrY05|+X+#-sx+b=|NlvM7a(f!hO9ss{B+5kn~ zuUMi|EU{b;x_fg;yp@PI8W`8`K_~EL?6If&9xtygcz)P@Za#LTb+lLHrH(?fgYaH) z$G!7#y%Htj`9TUa;4kY8r@{~VsTW&0Sm~+ia716VG~`z~y#~+ePRjyEX1(%Cv}V4i z8Hm%ZUuL;6@O&5S`J?Qmnhal0C;S*^qylbT5B~cb<(;DgS5+X6_giQ7(5_!F{ILxb z1VpZl-QcPlRq0{FrMN~L#B1V%V7eV}dy{k-aA;5)iZN+XLZ z+>JE8$yJXS$kWVBy~6~5`9LoMrH3G5$#beP82sJ+Cy$7UwWcUBOZX8lLwQy`AkF7F z4Nn1D@>g9!1CCA2=bOt8<=lJhkLkVXAS}EgMHs!U2@3)-MW1~{4i{@dTKx6 zXQ!V6jG%I1BPQ88sQeG*)}l9trbknaA|}EchsF!vzhHSP0-|9~j7lfXy3g+k%!&w|aKs-YC>pfD8Ee7Nd+cvDs| zkh5>?CDv|w!j?gY)hDnYII#-EeRsA@EB}QDkv$^BVm$2M&LsK?CZm@26t;C2=GH&+ zJ-chtFW?dt*;0AXvn2(ULNJ@-%^z*%H` z8kpMpX`0(>=WN_k2}$3`$lO3`F=SXDE!DP1&=7GC_OT%%pJN6so)@heH||Zezsxt} zx;`h;EJT-+Ut-bT#f`MLg9oIQ3zgmArPL$RdK{6!>LW!syJ6by3I!v%HvPtg)`a^# zP;Whp7~UOiiZWBW*F-R>jC1qjQkmRc|Dm7eJPPjxG`Y7fG4WIw8;KjK1n%Xt-^tkP z@8~>F~BsUK!`gyfzi5n5f{w--Pv8m7~wunSQ9 z5Ax{toy+hgLr0m0+VRu_JKEG>L|@0|0sJ+6fcSo@)$Jq^Zb=Rf{?W(bRyF(geg8Jk z9tnPscs}0$6d*A^euN6dW9A+njhyUhO9)L;pNEwAc#9PvD13U{&zOqMr)ZHNl{v9% zk0JGPtIi&OXn9FG1PPEDo5ZB*?S!U&rjpmEf;h^otVmCV_kA?{-0w5Kbpw(NmW*5I zMFSlJMM>zv#k;mMoK-l7>ftn^c}(tqyA32SZr9sUAwnLRP7~fiFAG(xQ|{k!Qc$L~&74m2SiN4gWS&t^m=SX#t5 zZU)K^&4X)VcOI6`!O zSJC!49jTLcd**`sxuny%29y|YN`zGIYYU@`e*aZRuYU0(gf{_b4g0%MMGCKyI+-1x zpMCuV;>c5r>GNt17OUG$MtUutf~d2fxRjy*cO;(=cz-xHkO z+jm-2KLt@*yCb2fWy})9rG8uGvFM8HaV>~;dmAYY>^l<6jj@00(-vZ-wSB02AxaAf zAMXVN&)ttXo&1?#F?1&Sj453^$q?7z`|U_yb#!eIhdHSlDvre1S=OLruSVcXC(?SM z@*^rZ>d5R5EN+m_McA@Cam!wD;dYGI9jt$Gva9i{P}R?^ zk%0#%2_Gh-B6elx2etOt%sZ&?0s5vt1~GVPw;!sWF%IQT_$XU--njrJ$qs$Nn}C)v z`+orWp@XTz#t+b*O*|t_h%aFI`!2bLNQ?4)3Q8awN0v<144{2c2Hib~FL+qH6@hz)<$ub3?jnYBBRhm>UZtWjy<7>AuEc;QJFpf*BS zJQ-6>c{G>z)r)0*;B@cZJEeVVM{J$QMG()S49%EdBrl6Xn4nxNf3s5H?tNw}nbx4p zW2NP$k4q+v%X*A7?^gNp(jSA9-9d4@Gm*|eA1HNc44PHixFn=;dYr0OelQ+QP4|*r zq)^<^*gH`2rgf(=L+Lzz7xXoMlipQ;DJ17>=QC7XtK^4Pe@my`?~NyAch%`_e^ZJq zC&#!}SFZ}{vw9)#?K^!xcl3I5+a43jZ@o#UH3A1QZ0=V#tMi!L{6TH54w=|ob|`q> zmn6@s_Uj`&656@Zz3OY8A&z>5#~{nzM@;9YFnhLPNc_yP=*B#-{osyKbp!AyFx=Sc ztLw1??Eel0>*HkNJ@%5M?KQ;2**->}^$zkt*h0wp3&M=y#&lV0=G=XudKE|L0dwew zvVm?<`uBt4F6@cR|X3IC5Yq_AFQabwCvo}Nzt z5*$eGj8#EBSLN;Eh6E5sn$Ok1%sicwbYt#gxDnfZybm{W4bBC4=-m`O zzkuQ@58aJ#klg=)bD!@!Vds09B)mLm;{%A|gT(L`VMZ$4)iKaY{nzb# zbzJrP=vRzt?hVt(jaL+XLifH+zhx0Vy{|WZsloyAP<76KQQQuP1<8L{gnKny5NN&f?+{TfV6jk+;+3b2dWJ_5jg#u|jOlP`pJ$ z{*%(2t0eC(0#Gu!SZc^CY^H-_Seg3SKX25zBGyku7dw=e>+AM$t6DFc*?q43>$?8r z*%yWB9oCHSeGQ|3;EdD(jjO}vBlD-q1Ao4Y=$X9EKJ>NS%qrVtE^-TY&p3#XkUCgj# zy@L70{M8ZJywASMpULEEeD=R|>4#R@we+N>znx^a^(aj?pfB=9Uhf?Jmh|U%${NAC zyRmy_knh7v;*CY={+TyZ{v&V7dGuRSA}Q>?0|;HpYE1D;w{?4A4hQ24qS%m?E7}|8 znae>ig9hp@8o`&)%UR!{tL{sWJ5*`_yRi*>xFz}o(UnCR5 z+iS_lANyRNt(&NcoKdv$=Xn)r+}ZT$`PFumL`g_ulO#zq+9mX@ZnqQ|W)?ZPw!?V!Tk^_bNgKFTEEBP&n^&@#o|~ zX^oH%Xz)ba5eT$fJ~HQ0G$!1O@Ie*9ZIY$~gU0ajB(0d&>_7XxJAeDS(jW^?P*rI1 zG{5toU=NTP1Q_>FwupExHu=02YnT@`EXJGrt7H$~NS0Vz5p_k;a5yMQh*&9!)zq?k zDn;PJ>1B&Iet0&Ijt#1SeuD&`*5tk7dM+xw%&ny#2(}m{~(aH=0*=7 z_7F-(W1yL@s&QiiNMOe;El{&iJN%vb=OANG)n)W&^qi#HUizykZYC{T;OQ0|rBS;b zY8+5lgR&w~MzI*N>yt-}Z(8(K#t*U=LoV0NdncTNNU28eFp#OI9&fgTh}j~?0mnN!>f2IGb*ulY!S-P{oXWM@mdN3-1BaZ z$LVB97nA1esQC(XNaNU(ZVe&v+5P=4P~&kD|M5NnFMnI1jd~nh;$$iB8@8NHMmxJb zsMNhq`ri{SDwrg~yJ(m}Mp^!$C+8PU5jy=mAkB@dE%Zp(|B4^(&@*RD8E|xx%WHRt znWexhe)OJrv+q^LHXPAl+QWXn&COems|Eb*4dMBihd(2*PcU}>0I^L3qQvk2e({vD z+U0Z2P2U!kEXNCzK>dlu_b33#hf}KM*LSh)Ny@nHbgj!aJ&V?B)^g|cD_U5WZEW=W zSwu04$tm5dCA}I+g2BaAxu*+QnWhVSNfY&v>8$|)?DD%g5jrZZK=2y#$Mix(S_80{ zN)>H3%y)YvYCs6=apLdS&SVv=69|vECqYZrzvc1Z+3Gt5s>+_)T++X!%4z1=ytTr6 zKJh+E>+su4^4q0DRy-W+$ay7lJV1fw2M0(xg!{G+{lS;B?s&MAL*zcU#IUv<#3hkEJ>?^&oKFA!*S1ixpAm-3`G`Jbsc|2MzVv9zBoFfQio~1+uL;GWdl$7I!js0| zH-MudkWwdbq*&qx>v;kJ8T#%sAnM;-I)2pcSZ!cS(cVdo^YokV4Tr4X#D3jcO?2V? zMM~9Rxjd%f;gE}-bl9*jpQ`kXj%7pv!MEEl#ha|ahrq`HLR)jU>4!H<%~$73_hgMy zvzE%E1!5MH$u06d$18XlEdG$o6qQej6uU~ax{YH!lb%l_BrO!9UT^vzw<_WE@G%%a z-l9hQgiqq$KCeG){zBDzg&Cg6X6be;eFI61ND%M;>`S0mzk_ZS5Unqxh|T@Wm=pEk zy`vs-DY(;)ru>d({1UY-k1h>+!94uNYuJMS*u8q~Rhcf&`F1)eJwAOu_5ntSp-a8Z zsgPZ%=i0EHU2&sX?s9xjMx<&gG(rO!4TVkHJ|wvh;o|CuUdrK-3@@8r+}qGPtk>-x z3(Xd0ms3VGCAF#deb?o&_2FDu8RGrLk{|D7#&xlaAwr@Z`^Ot*Qqm6+Mz3S=O7d(k z9JDuPVHL>5Ua$JU+X+`!SbF)~uHTyH``_6P0_+ECUS`vbP$a$N+s>mh02N=sCfFO>2@FL*EqL8Lyf)Ae0U;o3_9pY*; z_LabA`Q~jn9{rg72bXoFf9P zxtbCtG^#K`RCPH_Fb~E z#>1=8wYKO ztro)&X>F5?yRh!N9{chAd2M5Wm?W48`=DLP9GlDfj}@kANfPI&u! zKs*hY;hd{4xVv@f?c0mIPlx9im(!a(hYfwkU8Ma%C_a|k%) zxf-J&bWy`VO6Ttd@U1r!ebhf;3p@r$3fUQJTacv9o{{# zPiReH3$CF`7{$Ovr4p+*u?bOLI3x4F^ZG*P$hStE@0`&erGoQC#}P8WYV>|icaL3{ zW@`M{3PQMgJJc`b8EhBgEG`!F1B+W48Xy}S=J>?h;`Qdp1a0_-hh$*&i~%(lJ(wQ+ zjdL(__+s$)3oY(!vzz$<>ki(9jq#5bVMXnYJ5MTW{MlSGuCkTC|72pVgXQjtr1O$d zGP~8mbLMuG@-c3`?+G7g1MN+Il_tDBmV?6>0mnc)i2baIh>XshHK)hwF89y%GdhWNA2>^2i*E- zcRwd!L*Wi;QC->28R(++m9i*{?_x+jgtaq%E>uI9NI{rzUUc)8g7N#rTs-L90;hqK zd>5yIF!_^IC_2{;(oHvj`o1Tb>g93ZQ^3kZ zCBhp#EuvAwtn)*MwoiSeIot9S>iL>iS3#4tIa;5_I=OXJ`3Lj#1o2v`s;mCVEB`cx;`}9UH{CYguPbQ*5|vwexcBz zBTB4gYf5D7jEQ`$8~1Uy($L$z%#(LEUpdmOnPBY{X&Gp^2N7u%ZK*cw9*#cZ#6&e z%T?HSUe$o03~{}Pf29YtNk11LJ+H1%zwnFi5rIF)_r<+}?XsQ-d!|N<-;8elECaN^ zN|&>n-csil@BN~F`>}i39o_SXMsNAPV_t7(M++Ga_zkR~4qXAHA|rbCG4AoR=T6kJ zGo^ZLvEL%Krf)9~E$VOL^eTAO5!FSAU#*%h!nrZx=A^K%=lp@}=Ndg=hs+dqD^lr= z3ct8xL_u&~{0{BxIUZu=jfwE`7{=`&1EeMHeSz2Oa={y^K`ukelig)I?$fKC;%{k8 zlovO*a|`PIqdVv$ST&BYz1zxXzA!ai?-$ zruH>bO4xwM3CT5ET)>bf$E zHB88G9+(EP?;XdXc)FauB12h*DhiSwk9GSxIWB@N&KQ7DFCl9`xC%=B{!3Lp+&UdF z<2saknQ{P_25U})ItOw7 zhx5XU0$1Etci}J#_;F9cVCUoR@FngusAadOnq1KG&yH(uzv4fBdwKsgStnUBTcu@f zg}>MJ^_z*_qzl)7wMG4_31#-LZ7GYsD+Ox68BI}w>TfgeKT(KiLIeM?qc8czRhS&A zDy&4@=55vFoFC2tx;zC*!S^9GUCIgraB*qC-azvO2bbWq>{%Fz*t-=32p7e zoH3bL4Il$aA=e7?DL7&q8gGWa&gGF#GcWmk_PF$+;(r0ot1$E*K5T;B;daDq7a#{b z_sQ`~v=N_nG4wa7oL@;t=u3(waOHoMfsfkQ+~dwS9nu}`pSH6ao~#REU%Ld_-m!PeT<9SKm z-(4`Kj)d2`wl-YR%moF-e@fKr@*!2oiE=l91vdx0!|1VtAudi z!N=CLL28i{|D^5b!JGuy0w^GPZGwJoPkQe6Qh#CB5%7dRr^baq<9u;?o+~cJ>x;1W zQ@&z8&|i%)a(CY|m6M1^69f;aKWsYOm)X4|uHCB!LjJ++jImaNd!F>{N38zP;rDK* z9Pl@vMg~ea?U@+@LvyqDME>!{-@Cw0b|rD~_J8yQcE$H*Pf`M}9|-(g-N!$;I2Pjv6)CH9f)s&-PBbYDBl_&vNK`{sD5n0J0MfWDKJ_Ua|s12vw#nR#{E zDsj!=yxSm6BiQNZd^zm^8I(CKTii6Pw&r^Q|D`e?r~WFdvGafp^BP7UVprq-w*_p> z?uRn3F`kh7=GTIrDW41aCl$>b3{y}D^+!eUhv@3)GteW+Ln?v0Cfli(C*7}%z6`<ECz`4(3 ztwE}0YA8nu>s;I zG-^ff_-%RccuqGVf}^r%f})QhE4hu3keXpPRr}Z#rq#DBF@P>^lWmQG*+W2L+D(3I zq?ha2eQEQ7q~b?7?JZaH&b!9`nl7lMzX5TOLYyRQHE)&%cYIt`(>VPoi{5(v`4>I! zv9%LFUUuPVE#^y9+vD!A9ECZL0(Q^r?^`3Luti}|x(dR8CT~RKh~=a`4ra)x?Dgv* zzw7vqL}(%b<=QsQY4(YkB;Ge7eyKW5M}cdMHk>1XBM86vgQ0fwl{1>)s9Rl^x;fQf z3pNq3;~S9P!$fOUP|xp>+YT7&yHoQx3kO{Tudc=l>{w_o#37C3zFb`}tq!yB~@-#t*s(D18XF;a4PJ;AZ(+0r`F~iRP>` zr8cDEJZKV+8I??m@9)G^&ai(hslj*dHr9vv_{Dhh$n0{YsjrWNRmKRA%x??`3FX!V zjHq*)HO}ed(D!CN-RizpxbL#}!C~Dm=9v~4_IFRdH<=c%Jc=G~G!c{2^Ud)Rw>L%3 z1S0;{Z~H{21nU)87WrP9he)c9Dt_h>eSypYU2e@a2*Y->?VlbSwTW z2S2$T-B3fi9DUPI{Qa&%0k@(?C_5(l6`~D@{H3{VM3BOfn}Q^!)`KbV-fx03ZJSvx{j3U%J$61aTgolU&{sn9E!wIdXAq(s$33L;*$%ffTAJI7kiXceZ z2~0hg{53NZPdL3MwIeBf7Q=cl#xjV*7g3;|SQuU^TOR#YZnn)*WuCq!huzoND=ym3 zlY{(_OL1>cmr}Syd$uxG3Ai;rf1O_xu>TyY(rNuU6bc+Cmxv9j5bld-K0fWadiLR4 zTE8GlwHD|LfrO3=uw$o62H*oKfV&tU38eHqcl>6t-Yr8jR&4d2kBdlDRQgfM*NU9!fB7HRMHqiUZRCFUP5qle{c0p_~WMh_?7>&MCZu)rR6U=iBcE7$qOs;u~20N(i_%jbl<_IX1y zA7f{3x_m?_Oq5$ZFsR&`yOJD{}O`^3t7sJB>LIxiPD20A6U9$pOSqSq_3CwBwy!OpgR zlK~g)eN`^svTfl1JnP#%z-DB8Z6-t^&#{fOc0RvQwXe3i2|O94W%^N2P>n;mn|@}T zv`!kTrtN{~cZw`>hmz6CYd#FguTsuUeqametCwCvl1X&;>}?L(7S1Tv(pTb8u+bP< z?z8Ysd=K!#S=aNl%Z&@qT^1aOE?(LD!yhUBhRhA3%Wc!ER#&ERYz9|}Z)mb}kX+8%YZ z^99zfo1~Yy9@+Hwf&!(P%)x0Ft%W(I%=dNth(ZJQxgfM9m*&kQYrB1peaqtP{XS>q z!z*^}`;0R_8L-gr&78s_gmT9`NI`EQks$MZ<8E^F?Ayr~@Vd*DR~rOB#|6{o@%C4g z+MO(Xv2RJ_CN`WwXyHRbcWH$paS3|Z-l`HKny1zJQ#&R!)(hG_y}L?Zu+MfkqSL>| z4?v;yL2^eP@sxQ5-Udgj$~u>0drtf)E3J_2)faYdw?3;ek_Y>WVFnnGUN36~xPDz`R;r zX_o;AwDsT+z}fz>HJ?f^9hb}Tkx#a4(HOlc>j#zA$RUTPdT=b9iy9A?j*P_2;Bw-C z^>`C{wEMQyrwC8x^~}QYfk`I^nC|wrf~ll0e^o=I`$~`(xAjBHIvwcl^gdW-4;!vQ zPuClKtqU0t^7qYMY3KMl!oxa@w}+aLeoZ~K;a;UM-{C}ZzA1RsereD-!BM%!ouk&t zT7V%<-P|wNoL+b7D~O{jrPF$s*@-<&l^nyLRn!5bIkLMyEU`*zKBlqTP5pU$U2s%O z+e*$aDDP9+MH)z6%Dpay(Dn&g7{Z|;Of^ABb?(}L>`AyN-?!eAK>(;1r_0W#Rb8H+ zmtzJ+1bR;l15Y`m(T_IjRc@12p`jbpfgaI9yUY4(PC3^?`yTEQ3FAoY@UPN47wcqh7)Kok+1V*HjB0PE$+g9%dA&If;Y21w6=-!o1Xc6T@? zZ$yFja6Y3YG3tqT2alwn5g|Qw9^!|FsZA8)JWayaX`n!0kWolZ{sCY3tm=eaDELX= zC@&$LbvRflYVfU&k8N*(r?xSdR6TRx!r_#K5KDY1rd2JU@^8owmve2J&G#dyP(aM` zf_{9x0|;&hy6$+rE&Z=v0|*hp zIj%~Uc8Hk;@OQAtbLD~1Soe`(i;(HY_}Uk00RrYVcfaS|S|HHUG^2jM_4j7&F5Xp13ta1)VszCDU` zBU;lsySo>pa04biMk!rKq+7xQQ`&FBxR=HAC-~qEr3oXQsQ4`z?MIrMIH+unr;-!17y81RCCO z^emB7-t_JD@~cuw7VkKkb5ceQ|9P7&|IqiV(%;30XZDK*9Y^5prlBF_efFY{>OEF2 z@$k--QxXfUt>@Q^u{lf8z3exi^6V+A&im_NQ3eF^msa{rk!~E3s2Ddw(B@acSXn%OxwhA0MS)Vd3y#@q_Xb5OvX6 zzu^MjzBVju1#vt7z@a`YD!i}vNm?OiLmTPJwRo0U)@Z2(apbq$$tM$wpY?uB^PSQ> z{9+;GZ2IX=eS(+Sf^kPpey()#&BK=o#xA_p2Ms3IQ+Y z^^?}0KKlh9feUEngIztWO(@xz*k65IbH-^-Y?wyGE8 zQ(9ewOC|aU8sR4EQN$jdp;_mOk&eD@vvSkTV% zbyw(auxoH#IMb4PyCLYB?GO1|LujJ~kAT*$&->MgGfsiy;B1}CciAV8-@`FYOu~8j zQ_ojqbx)_CxwGl>ZRedo=nZVUj|MK#9EM<6*rV38Q!S~>HG;#0IV$>D%!&SvPa64o zybKWtt06TGvDs}_>l|!i_dSME_bh$@DwK2y+7+z7jlUbrFTg>~R}@TbcZ2;!gVt*9 z2zTji`e%}8mD~R)I+HC$wJnN%5Dg%xo1hd5QY&CjY5_q-%CFCry*u6*`R>gKg>&{^ zYt9=!4G;SkZVHhe$4^Z$wM`mYWChX_^A-Mew7)Ga`WgYCJ(>ZuYaiTZPwo{tJ70CN zQEH0VGbLGNL@5%}gPOa^^3-!#eWQalUQ>UK53iv_KWKSnV{PT~fD-40;~)D@dZu8^ zsA(6Jfh+-fHo$Y7&f!pFdCuU=3Y#ycor3y(io`NYpW8#h>$S+rV7>SU1pN?h<=&l@If0_f>8C3AT@4daac@Ga^JyfFkl*s&MY_u43}knr7J?$s1@Qk z9Gx6%KEix=zW6RPGp}*u!{lLV&gi8;&8fgMKkNGdnZT0A)*W9LL&3H9a!7O$$2LD9 zPT;XuL9K?gBd;4kkngk;JZHva{D&J7QgSBKhpQ&QV{Sf>G$`M%73p2YiR2dE5JCfc zRIns%!xy-J+ol)!{_CSmg1@AM5ekmq~=MP*I zqDS?dSi3!))-NYE+z|daH(Z!+aivcOGouT~y;H|vfjSkrT|klZoOfY(a9J5b7FUUkWlCz$w?DL@c z=Jz`vkL2cqID2FI22DXFw?Z)9uD^Vs%deE3mM+>N;<$J?#@y%9tRUyO74jtTAvv8n(mf^AZ9u*&BTiIS}L=y#V=EESGq z{w6}7c|@KbzsJY(ImtEQf|2(2De@E*9G-RAn@Zw+0Oa%8&Nf8o!Gz-)?7Ua+^=WPo zqcznJqX3|>dXAcEK*_xIqK8#;{`C9(W zdoD?uUpaOgs5BWRE>7M)cvgckr^D1j$y8qt6Lcl$7azp*liJI3N0+Asplptqzbh$$ z-j+`_`4WVWv%I+HY^tcK4ad5v2(l^?!w*!bUXdN9d6Oa8qCSZ4Dh|Ija6*NDRNg!B z8(<#}fjcFl-3)~jKa+4J-pfbvaPrC#KNx+`zUzWBJ2z(82E?=Aqw(<-+DKoeFR=UG z*{eF1k)ftTn$aJw43V1x_lQtC|KSb&sP zbz-GH%evt4C;mZ+gHT7VbTIs$-5#44vte27&2gBVy)s4pMLuz)K9V`!9u)R1c`1qn zcv8pP^-a1r{#_3PCJJ_%fco|ao*5>UApQ(t$^$1lpIj%17{#-vpb>n&MB zG$L^WUOrwwKm8ESHEiN#t_((X)2FP>uCNhwUu;(Hj?|cXJCobRKEJGt&yq!txIGwB z>q~RIs`_rU5ng0-^p$8xj3dRqf@S;vRQO`}bU~RM@~y&Y(FO%ov;1 zw*=h&wo|rz%UL}f{TASktNAXkE{}tmgB5@g1j1CH3pOu~1?;VVW-P9+e@k#+x|5)D z=?IoPn4juHG8POG7$W()$Xxy*2ba7{YrX;wi<<>KE+;K{oTSlfTIiug-#y{uYo3LM zV;2l$bR`FiAOx0LOP7SacPx zW5^_aVIY^6ZjqB*NbSAXLf2Gm4R3GR);KgjZF?PnrmfyfqFDCl4_7ipu%6dzTl88( z{|wLlh~=p%@t5s47%%SFWFLEKsJ9;nKd`_Jvy1i^j`zfaJtJzAVuT;imsma>?pBm} zgm1mU-Q;+ZR!T9!#Tg`PM%>Lfa)$w&Z0f~bWPXj!53@sb<6mEk^E3XsCzDoqJ}ODI z0x?fHT772US&ONkKStFxzo}6^2Y&{_DcrzKl^*dFdH|n<wL3@yoY_D54*tiRpBwx4-)qG#RI_ltybudJ|6ZcX1dK7= z4h|N4d3jPG=3dlE=p-2NZm+;4Tei4ui*aG_GET)?D?Z@|&F!@N`GD!*bU;h~({-^w zIVb4Q=<3NkrZ)c z{r**9ec8z;8-y(tIC2VFo)d4of+(9J$wRQ{EZ`VGnntu~8N2NNg+&IgHvheUX|OZn zC0_W;Lx1?GBPgHN>suq@T1Es^L0f0<$0EMAKbTYY+;7v0jQs0me!k##K+jQq=p|@Q zqnH227k+KXrk+UnLCbxH>FahQ2_BgD$L{^L#KX5kgsrMv+L!M_^;{oMzW@AD;qPTU zJ@_C-L~)t>BjOT`yT-@Y_7YjC^ByrM4c@z*_r77j2cwK;)i0YQPlRbv_oGYSn>=oJ zl*(;=FnM@>>@JRui?Hxm$vv8nRnA2sJk^-{y9Zqk0IM5wB<0P@V&wR-Wv7F%?UX?{ zhDGGUp!HAl!C!t9^lQGvMfP%}2o?h&CN9t4?N9ldr)TgMKBLK4t$++wVIqUzD1VC^ z%jVWm4xA!$CLZsL;Acf}qK=pzrZ|X^y&F_3!z*q#jxw23D4{(3=>{mB*1mVrdJg<~ zsj=MVt_ecw4-|BVF2q%&dg|*w7N_1weXztY7uXP!AHHWd<)FVw^5}=&1=gfXFr@%< z1S}1m_UNf}ZA4q~tKV+#H~OQLZ2Xk{lxWK3z%ME&ZJ73z8JK-1lNW{4s+DwpfPOIi z5+6~Q&<;(=L&oe&crTc@cOucB?mewK@dC6Mj^McYaW9)1kJs^Q{w?6$b35Kj@4yM~ zfqv!wG{P)Pq}`h?>OHEa%r$lE_NI2Aj1awbcQMDkB;1YV1yAnerN54{HaO+$*eG5x z>~%Lh=po3 zL#qM8LbO*2@jy7pM8(7Bvk=0G;{udcOUL1Uibk2AG-MbwGd3wuFZatPx|}TQ6Xxva zTeHE(^%%~#RSfGY_-R}4mux7#VIJP|Dw*7+P0z%rA5R998orIC0yH;fUdPuqGKz%8 zX$AA98Z~e72oi_>P6AwX3;f@b>v@Wg$cJcOY>Et+6t?XvM!cU({+DrZV*lu<4FJ{x zSPXTn;o7CX5FkBQXc4XZ+Zg%G_TCPUzeYY}1r{4^X65BURKIOoFU@x2C4`XI^w?B%t zS_NNOGCMq>Q6P1&ZwwXn*s<_ZECK%B>^rcKD0%1rEFu&!-!LW3H1N?S)44Xxanv<@ zw3f{|y@IG!#}*{e>(#ZPE?c5^@Y<;V4?R$_GS1uLqJG|_3VeuCwh4zI&wu^&TEdIr zm+TX7B0Zgd?^gi_w_>G-KP~Kx=hlZ^hR8MmRZ%{v+XgCyAV7w$GdV|JWl%T)@)!@N zTkrd?@dxCySLec*&at*AufOkOXdaAr4#M#}@Lv(=Jm`IM*EB5i)c&1?nd&`Gzv%t9 z1>j$SQYs>^pY!|&3Jz6V*Bxa2^M#6FLGqXjOFaI3h0`v~ciUjXsL1a6S7JM#@;4L~ zipz0+%)*{eP0$-}NK2^nPMP7Mb3Hdl_^hG((Eg_6%cb|vHKDcET`~I1RXl+D2OQIv zPc!uB2i`|WxvgSnt{!r7GI{tL?a$A_J`6P#VkeU!N15~frZfaU9~DR%pZ{O`IeYh4>0Eni=G`OdK|qSnEJ0P0K(WaoWU#w- zI*lyvr|%U0+AG1O&zIc2e|M1%%7R(SGfUo+`?Wex5~ORk`7xw!2kI?lJxSVEPb8RA zh#Z!D$HVEVXSWoAJkreS6Jsa$iRI(vZ&tst6v7B^+8w^!7{^38?i#dxu8vZtn;0{y4P#|hCqC8z;ds1K6!ir#838D=yK1{ zu8cPP5l02E4Q_UG;<3LW@DZr9rPj&t=DrZCoadg(`#)1#m^)rqKj;Ig*1rW4!1Xre z(v;hf_)1Ie?~B7)dHCLM9})0bFN@|+-A(y-WzNeVUaiB;FfQzRzdY*VP|M&hrmJ^k zHUSDr*7&m@Nztot3!yA(N9Qi1Wg+;rlkO52d-<<77FqHMf{pFY(?99YC_43hGQVGC z;GKy&p+_?*cV2wworD`^8cDXT81lgi0pP_qg3mL*3(R@0g-Jbx?nvnb48{VQB@ll* zOZ;>~I4bOWvY+#^nI0Vqxr_Oj(rG?Jq*uI)vVs7{#o*{a0`Fl`=rR_mOkU;IrPUjk zg6z=t`sGB;dSQCCX+#@j91MGSI15jKra;47t+vO}aDSGbwbN)^yMV-LTCIW9|Dn}gL`{6r9_`D~U!7%EH#8;aYQL}x-9GHg zXHIAZvht1R$JQCbbMh=CfB8NyIn75keR#{rETGHn9u7bGxoPv~`^V`4IU%A5CemkF z-(8qncO1xm?+3sjb?31&aYC~FM6>F(1V!5qc90`W5HP+&EZD!+6F-tKb^Ui?Dbjhi zu^_r^_H*Z(Uze*;nB0EcBpaq>kS^ZA3z(47}^dH9aTx*QUG-X1FhT44$)gH@d z?BuDFX(UJOZG7eY#X;n=LzxOLzOUJ zeNPxMC{7E?xRSt^uAYD)zate1Sf%n5sH&7l`z*Xl0>!@j;Ua9Ee{3S;5G?aIB(^^j zx{!Ht`n-ez?TA5QJj_%1lMdGKAI{-D>-dNLm(vQ@AA5qO>xO}7aJ}V!7yiMDo_hgV zUAyPXc{-=a`~odxliS(F@~NQ?N3-5fSWB4zP1@D?l7aU}|w%jKB}x~<`FQT#|O^6&}9@@Kw3tb#cycNL=+;5BN;D78#5 z&sCrB-FUamF{p!I+=;vNBH=w=B+Q-M`ck8;qA-T|R6rbr zs2Tr&&oRTZ7ln6RO0VTb#+x@b4Sr==)< zxtON8gWY|O+)L7UlS|!vJcH)-_uNm`J8-#!O|=CndTxY9jN~D7$Ugl# za;~vz9%=GD(@qL45SAQ`xJ&=>^F5q7v^Uwg-uYdq!`5D4ny?&2xejPxAMW4d_f>0! z6{9y*j+$vIiCUgMe1}o)Q$%pClk=oD&dcz#oSu z*t!9!>rwaY?o=mOPpC#B!*Bs-;^Y$f%zXmeoWL&#bf6 zMKsqu8J@o>8Yuqze$3RrXPxqoGz%9=e0X=bF`EU^sB0UVzG72qBr!ZGmqPYAPpE5s zdqXQLj<54mEFalChevM~7_7hkVlh@p>Aijh^;I{Nvmi-K^jL0q8U|y3ma~~{V#I;n z2n|$9=OZ-bC82iQfsN`=oz(^kyM^QD8pmB`*RJy1!8zo@4oLiD{SSr@JN%m-SVY~A z9QQ1h$KM-|{h6a4lm5`f4;&EGQ7r2eJQ#Qt546(S$S9*$xrD z%yRcLf|NYrZ=^XNYEZ?~<$6B8F2rB>dZfSoR3-P|nDy*qa=452Z79EVF&MuMgV1I% zi<^f66X|dLTi&w-qJ(_=RrmRxi|nH?(y!H3VVZ$lbN^71Sp5d1&9z9p#-<4A3z!Fm z^+7k>fr%5HD&2OoT>@?b!{Fcl803Y+b5e~?1vl&uhn%>$o+f~8Q8(NJ1Zf^kH&o<< z)HVb69fzGO2AnzwLNtQkeK_fH@pewMpg*E!`YZguXBiya>F-!X@8?)zLD+w~qvD=F zA8Xh<>@!Z-DwoS~?{}gG*Mf1brKQUk&v#hft*_cX6t(4Xy>}$^XKn1-@i;MKPDH z;pa^Gd?)Vby@a*2V4_Qfy9K`M6$Zu3nRe13DtN_uh#5_rn7KDlPQV zP(u=hW~*$?f;}Qqsb-~qinyu&qU!?NR!EGFjglk4&@eMTXzL)V)k z?pa0AfY)@X3p-+c<8q9r?VK!zEbJlL52god!<~6chqG{~ht~4cg#7iRY67{;*?zlD zBiMjfu~f2&dgrD{2Jo5Lk|}+BlIvNO_0NB4uwP1^b#}2XKp|nh=SX*jo&N6i8=m(Y zr(egK`ICK=#7~vuicjePcy?j(v~}j5MvW^G)HD9aedU+G!QUus8dubew5p+_9f-U_lfhL zFY&zk+BwYkjrKssMP6^6!T)#Xk6f^qa4>DQCKqQb(x;1u8W{dNj-DeD(<;wFnxQ4!`I~h@ik=nVtCuwZQD_6JuyiE6aXnqY|zFrR?qSoSq&JKX!el5RjMu zK(P2-epMxl8K3CTD=2vozFR4jweRh+xvJ+bV+Cri$oaMW(Vx&rk}=Cg7bp8jNK|fL=QxOx8NSule?&I|#nZpi=dNte%wSNa zdV*JL@NA9*03UxuGbn^OV?c9SkK0&CD0RM87Ez|k&hDR&eM}gmU84~4!zX_) z9Yy2&79yxWm6*iN04BU6R9Ud8M6SD*u_jHt=N&qFAaf8L+<<{UDWVokk4=*AU5UVM z4=(;QQU^3wAYnRp?86ivYQ+n$?0w~&W#F%1*5a9!p6I|a%{%~P{e*JdUhFHK%7@dn z4vd92CX_fTOv?2BiaXm=O5V*OMc3S5snfRK6w@R(yduo-qp`i{u{GAsJCH=MAfOU&exLN`C&V z<&g7VlfOuW3S&Teo9i&@guz!kP5z_;lMprKPn-w}RjNNMe% z7HHz;TCKk%S0RVckIYgm*aq;c}G(R{lsBQZgDgzgd4l#(#&c#(Hl6GuxUtm1= zHB}Kv!Z6}ppV3_ddPqKz3PZ;Ow9r4td{Lcs-uyLc!AO%~YTPvh`3^-%k3T$omtzo8 zdEJ07OuZ9`&t$DYimPvV=a-~^vhLqfzq9v^>c$a& zZmc~S8mF+MXq|8XyM7k?7M&Z!@5K4Z{nA=SDjI@7tNNWTpu=B>g=_v)qpt2yBteZ` z2W;$XnzE=}JZmqlVLf~X$t*1|CBSj__|PA>IKTvF|AY2#hQGp3x+INt>U_Zje~64z zmf~gPm2YrMu#WV_F^}G|^Lg6&ccinI_=ap*n>wGlKRNBq)Xg-lw(vdikQ9G?5i$1_ zb+`A)7^BP2L5fHg6K%rWn>kdU=x@;eLIh3>VR5xv(J$dq{7RT#OKB z{oM?bRTc=HBMlmS2M}gj%kFQmxZj+Uk(&7IrhNKqqQCLkp8*{!-<}`{Sdf0ZcOE@` z5D)%*PkDiKp16lgyjOGT8TIFAu~<jXXtmfxAe~;3dn09dmN{3oG^UOK4z$JwkHJ z5EO)X{CoQEBRFj8elUdB9W5R%-=$yBeWywF8_{(6yBP{lOo-f z0>xJVdw189qjBB7-9sJ^KfOV#cFbcuwSG_;UqUAyH}dc5ltg~1*nxJ4C&s8(@q9qL zQNZ-D;6G0GX57DYM$lw@eJ0Ii(idxA0xw!U93#I1{C>&h3|1B%-M1vkI~Nm1TKsb^ zKvnJ}0QEe^6xU)vgNHFOTee?-CcQ8fY-{~!A-!`n~h}l+E5f5Q~f)B zLpN@m-EvROq+tw)ltJ#LJZ(NU)+ZQV)ew65-{JAy%#^VRoI4ca@20EmBdUlxpMd!K zzMlV~5R}liNJDqb2y6~|24ZGp{#m%s*dY^qyYJ=G8sTM9nwxdG*Nr|}^Y7{|MWKFz zFSk5N<)*!uI)AYQwVd9cU69|mw!d0mMSm@>scXq^OXru*%KLl~2Slg!S{(i|`vW#C z<~lcvKdeyZiF|?<;j(wxWfCv0^$ESB;{q_^as8T|blfa9L14cd9~EeJ$}O!R$S0wG zFgfE2f11$!NhJv zQoo`xPJTg}8h(+n4k77(;4019sa!L;os#He%tUKRG&J`J6LJ#QE;j$%`A4KmfYyI;5-2l1!`VOtkFf-5U)Ln7J_SMzR zJyS+Yg9A+P8Pra>&;LWnBIdEQF0)s=_mgz4X2AM{%@x``S4-w7eSc65MbPRLxh}gM za@-#OvZK$2`R1pKy9^9*4qe$a*J^OMALY8m=5@Y&5bK=gg|*jxGh*=oqC^!#tEMQe z;U|aJpC&Tedu+=0OfbgZEo%ui?E~1vpw#glB#qzk6HVy1y)ycl)n6IFotxtEH!t3SKX9nGMj9@LXuRr96ak- z+3+s(cZt!ytM>Wp_bxDoVN=Pc6aX4Hi68xW!818Uw(iKSaES!wUBWbeG2s&Y>r`Zg zt^J5^_AuR8tf>zQdjc|*`+fQ0ukqrtZiyu#_%sMew)z`+7kVoiu-;5Fj)70_VLwP= z%a7Dzrp|Ko;Fr)5?0^JNL~wspYlyhV#diLe5Ad(nTfKatuKkKHJv~i#>N8O;qsW(p z{agm_7-?++9fuIaC&M3QTY}l_dnE#!A!5#hLu5XYw-{RsyHx&2>$A8nZU0sj6g{wB zd*$ULJLakovapZwJzSTK3o}ur2<0`d*0MZbczcQQF0{9u@`p2V_7N;8$RBH^f0Uc) zVRdGDlHJtFN<}?5=@`>YH&^#R>B)8-dGIkIu{pv2KFDUc(itu)8lsI0LHxq`yi z^DJol#~)C2{~o;#TY;MW*274I0hS>Av=*d;F8xaz--itw`tfhPG5{x68=u|+?L`J(-6r-wYdg8)=B!!TS;}ZnVQ6l5<{4how(-Pd1szPC=w#vu5tEGLlF)k5}6{ zEg=I7pT#CuX8&BGt}`CV=Q-G0tW;T+?8c3m$m;bJFsSf_M4M6b0^;o!#?5?IBg)nB z*S6wUA|A{lHTD>o#p@56s*W|>2=F3w@R+AE(nx7meg zBAA>mvFElgp4aRx2sBqH9&Ri`ZF#kYdGq(k?dx$kq|=jk zD;+}%P-hi)K(FS5cY18ALM~#Qr0afhUgDoB@`p+s9#|E@LPBX3o!{O@n#n7P0jzT5 zvmu)Z>iqS8mK+)b{s4(E4+=67@?1v#bKw(yU)?8dCBMHd)BJP0(YW3zdl23+rR>!x zGtqW4f;Na{lve&v$1JU|H$Q@|I)GuNm zy^Q0hAuG2SPS|^hzIevbV(CX2O!YZfLrF#J@%at6E)6^TBXmE$xFAjUFdbGfe%RLc zAIb+m6EX?%I&F&W$prm7rK_>m<_nX6nb+LKQI zxrxXtBn=h0GC4KhH?Y8sg%))nnIjOL%; z>cv4_i)i-&Vj%-qRu@v!Ri~c0U1SW#F6)p|JE!s5&o3`6E7oHeGA+IB=Hq|A&#CO{ z^Km}C3kS6I6SZGFSt@;%LhJ{|5QZ-FL#^JJqI@5iTmzxoWAmsNYV-b(f*?!7<^CRV zc?2^RzD4PJ$*sdnq9JBfbn5SNQs=K7lF)m!$Kl>=y9X>uKqd-8CJrZ&+48CS8`;Hs zXDlF)93Kleaoy{vpyH$9V)&khW0|e``*D>Dr$91``dzY2^l=wC0lTqevl>{^h9j4{ zvrdS{xqRNPI2A7Yc!YEDSpkD`k|a}mtxq*;krR>N;5L;dTf;Ht6HF}mXgL?zukitr z7bXI-wDTkI@O}SzgNWeHlf?F-gLA}RuS+#W{C<4L!wQSDq+LW?qLnwacPUP|hrcX) zE#^55>gDmeq@*FQ^;%5G=Yke76mk5}){Phet)lrqg-DKH{J?%XaYfcH+{h|Va(Zzl zP+V8s=H9n5w&f|u1@Ztb#Y?(l1x1XfT}aq;dH*!&sMXUEe!@uTHlc%t2|t7z?A5Hg z>>4L{UsjEPX_Q%d*|#UQgd({Y&jaQ>Tn31RabqQtn{W5eT;mo3xHC7Ksdsu##`AW* zi3m4B3p)J{c?Jgk3>={Icql25MzH36o^X}M72H0Tu{Z-F`M$k#qV^_5S+FyC1BoTi zGWl~gfjV3ZNpqs>Ri-?*1byzzIHU8x$Q*Bv2I(c#%oU4ED?Dcq?tFEBxI1_o{~{(s z@*c1YgS0MS%H;b*-XzA0pbzDR?9VF}LV9k{E9z|)Y8X**fj8AQ{LOnfN5=g~$$A~i z(^rV`J{TS=d&23Lqr*atuf(^vY zdG_sVyQR}|mO9Kz7~hLt@VKhoVc-@V?yY)8j(Zj?s{)7+tqYA@@BCOX7Re&=8`Ft- z3jQv2CM4_bGFQ~ELe12kY(+-Y1*%e7!Xo`VWBO)^vaz45K8edfJ3n#Tea{|R-U&0B zBWirZwW$!`%88{M?Rh(_(YcEDcc*^#1X}uExkrZsQR_qIEXGd-LDt z$JqR1+Bqr~uZh7pM)ft$CCDN&%(SlZ1djwgS$p=ouTK#H`O!Q_0z$RY*g}1te{W2L zY;7O(=q@scatzCIu6NRa8A&Y8hnv~W+4m|LQ;q6p20dmiL9|9G5Yvgb7gxBHPma&ei+TZ-=$CgDc z?9v#3iu&}KG^_5#^ZED!hAzBKs;}zX=G(m7CrW1)!3-bXzLwK{)GuYOjyDGw0 z>Sg6yHt*?+swxU`L@9qeCgd(Ci15e2S+-d-{-uYr9-4pp_;+|ik9JX@K(v-?bpJ>P zpm6Yv`1^U7e)zLdEyn^>v740Ua&9Y|@C2L#{%}D%)a-mKECjrPRJ!~E@kKsx_<&5v zqAo?WT=vuLlTU~;2@iQqt#6^#B=W1ytuq-?*@tZ=Tk zPx5QGW3g4jk7BrEnhx_PeIo5aD%UvNK9z{1p&%dP{P{o(rPRK+VG%&&_%7ry!`~E( z8i(51`9;~{s!4lmw&%ZmH|+e4XUAsU#>?hu93SK#xHK-OAHl?(j@@KPv)R_DG zBgkMN*t8k{ZEnHqS2Wq(?UPco#JE@d0aCva_4ZqHC~s_8o_d zDz0iq`^5+(cia>oc&#oP6U+4*4Hz9L@MJqzex+ zR=BiR4ol@y)0 z4qW+KQmO`P#Zr36LR6qcCCbEx?Cl{I_s54|rSSB4g!Fhnc0KC{lKciY8c zX+rIUZA`luy1cSBhtDItkz`8Am_}r87?mCINdCM7qy3)Y3u)@lWBslk zw)ppOFDf_0*A$7OaK){KAAYdl=b@=}+&it6rz7YkwPK&L3-r4|EFi*@XR*R6w-%IwPN6^I4)~_&Fjg?Cdt#k85MFzpA#Lx>> z6cK*;Mac9%)kwp@UxzABh>A3PGR+vdT#0=b&+V%74Q`#L6W;6bI*cUq<~0Mzl=tUR z*$2GpfQ`Yw=oa1X{Fj|NQbKC?QrrE;sr^$CRqxWw&$Cc|n#FuK+L=r~*N5x#1K{>< zh2rliOoSiCZ?ic>EG?KA5c&$ToB*N41H2Q?D%l51)1Kj_AVxPxyAB$6(;FPaZxQ9 z*NNiVtt5o=mWAM-e35!TuTt7A8YX>%5-Dg-POIwh?>PeRgb-nhDDO9KOVx4>1GG2J zfD=BxmmwKfq~mSvar}+J8JcBYT}bieC3C0eU(7rDSkS6N=n?9st)$C8h*t~HKHnX9 zGjAhvB(UEXnMeWOL4|(^p_Q;W{DDP$qmxwlJWiQ>1r10>OZ=9bMVR3=O zJm(c)gg(jStBx1)jDHJ|b|mv85k@A~<802o2D1tsOv+i93snc$}V> zNj_#YbY;M2e1}=QJSYMgH)pzeolx7i3btjy8vkBf)3ed@CvERbjC#J7>`Mt$07PLB zU|8Zkul-hgGTqbjdMo(*2D92pqO%IR49RE}#uZ0Ga&W!(^s`ooK}flSFZh3dbg_dz zI(`6}SWk$#+&`AP=|NT=9sS03qCo4(iiaN@fclWqeJGOy)#sUIas5FP*V{+wf7EBT#tGN>y*tsLxr zof*q$STlob5n&y!v+TKpb*oNUd%~dzWiyaLnnF*j{=HbupNt=t=;tm}#X;(LSY--( ze=sHf@5u4zKZ;V#<9U-1*kTJ9fUT|la_%F0yv?+%=bKEV03<0=*)*0S(ilkcz2mG` zR7Xv!s>&Yb$WTCG>$nWoSv1=C@5lIWz0J)Vtc4yin>{Ia%|!CgfxH#{Vd2Y#G5`;8D?MsUS0l2UoT4eyO`gwpMpmm zH^OznC&;H>jaT0vhRhz|CYcGRRUr7*9}DE^RdCS`79?Ld#gSCD1_-J ztvo++-7q_G6vIhwnm_D%5_bph?T-EB>9*W}lj+>_2WT`Y{e`#CREOJN{t9z|f`=IM z@CRgHTj5gCZI#fBf4w82mjM{3%+p%J_6YP4z_M&%)IwR^=1zVYQuBjlj=+rW3kk#B z9)H6jtmIW}vZqR~k$Kg-6*-EC7+n>aYbqb)I~SmroN`mXU@RTz zkaU*lzk1Gdbgu*3jPm&{rcW+^_7|gxjMs(g9_{$M=QBX0U4=Vg6vaB)7=O>q}% zikR$0csnlIHZr)1p5d>yw@)Ypi!^cnj;JE_&-JW+a~IX=JO43g%ZSALt`{Y543$BcImVY*p(=!;sRnj*p+Q(_0 z*(=?q5>pF<_?J(+FOpB*Dc6g^klC>OedfzinID&8Cpr8m3MUuUI_*KIi9Ks?^2-WZ z%3Qu){NWhi@#_OgL(pcxwng{jC4VDjAlY;f0suYG4Z#VP zM}}w-%VBPOa^BupX0^F@tD28m7z3QaOO7X3xZhvz zn^-6Uo0Cjj`ELM#e63uj2h?UOY|ezO8GZg~Hlr@J>)*o2G)&k zL{!?@e7v94<0LrOzt0-=Ru}YW6W0uJ`qNN0zLmC4ccGBnK#Sw+Hv7dGyH-;W#kf_fh6a_{dRa(EciApF4bO$lscLRysbi^Aui9eyi8t z<@7ZuA4wZJ;JU1I;>1iQ<$Q6c(a}C1y1mnuBd$=`RKz(%{NUD>0`q)&G$ypV6$0wW zju+PG$hEH<=OfvNjZ$Diuml(T+{*xo@HxNj2&fpyaW(>+1ry#hsP`wxyh6Y5e4u2! z-Opjf^6ZfP#lhPfB^$3Gw0d<2>wZIizdASbfyB@GcD!$Fwz8CM5fwul{>!-(8(cp8 zX0UL+{gH4}22V;;t*3|m#wV66+rAMnnPOhlRNK}xlW&nKuw~$Uz#rM8;C@f#>^0E`VUv$Y_>R`^x0#(Gh&G)4#sRCW z3BBMSZiIuksKRlKXY{}GSJ-fTZv}k^`u}}q4&W}S{+BGfEqHQd_g)kty5Fed`G%re z(R&phV*>d(`|gCe@p}~MY~;lq(OS9hGfz>akshJ9ZJE)XcQxHmN-;?LEgo!^_ThAU zG}M$U(Qyj(0_pudw1j|dZEaJcjm*CR%QE_C!a@t0Mg|=hEJ|TU#>R?=g&B* zjSx$W6HDUJTBO8tOryA02+zvR2grtEGH>>RJVG^vuc6ZzTK+5Ky1T@thv90lZH?RuP?IIj{Y-$W)-4A`H(iN6l(;tL}+RMCd$LlXRGd=Y|`LGq==iARHjxK)>9o#(_ zIj&3PsdYjHg6lpRo||3=*Wc%HivXIpu}XsEUH{_n;}++fxY-%tR+Wj#b;a2YP_cvE zK&i!g8te+9kOHG;{U+!g2IkA{s%ybLPV z*Zn=E4Ig`_ot9QV`$Uf0T5Z=L0PxQS9KW+jlL@WS*sTdVC{4vfT3nXcihy?RJfW0V z`ODrOicAXSp3_3i!q8yB?o+SGicG+GGv0NGSEjcs0`NEVr~F!r<1C*-d`NbzUmgUg z2l(x4@wh!7MIPYvlg2YCYgqZA_=U*+ckz|178b=S=X`qil7S$~V?OYlz~peH>|>l` z8Bah$yYYm3hf?cxLI$ zj8~w0&O4cS1}t~I@mffgmmd$1FnxIrH;eum289*-kgyz>Q`~V~_Z>Gy zf2tq20LsMtvK|0pV{9<*-`_a6dC}qBqT=y7B`8lM$W$qwSJ3v}D?LOwrcP5* z+~*BaexLDq7k$X8=+CCc`#aY`Eo{Vbb#jU2@Nwg3z;PeZcb{4oe~Nf7nE;)`h~`<1 zagfE62=5FX_aAWEjtB9JHY~Z!eMeBOV zA2*2%R9?Z45yCf?7Vtws9E0$GVt=_-{NeNL8R+N4O{=$?HebFUASDUo@vCrX3mx0R zoJ<%TNFusRp$^wZ|6yqFd7y#?>egbcYb>LlYX*V10D`pS5Ae&=2|nfIZdaTARsA_3 zKT$rK3o2!);dX~#m`}LphGe1&Qj9ltuN~_UJ7?uHU+4!P2BB0FBfBw*LcD)nsevjK z>ojYJ%Em8L?0;Oi3rcQt zK;CILWG3D4X!Tm)afEg`yWV>_Hon=|_urA}mdnIp@`wL?i}ChF=eijqp^2^gi0*F6 zjWCL=82f{tF)8n)pD45_`r=p|W)my3ABZo8Nj6jbZqHd*)GU#|uY%&@9|7HV1B$?; z$*42>?#?mqFMqbs+EAfcK)p0eQV4tH55Q)8vRsDWr-Wwp9E*=R5@N%94(1Ku4EDyR z7(`B!hm5qH*}{R!v0Z+xtn6Z^7W&cy-l%ia6P$T-*Dd-SO+Zlg@X7Hh{?a%}Y;<(F}SGcEmZln{#eDPNHczGRb9JZAmT~0 zs*3pA+sl58_M(0xCgId^6&gAb zu9@e`1B#Oh_lPdpMLZ@ub^s#j{_N^rW5uqCZoY2rlw@WQ0ta@kJ{HUe-kv(fZjn3) zve!ny>GOq?KzWkVWalYSwE@S?)HmJ z4*O6!;Fz$-AjUxO@Ib|koBc{`3)iHH$#UFodbUgN8#Ph#Q~$=LOfMHgKYms$CiWeC zGPcwRtJv=C$t4{>Ul-u>P;S=pQ)gtPCYM}&^e`FK=i-`ru0%%u1Cb%7x;uNVw#g$4 z0#e=?kHgKC0r#t^q>6tN@pSC(mCUb>t9`<#yIBg;waCBS;&(fk-;egR^!RrG2b-BC zpX;B8VmiH6MTmt_GC#-p3gU;^geb=R5Wp(V*@Ebu zToJvHmd4QOYgHpM7omKy54Q;UqlN^R%?e-UJzAa7GVs_Qi8y5wPa&G0?Rr|yCo6p~ z?vk15>NG!b@i|iq`PEY4EDBI-=|UD($H&*NH#FgsHb+g+ z1p#SXb?XZ_0Tq|aT42kofockCYQ8ao304ys?Kh|zufK$TERg^CQY_vh_!BBUx55*M zXr_1HIlG%H*1(7FhVns>OuyHjdV|@oSpAae>7NGz2!N5iHCD!CXDOX(aMB)tP>^wF zeAxaiHX)$9Nn(Bnq;GfHOhcIV+n3joTRtkopAmIopp(XuOy#G-oRz3ArM*vou-^uqIEjum@4-9^_tn)mO7w`4oK!SFi7w@4%Qt2Ane z_jPu&oN@kWnw5A(Y2PQn)mxAFdvb2XcYc~cs#NbYHj_XAs3%w*Kb42?hQDNGGnqrX zr^^2zN{F70ww64tg(~IZf_dHMm zBV^s_va`=2d40^{?vh`FOHu-5MtXrV&b!ScN z{S)M86lza*=9Keo0*b~yzFX|4*BY|*AI-6a$$a(m>cOB*GOEC=<$}IWGC6+f+pY3Z zIEXoT3)G&zR+S8YK-~hLDQ92VvCb~<<3-z<*lD0rdlOWL zLK)dZXmY52n&&9;8Iu_EMn1}$bNIebbg>L=0J6h#dr3YdDe%57NqXG+yFBOCoOw86 z$)kDL{oD|6Dd7U!g7l(y>}-^GG+;@D_LV=(&X3<>WSX-P84E}hsKxG|Xg|i#3 z2X`7!Yi4gdiahD&`mq>44D!^P`%Av}23)IU`mIq$bY>!AoDTb)&^h}|-zma7L&D(y zZuFXN-ugTRzjDdO#;Ak(ta<8AR2m5p7Xt=bO%TZtRhA>r0!g|{@g%X!+P3&8PG^)M zmFr1-(fc2|A%3iB`*tCnd%wfkwmTQE2A6@Cf}r~`mUV3LrL!U_o5Vf{om8=Et~(oe z^g-t9K2S=LC|PZlg`0(PDmdc6k`p zFTw5;Fk$vgvQximi%n5}Ke_H@?`I+i^yxBm`Pu6f^av=J(t6XPoYwC@t#mV%2&llTMU_0WJK>05zTC%_>Ebm&RI|Os*}wA-a<2~evq+p=`WOO@t}Bl$V8+7_ZWSrJu$Tio-aG?J z=j8mi0?O}wLW%n%kV+8Au~d!kzzNSm`OmJZ40UCro=!S@ zLDI7kB>*Xh5|OZWI$qv)g%3J!f3kv}nK^E@GEI*^W;GtF^tA0`j(f#(|6PkBCG-3K z`Z^rpu!Q^c1`fsZg$+P+QND_-HOWTPw)Y`j`f0yx^jahfo4;J=_ba;@&2A|~GY5FK zBTx&ScA=~C>hqePlvp`)IA$l0OEetMs7;j|mCe}Q2d~N(&u`~Vf8EcsJWMvE7|&BK z0~a65$tGe0oHVC6J;e~F+y*s`w7nj^zj#fI0iGnerkIt{8KRAEy9BDdH5Qa3>1to2r3#M|Tdre_8lk^Pu^XAs&xU|h10JHc z-g&`y&bs&eCYJ-O>!}fzH}h+KbR?m4^6I>lcd)Wlj6e$UKn}r9nU7RfAM8R;jfjS( zV0C^G^`TJ9GLs6kqW)_A`+eH#6(xjA#;u2t*(}U=-w0(5>Y6OC?E1`G;-Gc+t9?43 zabc|xp5K&KD777_r0grI9HK~rBD|3Q&bl}-q|2%HJtHu?$DFbNxht!Q;;Tx%e7Ngj zjefJ}aqu@xQ}t;fwa@GA;@)S**ZG;vfbW0rC+1s?CFu@+?^X)Lf(y4C{0MCzudJ_Q z3r&qu!ZDV4*LcBb)&zrn>E9{%UpjZb-9$my&PWhoIKETWP=5D<1jZA^d90KmWq#!F zX!kNgYS3UEtsPum%}mxoY~(V0Wd{spndZcb*JGIPF=xquOS}gZR76m1@{U)S3ziGJBdz5fJT4?6XL$-644E!b-Sfk{9HUHIzOZ^bM!Vkv!#UYMOdH* z$)K|{sEb9u>G!thvEs22v6^m)1;%^1&?Tu5BDXZZ5p^WY^bo#n=6wvT74}|x#Pc%* zERAcnAQCA@(UBBXz?9Ka?br9EduF{Bzt5P4k@Mk_#(XE|0CR$Ie?N&K?ho&>dNnMR zSRmD+GcVw!>l95lAL}$HB7C_=U#(jHxet%;4l(&tM)* zRAcT5DNrRnK@09H-cMhHS(p}Q=?#P^fa_jgg|!^F4DXYWX1E;gWUf6t1oP>!KAT(< z`FCYmAtt~PlA~YH^xty}bYrv!Nu9s$IB@WH`GGGa#JbR9% zZ^9khYUf;RILKCDGXB7lekixeN zm=Md(PcK>r$kj?GbZ)BF(yeZ@5#QyR;eSkh5wB6a;MA6X3Qe?zBHZ=Vqq*sb3pSEq z6TmM<`+`Des)k=d`+=hDhds<3wK#J(Ur5)MzwPgbWs28IIAA}n*H2?Z&ip|6drpTr zrfPptV|(uyBY2SwOC3T0O*)NxJTo-ZZh>4$6`LBVT+z~eDn$mPyT`cDuuK_W9`^tR1C)&$oF zGr{FTW&ZE^fsi4Wz$s+~{%yi?{8vr66cX~W^T^Bg zLb%=e+ux2(>}PnP*9T|Wg>u>_;wBI6V!;!{KRYY?vEIT^-Yg)+ROzM5rte`Q>q7-# z_J6nId^uc<`)5R$)Vc{}pZbVKW2Mw_Z4he_+wgYw+X1yMYkc(f&!KSDKi9UhyqfqO z5+gLZfadXsKb>D{!QbUc4nvpf<%=0-E?;A=pib;Gewmeb4BO|A36D@QpIINqiHv%Cy=mQ zD(sGY3Sg?upctM?9}uy>cxo=fF53Z+`nebOx&~QNlDrCiH+Hc6#vn z@E|B|PCxDWtSa5k-j(xKs`Pt!<2<`q`-!_twre7_vI7jSct9HERFTooK-YMeWT#KI zhh}q>YW{ystG&kj&rNnIP2m~X7akt&8h2@J?OSgXlC<1`o24sde8U^KsxIm%i^&1V z@(HBltM}b+dPsflQlVX6$&q0nLH$X4Xpv9pMb$iT9qbeQQ9sUT{B#ftnzMhr|JXAp z^b@&|{S-<#+Gp6`p^*f`Lw!BD-_g2&^u3^c@L<-wERnOyrZc(isbPv9-*}{yA5!Vb zAU^30Jp^KuZdf_$6WH`@c2XH!zDrtu6e&~837Y|^xv zxHelHo=ufS9k=t+VGr&?izG4c;G$ThhQIfCvu@xcN<$oY$QwMfgEP z-F~I|Xj?c(sp;?i)BBxs=D^P`lRU7rGsCF-HG6-HoVuQU`qXJn0c!A7jmGr|wA=$@ zpbq(x&JIr-sl^#S8gcbd)}^2P(afJ&N1@QzsUxph_-c3#e?cJLPGOr*>35QATGhmF zeM}OvkLF3gY)Rbb=i#bM!~XX@A94Z5Tf9yTDm6BBVkgoLz=r_DM~$3b4v|Uf|2Zdu z{*e!t21%yzQL?*83qCdPJDKr2hG0N4H(^(}EAUT2S~G^69eRi===H@r*YX5xF3RPy zS0A$eF?a`{z;7RuI}NdG0Gi`?3T5p5<~*P>vyK*f+@^h3aUB-xypF@Ns)wlHadR;q z+PsP$OE?XQt1x|K#L!BG7###Z93;;Z!hD4yA32BJ0H^xF0Ak>}E@BB!?-yd7Xayw) zFV|m<3=~#mdAAU)yV3qMBRwsw3fBR2X>auJt}tCV7u^`7kOW-krQDDGH7&wG`0b_d zF^1rq>Mrzq#MJtI4#q1FqAt!}rq>_rJqev598J>wyg{NeA^zmZ%i@%|K0F7N@~e&e z?C38LI_)dJ6um4~VlLwDGd3`f;#U?k3_G{ZK#QH~!vrA@1@`A*To$4{om_sd%=dhZ z=~=2*Pki@!6;z%(NvW$9?0AufdfNmX^#O#MKUDU^=($Ju(5mt#xV^}S0+wF-;q?;K z~)-+h>N9RGX2>b$+^s{^IYn|46ZzK%Wv zt{~E}-)(n;`D z$a5UEL$kV%*zp86V2-@CA8QKIU(hTtNH$;isU2Q2;w)}G(+Vhc#uI_jF7MX8bYh0! zv@gk%oUgp~Oaqe;d|qlgFpR=IK;l&jf79{&sQ3k;`U@fraSe14@|>~MqQqOq7;EqE zctRmleuuv-kXVq!3<(Sb_xjZ_Hv@Ep3ItcE`$Znrv*)mj#hz|jjl42D z*l#=xp9Vit#8tZ#$@3x;F2fhUO3pcER?^^`V1S6xTqNu!_lZ^aMECecJaJ0blIciO zOs(tQ@fbc=!|_Gtdr0hhgUcy>kz3u?m^Fa_LV(jQ+6)GhYA^1Klqe1|&+%i$#BFxn z_-i>TyZx7YAm$h`pZgp(*m(FfdRTM}^|3NrL9Tn73!ZPV2lvn2r_-hh%%9oa&<|{MEnE42G z2E^6Q_(4^{n*9z44i3_!ml)<34qYrBK_e>B>GtF_^65DV=Hq@o514Nrg6bI?s30qj z-sl5wrm92+5UXlYM)DHhWoOaS$?4D~%8A4z(h4EVzxtG%Nj7x%>TjXNmbblQ0KjpQF+#V5)) zzCMexdC?@6d%%44%}WHUXc0;hB_X_9nd4YrRd6wxa)Tjrj+mV!`5WM#u7Ni)EI-I3 z@A{VomKN}GO+l5xLMT)jGv6Q{I_5ILRT(88WSJCN->rp2L*$Tk?EMV!fmRKh03tAq z=c8w{$Hg_5d&J?iGkPSzmUces*PKnC3-Ky(NG@&9F68pNzoAJgXz$Ba`nr>UaoHk( zTk=8;v=Yu5-P`Uwj|9vB?`<}TLHJzWacs%J50^vZG)egpc_><$Xx~o~7pl!R=g?+(TZ>(+@kwj7=8d(W_g5i$U*(g80r4OXmj z&#zvBfL(Y0-VYG$o);-40TH7iK9^p0)9!9zHpaxuqQ27eJN~M`5X1Oqu93P&t!9e#RKP9$FjeCaY7ktFO$epgAVDmoB%MXQaq)PYxOTUK> z0mBsHhvT<9AnGSkkgSc)WIOd!{H)EpcgRyn_*^g=&U51S44)r+#OAj5_!S<9m>27#zA?~7_Zg(f1&C2!x^YS8HwCCr*M{u8Ze5Xp4CTuJo~&;#7a zd^Hv2{c!lb9je2&ie%W6I|akxEZct3h|cI|p3iWZ_bt$#&dvwXhTP~S6+Zx}qB!gR zBM@1Zj`y*Qqx2Vr1PAg9w@HS$(|7#+w~veYgFNVP*PP(ST@q*T+vj9lvo=RZ7RhrCZhG z9vwU9Wd)0g+bRvZAO}ck)ww>NN>?8&3tJM8@5;^R2W@v&Y_8=aza58DRKpw=lVj}s z)N5HEVXCLyp$fOjQa3f}UItz;iJ@YP_BGx(Z_c;T)(`DVZK%uBnQXQmVawmQ+GHCB%)AMlED9&0*u>9PoaQsT1p60md%Ywqs@ zw4V5A?#8QrZxHwWL78+G#R878S-&y>SXi5a|mxG@o@z~-lbtNX|3U(j?8 z-D1~I?E5RZQE6MmDp0^H5;Vj92HW=VQ|+jq?K{2_M;yHN05%Dt3oNQdx=}%MzcyWZ zFs_%=FiK>5Cx70}W5yw>sZVJUz)EQL(Cr+1O(GI+oDnsU-Rq{QqE1V>J&%|O?OC#a z>X5fT=+q$HOVx!u?i81F;@_-(c=IiLQpwWJr14>uTo2Q)L=-Q3&S&L)Qr|PXL#9$t z^Ag_j;sULM?)niedLKJ?mMhSt!L1k$vE6|i zLd8nlo%1(q-Ln}8<+L7->hMJT_sAIG?E+k(J9*8HndaNzcbh_IVTR*STRvL{w~BT_ z7(x-Nq>dF7;g@uA~!w@1RK{%(A(#SdYH7x|`v7V1H^HTAQ zg!rKz9JuMy{HhF^!ip+;{n7NVSXV3; z--&(o9QoFV>fUk`*73iuqa1dEKLBDtXxiJ#D{^q&cz~awn5VQ0Jes z+^F`6`_=Ckdw{vjLq5o}9uv%$f8@&iJ7@Npyn4X)p*~-j4}*kg$XBL&&<3tg#su2Y z=tVU3awlh`;ogsnj|2-zE)H!t)!t=hwPXbO9n{ACes}~BPd)=jr}WR+M1t;Ak8f@(es{Fe1R-#FR6)BW} zclKxD;lO53Q`oR0QGIi*T7_^hu2v#SX?KNv8*@difX(ZU(m3I^@kps>qDI1rjTm6| zLau^!nS8nCPCyMdnr_m##`NVkWTi`WX`(cHad-Evf)KSyx@diRk zUd1sH4T;+&GU`+>vSQnYb5kLDKdF#{wUAZ7U&@#I+IfISC6`$_-#!=0DfZ({h$fc_ zi$j9ybO_6>%j){P_ghZAc{8uYg?9QVSrL-Y5lw|AcG@}Du&oKM@m^nlLR?9g%kFDR z)Usmj!9Rsw-o4+ukKTOD8nvaJa^EoWbp}ca>^J&(pP$>7X|tZPhDzljdQ+2z3R+A% zv09V!E>zXwRWF*VQ{d@O#@Ex`Q@rMkXw`lBWt{>XmotGCyXZWJ?MV2G*P8UOXzc7DDqH0zL!I%-Pd7s1acfjXSF-udlO0vcr`< zgkShnb*;lpj|0d?Ouoy@Ow#mc#rH#oZTrh3iVde0{wYh@axD)W5YyWkyu6=clP?%Q z6wy4s^mT4dyqRQkVeC*%66RTI(Lnd~@ZmbPl|^)4H^IR{Rq!C*#?+f z!)S`_C>C1X+W2!fLM^UzC?~`5NjjH-^S|dGX}qa+H!oBgY*ZwmT-oaW=bo`q-b6^b ziu}>PTq76^a7uaP51`PzYo^?_3yVA+_o+%6L2b@sV8{j^_!E>i*|Az`@44~>=C%gTv@9FBWDPF&%j>h{;g4FJyovt5mg^ZuQL@S53DRf_XW7+cAq4~ObR#z!k zDehE?x=Z9P7?jfE+U)qm#0|34>GfW97HkdE4Qm!_5^(`=o-;a=nNS}cXL@Ah6 zdmBi)-^{GbGfA#@c|}VwOG!~BwlHNed57BS2 zzgtDb37h~rdJ_sWoouX7SkXQy!(KzIs*)6Wq~B}|ot&BLKi_3P&;*UoVD|TW zBqL;UXy=Qq4#w>**wSg&=E+{>7|1H$?S!?MZwC_BOSA7G6^QzbciiW-?kyt+xNHp1BqdjuGWC|6d8+Zlus!6S zY@DAjRu)Q^xpR1Tjk$rpOe&b=7wj>R1K52dZy$b!(fE+!hJI}1;qzloAefFbL3%>; z>iXAz`^9A|#>#ez#P(h(w!7{gA{$`kH4$+2%=;|rI>LT6D-K=95Jw1&>a`NT}fNbCkzQ3>R#va*$|Kzfq^|Q(8VO~#G5Wo6T z6QjnDaIL<6egVPm)D}Y)kjNfDhaanV%{=EK^#WFNnc%aMRk|0$A6hF}bbO0E#P(x$ zy<@3x%idP?E)R={X?kmd0`Ah4RVFYFaN|FXGh)l}s*vsG+mM96j9$jMx_VSUVNYnr z^-*4G)_EtNK9@iA^Ch5#zy-w(nte<_K&3RpDcN_smcNF%+wO#FUlIgbpMn|dfw5ucHBWVWKY8`~%Px2#s?HP6SM&C*5aYR28|r!2 zVXOg(FNc@Y+9S399Lt1m778z;_y_jO!IPf-Np!at4;n0a#wH3-;UXfifr+rjL3{e` z#LpESfJ-Z1%y$&2ep6rI1aS125CRez`JO5P+D3<{!F86^5Fq9!b zGox3RUXjM10oUG6L7iYqCu{8A(8^pbGcauJb~pVRBIz^bKM@OJGqS%KOAG9m=^;lj z>{sH{*Oml)KXup<$e<#NXrVLaJg?_f;{|bj@4qJ3qc@EswXt^wCSmq$d|6eIf+34b zGzQLxaIs8U*q;*67EyNgj`dx*q#LkRZEj5#oZz*M*w39`$mCYE-|lsr^v`Llo;y9e z>&rntUDuCjD$QZR4C4!^t1I6%(EE>-=3j!7-db<%7gX7`qSvu-Q2Z6U;RL3SK<%HW zchZ7`MY&&2`cUz*X20tBq;Q@tk3I_W8W$X0>`&U*Okad3CvEnCfi3&)bUtJEak9_8 zdQBbA-IqE(x~DPSOwxRm0UYA@``yx)TmFF>%|7-)pL?79;Qga|+D8p#vRafjoA84S z-Q+Iw)zeX}rd=us6m+#aMHsay+=!r08aGIYw?AQp^QsUjO|Gw{0czl!ukZKA?{1mO zXkiRjhHH)cjXsEuICrTYVmd7v~!H@IFR?awFqgci)Y-(sR~xTuF>Gvh7z?I?=1uhpa3e9MB-;;K)*pp`?l-P7imuiW3fB3VF@)9O0CG_Chm?|kGm}# z+<434ld_Yj3lJkKqD2>F1NLARzL*R^wsDzuPoG&D2hQNB(d_l?2e&v!o*dC@q9A!!@v4bWAKAIKZq`T- zse(LYDhwh~eIIvQA96vabJj7qC(Zj5 z3xwl6i)pw~2U~b85bL>Qe{|z>6>HWzt9xu;cMRm0#Oc?(@9FztC&;+0P0ERv_YC}{ zv_D({Nl;HYbea}oeeDHc$dj>V&(HJ=@(-J}U!vf7XTC_UO8m0X{za>5?|Y17_`#kb z3m*uGd~RDw+F=!k4JSvMH`S#P>b#=^xz7k#6evE2rA`x1k~jm3p8H3}d$0$Oj)zOm zmErqh46MDNg*cc`Vc!x`ff>yg3*mRhoZ5DG60Ga%8KqKR>ngb=%UqnnnLa&a!B0+R zqo=`Z%t3@5$JU)c49?9@OeLeD*kU=oy<$J*nN}lQjXgRO()>kAtrD!OABRE?yOw{| zn$UDqW?v1q!#!8Cz_7F%8O^GRi{6VTJBB|H>7Mk_E;D;7P0R1^tC`y(HC2>RA)JWs ziJ<#~RzEr6_DJ%yu(<5FD3LaB{23csBl=W=I`df_z3knPggi*zqI6Z_%O1|+5=@zA z#YK5i?7Js&6cdv5h)PZXr785Wj76Y8cDuH9_rjC9)(&qGBA%KPeTa$OLn>!?-Jk2k z_P@#NB+L?T45K@x&OYdi))=89qde=GZ^h|ps)D1|=r~-J!p$*0fJOu1Ymv3jPd`FL zt=wIIh}?-zYUxLo*>f*$$5hsJ^S&xi$>oKxzPglq^V0IEb)LwS-ML@iv46c-hDOqz zGY5vXZMe|m>Rf=F6cDEZAQwhO}5Q~KiNVnGpeo|*b- zUEy0c84%0EGjM3vgwwRg0e+TGgt5qoE65{m8uz2MEJPB@LmJt=`* zcFYrg?GeHY~-IVOvy;`Zy!W~M2TNy-;9g(pP-mPp23B6 z=A9NwfgCrWh;~lz+vGi$t!P%XtA!A6EaP(wANd)=IG9DqMAc<;kE20oL4d|Q=1Ph}DGVEf z8XzNUb-UM(y;||j=UfA2c+(cyBv)4Zh`N=l0e}cbL!!)PT#^0T=1UOM_rth8+9$4m zJwDa1Spn~J&kb`jg9rNW&bX;$Ti_nLd+tWb)!G(A}GV6bAUi}P+BR@@z*WQh@fj>ifz6hXIZsKwgP&_>6~wWrzr;5M zhklUhsJJ@^x5N&TM_>_TUk)3{o0dK5@x;aA?Z&(O^RU(Eot&~~u$FM4ou=;i*$C<| zzs}1E9-;K?!S6eB5G-Z0iyoseM;oS`q3|YY5(CTKQAhW8{lKk(jkY9I+`qNZ5_h%g zjWK0hmN2Fw>Vr3rhkb2xt~s{wE~TaJPoOaYo$YDM;YsNG=X%Zmi3dAwWf&lOEd8!L zBcs4xfBImAmLE2NwVfGPv3sZz-P(Oac&|mU?@p#i>kChXB`DQQfp#4rz7GwLg>82y zWn2YC61(dYlGSaPjsmSY>@gO1w@UWg+uUIO6l%GKtc|Lv_OD=i^^?xzEEG9sSm?+L zU5ya=djzI|4n?S}BLfM6S3|00s+4!2=#<9Dch6Jz4C{x!zbRLGRjP};UevP?{&vN0 zHU!&67i1uA48IV|P269Jm)~sHh~6`5aR#C&8mIky$IZ+-zsy|*s5{`6dV3`c8=fC{ z+zQM!?|TjhPDH7I$eSjUl9l`nL%Hy7-c57(rmysUM+5ZZ@ud#8os2;F6-dl?o;I}% zL5f$iILq6-jn6VWE|?KXM3*(&gyi3PXnb%7Q?|(nh;81}uTRY`(H_~2+*{=N8nL_l zi*Qyjq>U#~Fa0jdH&9Vn(;qLlSA9_#l&DUy50=O(J^WFz&ScjTnRJCUPA4z6;wd-t zTFBCP;Da9+A=tg1DcvOK^?|5})3Es313a@OWb3G;oE0bdwY*2dL|JCc;{doSK4?3) z^8C(2!Nftfr^qirncC>S*&~=Pd!WnKs6z07206#&RzdYv$^!w(Hy`H&vm6Tq7d+(m z4ph*b;YsOic_gLRp(P*Wz3J0WaDlqK^%wm8AGXtwb=;+6FMaOc%ZGORGStvVmp9Y7 zXy0aIf6D7zp0j6;Wb)`I=j{~Cu@91X`njpbIoeydu&8I8GiORjn-P@yP zka4+Xq@4FRdcKN*wJ+CTGD%KdT2NN2v+6!x;1E_4mZ&%5`~(+*+)*3j5+>Wz;zjm< zHY*HacRk;1`9!~3PXFE@7x1d>aGz+I)Iu&;cp8pFfkd)jyKpPn;(CzAXWj1BR}Pn){OrbSM`>^VFeax$$BG)!f<)Im-f9c? z8Ni8iLdZV54a&LrGVs2Il#&lef~}?VgWGpK|7cYjU2lvTnjbqXw$wJZYwWJa@;h8F zN$1~Z6C&l`nRx`NcObvV8~^pFQN(%uwN1f47yFF0(5n#L!J=T!Kwgewc8fajwj!p- zoypDgRyoffQvtHO&oEoRtmP%-P;3jAAFDkmvrF;2WN@a7qppw#*Pw%u9vAFj`pEPY)8)`3ba)A1 zbY61r30EXU!;D!zwr`Jv5j8EO#P}{F4Ng+J0o&=^o79X(tSkW5qZsbrwuvs{XkdSr{+$-(+9|2#oKXU zi3ksgu$s};#wODBoA5P9O;)x;tw9ZlF@rC_;-1j%) z2>r&;v-r(JZk!hmEGB7`QC#*`(j~NB-M;B+8ogaF^eTce`4V)HG$3(0**Xp^q^A<6 z6%%|fZu*Flu^6Ldk^2I?%bbyyUq!-UPfmy3QQYZGA~dt>_D73-SUX;Y{yAew5&aSf zOv@>&^t6GG$q?I@RP)67a`5h}f=DS}pOLTq#vOSw z74}{$V$OFntYzlUZYC1X#6#cl_5bA#L%!g^mQ-ofv~ffnx~JpeCzD8AAJ z*;xo>iGRlZCt5LzGMLx!ig!S(Ft4DX;c;HRdqDY4CHBzEgX5^JPW?m=aS(gl47#Be z`PzQQ!;W&qf<>6gxNrT?=cHMCd?Bbxk(x{ zZ2{ptzN#xJJK`+u4rwai;E-X}YfwIp{`n|FM`E7Z8iTf_Qhw%@mO$E6m!XNed2mp~2 zFfiWAWLBl1fXmk!R-hgBpY@~OnFvTUtma+5yX?7yW^{f|Cj=_euau2WDhYtxexR_g zQ{gv=@XiFbn@=CRT@=ES}YG;rJ)0%kB(5@bLk7qVA!c@L@V*%S9-iu~q; zx0Yw0-=F3RCmrI;pNJ0s$IMc3Vmp_QoW*Pvzz%8g2Yyphh8r$F*Yzzrg7W6}rGK~d z&{8TtAJ<}`ey?%x%iT&|F6}p1FWjM5Wk}{V=Yy*<&W<;iB5n`vm*u!%ocm)T*7v4X zwja3QrAMPselfK7Zxm1W!@1@%xZkiQN1m+Ct{2TCZ&@HUa0Z6_R0~*nBnQOEBLXO& zAKJL?LNIGV=>VO3z48%W2UeRXqc-XOiMkz zXQOqmd3X|4;c3awXu7G1+sg26jEH^(Z}wR--k4?l*P<%b&BZH?_d6Y7GGJT|O$*=cclbu)9Z%kh4Pj&6#+~wCdeUx0fZlRN}^7BcZ zkr}#Z;hpg26js|ry>Adl`1Ko)O*0gd1KWeHxSf1w*G{&q=3vg{lwF-^v2*lA4i^X6 zi0b#e?SI=5FiWfg^o`X@jwVggzTg8yUa%uPH*ZytEA1={+7a_`U=E@FW5_oR=&_W2 zCP(b?`+BYn(lt*8-%13gCii@nsrSZLVPk4v^8I#=K9ijlp!R3|yW4q^5$aMBw4rUsH$4^J2~ zA8w6I7PJJW_nSy$eCvzz`L?*p@0arPos-L`mn61W8|{Qhe+Q?sbRAUXFqfCk*ZDNO zjsVr&(!lR?^JJe7j>wQdN_#VH@jl*SzzoO|D?*5$V8s>3-o|02``Gn5&%U(t-S%-@BRYE~F}8b=(!?x!HXMU$^yD;ny7>`EDl<)H%;D zV@GEYm(M<*MvdeSIkm*3JQ{FC#?VWCyPH>=#A8a9-S5LQT=W`T!_pxI4-1A=zo^t9 zLVjxC1U77q$(HB?D7^9F_ir;n_EUVkL9O^q6zLsrNUB7p`I3^N>wGdLxryuCC=o#{ ztnh61*<5#}ts#Bc3GK29ECw3_gK5rN7_yH&Sr{@c3(w|AA3;PxjepLuP|}+h11^51 z?n#7+C>7~qWip`F5t2p5k0GVWhjvC3+1b}bz|u1ofo!9Z(j`DGU)NE5qu_Ld&vM*5 zM``j?jUTncQ;e5eJ)}v50Ik^=fiK@(l;{CXFE8yR-R^f|Pw-nPesF28h(@`DM34Wk zik!W8bAG0NIRnJ0$3K00G7*V!T&O6!4I_1}%{E>E7@=gl8x4#YMo<8LMu*h9U{Lmr zdhnRYW(YDEab(bik zd#+OPKIBTM@1b%~XY5&4Z<(7QM6jIcKH!)Wckqj&C`YifiR_3FHNldXU+u5=be3N|UO`_UDv>)F1rB~xzM_9H~yRIjq}F#%lg#&f-=$?9le zya(4VazGT52ixgF1^3~498;JPS^ACJ>h6-%+Ph~PN5nu-Hu+5Kjth68o9{lE!uXte z1U{utJ8*y|f2Y#-^-Qho_9!0A@l%6ClOC`@GJBQI;7m#Lr zl`&?FM<{QR#38+GU&=7aRu68jDR;^6V~_Jko;LEil<|qnPRp&aVs#l`7f$tg(42Z@ zKLQ_r_y8(fY@Fl&^D9t0?;D)V-W9%0FTzCSXb_oP^N>hn@I|&FqKfWBQC>P}#Td$Z z81Pxd``5)v<{-UL$W+snvRW<%cn}4=#OfQ_)>5Lgz5B#T5F!oM;uO6U-4M(t6gh3{ z1U`7|)W+HF=RFHE`q|dXd&+#z(mzgV$66T6B*V+EkFyn!r;$84d=7)cP8qQ&bxUZA zavf7JB!Lk*4t}@fWap)-itCmXr)h^&oS|P$0toU0$|cep_{JO3`Xl7E3e3vg_@uya zUJMBaz;8dh-1sgM2CqQsK^-ob{|zo)umW<*z!KBu*z(sp&Rn}$o8{8-(Dar-5c0}e zc)jKgt#UD&8}tPbhsN!UX6tQyX^HiXdKQ2DVYhBP9>~Xf##K1=?|X{rH0YX+CnqET zsntsY=7RtHZnB?Vtje>|02I{iFjvymRqZ(sH57FqAyX1|0K=KVTTB_o|GbCVnmzQOT|(+ei&jUPPeM*LHwq=yY3d z-yOgJAM$rgJ5IEJ*K|%RW4s!fHQkYvKe8i-y5o zAE{)*2_j1y+Cvh+D|vJ11ijZ?2xt$`8EZZ8QiP0TOG6YS985}0S|9v7=j~$$fCk%z z@@*Uk`jOAct?VbLSN06ub!R900wO)hgnN;;t=rM$6vyg*a@*~>XnTh%6n@-o?3d?y zo5tRH)`2B;>PHZYnu;)1!0*8OkjLU<@2DFC*#Gne#oQ2?xoiOh8kqiLP~aW0)nV^` zUUS|3TO~{wgEQ@FO{il=%>572(M)MEtT*2EwQ6iyZu*ENAIf^m6aX$>O*){ zY%@Ch2~l3OzqgZ8@8-R?P8b}i)HlH2-S2(8?3R%I4eBe&fs*SS%E8nbBV8I=}nRgUO3a)a8Cam7hu=8D(V?X)f*|4Bub$p_}Mq&IofKS!iVfF$_tB~eD`K@H{O>l_Sm z!2!+`-3JhzrUuvQn(Z4TU5ZFNS_3KLcpo3t4ncm=sUrAfE=9czkIPYob^+#s$8v+< z4pUR}DH>j(Wb(r`S3wUr>wY>6J7w_QxiuW+`#DbHF5{DBL?H`KRV&O6iUt>f4sEfU zJPer8#h2whHXWT)*}uzf%&`MN_uC!f4ykV+tnxnXIK#sGC5nq?f(wGhzl-}q+DsiZ zgJd5O%2OmF{l9A*M=yo8@VGGak2ao3hz;PHwb|jyz7C%mliSNA6G9b>0Pj{51oZj- z=iHv1(<4uWPR)W8;Qk+SWGHe6SpR2utAT&^Q7e=BVa=kU)BRdkax082A z>MZqT!;C%h8=U|nDD%mlrWDn;4B1QlaoWd%pz{aJLA0`9Hg!uhr8>0p?Zc-?% zXf*1WG|Uuu95{mOydku5m#e*Rw(sxb^7H zy#Zo-NjC9P={k_XT2($zg<;Y6bg+L6dJo{@(@m81a+coCWcoNcMe*>TzoCsZUbgzo z@iCGUQ=g402c4!z-Yp>dCuVZEnO1klXb`(>onj<;FtY5a8gcl>e`?xWWL1EmRqg4P z;(q8DKGywH?1pL&(f~h6ABgE`hPqQ6 z2X9?$Z_#{=h^c-gTEd}KGkcIm;cBy#24#x{o;4%h|Pm=X#?{?MIcTizUH9a0%a-y*1 z@$(E@vvWgK$CQ4!qjKr|=AoKP=L8r;7+B`ud9|~a+ueIFwfkH1W+Z;E=s})8qL93q zx5t`q-0Ymbh_oF2SwjR%=I(`Ni3lRgmN z)bAs1-DgyB$Un2rhtfv%s+2gbxJ?*wZ-GhIN130tr%!)nDL`BadzLMKjkcuDxNP5g z`X5_7@^Kt~ZEK~Ak|d!Tm+`MuV)%W2Vj)V~Cgc2um(-Z1dEx&LP50c^FdZEnHVb(jvO^MYQGmuV^~S z328QHU2Vh4(Gxx6Vp?PAwjYKGZg%l=%ItKf(o3>Gh#W&`qK#(U9T>jZh3Y_w8g z*?0RgH6xlmKg`)OKX4 zymI>der~rr8`EPOUt$J+$o0p8D=OA+I9DAz^Kqw*zU*-_+#U;jVCDE`$5+rT+CGcaf zQ(lqY*+aNvH=gDSZk~0}8{<+F$Z|?J4F=oN@7tHxWe}{m@KZwZ)D!bc`3&D!Q6H+j z3o-j^5E76>up&9{XvI&ZL(V`_V@t0rsol zh>qnAi+IZB4rtGPo&o0m;mZBTxlSm^-Bmr7Dv@i|H2C!QszV?#dDcwC9q%sSJYVmG zle*Js3(-|q>!9rHPonM9{-fyr1psLONg1CCS7g|54cWFVy=Lhv>T-Ssx%=3Ox{|FJ zgJH=IMfd_STWx7q>Vflf=_X%MV?zPipN(EbK(k6Qc==;E=xumLtn&M^jkU_L?Tmd+ zqZL~xyAx(JM&kw?+lB`r^F}N5wax#$#-P_C+UKSvyZshz>9t+}X|>D~CXe2V5z zs-I{sUEFF8>2``jBZ6UZpIxgbp_RRT+{#c^pWfYj%uEA|BdB!0S*MHZMOl2}Y-W%B zP6GHrJ04uF{uMxQ<%dlSJ!{2C;$vPd1I}cF=D^9&#P?<&J$Qkgr7E1`T*w3)A2mIG z-M8;{BoFB{pXlTJ`)H{I)Gf_FF)^+^(A*yNlh-t0x`JqpvwRB4Kbd*|i=*94kx##_|tQ0M-AXy&pikF9X_ z?{b%&<(tzT3&_TSRG`Q$v8*+654TzVm~wwRKl_^Et($F*Crs65l2k1&^`C>G*@v4j zg2^~qBycVU)ipn8g+yor4v&M!W5FmYxhI2^ouvj~v4k7Sbx2M;1 z>d_kEmTaKT6%&+w8iB=X?{_gjNEnIiYfnqEB(0q7EWE7g1)$)QF0wy$)ygTZR)3z_ z;vjhk?U7@jPD_s@*VR(Vq6=pnx-;D8Mg_W{y5cek+bm^0t_Rtsp68u?z)u~IZ;A{L zQj(~iG^TuU3uVf0Lrk#|m8d?R`a$}*t zaPf*06u#P+!)N;;u-37uG@*Ol%Ac6o_h`0WxcLzAcdY!aK^5BMviR9gj>&(f)Arj> z0>=!?x9QKPOI7ek|F<2ALO**Is#6E{65bsCjvPU5HZs+l84-V99VK2~DF)O{mLC!g z?7_ABKuh-NVHyZ#dLI|vy@2o8E1wG?9LZ3YuDc?&-k1B8eFJT>5p^8OObYh_9f)v$!eqpOwYllwU`q?#s!5=60dBa z?2fd3GD$ib?QZVQGP8r6>lGNPA^%&&u80@jOKW>945~MrbNb5r>*<4(^k~haK^!?xqw$7|9;Ptn0CS@c{M4f)XmLuF?pY=?>5&)sX>KFT;?x{qsa@zdo z<=8y*jT*N{V}eaoViiA?mcm&#$hVtBI12?blW2R<5TmPc7Fvue6 zdU_4tMWWjl1lRbU;-d@p+rxhaN~JVl2$#-u*m7*1+PD4fc{~JWX_*1QGs^~x03i5W zveawn>#brp%UA3jpAy681G#76A7alm=|3|4c!S!;}% zDCs0FDPE}AsE|>2mke@Rs8F%}569L?6r*(&hyYPA!=nXwf%y0#8q7B^9urJ4$>y_8 z$eIb==ISoMK4g8u>JL>|<`czThlvvt?$(QH8Z;C7Kiz4EB;oVa2%|^pad?1ZP;#@S z+_k^LyGi5ma_rAa;59h}Pw7YCU0E`P2giq{_mVu+<;_DX$7$pDY>jjjd9Lj*nnMD0 zxznb2M<@}(!HFqv_5t(hymCZzkm~s(d=xcpx`u{QeKXQX=zNbBNj4J~Ks-I4&v(s| zosgLGM_;fzG0RKl$@ZhAmK+Fh+`8AqM&t{sfpM1 zbUP>QF$f-B@fss6iM!45EF@CPUBefx{5%P*1UAz2xf|ZW8js5FjXsOz8T?60g3W}E z<7^o|7W2wAEr+SH+nMYntN6YlVyhpKAp_BPZKT1j2UP;h;|}c&xARR^FHj6=wepmK z^EtZ@m%Hpp+0ZuZ$I{24EuE1Ct~;*~3f`Z!uLEK$#^|>_$Z-?rtF=m?l9s>!$4!{y zMCJ8%+|_sDR7|%(_^qcv__o`iq-Cqevi!aiH{dGl14Gl)`Wp^%{fz%EX` zgOURA>x?G;{3O+iJ=}6GjHLqrt|MKayB*@Cv)AQ7ofj5zja6}4UAN_t(pw=t~ zl}~?9&}*mV>I7G11`^n@9Pjri4HM~u-3_0%J8=F_d|psJQ;pk$YQ&+DThL#&q*b++ zqR)<P9%Yt(EwpjbMw2zbjqwIk>NwYFF80;_%(Oc%X(!XieTuc-NS=hsvsLB@lV12 zGhpV>KpU0XE>(U)cZ~eGw(9{zlF!v=Y0skdI?^uZ^#lwA)-1ClVtCM4Qg1!09Ay~C*pneUV zkZ4#7roiDoo&@WmOXLNjfhP4U%M;h$BA&XZ}o^A17!4wnx&`H4k3-#GaTyu zzK|6auORrm zo6T1;3DLhM0iL)%Pu=b?_n>zDs-p(HS@J}7pS5l@7Dsd}Aay_EC}MC@{0K9uv(-_o z0l1V#pHVK?h5J1FgZk?OvXWjshM8*`TgwivcH`420f*h=L@cVZW4zB8=aUau=3W$I z(le@Fbj>GrnFH^+*^?trD!3TAUJReL-Es5d%daD?u)iA2C7Saa>r@bZ-0$7`N#OQ0 zE+;~5ayhz~V+m>1J+OvH%?TT@dHVK%T$O7W2&?w`>67q&Y`e!k&F&v8U~k>mS*|t} zu#2?vn)s-=yeF=Y>eFcH9(Qz9gDyZ5VmlrbSN>-&luk)!9a=ljsMEtrX?MKzf)<^C zAo1TnxS51bEd{t9X={_e*J@ zs}+SBMD*KryUw~K!Hd#Lw1^E#nP^j@i=esw63jH}O>FU(7QJ!|^ZPE|xY0WMj7zu` z7QekK8q1;~6W2llb7i#Qz0cj=AGbmw>4LD6jP{@I*~w&z9M}z*uawq*M3u{5!;{0JD5Lm|IKAss{L}~%J`cmYE9#%3{01Sgx2&UDOc5t^fG)Kv4SrWOaWCx$w2I}zPm@D$jqcgcz zpZx4pwyG!kv)7d%;HRJSeMp}@GCn^reninrMT?Het_EDhGmM@6TA23`#un+_j|qE( z>w=ztyqjK0wJo=JKrnB`;N-On+|}8*kh11**b~+1#U25_Mc~x)Ck~uw@5|3PqUxTL zYQc>G1{^wy3bMBL6DqgVBU z!F|f7%t=O}tf|tEbu!BfIvMp>&a^3Bj2oXHFC)70yZl^z;8lrRaO5a(&~`ShF#DIE z_2xwH$Uuvq=aj;MG+=~byWOaftNJzJ8|AkwapQiRiphv&NV$_CO$o2q$lxg0WR8<6 z^iEC?m`WD7O{~}pzmD#=Q}@D^xi#T)QHcjt$cZT)LwN_!*XJWLuY%m(v9n>JMh;Gj z=wxz|cN*p|$HqpnV~PY67z5WmecC!=fB1ITn}Pw48AVOy`TMFJPz~GlX48|h$iEfF zkA{}Ofc&7c?>AstNmSmx;{|Qc;?tRm3{IXG4r z##+sc=SCg2OD_bNm{&79YW9lC4|^cQ6e9yfpFbK#ob{1J`BmTO<_xQ~vM<5Zj0`e6 zXL9ArqWA*!pQMB8!`!WaMpS2N;4O}i*A31_=AaCCy?uSlx!*F>8ZWr2VMrtpGAi77 zyX@oh`AXrBv8JaNnE1bglGzvf(9(@NI&ORP=dJ2igi_jAU%j^p=sPF$*yu<5o)VO5 zpMfqLe|I~lfRAtR=a`n1#Y+m(^H1@y2Ea1ma?{re_Y&~ES$-`>xTidDJuWX7(w_g` zqyDqme2@&uvqy=!Q^x7 zRHWW-4Xp6j3*PIEK8cux3eQ%2W^h8(#-JUME>U7=Zh>~D;_?|$KUXIbpQl3})sAJ{* zm6cDZJRV`xT95SWm^GZbtvln0Mo&jZjXsC7lc_hYf$lz!AjXi^iqopG6nZX)u97t7 ziIlqVN|BN$kdMmE%NJxr>w5h4^u6OBm;N)ggV@9ha`HC?bK=8KX5^2~t3$8E!tNin zr^H6Ww+%t~X74`I`2L)yi2fBe7E(I5Jsv(&ga@K}c8|gM%pD@!Q-vG)dw2)%7UQ2{ z&rZyUvGb6yh@B9LUpnmJ*Y(BVTnMD}W7ug=*9wGzv6bYDEmk_Zzr}E>gqBC9?r(kN zS&g(*0SPQWr8EKdM@XF=?~fGB8csN1h-Zk3_*k3{%_e^(Su;8!^&-A4MN}0c)_CEaZjEM0!C}_(9a5-~K;t?p* z+;+^X_f#e3KhitZLBK!`r?9TbKxij8&6XczSUj>qvTT(YDU4hG6Lq4ID}jfc^kg8b z{2ku0H*>EJe~dV5mT1ud7TQ{DuPoPo+3y(cQ%ad|x%TavK*dUoz!S`^JyRgz-qAm1 ziQsNGT(Ccd`p+ySx0~x5E3?KtVvJn^s6*UPn$p3iC(6Z9Rw)A={BX|l=(j(p=#z~eG)@Y$et*U| zocx76usa7=k&s5%82;=|CMmipRUsAH$g zbMTT}NV#tmeMma)`tFei52oki<;Ps3(tGN0wV;m`Z)2oB1(hAn1$0O|!d6}q;1SO*l zP4w-KDr!0~`IscN_%>a=d&&(L{PR?7y?MUArtx_C#sm8ZLl6)Bk3ZdXHKsQYu5F#f z%IpO<)=BgFka%k=&!h!n--#@+Du<~(N=5JDg)l_#HMpdv=;&ny%eN*3_45XT%l>lf zm^l^arV|dg>-ZMQQlP{`Er#tiL`H+2u9qCVMCFlyN~XNAd}3D#^3v&AZG(1_>WvNq z`Tg4`;ck%`2FZv$C>6_abG`2wknVOsz%$=`$!yrAXSE-tUw>j08MF09kDm7~txIw* zah$^OC~8=x^-oDIlyM&S=G~10ypbSC zMcw*+RSJMUlzzTM;7II~BfiTw>ddB?JXu@>^Y7~ku*8e!>XmbpS^ZRUX4?fE^YMG+ zZ&fEtZU16RN>ccy&rU7=XQ`OcSLWf`Sk7A5!E*i}@P<6zMReznH$2E+>byJVAjVPe z!$KlX2fEX!NOwoq+|yLbauzB~yK5(3m;I3-wqL{|W$A61drcl?LW*IY79Lx=+j3rp zsi# zT`q;Zfk+(%*+p!lEq27|#$a`L0dmq>u5S>TkwDPdemlo@_O*KCBs=c-#7RZqB){WZ zog%aag79uxO$~aqRWm~s?0tCnJ_`Df!!rhzX}`BTAoeBSGPV;~pRb=dxoQ&V`DZ@* zZgQiBTX`|h=f~&My&t9QoXZ>bZfgR5)aRLB9??#`-KOxom3{CYziGzOy|+?Uf4w7x zY&rTP{SSh|`?es-@){W7VdFC!ucYwU(`EmGUp1GodW-@vk3N%13L9s_9M(L&Zkdno z^l`Nw;p_Arml#>`Jh?UTBvS6GksnY46H2{CR>IDwdJT4G^J{`MxO^ILuz@KxuYA6h z8-$u^MtFTEHvxghikeb1aD{Kz8h<#WQEyXxvnv;Xa`-x(%som^SN2IzYMM4l2#2Wu z`z}F6J<6}Nb5$JfbNf+-9edgxeLUjak49IRbsmlIX>OdZ4rKc5Z2?sV#0yg6NMQ=; z3Vnr>X}s9-?uNyNuepzr!m>=TN43nlqg80Bh@{io)9OT8J`P-6=sK03%`^ElTM^3*@XO>A3bvGp3 z<&fU-lGlaY&>(ofUnwf+1GP-24f5=r3RZD2V*R>%{&0de(GyOH|Fz7++2g~+cHc}< z_)qwi+*o+CoEAC?m{!%j7Om#^ebm?=H0Vy!0fh6HDc?@4iQPEPnF9#P-3; zFnvs;^8oH$>bcR>iqhlt9@ifWvF1ly+iDfhnk?Vch}#iK^Cq^K6)`qb`cWsMEVL;; zh|v?#Y3YY$z{RVHbg#3Q{@)}9KncVq(HRwAzA_q>xJQ7IDh;N#}i6 z4T#v3nLZ_zfB4n`r%ByjjrE7}4oNkVH+qr$>K%=e)4}Ge=SdmJg@wbef zP6)~M6}z0WdYAo}(cC^3%#MXoQ?#sq?oi@g;q&^P%XDPkH}A(J5$IO%H?+ZPLsx5Y z4(O>y59htF+wlihP4}!EpR}$xeVXaGB^%Rta%ixNCKZl_KB6@f;^DQI8Iuw61HQyV zUC%t-)W#f$Zn_Ak@J+c9Li3zIWEky_r~TA0_wOEA;i5vi@@0EX6B`}%b|&5#+8s}= znf@XSz9c|2eO*!9ntu>g6{7=}$<7$)K7ny-O$Fc(ugkrxw|IJO^2I6%%34mr;a#ba zOhLAdXR^9~lk98xN-;?)%xo@I9ia?NRpP88v{z5OtG>Crc@|}m-9CKJ#V6n%E*@9G zOrIlO$&SlzjJjz!}&}4Eu}m_vb0aB zK`rti(4UY@<@RHFOFIzjs0wR0wM_MstM{Rl+>3B1mRqZ}@=hREruR1o84!28zjv?W zt=*rrw}|Qnkq35@hO$?lJ}3FdDqaal{P7v>8J^>F#`*yf4l%)IxT>RKkLkl=k7t?Tn>l zT*zC3r<8qx2;L4OWHLC>)JJ9G&S6~5)?na6gN6o?evl?L52tl>d4E@6t#-EJnhJxw z6qW}5YI1X$xC7i`5XFqBi3SAqq4c$ubmW9 zy|kl_Uwro$#I5%58nPtv3Ze6VJ8IR%`Z}I2>@#cx(BfSU!-nu+@x!|Gr~ImL0{+Bt`@@oT%yVO>%dk}%&h3Qu znmj}M#5%+gaVhV4-CFZL(;ar;UHGzKhpswxcc_^UP(zz5@QRsdrBw%$wP z+DxsX9Z)|)(1k2}3-7nlc1*eml$T%8>dkBPXj~V+yR_$}gke|Y`H{ORYrx6ah~v!r zjo!w2wj*`j_0Om0@CqI<&rWM7*d#0zDeql#oF15C{R%jQ(OQXsQ~b!?+mMnspG*G2 z4r5vGn=^#B zrUd1CKuoH>B1c1+oWGQV`Q?skZxvx!TKCE0>F;ta(~Dbskh;wV__wBbu0?0TQ&n8F z7`>avw)nf33t*E922;^g(x`ifNo+q%;~wy6-fz~to%D-_eBa7j10G3*4QRfH+TPVL zZ%Lc#*&*o3(SJ(!XSr9c?fx@afGmIjNAIq2Cv7TOg&;LF z{+A)ys}B~S9mln{6|8X9&NUFH$FXj!J9;mH^rRQ5A@(w3TDX!K#I~t#)8C(E2NGHiWO8f82G~A1M9HdL=Z^-DO=g#=%nse;Z4f~RW z&}qGC>{l4Sut>h{Atx(Yv8q9S z5%R*1HxTC)Agpy05Ai)(I|Q2y?&0Z^U8Gw46+)&F9r}Qk#||BPK}*duEu&^3{e%hN z*yoL@BHH->jWeWo0?F(S2oBm{k9!Gs+yYKHxx)rWFp7c0AM{Gz(`lXJ4caAJf` zk$9|EvgM!*05g@k*f-hYibRw?)R))hbHOp>N{=m;2v7&UzQ;RzH$q`*9{uK4u<+Kg zb%!YMdT5ANrY1~R5AJdxNH?Yi;Z;<>HB%B)#5V*rv1md6hIj6>_B13cumjR_5B_>|bjLs!tD=+jZ9}lhktF0We-wm>e(TsFk^jD~I^z8r zL^`J~MP z-Pi->xDTPiy-}=SLTCF}YOQSw^)=7IEswp@k_D?8jOy!14FZsD_-c8XGxQl}nI!gu za(BR4nCjOnakk*l zYCU9MY*5`SYA(XCXy0 zue>MwOxa=l%e&KX`CfzVnz_gjoUuGR%v7$r10myEzCjngqvrHG05vyrJ5)jI>h*m) zdpua=xIRwWH7Ra4nHZR3vn%Q-D!F@`fxLsL(C<`e1zu<#+zdD`aZXV_+_~YcG|fY0%g8{F&H!R;$V?@TGlFf zZ^L(6xTVPZ-^;6Cv1{Q?B)C6SqXHAdqp+{jd@aVTTr-8St znE()e?CWoTr->p@qltZ`%sO~V`I1K^5s$$n_@Xl5^LeMj`k?Tn=1BdMnkTqO%%78| zjZ6<5!h&d;4`xm5l#PK(b$LaG_rPk^@^X`(mfYsJ?X_0nW@4Kvdvt;LHt~AX&ighR z%elEM=Qm<2A)YOPszv}oyII0*{I#HFzh-9-s$me3Pq!B?WtS5V2ZzOBf+)O=i7rY+ z63dA=GxFd&{dlVI@v z8yYvQ5-qR#W~}PWccvUtGn*w{JbnQj>s4MQ!uuh=e;tZ@tdq^iT3eIOn(qrcsXs3H zxobItcqQBpS>W=Mthm1me-O^~hu3FO$EPgj^wj{auBja%`{j01kY#5Yr73X%ZqVKs zvVdFt+Q;(DqoXt*ybg!c6trSnd_X%d`0KUH&V6eX&_-Bd8XX$!Q{BVXC51(o@+%)^ zAA4g3Si)uxdwr*n;r6*pIv84yl>zw$-hflVbeCazgnq~aMDJ88rrj^Uyr27D21K-- z`+cAd0?zp>Q-wr$eGfNAE@m?$b7H8tCo1 zN@`2GTVZQs`HE#iyCxOkwuCk*^~OfJN9XXhtB)*7Cui3Tqsob2q4N9HWTMiiUfcNz zrKG`L(MKJZkNC&YnQSSFMN#yF7$8VHMCnunL_lzcw9-kZG+&=5a#~fZDl0#K$969~sdaxZ zj<^$p*fU88CFjqMFa0(yKJg6$AZ+83UO0cMUxG#cm=;HpFJLztj)*20x_Ugs4jeAq ztlAX7V2_QtoFvb&-_N~3Q{36eBFGO)LN_ivK7Jfb+1{8m_I{xs(5*GaTusmR%n@%P z{U#Wa_s%8n;TU7LhtM@*@?@9Y#duP1bR9w(gG56pL>rH?hxrGNj>XW(Uij_gYztu3 z&HB)`W$G(BCG;xBw0I|LsUj+%!qIMj$>IA;?vSV<{vXeN>stcJ;-F5G7f0cd?X~4xAtz_iRzl z%z2+pK&IxL0nGeC8TzAt5Hsl;R1@M9UK%64c%CyNxpw?b26v8>oTcOAR}yOCjmrpk zx(r~1gRK@&!NZG1%S=iHd%lsmXQh|^L9{JAJA$ygvpn-TMOX7g=fq1nCWhZKvV-B+ zvGbUle#Ogb%ry5CdARhYnjxJ^$-!y1o+NXd63&9w?B&o8X^q_|dkbG6;7vu)5P9OQ zaF|H4RNq&AGYy)FHS+ejlY)~yheLXFQLv3oB3AgNpU-hs!dq9LKLau&FPNRSAEAP2 zOw2}8HLh8Fj@Oaedh;UWjW-v36#LTE8lYW%O_Y1}?AP&Nn<3@l?1+5etsv|KMl(A4 z+z@5}|LH||ouGo4LD|6+p3nL5oMyjW!ah>WO@WR4`{LfJD8lWDIE)6E2m4!atn_}3 z((VYdA8{Nl)v4{Ek%zZlezX%MoNsAXwMDm^iw@qWUx?|sOFR^~;rbTu`tcHD;z7LM z@57)539re^?ewVmpz4M~A#j;KBq{qtBxJ35_-Xd#OVqUNl3756cCYccqs3?rjgJS4 zV>$!Q?)UE*F^vg+SF7KX(_zb&E1+HVDf;f8zAy^k7smD_lO<~s+?Fb~e5gi0ji@Um zxzb*c`tshtG_f_8b1g%7$6PsFEn+1u~T+D`GcT8TZ= zpJQ{qB=d2n(Z`5fj|>a1)?+jy!vJ_*2U7L8c$8w3Z;22H(PPrHB{oAxCTAEwZxlbU zyNe*ATN+U~yrV($vFd=~a%vQ>#IaHoYmXoFg#<{tM&|H_L`R%`$rF2z5mamHz+I>5 zU}?QFem|Fxk?#?)&*jZoo-)K)l0mKMQLCv7{1e|ZTZcsU4#1EDoJy3rkxGsVpA{Eg z)KK@i`S?k%j0WUKUt(%jY^PAz?{5kc&Tado2QyGk=I)POHSP0V^P$88U|0vFJAcY@ zshyKn3jXtfseH44sP1G(r^5c&I&nX!Q5D)>LE}JxE{rKaN!DH6=97AtSB93>sqw52 z+7w!TpUgc5Uk_{ddJmy=Z9&e>Hx3t;{DTJfK!1LDKz{Eu0MwY$mxm2q)?=9q$L+Mi zr^Jw&{cT#DCgQ}ubu}c@^JafeX&P(usluD`%&@x{a$cPYFE{G)=CYfvat4)CUsF$d zIVa5M?H1%dax(7I{A6mbuOIZ9FY4Sx;iy-~=a=a}26<0+fB@fiPk!hSrxdTB>zPtp z>ARkX??r}s5FBJx%U|lgrI9kznP~_UTP9~a_df8Xy zwUzW*=Z6dX-Wnk|ve`0c>eqU75^3*xP^+KmhL43*8uqto3bS~0SO+|k=-J&Wfx7%I z9=~~E0J)+0{suE)rkeqHZ8VTkh^k{$ot=qcgjWuwB&WD{?z1R>zX;*|zz@uGs|^85jHC zn`q(pWD3*PKb6v*dRYOwB^Mss0gD}!bxlrKX7~!nNma>WCKBJ1-Y)xz?$uD#DKf|H zZ`Ii+rq90N{``4rPeC-y$lS<4Du{8RVB;T@^!C0IVsK*LyHxA~ezCwskOK$QbM|u- zfh71nZ^Y%Z9^K&!6Q<$`$$};}x)4A;D?dHV0M5B-^9u*shrykujt0711I$mRsm9+; z?QLm|M^fCZ&hZNnjnoZw=8xZv_#1bV;hQJmJh}_tF#eTW@gX0Xt#iKl;ZwH?l5np) zIJN5x7X&>|e4k9bVS;c!jtZ}KKLqtgBU(oK^ckoDR5DittKr@IueFQczpuWucoE_^ zZ5EAl&neV89%y3Z1MQV*&(Ij(CT(`4o+Tfai+~!0s4)mO9(!+qGi)#3a!y2CbDtz_ z3{2-C>7GG+jfi`i->mStKQZRw)-Q@TU*r3J#T@nxGPt|f4?&|EjXT=XU|KV{m)866 z6xhL#N&-!xtG$+-n|t3}TKJJ0S^2Bt1j@YoOo_{86ET*zHK8CA*{^b^~FsO?32phE{?cUwv_FF3_-F-lM#pbG0PEmg$f9x_p zp(qbbAi+%+Rm3niO~EY8iFgTkWwZ@l)=9IQ-6vy(^w*6Z5ob#Pi794l-ih`5$TyKh zVKP&GO@9bwmhYQS0P@B5A2}iCe)mp&0i~ZUs zDy?p1Ns4~a?XR_A9Qmb=<#Z@mX3sKaa0R@LrB7IQafM8E3!V}A`-rf2b$9U^wOboU zgDV|YRFs|>h(@?(F!riPgjS)VoV1*`>(RXY(#I`OeSL74gaM(!sVQe5jsYeF!g)Xu zFkhW{j$hw)W1{C5Hqx#%2(&4z0zuagax~KG(S02`C91IVtbAWLCyNKnML`KP?Zv#TKHgxc>kw0U@n`~J*r7g4#gk>)qjEp^jO2biiYyo zd_U_0t=L;(e7J{mQm*B(674IO*$%4PpVxK>thHI4uZa@k7_E20gKDD}-pZA3aw*k> z76Z1^iPf*}R4%7nqxE|Ut#7ZA=FBxw604TWYa%Ie?{0eA<<`7ytL!C}174_xh6kVd zsheDoEu20@(`U=0Wu7bQt52D7;j=7`9ti1``;)5L5JjLOMdkkUdOS%C7f#H}-p%Ez zOm~S$kKYFzwiv#m^mBFZfbfepgk0w*Ur(Bd-EP>F6@2us7YHTa5+F3S^PWtz(Y|=+?(zr&h8JpY$Uj>+QMhFD&=07PrEZ5GuF9OjZ4&u?aj{OP zezw$;86H(WUYhT4Z|XX~d*s&PY|rkFjFE!W-ilXb^uLQMkvlwcPC|bJY%<|Dmyr&q zTEKJqRuo6ueY!!0R=Rt8Z`Y;wuh#R@!&(xv8t@Mj5^EO}G~)}Ck~PIBTLvJY68u*F z7~|4-Yza8pN#twhcUNLO_=YOJC8`@C+-!PI$z6NTE;4t2U4J}? z^z3N`-6Q}` z?-bC5+2kxFw$6>FNh=lJ(U(?18;3Y4x5MeU(E>W{feA8IMj$@lk& zOo@V6!x*nyi*{^uS}anhFjY-ywLi<)9W5qn`vd|*r{B#+is}MKg1~4ok;#0uO5Qge zW@hgPUhMA`GT!r7zZ{utxu?}$P=R5i#k9HVZ=;R7em{?mR{t=w99VEAw%~-!{3KgoubNmewj6`T`U3G_l9nchkYZ4Pn7gE zNYFy-+w~d1#>dn2Hu=jVwXKlRC<(Q**L)JM_eOXG;{{_9Rz8m3`hyN%USG3gF87NN z2{;XJoJ^{<#0?-z?GUs>Wu*uVT43xUi>?H%H=3UnCXwt{OF)geiOHL%eEseT{7T_ z>}AJ(p)74d%bL1%W1nHR;Fo+xBbtcp5u$p6`)a6u7D>#%1ylSf>IWjxtNY_j(A;jT zdB)`#kQ1K&OH{k^o8}zqo2Z)Pb7_5o5B=oe1f>*oke$4TbU9g*eTsk5?&n;^n?w~~ z7|6p#CHzi1#{L(DbH_Tu5heC!y=&&$kk_>L*#4x^0uas15% zG+<`;3>VZ>MjM~rv9F!#*c*HM0@p#8C#QG~>W>ER$VAQcWht5QYbp>NmZ94Tr~Uq* z4hL)33}`x=CnzB~%W#uE5E9Ed7w>vWOCh;EMT{XJ>B}bv|8GUsEe3V?mW4{#PwuMk zx~~w&Ehj1*W_G{DYY%I>o>Mv7pVA_`h8NT}-4l#0NaenW<<04%hz&u`apyz5cTB!S z6ZJL9;EHh30USNFve?W7J^$5-N`i;kaXOQRUIuUP93gmPVtK%Z=DFJ*w#HpgowzSJ zTKg%`Ij^syyenR$8AoPE`3ay3$r+185x41Sg3Ao4kN9h{dZ_KswQDAvkrmghZ^FNH zf#QN1dpW9&>&-BFNq3wtZrFp(E$j!lL?btb!=t-LI3MyLoJ=BTzyG~YC#c%(JzqsT zJkAUY{9OnF0;J|Ucf@x=>JU6{9@}3NkT?nF3=R21q+Ag|Yb~U)T zwyJC2>AuUh&2NY~aWd7SD>pltXs?gUAc#k?ny?2Iv{&%dC4`LQpSugtkJYBk{^hdq z0Xl_Te;E)8~1>B0EzTA1aK-{~# zsBQUVi~2WrT)B41#XU?3$qD-N)O5p6ezd}C71AvDxWEtiAM(`h;bU-5{Ezo_{df4L zv2xyYZ5v(Ww3XK+70>-`cw9-rRv#0@IVII;+0A-h+jw`e8`+Nu*j?UlgrWQE#bowt z$0(Vn0nEM5LE@VC&Cx#^dj!rlPDTOf_C`+5PToNz8lTJvE(~&fs;+t2Nu)+uN&e?A zVh#SMzZoOL?b=V%k`tK09qX0dz6_h3vs0|&j|_I9#e4&s^$Y$p=JddkIhrT%1D=?Q z#y5X4=+Z~G?HL?jEJy2DdSbn-J=4Di(eSuzkH$Mgq@sUQl{#g-q(IMA-4(jO#Gcf6d%Ye{0D7dZB!+~(ETy?{qWaq^Xz=;_*v!(6UUEOyatg8E zXSIttJ7!7yP~|yu*L9KM~Nyi27=nW(o(s2=v zaoHj0e|NGy!$C)o7@!5^RLduG8c124TDXic{bBj?O4w-wcUi#EZ>b`c=E zbWg}om0#ErQ*taSm5q>Xmjc)8cV^E?5XFdt(YY$Dc4Bk}Txz&|`@tH{F`O#&?(DX& zggzUivb+w*dW%KfnJf^knULf0R;%F>JoyL9WN$B2#NRUQomJw%rCJMxPnt`AT@#sk zEZW{ogBzPpU==;+H}V{`cO;rO&8TQet^vxCx;d-$wr(RHSj0NBk6HT3Od%DpYmmi< zrPQ_lG}8MTi>U#USzsj?BQO4ue^N(6ulJ2EWSLe4hZX9X-jmUGA{gHCzk>#VH-4JF zTjo=eP=_6knhZJw9(ZU!=>&`dXKy{j%U|4DQ=EE8fC^vOI@DD3cLURYbzXo@H?$m> z*67Yyj;ISWaJD~3Q+}e9UUqCWe>Nu`Iv?0{Uc1-^FhRNfv_j(8cSU{G!7xcn#_$gJ zOG^pd7o+<36wfg@o6I4jAD-8o8QB=UlU-FBVK79ltnQCFoVtTeg5Y3VgULNIQ&$vf z!^Slea$fql4>!E_2lchSrLn+3AJL36G!o~VJ%80hW%b{!AC3{)ilSSc_3m+CFsx<} ziF&fm^XpXU_w}3?bBPA&{gfA?bsxur^GulhrQC;BTk^&h9YS9yZ|k|?q7hQ|3RMoI zt+)BRC5L+=ep<4=wBH_8x3gEE(MLPyabe2${wtciJfZvDsK_?O&CG@tmVXlt{(-75 zI+;=2cv8nX-aW(lV$t_+QJBW_V{V|(FtlZ9`Ci8w8@%!NLhwLo`bZv+bS1UFnR^?* z;tH7isqLMIbPJYY*Q`+jXQC2CU~Yj-IzwsZU%LG~s+ zS8v(!f5uLgp4-$%pV#4Lp3e{YRqJBe>cp`&drFw`(%5#4`T1tap*=+8`}GUb^OeG2 zPk9Lw-0I}I#V*=wD0(Zg+jRR_^7*uym`l^{3`|MlmFEo9^6STjLL$0sd@we zA%~|&rqc}o69CdUlN?WGpQvOBUi>TLp%}Vt1j;JKBSb9)C;*ICp8d~2lkdtf(ae68 z$7fcL{iXl&QyX}_q+c{x&;FRA1VqWD7pu@pz$;;U-%Ba|*x+(e)o0$vW5elQdT326 z-Cr?1{GoU22L9{3|IjKV=(qV=-FUmQ>L0&bQXUV6LmR(w8KP$W^`*(He8EZ@1ux7S zGCyCOxrh!923gp*lh^xmFg{IjiC;tNmmXMo#3zqR4I2eqm6qBzBuM9;@La_E(*{D{ zQ>**nerqg@1zPZuV-Nz7@Gg;u9$(xk#vZg5V8x&&;sRtx5Du1TT&K?-;+u4rmPRM! zU6?n@TGI7e0N;P!2kyr2S=#m-ll-e;4bZ!-WjWd~!at1ba2cfaI@pam?Jp zSF3l9avnQvG@^63I#9Q+z>fwK-^Rp;u}3|PJKU;C{2JZ&i0>j-0rM4+4CmD*Y?Q0i z`Y$AjGV-jo0m0!!8}C2goH|@Av+!LncBsuePi-&n%7whGG$DVtSfg6UQq_ERs9ErDcfP|yg6No>6ZC3 z%J~-zf)XeBpxJeNJ_@jE&G@jug*?J)}8CQ&$ES$?)eQjU`+eR4z+Cz7r&oc&e}N65_|p0R=!AReGmU2V;<1p^UuD6fcRRIjmpiB&T%@r4v*0})S~DJ^SqEnKx_JI)TElg`DUJ| z59()vvAB)>8|63UgkZx9XTy2M(iK1G>Aq%5s~k1{us;h1_b?3q;2_FgI#tpUvR@i{dDItc>d^hO6mJkrv04JN3} zi$Pi*@*ZKV$iYx(v)+htA#Z#nMi4GT5h0zLGIbV~p+XYO4)eXpgiCrr>W zfI!%h{to9TLG`LwjHl)cKyPyY`;A8&fq0Avt+Cc2k2Y~1K)rsMHWXD>6^vIKz>Mpg z7OeGi+_!94Jg3bbtR9!j+nphzBbLPwP6Gr2Z&Y~fBqNeXU zC49T!Za9ZKV}s%0tnUN2D3eymGZG?>@?5js&5%WJ7Y|%@8lp+&tUCsBMU8q5%gw)I zwx3OcQfp-g zHwiD>ygYLtu27_~fNyA}(3?U3>@|(@b85iWT*Ie}TLzIh1nr*c6vXK-)8z~XND9`* zWV$n;+SRB~sH9+p{5U(y8<(_qpcd)zB={`YhDJ<2(k{{adlejYy@HK9h|{kYXdL7E&XM346_4owHG*YgwYt{%? z#=7lK7whvR3ZDcp#4NaBr3#khA(_(S^>BKcWJQ~xm)d|GKSIErmi|n?^68Vm_rGC( z*!@}4G};;AMtw(evh8kq2i-c4C{-9-j&;9(xoGqRt9*$J2Th2hB!Yhs+waUjjQ~rO zM)^es>i1R%)g)2v{+n)@{o^}>o3`hU+p92G^@EC|Z(BF<_0iFD+2@C;z8O*{M(QI! zUrvTE*c#G8h%|B>DwzG}{EP@OGG2cMfD6xfx(UMEq*XfvR6^nUeo}kcy!%&TKU9}9 zM6@_*gR}Ab{mU#+@*n(a3n0pH-9 zybtw5q@~`!RLV+8=qcFGO8u)n5}kC%?D;k4N%kQMqFg26m&lUbMm(*7x%`wIeLd

  2. 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%0DyfxwNjsD%+k2aM7D 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 z zyeup!+R(R0L)HJ*o^_Y zZ{@<03xgYX77s?>%EKm-F#d2}0f((9Q@dX@mqjcbG_XDuc9cogD=|!Et%GEeZ5SIn z;ES2;kG7WvzFBvP|}WhQ&(Rx)_fK_{4aePt*Se%_!XVYGkhnz~^8y zj*Jn*e=;(bXIg)E-f5|kaZt*HFn3@s1ltJ;^5$KE<&T}~%xb?Yoa7osy#@#?>wYeg z7&K2$MuMk{1d>%hM!G=^sZHY=Ru0QXT|K8R8qA>&B*?RmCri`7n$zL3D5at;N_y z`>i6#<7n(L**ki!*BRQ-{|K_?&waoDx8+0qziPzMOPD&tal$n_QWy2Ju`ieoU|6`!!F_VU%B@GIaKb*We3~najPf@|i z!ajj)pbgTQT*xmZX14QD2(t-}X{GT1is7@3&5=#2wr0d^=umQ(mKZS`)MHjQDeVg* zWHQFc7*ZuIf(-uiYyMk6|9J!b=M6@^hN)g_ zowydzctK0J6^}YRG{kEpM37fYNW&bP4)dzGGgiaAQbL6JMF|n+6%ZLbF2_T| ztd$VI&6bdcIX)fc7vj!%4fFF7BFtG5BFxKhs16>N;-O()A|b-8k&uQtF&*Z`m@3dP zFOm>pR>y-AJJfjeiDC35w{@DnKM0$2_Ne=p>Y z0d=D}$0z8-VRBHOL^A4AI{|;b=^iXFhbgajF4_|a;VEx`ryM)-%(l3pB5YE4MJ?S6 zuGyryCWBvc?%ye$X7($bGs9MAZE}Cv>X6;95Fi%5=F`b?G4F;Ku~a7Ey?M1E#pq;S zs*Qv<|6TVY`io4B_5QN|y_SpUr?&t^a{tcijRO5~>9n|C;V29F7eR}ahJ59~@Q|wo zviA%^_K=>~UskUnyY}xq(qWLkCV()RBp_`$t@XCXhx{+(MGGW&Oa^ul6~x|Sbg|IXlU zFsR1x31>FJ z6`c4PXosch^m)njio*c@nL!RcL9I>#9zX;*(TGEV(QU_ZKoxS|yYEPRjcq93T|R^j z@-#WPLB8?@U-MGLgkj`pSJK1A_4cSZ#CRUCF4BoUDk(g^d+LzEw^DzO4&>PcsG$@M zP*Q>TxcSecE#lnzZ@ON!@Jeu<-V~cyJq{Sz+QRX}p$+PS{SCd;{{z(j18Njj$jU4c zYStyvgw6-brhr`z1O5UA&_frg9YoAO?yZMr!R|(K0`!kl=2gZgK$7JMMrlw=_%&IE zRc*GAQYj>{M0=;uufuHxmzs?ZGN8^35k!+g6ID(tKtsUVdMQ4u04X0CXsvqGbzu!k z#*?I88mIt492i$!QWmZ(Nktu9fF9Ch79bk^zy)aRvI-!2>O@n3BW;#h01dW-sDZ{V zs{rX|Ixf&P=*n3@fhj;k$fCCGvNW}Ke@=s{&k1V$L4YD>NaieDiHJJJ;Hq*KAY60+ zY9~44a|YLzoS>-MNmpG^R<(6W_89#vT!k}kJpW+ms*BGmK*~?z`XeI{%W~q14MBoy zsl;Z1(mXgaT_2nIui`3WBOsg-WofYM3}8*iOzu6{2BU&j_ZvYN0Th)NB|IR25h%4K z6d2lMsG9%*w^toZ<#n-H)U_p*Np;^puqXU{z#j>7<^Fb0TQ;eQIZ3gCur_9qXp z*A16^4dEY~@B%ux>L3QXUmtMw>uW!1`*j#b!sShRq7LpcPO@nRZ7OL%*lG$#(qW$@ zzRB)LSGpF2b+58SdtrHml}WeMm97n8(u1o->IL2dCCf~@6|Quv5Z0Ri;nZpMCS8{+ zT{ptyPo9%k3V5`nHk)+4u5=1vsx-zAnD{-ec%IX5z89FVFc?f+wcVOu7bFx&;WA znD~f^Z*j%9ns^>8ztqIHx#E{0EObRZR+#uzuK0F@bvPNR9)iC2Z{fYk)W=EmvxTGX#;vH9f4Z=GA zl9E~zU+0Ricf~iD_yw-`h>4d&|4n?WD}E`$C4%3>C2b~tnJaz;!qN+a{;N!UyDPp6 zVbZ_6z3=}74E!p-mEruaIY}D^Qx(t}1xSb*Ck<>)S>P>TKWmd1PJlACat2by>7YrB z4Ps5!lN5P4>YuEa=i(TiYJvrT$G}KO=65Vs0Z*c`Z zoqn(XekvfdWZv&BG_R{zjghVLVN@q1VVRH!b!62mY}JDds334LW3Lvxv*@L!EWRg) z7y-VJjuLQnMmgxIPMb<>y>I-^4C!w#OOCsn%w|%#3 zmVOB%(f}ZcY?Ly9e}*b$gdF!aba51jlOTZ~lM2@GoGSv<4p|UKUF*;x0ZXWFr!0W! zdx-N>aA4!IMRD0bs+Tszcvux3tLCIO%+JD4lpILHZCk_Xup*SigFox~0sBMMpCdzS#E_K#I7p****(bRi#L4UuYn6K;lIA(ZrdzFck$c| z|9F&#h=6_pA&{YUfx2ltX$`pjzf#W}NvH1KzX7ee5J94q@^{F5!r`DLaB5(`U(fM; zJQbMxowFyDSY9Z)IbMSmH&b3NHb+MVpB!Rh}!E=Z|nnKNLWqH7vJ zChy|x5@e=<&EGQf?V@5@65Fx6em__~* zDdfi!c|<`&vF!pts+0%7{P@>KiG1?oR3hHD){qRu3%jQXNJC5_x~jRae4|+)8paI7bi|eik@Kq*}bj zNh~(&GeDn&93e_wL-j4?AW+1B`n_zH9T6eN;2;RqxDl!~FQsY&HZhHaP%ZJdT2nm* z^ohObQYBmpG}EY|Z4+Rrdg*Qi15+!LYU*Bh?gEM?nIJ89fxu+$pGt1;AC4l=jC)8P z$NZWP7|yzAOzEX%)5Gi~a=G9BYnPPX6*6FEW>iAR`hk2Vo*iexrP# zLK*G95k@3OH!XlnOC+76n~z9w^fCdP=G44C8Ey58VQQfj3zGnFahMsE(loWvr8+w0 zOw{&?jSe!PR&c-vW)YoLN5&RRY@6G}rYOty)^@PbQj~hQT9bygB`>9*kveg+lmqLN z-722~?ZyIvx&#ICxtvt6A>&ES3r$TwI;473TpGJ9>QF#X0|3J$d zPO;iZvn7;7m#MsHn{M+Gp!(QsUP{$fvgZnC%Vu-zCM*NhI#}!$HnE5-shQ3F4I8~)sjB8au>>x9%ce&stXsP~rB`x8gI1G%((+n0WU5aQ8cM7BvTPqq z=@NBRDyucqGjoH_w5+R>CAasp<3#zMDUV|Ud?e&-noQlO%gxe_`g6K&{OV~aB<_8E ztbl%29>+Y+2lRT2V2}x2Po0W>e!AWieOGbuPg_wJxA zbXIQ0`{GAkDHTRwsEnKO3Z!ip>%;%ScwJ0kPolVJ3m9*h^#>@uP0J&PdEmcZ=7cT3(U)CTm_#t%=?pfn;mWhL3W*qj;!N?^U%5V=ObCr&vaj!-?yK*(tlP@SP> z8N=#zr3b{=0*-bBh+YQp0x2^$@S6?r7D@9@kVD;d>H*QpO-SV+r%~kg6doupy`Uw@ z^K9V&k)p1ZfQ$Ya6=XZ9Q6Pbe#x=b_$oM}n z?ca}W`nMOT&vOO9*-&Y!|9OOdo?P^d!5m0+GgcfXg~!tJ<4?18yK(A&Xw`nn*}Hc<26y1Fjx5Gcuk%Q!JIH?Qz-t(lR{B1B8A{U1_P3v zdK$iwQh9-8MxTXN&-)Sb7k@O1VMwK~w~NtwT1;5I;eR*uzfo zs81X0(afL<#W;z*xVaA!`@~$91=Q0uBFj>bP*x8bWgwD;vS31#MfUG5Cc%g6Ui|+A z&4D$F%fgz)sl0yzYioIAAuh-eaWJe$Jsr@9FC&Usj5TI=Xp-kz5GPf>(P^NT2P(6oY4ie{#0*GUTIR0KvbvqOsVfR`pWJn*W zpep|*+>jaP<^QK}d+?AOCdrrIoOGz92i=yTc2qYRbQ3F+WSlRoIIe;qOZ zAtQ#`=&l`gWYy@oGd^mqMYP-RUTG3z#@OQr2y_SjM$8`M?OTtHSxo5j0BfT)hp)#4H{@xoWsnoj1HME;fRWcB;!=ae!=~#?%HK|m z0O>BoOuU#M9L<0jGL!M}K2DduJ_`lbQzIvxK=3OWDw1Zgz9K+<~;l*Bk1_4$N zQCtmnP68LtkeN_aN~Z`;XlFovRj!&WQbR|(GOZ1A%;<6cgdcHMVn>97jRiHJ|InZH zlu?avgy`6;8K5YLFaBfrJ2wM_00WM_2y^yHCBfSJ3a!&}i5{E6bZ$i&S!(cC%&&U- zt|q-=<}%B;H}JpQy3tCmAqvSVrc=A)O^EM6Y6>Zx=&?Oc$4=b1c@4x3cYO)1F;Tw& zwBF_vRXGp@VbMR!Q{Gb z8HbG5B30y8YWPL!s2FP1XG?VH5ys)nUn(igF)uhwD=*+BxyHyz8=5N@8{(SI4}kS| zL-go}r}+|#r6^H<3jwcjs2v|}y&`0Yg*_9|75Ea4kKG%Jt;d$k(5Aj{;+nirIqvy@rC;exOo$s88^KZD&Bu#V%h{J`qrI&r-7AHkZ-Mm zn`bW*ZrUl)V`-y6-1iWyxvv0zyX_C$g9b-8oAADR%Y_JnwbeNt*pV`ur(yzA-1>FS zJKJ#a6 zID(3RSkqw;4UL;qIXL%dmqB)}l}&1C5vrUv5Xa-J;V?Y~{FOjaccV#FXPG?N*J$`w z<=JT6*IaENNM+fY)KE4_5`s`_7#t=V2ttoxA!zuyad_!W**1g@O&SC?EE?0P{4kAR zg#)_bK+%Uy%RMTqPcsv$ovwsZESUioO=iNsx)TcaOn7*9!ta}er1S`FHB67{YQkJS zYQoHpXcFgafI|a3)d1F%|2G2O^0AEO>dMhvUoxVQ)?CtqXS8djJE3i^0(3T+&E>bk zbttW%=ARCT$oWr`SxrMusfFcEF7?es?p7){sFk$p*5|0j=S)K4GD6FsL)Dy?Q(|c0 zXtglQnBG=mwUt(R@*!4M%&P)qhOFme)?V~>QbpTPP7b-cVS5f*bmgGMXHCLGk}LHP z=Xpn_Vs61voPSPh(bB`RTl6RWu3FgYsvHRyn1qK^ivtmS&Pj(@$pZmC7J$=e(2}ES z55Ap)22KtQIoBj)sa%xJ10j5iRx>3mpa8#MF0VDkw`P5}Wn0tHJYZG=TVF8ybFt1P z(9!ojL+m$gnMVkW ze63DB5|_Gu$XB4t&wcNr;{i3S&>2HL13L^Ispw$#>DicefMf}HJqC{x9Bz9MD_U(P zWszY7ZRYBBG`hAn#`axe6ijXnG8i~u0l9_i0DMQw8I_(@;;8XtIBEQY zZY_vmxK@%m>p%m%hV*sRFQ|NA&ckr0bv~wpPw}(Vz+sT@TeL|C&u=3ml)KJq0=wEn z%DL@hhnn+$4msydhn%xqa*|BZb}%yo({8B6D&Xr!)N_waJC-Jr5~o;UVXI0Uhh1mHFTy=lrtCsoUpY)qg#`P7Jqd z^g=mjYeINuJD~};IK`a~&e@K>1`UlHJ~la6=NNq*z7t;e!8HkxWECd^LAi~r4FS?> z!}V0l|4D7w$7zF+3&^b*4niABr5$w`HPFaRmqeh-bU+yz-40HyJJv=UZ-&_m;;0|8 zW5IY{hR&Fy0J%FkK)(-bBFzB3MS?vlf+u&zdDMJ_T2<@A7^{DAz|3UGbjFi?M<8AY z<=2TXg{C$>G>+xFat1hhrBMxmS#& z@>6A3?5gs8>$;Mf>u36QzJs5JH$3>A|F>N;d~??9^3D0=^}cOS@a0Loe9MowXZZFk zvduX^aQzJ5wr;+^%=e4R`2Hf_-{AWff_#6C@7wu)bq(M90jL~*-|+L>i~xT_W&FJ) z$luGEYRljG^8rxVvW7oT^5;QhQ zDZ|eVLHx|AF+`C1he^MXzJM&r0!=bZz$Ftian291$e2> zdpA^QaN#$Z@?KmdGYr^%Z{Ca>b#EX z!hNAagK>8_)>R#QCe-mN6Wx$Zw7$Ahj(2c~!@@g*skmy5o}RHdhz!O=6Esz14+%p~Cf{!d;>0^PcM1n(Ek7VbB9v zqiQI8{J0mE0NLnEp78OLo|WKMPqpvdHTZif>^m22dv0diIB#L}UH(oQK|e#p+yo63J{yWY=cz7l568a_){xTjOabH! zmROy)PsnBYir-mqb>4pceOOKk6+Rb=c4G;btGyn%&*GrlYmG@%UA_)Dfa5d{hHp|h zWS6CJNaxxVH~&N9_IRkUI~45!4lZ^$D~SVI_JdHNO;laJ5jbGon8v|XFHMK+vNR61 zEX`FZ9QJ4&+CzmsAuwDTtNr%7mJTmh7ybi$n@sd(b*#TS_5@ixx*e=_`a&j+ZU$?O z`-TL;WxjLY1WWbf?+N@p6ONq{j?IDExBzP7Vxu-v{1lF->G$gLH`4gxq$Dmz(7+eM zJFa#c`i{jn)o$b)H(j?R)1>Iic6E!`Bgr(WdWU0Kb#7rYUFT*553;_P+GM2z9J~}j z$L}1%&-~r^+4te~RlctcAk?ti1Et@NzjgTAh`%lPdjo&(;2u>!6!)%~zBxPj^EV{_ za3?{$iEido_`6fOnhT_>xmdcI+0xZqgW<{AI`kZe*xg_>Ixm5~WfcBC$3Ev$_BmIu z&-oJjoUgLaapH$qzme;83hFfnWzM+`WzM-%YIT9s>f#!9qqFPydrgDWxHbanu##`^ zXM3u;8N>p`a&@+AK;x(I_dNc#Au}2QKkN9jkw05N1zc``DKpeKlM+(@RR8yH)Q`~n zr``*0gEt`V-LqhpN0h4RMBICeZpt8J8u?D7Iy!>?-duwhSveQUh3 z#(SwU_R^3EP3Z_t*vQ%9!IO8!Y&{;kHJhP-r@vL_S=KaMD@DO5Vo~q9i`tbcYF{Y2 z2}P|AP1poGeIye+e400if?yxbkjF9S%45=bEIoSAhWKe%NMwd~dVE~ojt0dzEi~bS z(1iCLnj^7I;n<7SvEJ%fUnshID17v!tt}ux^jS~%=+n0#NM{EIbDQw@A_jE5`0F!3 z(J1Iz=yi#)fkK0CIkqnWQ=q}#3gx+mFAm3Y*4PKJnODC%vFGF+>ES|Smn7NrX90tS zF3FzCeg-u7aQN8{5W}(FR9`2_@D89^xqAhuJGV|PD8fxnphk^78;&UfDws<$yaQ-f zZY4n7xpis*x?KacgHeYo6JEg@F^(q9&lMP8=%U4@_%eTDiKEOIVbXZR z;rPA1x)8q*sv!seF`^az>jiIOR4jts8_w%V))k+?0vOTblL3uSXh3{=!6{tp6h5EU zLK~Y8qJ@5K5{=kGEhf>3E%arRXxJ9o8Y+AyT(~w|h)F37cd48AhhiUuV(*8d(n1pe z!L-n^1cnwut2~dtZD^&p@VBGWy&kTqWC7RO$amxv!hf z^-_77^CjSY=dli9oINAk!SSreJM8b#_`8tS_+_-lzlagQoG)VpFz2Qk7{&P|_z9OF z`c7QEuzKONtcu~l3_S7Jjz>6tNgy1* z95+B*i!D$$Ryb=rxmpd2^TsxT7;D?f-0)}}hBpTTy(yc*6JD&I&|5tL>R~gOYilTm zap&4FXZkvaoTJA*8zm7j-amR=4}uPRJm1W%_7D(%~;IU^TE(i7$@`uSP=jymFGjU z@;e+`E{neDnX3z9I9N}^rGbvl1!@7d)`#O$OZXiQ4_ryX??uYb?*JGy038FcMxM)M zxhnwzlZDuPg`XN`tW~F&jJ<-gKJ6kLdq}R^ASPUk#j7*~Q?da8#to+M?Q(g#dJWgK zhOrbWB8l}m5j>ZObl^@HF4mu|vlW3Vqv_hWCW!*395#&4SAp}A_gg~eV*8{6h8z2$M zgpFGAe5j;Vp36&?@`?IrAdl)fL)4Q%SWf}+99EJMlXl63{WkJ^sH9t-*jvdbDwb8x z2TVqf$yi`A`c1|n$v7Tue`N`L-Pe`CA$xO4kq};@KzKZb@bU!V@l;g?u3!yjbC?)} zC)T7Nv4(_H=efM1;Qi{@^KcJ_V{e6HJ3`SN=m@6&K0>kB=5dZc`?nI@Of~Z!{`QA_ z=YD{{_etY60tStj$@8I-74p<=pspX(ydvZQ?YdYxo+J-xNb;x|OvKhCLjmPw@&qJ# z0ur8X{0`W%1K1QnLe&8}wN|~9_NcyC3*Q&8)Z-0m9+RlRBw_;)wIU|^IU%um1r@!W ziqz~jsBOlR^DDhb3>qjt7K_G$X46MHA%OD$kq!Y32!RI#0s;?}^y;YPB81obzP1a0 zd*PIT!vVe=xP8P2)G$O}#{2>P?4gU}L&R>|%h1>o{$hVBAGqIvkL#dn@wgef77rZ5 zg?wAq@`n=$TVCJ~y&7BI;?GXFo3=d7pXd3rl|OItX9s_FBgxJV{;cQECjPw4pTF^E zhhWK4=)TezVa+=~VCszztuYybY_YNkoj$34mITf&K>%M=XeH>?ds-x~^_H7R-rJb!1M-h@Z>n3t-@yjDHtZAKe=+O<9% zJF&S7K>FiTbbq`8Wpe%LGCr~XRG#3gReT3yb;}c{4&Vu{`FHiZb1nf*=3EY%%()gc znR8O=#C>`C=V{*aNkR%8iz>YlA z`y=_p&Lj+ z8<(UIx}9wpC&-T=t|L#NCr@;jk{FkZu_UA6X%R`u03sz1SmGHVr3Ofu0a77A9yUO< zVaqxa2zgt8#4-OZENp<(8z2n^$N~eTPB0m!Q#;=Pi7*kWlbhjYW!b1~fe|H-_vbQ^ zro%8*=wc$Ywa1iRAkR#r59Xy*1xzMSn3wW|d12)CT0K zM+E2?^hKr!EVhP=&VnyEM-^!icu3kEf#qiBiS8NL%SM0?|Dpfj-!R=V`nwiZ1hVVF z>JWCx%lO{7W(6Ld>c;P)OMcjN$sEM8BGA!fH+GuxebOLYkofrle_5v3=bOdC6jpLssu8b9-`QUts!gHJ#%F@&swrwVI_ zd{yvNRqY5D4^;b>zm$ic*ZH$OFXUVPICjv^!k8K5m9o4tmWMSaIT$F1$uR?0$>zfM z;HdMLuP3RqN`l$c38QJ++2)Y9E<7oB-SWhUmfsJ+BkHfXRhDesE{P2gu(bfecLGtT zn#*~6nJDHD$7-=;q7KjcA~(e;Rnqg*I(Wa%DB*QV%Q-fwSi{A z`PG0T^y}Y@Q^TKC1wgXz%V3kFrm=Pi_U<>WmJbDV z8cP?EXuvVYkCwFYGk9)*JU5^gJ+cjS#U4^*m1Lwp+7M~Aaqdccg)40l%^i@to*4t? zrGYP{=4An2%H##M7)n(~UPsP_y+st@v0@KKQ>Q`_=~KmMf4QYwUHGZsKL6o#aZZZAe2rsSPOEptgR6^x>`!5GO(mKpaiz z#hS(-&H%qRu3>dL)wCFi^TgdCP9A9i;z$)poR1sgKwPam$tC}wPphWSlLBzNz>O`} z8~H#V#m|;Lzn2%>0KzBf^Bwsh^ocNN=%a~{q|cN;rsyNd-1Nyv`wuL~wu~rsu*_wN z)u8_G8m)O2v{-Z7pxL;F*mtVaTS$&a7J(c`8FC25B*%0^jfg}lS*dDrpq&YZ8YQd5FTHK8s#~B$cLuO3*FTWcHCQHgiJQ{2U*9rmj={BT8D` zeHUnTBDoDhS`Q)hHJ@vE@6#^cWBmy=ja~r&)Eg%m=(`yin9lx7qu2aPK&t?0RYY2$ zqT1e?L8!P`qYMQj_?llh`+0{v6a7cHGTqEYue*rtAA9!VMBG8YsyVj?|Y?XffdlW04oBV}Gh?0B#7Qo`|iZ zJylO?z!b!NwCXIPqaKT(CBMp)QA8_ zV4K9THi;t;FgVsT1i~1u29AcSOV!s5-l(}4v_{Oqhr-{$J_zicPBpKQ*bm(a?5{9< zSR;Hm-|*qr3?HWOPgIpC-G84b(!X5`#&WGJ68ahUo>YtThM?@Wu%;x6K1HOPH8vLD z>A&2jJ6?#tNd5H))Z}@vboAspoWq9d1^H=#d^*Z}!l^cF#2Abs?bvX{Rvv^Mu6i%kPq9Hi6XmLLP4EGtf;y?L)}i? zRIG6g>xlzsGTsy3%Gt>yTt0TXJ;G(-?Kr}P)?usq$+tk=N3G&B9Fd|Y$BS2G$Y;Vk z_6r(e;#7cwJ?gm6nXyK6`Wc|DXWnr*ukIgLlTP_1>g8FCwK9rxq+UmiTJ#`{4b$=kTf}7HMjVHa6kVnui3UF#+mJC9qKpBdLl9bHT_23j3k;e49P$& zIF@ID0i_DCTCh|7;0_?sVv#u5^1UB(m(QaWbC&;D{Q=8AZus(ji|!#SXXr>)gh!d3 zCvki8e9i2*%iGI0g13Cl!Zp#o1$Uy7@Z0b{=KiC@iSzTEj<*V`d@IME6&`~%I8Qj0 zPcKxsb_vG_4Q`3-4>}We&z#UM#|JsZgEI!ZtHyN3aF`JKN2(5x4%Fqjey-N^?(mTe zV0p4bA=%-F|80k!_!Pt!NZGjE(`O-BShtTGLNZM*@N75VN`KSFd1HJlYx8z@M&?eA z>>HXF@~y1Ni@p|#?2Gu8tY$PT-}fO{8Juy-JQqrnh*E)|Bqv9cb_wqdK&S5+Bro6C z-;VdA20xjq1$OIu)N|iwEnHcqGRp(VqP}`N#OCu>Y|{9}x9B^%z0!0%2}g}{zQpZ8 zdp(CD%Ga^I*7=&3lSEL5ATdN8bU=4%Rla(M^NDy3Fa?wXkGySepLdP(AD8wpXaR)6FhXtGPC$uipOcTmodFDM19gkygP=Cmf-^%BSS zdLJ#P+iRn*`EfR5!uzvx&1v$V?$8WhphX1j1PgDS@1FaZ4h>f4TX|gc^+;rY#MeA1 zjp1GUOQS?VePqMpJe7ZnRupJs>Bo_;d`tg0-^!`S4L%=inOfuw;rg@<3wN{-Y2cf=gamI2u_z+U0Dnr=XLjg2x5}h#n7M*_!Es`jA?<~@k#E7J)Y`M` z3H7mwfOaLh(0ljgy0`PI_t*F7TcjMhHvU^D`c@W1-_2`5ndk@2nV=EY4t#=rO>1g9 z%h&by%Gvez|2Guu{{Zh=pbM8vd;##AY6^jF0UA7XLr_NL8#Lb0cQoEX;tiC=sU&z` zhz#ce@AgZGcQGoWZxY0T8#xgn5>BjJ6%voZ0LmU-+ZT~%$_~+WVA*KD zEPn26$mHjTzDq7ZOKSc}95cES+_wSZI|4uR6iTQd^7Fm#W%Bc-nGka>2YP9CON8FL}q&tek^7NrU*&AiQi38-Sh4m+ruF;Z07*zH_k4 zV7imYKicWoGn(7`c?{+hB%?`Lx&GENQ9Qnt`G9?)9NB8(8{e9R08d2&w5#UYFn_$aLV0%stNFW*+?MYkEnl zL+ejSTB*WDKJt`b{pKV}6=i{_x05^&n=4`TtvoBZaYykJ!In>O zy(21t@xqK%z|PZuwi6u+%$%@prf=n}A{?EEQzG}y*!0@W;`QgZj30GAdeG5W&p%^h z-;CmpnPcQ*XsA6@Ik4~vmI|F{4y|uUDNT|xNLfLwXj7x%(~_WO{m-k9%tPZoF3Jk@ zV@5QqG)Wh9sZ<8lD1detEjpnSjUAtg^HZn2$aAauF{r8Vbn-V(en*%O@GW|uL`)m6 zqAP`}?f){Ru!6|eh<*V(6?_DV)n6`nReB^r3TMycdOAl>4)GP1e-TM=z_Sn$9DO-k`fcz^RKMTM||6uk;K zKVIOc;KE?(`wT@qhh&?P?$2%onRi$+Cpk8we;CyL16nOLp69rR{rP!}ON{&T_sDkW zx)Y8Z^XU*zjjTGO*lKm)Tf<7%OHz;kYEGzSjtTO!GDRe%x}R`upASkI%~wILZ~m?b z(4HD!BFqrXxK&RXIN#|l?q9E#-+I4~V)E&@6M@q0tKvcs1UCk*Np zB(kViehF{GC}64utQ;5sHj7$MJdq;6>Zey{9xj%g%lr$0VC9Fm#QUmEVlbU`0g*F| z|A$Xq>JsDjc%Y;W*iz1Pv+`(~yS1b6;gSfWl38(Ex4b_(TvpKo&AWYzdYKM5VP)ds zBnB=(0ev2mQ2Poeb^%%!Cs1j6h*84&9Wu%ZZ(de+^7+Nur~q4NI-qcSIaCV~NsL?l z30ib1A6Oedrw9@2P~G=$g9HpfeW_*yMZ4kPEVTeHTLL z$o3Ch&XH_=eiPd(!>2)RqmE_U)>55NQK7iG>{g!lCAJaK=pL`HNxTjC6y=~6dvFf- zt(qg5>~4?DTkSMrG5XM*cb+I?957X#QL*A-Ah)5~W$1z`I)&vJ z%MM|F$kj{Zyk3v`5K|}QPounmAk)>B&+_#DF9I{OGCU<2sDdG$bpQbpOP51QPK-MN zIay=_^^qHmgtzme%)%Q-hV@?AFtFHyJ*pGdORIY4YiJX0Be4oArLW+0F!$T-;;Nn8 z_uHlPwLUbMctc|KTryuknI>~|A@q@Y<%?Q@l`^iDbq|o|A|OPolQ?GJU8>^odiaMU zT!k2ZrbRb<%)otg6k!1Y!Y`X}sk$QgH|apYAL)i2TB8QD(YUq=Liblf3n#qyumpab zOWlPD|28Q_w5IinidL157nqON=|_0d^9` zrGsS&OQnz{>26q*&@RcnrMFZdIdEXN`&Idta_8!U7f#uM{3>%ApiAZ)v4arwy~K?0rHbl3ZPa>DYQxJ{7Xuq!($hN_>yZGAcpn*%|g$< zhp8iM`H&th+>0~xP;O~bf4>2|eWna~UEH1FFZM0kz-naJBQmrAFJV*zLu9p6x%v)_ z=_eLO_Ltpqab$nxZJ+xKILgzsW!|gc6yJJRzg>#&Y8_@$sN4KTSAes}&77h;Yw#eA zkfi+)*&pyN>FobQvY$^fgkI$WJ+`0k1$S7iSc zLErbE2sZ7W_Y)F#K8R~Sv_|%ya?7=m{Zq^bU-Rv#Rb>BZw>XjgXC^;l${Zg9zNV`r z@M&MuED22aHC-ryb9_ylij3?()z?%hfscXUeP*IN|A=ZInErQsPSZYe3tc^Pf99e#N6+epNH(=!|5$Enk65KMF16|y zoCU=ut`)klX1DWx9ye$G>^fBG4A97OmVRc`@8rXze$X2?gU#V$0%55Mg3Bd8N9JSw&|`g%Z1M9Y;W7w~w{8L@$2`;Nolf7vZI{ETStNva)6US^8M{|Ud`)NI`;6#ocUIF4^dod;Gt0Nk zEPtbabZDrP%Tysv7`#>EvV_DVln=r>69Hc|s9}BlqktueLX97QZ#{Z28|rwYpnA;q z>gG4*{gH6smiBso>}sr&*jRu5mR0^@ve-TdFVOnd!V7cIs`nfER)$M1Xt6WxGX1`| zq#cl;Mz)r)kr$iQtJsjn&yfBG3}zPK))jAHz-2=CS^Q@Xu6WSkz{Ov4pyEqUbJd=c zZ0gZF4yyJCRlH}!;?Xn_l(=w)wfe&_F_z&AH(jm3v*iJ8U1Qa6yL=vjjt_p|qT^9W zt#&Q^_f_PhCym&Q;70Tr-rqO5h*?Y=<{ShL82_`f{Fli|LgaQtfRi3RaU>K(T4K-k z{Z6`IjZS!q3ms|O-rEmMl7mF&kc+`V7zx z)9iozxvm6O90UudFkNDtTE_;)7d=$MN9#eN6g{EK0YK|QN@}Ho!V#+x+oL{-^_4hG zR-J*Tnu4EJb=lSEPyP>%n&JABM3Za%?hn~j47Yx_$*h0H_!s;UqzVUr6sX_@tUoL$ z3PJ$h`4WF*p9kxYi#@)kck-D`R~6cJ5vtg-q~vZq%C~S1d?uC_pURth$#0>=*KwDR z9YTVMFr%UK_*Uvnb|k?Z^iG8CtYqeJ6;_ui>PV|~r1BIH~7sMH`B8S>2d6Gtt+ zrn~U#Bqko_RCeBRqqy{%+I>wY(b&Q2jJ+=I7Bx3^f#q(nfdiQQXNDs+EG#kZ8z<=I zuH!2xSkEW?05a${TMD?zN1Sw(yL>-x?_W&R=iX@SW?$1yy7+d#OQjrxf>h$R0~Y_% zqyra^{=Z3@w5p)whAV4n)oP%uxuyEf&Jgi0s9o zBztYXz6W)lV>9wZ@Hw2g7^gSw&AaWRHnnaQYRi;gKF;_D{yfyt7 z=cd2e;=(?V-2u6us%RfsVR zK?UQ3)2i1z2k@lyIB~r8n#ae0OQWn&^R(j>(wEKtyjbs8Ia(mlrIqz zQ=#s`-HYfi9M9aToR~7eABkU0ee`8b!eHW)Th z#+f@Lozre#^KS~ki;1xx301DcO_g|=@n=MPW;UVYDrOvtTYxXD%7u6eVKI%?d@Nol z;SKV9RJN7N!nGeDduwERD^{0y<{t0F#@&lhbo#)VSkK{W?qaLQyir+uf|{_;1wmy? zGT2Gpx%_Pj(qWm*iQ4y&oKp|jN z7ONmCQL4T%sJKA@HQ)b#?tL?FCJ6*}a_d|M9hB*~P#Vd<R5Rr4~*I;=zRbL#h?%auX7fk0;+=>bMD7Q z{!nbVyn;t;U;;({kR~pOr6gTsrFS>0_az&5K8WrzuDTm{zD=~M_jNOBeygs!8?`hw zV%rAc;v7zHz+8z#j5{7D8!XQ#cc~~2511#>zmBq@ytOTLY z^7K?T4e|5K?_71F8$=?LWhHNu~PYr`AZMsOdbfiMMv>1tGot73ijVQ&Er#DRjRXsw8qEWdu z%UzH{UbRxbulRXFI4se}z9geYo>uScVbts*`^f&?04a8HE`LsUaW?*el%@u+8SUk0E*_RhexjRc4Z0)=bYBZL z&5grp*!zmg5(O#h>3${X&X}BHOL3LKV2Low^|*n3V^k8`QU09WCnSV#r1Zs^xcK(> zQ^&~eK$JU(f>Q|onWMs0Z=>cF#l6GJ$I6r1XZeoi1~XF#^B_SKqg4CMvt!ekP$%gv z^`7KNCK+L++&vSGy^L|9H~{~KW!e-&A&{bkGiti4g~Ue zwo=@_l}lt5^})1q@qSuaJp-+L#b~5@Uq7SfR7JS{Mh#sH?xh;FRqbKe`5%QTvI^Q^ z0x5K>#aPWv-z>j~2}K$-sE))yPUdQ*>sxv_V*vOS%lVii#SfP%szl9}`c{coI1kXq zQ9if1LwIZr&rS_btA+<4pl2)v8NJpFviffB9fe1IOn7?lAD$%$?&9F_AG9R=ePZX5 zaMW$!(S>M*lv}9u^|set(bJ*0XHSaO5DlBfH(DvphKf{`i|jZgqq}3URG7VGl=0w- z@HM+tgI#g2^y~*4biE5X=33<}%1|cl5u}OZwlE_MntOFdQT!s-FHZS4^V?+@ttX(_m zMf@g=l0JH&aqg=O9cou2H$)FwhL7{JvyIy4a0Bjtlrg_?RL{n9YY^P5Cn1fjTL;ng)58jiCsUp~F!t-(}+Gh%-&Vv_f+hiJpX`H*8_bBtZ zHEl-Cn-~`x#e;#q9JLJZLjY@W$EYd7Upm}o++&Ah2+HU3!h;Ldo%&8JWLG4ktG&iz z$iC_|=28TT2{;I;OtB6Ozz1b=Ft>-#LGX?udVa6^f;Gxqpj-!Bq=zG{b`s+FMcK)F zX)_Xq7@hzzbhN8mlWyvA6`D7Y#3^Qsjq2-JeW+@w`~WJp0`_wWnIzqHZwG8gR1w9h zneW5N*##4nI^!u+Oo*%BLM^0&ipCk#J*ZzrzY6r%uTt*Vpq=Qh$j_(N^7K|hEoa-W z=NRKojxp}EpO~@@G09~15ib9Ynk2y&C068zFtQ0rtf24oqfZtv>5G;9rSH4+*AWv0 zX(lvYz7F(!@|ow{zn+RB%!Z{1sY0f0CGnr7>d*Y@vkRvY7~sYtXe&69Eb8%76V>A^ z{aBF1<6QN)-{US*2_**n*g$}IAz)KelE6Dz<>%*xZKSCQ9Pl#|k~yK>8CMfd=^W{F zpw;&tFIERsFixb^U^ReGXm5?cHXLgV>kWTGf^^;4bDxX?$tmUwXEx3;kHL-XR%6Z? zynuNjTiH=%e9!Ln&=n-RDW#3(?ssGb!4SDwLYYEybfy6-4T0(XdV9Y|)9V3BAp4j; zne-z2(xmXoNh}KfpGU+RI5&&Ken>RW%iZ-2I*Z)d7+Tc!WFr<+l`pdC`~{2h_9 zUs|v7b`s|LVOVy8mfD~&wUuPluHqetgHKdd`DT$w_DlGHLL@S8|D%Zlo5vuEA^8N5 z4E^|W2>g6)SCFR?&Kw{!2aYV3TJ|q)j`4rIbQ%NRZDGUzXz;d+NmyutcA}Czy`$im> zh?M3M$n7J!(UDF{$8DO?#jjB27}8*VoG(RQ7R!m$nB97U>S4y4p~Y83%%$T6B7t5K z`s1{>${BVXyF)|KWt+nEC*lL6_G8EkhFA_a?mSanB^xy%ppSd#6aPY89d6VN#uXzN z`>F8?0IwduXrRDZDH*?3E<=joLX+I~eE)lw`8`(f#)MlwiRMHokF#Av=5#DTG2hySWGK;s_K8KCvpH-YnVGuSYuh(Wq~nViKd7$Lz}n;5^D{)5OGKoX~=lSOxzsl;HT19px=&w0Xb|baBnw655)wJ1_D^owVSMs z3LxrtoTgPOMm_$Ri%}1w=3Pc8R?2NB4a0XSci?7q&KLb;0A#U5gr3`Rk5Z5;77D5( z?ddWHKyJf(kpU1BN2uxn5Yx!}N)3PryolkWaWj<%G*RG^CXoRUDny1o`R|G{${MLS zpSszSg57{H(hICMNKV`7b~;^w`LbCe(-2L8Qyuc?K%r~~1BeWDg#r+W64duyVV@dF@U%HQn1(~e;Px)vY}Ut6=bd=L${LK*TR zpC~-SJt+QosA38BcVdQ;bTmenOLnK)Crnd**H7=S#6{=ogydp)VeFOcpqDRTElIEB zZ}3zoE6s;BXk{JUF>B>I1w2f!$NopHyVQ{q+@A=TJ!}x9zz3&opwE{@kwC%Eg6a^$ z%Ck^Rp#o);NGL%SC`3x}K#7Ee1~oczL({}v8E~9|8MShZdfu39)iiurgzLGjsFZzn0h)9@m^laB^Xa##5YCm#Un zNjIZv0pW#^Ax%JA>@{kihqgp8fg;N_?>Q0_b@ZYN7r&)cAyXVYdF`jnC{2Q2LN_&2 zB73-4_Ggrxo=!5b7XViJS#^fJ<*&*nb)h@)@>u1RXlRF@C5HBEB4VYy86FBqQ;xyS z>YUk!iJ@I1IC=))9u4hcZD^Njn<3?PBh4KeT7{H0w1Sj2v{C01XK0s5H|oC|Y1Z;5 z^PjAoi_e7oop34S?JIMe_F~yK>4ZtC=v+sJGa-?el?5U_xmUzi92z4|n%_+%)DHN#1{&}-bI9C*s zkP;K%>k_^kNww&737#{iV4AfQ&m~PSzxT)FL&E3DBv;4IDqV8a2dt=Z^^h-ki3UVW zv6x_*Ue!a6r=io?0*gAJAv9uemT1H#(TG7Gj-ZbjbU1ES=ae5R8X<%JLC+z$N1E>x zR;yDi=-TIL4OyUFq?Bv7mjA|hero^V?&^;*4`V07kk1dv-L-}jF;+7UaeL3sc_kx^ zk%<@|J*Idi5P;eZpklZur2A@LW9#1ArnQurKPcf`@(401SH z{QghR(d)2*KN)x6q=Ood$oq>jYLyhDAL)NO!m>Qg!E(xbKRuS^+@Ky<`a}@+E4SO9 z$Ey?md%2|?`h`gI^|4i5lP9!nZ~L2)BKaOt)I=$wx$KB?zdORAT-Ljqaz@RiBI$aP zLv?F^41y3AOycCx2>hp04_+N#b%8SZE0jiO&_2Q^inl{Tn>7GgsREb4vtz1HSy~9>-pNB5>y{&*wm~7 z&afq$PJu0v$y*z7Rh@H6FEJp$$5Tw+T8(?erA!-)N+F{z!+K5Jf4}A6-RW}=k<%Jm zSmgwA`Zb1n5~E>Go|Q8kK-tL`!CYJg5zr5i75Hy>`M|0l!OQSTI{5rae90z^NOvU9 zm!&%LT)HJ9&(~;q7H7jvOpcNpjyqFbUQ7Zz92p8s0+a3MEYFBvxqAOcfyMT7S}=SF zt+IC_@q#`gDBAX;lee2iOy}yU_3<;u5H^Z-AY|mP<@x6&oH?e%HB}xVl(q+--GEsco;IzJyJm40+r7Wm|5|S4Qm_lsK!* zHRp|ea>jM}ZJ0mU=*%CiZcZ$)Ms#PtCJ=lzd;&q**m5r@{=uiNQ3;v)_OzxpW#F{W zqcRZQE#0@DC{+67qmIS#5T~UyhA{7l zixI&{0exi}Wm^j6oPD-LA3wERhYlk!Fs}v&WH%j#lI%oqsfo`%`vuAkq9nF~1|$7E zXVDNkdJ^{9Z#Jnn;WHSR|M=e5<@YO56_BxaDcn(fk~`X4-bwVKKpi?Gpe5v?+TvQM zgAiTfU7-#NK6~G}(JtH#CrH35tG=w14R4%)%2Te!&FY+$-9>>d5;Ewy6!)mWMOuN2 zwE{~S3VhX1?Qgza5v5A_)2QM;4L`H?cqs0pCKPv~grzB|06cs}Ct*kT!yP$p+!Qg> zw+sA8%7{~UWjlX=2t}&zvCEiXMLG+n&+vH$qi7(>Q>Kc3U93{YA-XtE6_3)zdKB4( zQ$2lE7t3`*QVdA&b*zTcE2%2=>ngy(V7o4>ZVNusW!e;i#@1M!YTzvkvg3?XvRGPU81F~R7;(d|5u5F zR~IPB`)@i982Cn5q{cX{oB=??{^nfBD-#FG1BI`o=t4_>k`SdQCpuc5nSXJ)kV8RX z`-V}9@;(}s#Ugl-5yTHa!2v*^?gHvSCpJZ#7_B4bH(>JL(c3urYPpDPZr0nz?;FCO zZbhyu`GF01)JK-k$!3MZ^qooCN?IxfOB!nO4U8JJQ*kmoHA>Ac6&KTY> zY8j*@Av_CZyv`|j3FX5$_mHm^q6^$FKXeLaF43sz1rp&4@iK0O&(ptWfaA1>u*{)>cp8+P#AoRvVD}I$sHMpJaw|V}@73i3V+*>b14kUJV&yZpouUSA9B)`ROon0n7dNkr#WN; zq&pi3pDvj)-Mg%9hK!g{R5NfvzMQq7%l@ACArzLt2%EDpbbA ze3o5-<~o?-rl8PcA|MN?8r8{;6HQQbW3sEia12Om*XEF=l0np6SS#g&?PIxE%JNKf z@8v7Y*e;dV8O%5&)GS4)`8RwPg`wkE18X|X;BKU91HpA%9TVIf2yP0mA=#XY;AE6+ zEa@~_si#nc>ekB-kR?lk7=CqzC+9bWN36rXOLYZU1zn9l+-dJt{X15En*zbLb}26L z8wjqjb8tD&K5ht%?ZcS*(r*76xEqYV?m)yi2|*s_!f_TRmaCOA>MO#wljRr9V@{1r zxPt4{gr~+I&{<2GW+1UtiB-+~uo}ltahHC)hj^1>9AK=;JTC_%RfyR5hY#CY*2R6r zBEEAfv8Ve1>M!98^s;W(dceH&dbJqvPTGT6JDLf55NF%+*V4b>UjpeycQ_XB!Kp65 z=nRZ)7QYIn+=Ehe&Nq7y$r-gj<2|UHS4i!dDdRYB0aCLzN~lrFtZ_Zw+fQgm%q7C) zV87j1tU_W5)Fo^IRY2*v=~b*>LS#fE68}I0eF6gqD(+WFXO7L;%h{qc+_n(kMTXmG z!C8>uwkE03naimHUa8m#c&qpV174zQ>q08UeWw%xjPdpMOfuYtv7$^oktj&ob%xrc zU1z9`?W&=+bM&mFO7gyp*vU}aZz4@(uQTTSi){gbR{joMZw6OJ2Ef-dxh;St?xg$m zlN>`a_>1(LP)4oj(dn-&-ok3h&8%qFs%HGGWM+k5@t=N8eTg28)PU%sgU@sTGE#c1 zIn#&0;A)AmFUo;1w&>m^WhDGQ3ObrOlpkOR;=Sil#a0c%s~6#E>~;jM{d=su^j0Om z@AM$hJL&)@<+qBzkYE04xa)a|Fmkc}ZNM*~5-HOCnFYKj?6o{Suca#_cR7Ab8t}r8 zU%AMDKDF6brQ72E(4(T7V$<6keq*A;orL4uAQ|J(HyV!REEs)DCXBD#SXMsq#v87h zWM-dT;l~aR^{6mW?P)a~TLo*_XRRVCEBPUHzLGj$YSb=+@y=g*O=a1ni4!K42eNxq z6r+lVqzX*S?Aq8_FuoE33BjoLq>lKf?5QzqU} ze$~~J0@?lezW18w`wUdVFH&}@_Z?Dk+^n;2sF-|>0Gc#qB46&I0bu3aQXxE7y^M*D zS*V<_UYixIFPX1QRIh+;<6*U7eaZ~$Aw-besHg@L=i6xKsMXulXM+vX zjM@zV1agpc6?n{rZXoeB0^uWZ5FV`{9Opo|{wft0{)7-VaCp9YU(br4n=josd1CoB zlgr9YlJRjofS}xL)INYKkZ&!43(w>GkvGG$^ye+Fu#%P+zwa66;4k^s%}m)X@ucM=)&!~`>;I z!+ze6SkCZAz`|u=|4gJJrZ=35;!^U+3~sT%8;Omc2`~#^pfJyVu^(Jv(jMgsqw$;U zA9y~#i;XwQU91=IOi17qsei+0p>Vnsrm4c7wh*55SA~E)SxTYJ_Ix2v#;L*zDeNVK zLv`XD;W7|}N&t;UyqL_~1prwl!(mQ3ybDh1VvKNIP!XYR+l?vPu|H?>foN)2O^%FZnYjra$gMC7}6T0hQA^Rt*yCkh4M zh9gUcH`uS92^$uzk+R~WNAs%+W9-?q8SQNuTodIlyU8>zYGl-k_?4qD+3!>sxLa{z z)UdEx0EY=s?CP=PvnP$-CcYM457o512BpZ)Rel7Qe>a$mfGxA~9P}dZnAPio|j7?o{v=5ngQH$vEN@LEw`~vLFB}AZstnhBn-2wTzD5KIlElzs+LhoP2tEm7 z4O&R#hGtDvUj&xq7fgm_H{Dc3@bMN;#=01k zy*yI2DT^21at}a}fr)!nlN@@Y6iQp0qV~Xk>U5I#<`j@OU5g&U_r6Gj)^dp1##4*v zooCMc+Fh)g{N zB#LEZcqw^Z(vp%}H{wXMjXBc*GEtbGGWP*$pfw^F|0_E{lQS1KwFZJ~MpZY@B-Gbe zzfl#i&PmMAUO(+=sxBl5_2<@2=l;W<3v;w71gjzFlrjiiDpk{O&sxSKI;q}DL?My^ z3r-IuQ=l}SM=b$D9=;f4%L}e)xrYPzRRj|G8FlZ1$zt23JKg-n@;RXY#`E??bfSnCirpohxl5jm@@ z6t8viim~@R)6(0cW;Y?)7WFUo^6NX_X1E@FOLoXKv%kv60uSS&xAL>GQ__ui#3jHI zy<>Ew9yJ9x48Y2t=eUWWjGO}BNHFd=10QhogSV@9COR(!nTHhV)Fp%6Xm=qu$& zISkR@W#sjrk?twpd<91SkOF ziJ(&Uoiki#;o-y~EFU@tIVu@@UKg?45Ke8;tu!x`?@*jdb7b}IHc00w&_O8G^v@_Z zB3j~FYQt>W^4$2K?qMD~Cep)%FEK+YSDX&CLwzsgPtaGLleFCerD_$(w1wRB8b&|~ z8?XlgB+_T;sv_9$l;3jyb*K!qsQ^_peuye6E;WOrm7POu=4I3@8p;cMvFqa{vU$6+ zQ(=u{lC*rR=SLweZ?jfW46)PQEva_%aWL+Wz|a7gCVL}F;jxf=ETZ-(VJOIfcY)!4Z%mwvm9>S>~xaGq2qZiV>?ZV@&XESh_~wg4m-&3MG1*|VN|596~8 z0o&ECGaOl{Sf*B~_1dp9`(t^sohpS6*61X%E?4pIgf7*|4LaFc`L*@q3Id-BOFds9#N*XE(;w0hJqoRVl^q7N^goti2X_Y1i=fFE|DrAM8q*JI! zDc_#VA04ffn!#SxIZtnMsnlpusp5`Q>W@RBkR3_LPz`FJO5MOJ_N!7?xIVt>Akm^q zS?NlpZt>c;<1&0HbtvRHQP4>l%pcg>2Fm4uRi-K{p*-1KgXzR=ZQ=EhcO{mqaTW9E zZRCE`qt|c+q8?SnZap-MN|1ua?2iU3qNp=2R8}4)=j_#LtW`_|0NPBz;!K4dJORU> zHTZ-6PZDq%fJP$ypSbv7FDvLIKKN29r|E-ewhs>S>XMEOaP=Yl{i_TP?g;S%#1g?Z z;xnpS83hHb3lb#~!san})X3rAO|ALa8>YQX+ahKqSAqf%;_TBpi3i{^?B71qK|Fvn z{#3xis$eW&bzqUDXVQgG;Kc5r54Y=!(1!*;KAy~J17b6!3+2<@=E(bT^!yX-1n3F* zodgGh7{7$Zi|)6vxd(SSuE!--ICigY^3$z}udLoP*qHk%%!=|R)@8s+M={vmdCtx9 zWO{m8b<^Owr2f*!5fhA{3Gos-Fm{h!6k7@8>0CjA3~DWyre~DQ+E;~!Z@bB~rX(U< zz3G^`w8JRb3vripqLZP7D;q_yt5=o6>kL|S3OPcjB2Ju!3f2@J4joK;+hTG=f@5i$ z)}6~zomR1QoZP@J%lI0~k1Pf2vhM@Mh0sc}EN1m+(zD;WX(S`Q;_9ZVx}-zR;HhX= zjEeL>bZEl%?NjMaRB$L5qy6wOae#~tEzdV6Ye@oCq-8H*0PswhqfWnllmH(MFFCW{ zDgq>|fD$hY_v^3)JgR#vQXL0xU9>=Vh;{nyO;3>)$bV}-l(V|xMCMV>k8oOK^E6=J zv&n@z)}504z#b=uB5yCKL)9$$bq&)-!ZFK zAYO3Zd5f4A)2q&&&DsG#QEnZ2Q`r8O0+h{ocO3@;v8f`cff;my6SCSKmAMTZ;eFOCsiGrK)KY=-0KdN&f(>Q2Cysd+JA>L^A)cCN zr?tJ`7Tz7T2yyx?`VvPErn88RJPAbt@16R|}w z5%$Vna4jcOk^nYYfV=pxPm>wM9#1{=d#NT5G35uu!Dl9lLXk$(SMf6l>Llnpr|UhxWh3Sh(eEYE2f!y~qrWc%N8nwIVU(ThSxp z55pF{y{dI)32)z6S-kOf5ozIQ$D~TifMi6tvOvsSN82 zz})$HO$(>E=2yviO~<6V{WsTMS}C($rt_94kA@I%tE5fUKAhLYL`3{~O;h5}Yr3MN z^P2MhtMi(MZw;RT`k-6&3jY5E|L?+CO*e}rWq3*jDekY40TR>G7(2=c0-UY%AG8?i z4AjY(%U(oY34MZ&-5lXH;)KeIx4W&^lMMuqyNz{bc%n-za*s}#k3Dav=2ql^gKWbO^0X4s8h0aQ)X^md0L)njly(> z)}-5DM~c6v-9{4Ebr>?zeV>|~V2&Kw4>(#J{$S`=rgiGw=7x`%IK%XdDbI#$rD~cL z%S>V$WiWO(VNd|>0LCIOcq%$u+F>GospIRM-7cRwDITR|)}Swbu7ekGCNMa#!eU-z zi67zyd(c99?eQwT2Xn-RVPs4uk~Y7Xgj(%)Fgb9ZowNs(+7=P(j_t{`63BLpEtQA| zUI`V0hGNGhvj8YCW`pB5$7iWi5B+A&pASKVcDUGa_-xYaUz%BWNming zKd}yss3QmqTXjxVNxn0~kitJjGZ!LHcL?Fnl*Kb_1QJ^>zv=)MEwR$ciby^4X+;d= z*1&PaMpc8pp?ApMFY4P6K9bH`5q<9W zghH7QOZxLxU1rx9Ag}$T47h24s7oC2!!ux1V`!0m%zuG zd(NTS!!kQhTf~2wN%gpd;dyh3%Crd2TpeR=ZNB{q+Qi9fasKi=3VHPo@L>}9%0FOB znMjz(p_n-&$*b5*RC9iDvZFb*4Yyqipy&O<1+;_(8&h0B)9>-0+ZI|WgEi3gc*5TN zLjFSF^cZE1aUAj(4^x2PjFO?wGR;bKnaAn?Hb@+#-rlv_6}I~+Y#H(a0ES@Fg(|GH z;S+a&*Bnbh^%yH{$NC0R2{Q{{p5~X;N7)nfvbWfcfSK4-)MSnIBj4|U5t-CvV$x5m+H#D<@j74}>((@?f4{adrb`nkwb3f_D1u{U* zyivUZrs`}_noG`3MB;fYtmc}iF_ebFW}-HRYaL_gio9a1CEio!)UlQu^I=<6A%E!F zd~P|r8U~wLp(X$jh%il!D&c2mz{Al-#RCAbX}4`4v((OGvauQZ5c#gB#5oiOG01@>;b1J-oiv6 z;1AZRe~MhaKrRmlEGTps->bFQByNn{FpUe~040;Lbg|6DPL$hf+y2T0A zrv+9Lsni`yqw+ze04mf%mG2g+{DTy#!r&%h_m{?;H1JK!6-1nJH8?T<`b{J9vBCt> z72uJbn@~R>>82nN5evX9IgsE;Pqwet&0D;4T~^I z^&z+wp-eX_DzRz%_N(ESf3D1XL8;0EIz^s#P-wt)&(6P-AVH;59x4~bBc6>;TI4^ zae%p!A(%pOMqK0UXjo;CC{>-~JSFs}b_%26EEwU1kK^DX5Gjr7kkh*7-vb43Cf=Y`)}>pCDA1b>6+x*Ic77E598FERQCd+rHb-%suER{W z>$m@SF9{rNO>iuB;kaDFFh_Ig3mLbDKg5`qJ^2#^iT1bAAkh^c)})tGjpTg93othr zAz~^GcyN*0FAE`}Y@PtM^vit}B4)_7?%-xhfmw;MQ(dbSZ6YI)49pbQ)M2vy-Rn6G z|E0cC_@@+n$PwU4u@t&tmO2WzO5s&Z1xMjT^#lb3LN#g|Quq)Y!j4QD_Rar+RbxWF zQB%w-%ao<1#vC4A;q8FiNmIyJHn zl#aS9c?+IZNHJ>_DTI}3t=%gQrR9(cjh7Q!7SR<54=qpe>XTFxZ=Ap;Xoc6D?*$TA zIQr5n@bDO(u{#PIp-wpO=#D$u#m z4Npi659eK{97+riVHp$0Cc8$=Wl#QR6Lj}T<0YtCDantkew?5Q6skHxH%0<96`_R6 zx!4nTeV|Xc$;Q-xBYMk(hcy16K1ETrlh*zy8uDyBOg`MipM&_2o1E2rfXVWp4fbR| zOyI9kJF8T;Vk3eoB_r5}eYcW@eibt*3sISFhtb=U99dQ}tkZAyMK*~o-8<$T;4%Cv zaEgPMs;&r%OzgoEw78SzcmA+NH*cl%(fieRRbuy#@WRpV96ErbbrcuJh_#}C0k1T=6!9X~SP3E2OZpH8 zuw8``3mW)s5YwbFJy)B1wR`jvQmIZ8hSb*QtXraV>Xd8i^Mzv5umDniC5(z}eLfHK z%bl&y8}J;a^(v+MNB44NMuy;tz4SXRH?gXJ*dtw2eT8CO1EGXtRnR)~urVhSGd=rC zhgf$Wfw1~S?H=sBAIY9O^Rq$X{bBfbOx1RF4{jm_VCB~HH`{aFI=Yfi&`TTMz}pK5 z+R#RhGS}2f-%TeXd8A5B12quFeIehnJbN3tEt6Jh36JeF?x2g6sG>%qZq6mn=kE4& zrt{U8IJ(RlrmI>iv~b%Hw)_(n{yboLjhL_LxH1?qG`_7_+nEjhhn1`;*8n?pB( zLbK2XO>&36`Itpu|U3gUnS#2BpBi`Kosr5vS2@J7wXGb<*`-VL!s8KYiiII`{T1Fs+qS8>d1bcYD&J2(cFvb7{`#2+z zZ1}zt@ujTgp4n?Dh>ab7bo(N11QxJ#%m%yHXNuwI!s(nY6d1C~Q7A_?t5By>o=AtD zmI!wf>|WD|Dl=q&09(ym$+oKSgoXfB%-1`T#6bKDoWjVDsCrxW931VXTF$*+$~-#U z43tLN8;X(H_niq?LpJmNPQqdJLDqYxnj{i01poRr3P{nx0^;Vc+u?wAK6~Reik+#X zgCC2vOf%@L(}E_@Jan|6cS!fhD2XY?wMLFsFtB?_DfOsJLS@$;?=;SEU=}S^HM?c9 z2|xH;FLX(nv5dYKCQP(bg!rY|`}e)_C4KJ@LIdyEz^Y=Pa+3l)i27d8CDpzq%@K3Z zAVUT1G2%>*qfpl#r&#EqJr0SWJkD@08}8WSD4^7e6EhngXBr}+{d$~do{sZ4+<@W7 zdYq3jc-@i5`PJ7^X}fy&L5jUw+T2|v&|Z<4P9dU}had41k$IhrJ9I$i|JMGF`6^0` ze}DTwAclRC?U*)*8dOj`EsUW!Y7S=FuYDPXVa!3oK(i_}g*->T;`o3ORS_Ss<@0zS z&>7b_8zIsDa**N}0HtDBeXHKXp4!b`qm%rn9)bFBRGr#YUV1jSIJZc5uj~$0IZL7ML0$Gla-+Iqw)?k&ktSd%N8> z4*h@!7P?X-vWwfiFBEfdP8!y-Sc7){oo)Vxw_zisN^geo zz{;Af74wuci}W*BOH0flSbckagRO`gu)=pf{%=w*N?_O5{D(uSOJ{UWsiqwVN2$G9 zQDF)xq*mXddow|)b;zB-6{uyka1~f>7s^FM3F9h;S8bm~#%D=+uG$RC^7O(vW&*VZ zag#?3cKYme1RbrQny%;8T%z*$a)$uFxUF*nENeM90_@QpuLuFmdnxxIz|ZNoLO`6W zjdQV376)bF7Sc*DKsM!M>YAXRV(V5$!bOSBzAZA8aVo*l1+0vPBww|>#15`WrFahMkmx`nj4F~9rboO`Z;K%@BSSbbAj{RWd1D2v$&^g}+Ee_mx zypleSfY>h|^)5i%$$bsa!GuJ8nT1RH9x2m=QVT85*B=hUhm2Q7tWaBS)0za`P*`BRS znVTtLs0>7+Ut-3We5nTx1Vixx19c4|=jaq@skFN-)oR7_u>3sX+gG)hn|=;K{eHw^ zC>gc=B`BM(GDA4ivX@Yzb}!K)MSYystdAVfUWQJN~0sH_FZM%eirUk z?YqU8b22WpeW^ePqf1Z>k3gYXcL+D2pB!@O1DS4z?_0_p-oW0?AVoqs*xTweY6tKE zMLDDws zbs@{1t~1IdBv~=7S`i}(Gm^Fm{wlRP=l6d>aBS3$r$Y)}>X#*^>EfNv@tZ;99@m>8 z>EEL}KnR%lYlWo-n$MsN%>RXwtRcj$r{z}d3Zfh8NwE;Tf|wT(Gou%xgyv{x5oVzs z_5iRv=|;>p&a_X_p%5SqaCDZlBmjwy?Py27q)h-=>|<86z^Fl6R6_;GFs*ou@&4&p z{!Fvgw~0m%mW8GW}V|Tz=hWXpT^_$>7&A`3kj{lZA&dh2_tOl^+a3| zrG+G}m6EoGh@0T?)9Sf{1 zEbNbFEtOMzfSR!@Dp&-8{g<0{XXkj*I3g@6qCS*9g4|g zbqD4q#BTd}uKI?tzVANhu)be(rM?*2AO|Iypwq(2anWr5@nXlBgDi5IdlGja(AL-{ zwISc?S0^kj&)Vxa$KpoKt+MLb9ZPgZ1SKHNDK1K6aPD_5VaGpB3=>5r28;D?ss63RFXX9Y z1Wv19mwS{%Uzp3LYA}2t=V5bIlFgT&%4?~@m!H9Fsm7O|#cQbwjAP6EzLl-}^tX7P zz$Q^vAk39PB$gE@b0vAeGV5V|nXCu(Wy!Bo)}2~}4Ye2Zf#pe`sh!pl$&P_S>xI zr~n~8XT}5KYwsd7^tHgtukj*8eA&m}*tleztIqd6jHwfD_~)!s;u4qy&uy>k2j8>>x4)kda~~!gxePaI3V^@#asUw1 ziq|UTH84cLfgB(Rl0*pNL;LZOGGoS{P?19ES_qiJ^SPuszMuT(_o8$=>Vuzujf4>JPP%?pljOYb!t-la@L!u zFQw`@mVJ}co@GrtJ78JM)+ozv+;(s*i)a6XuDXss$hugEyfgI{cZiS)Th|b~*baDM>K*KKv@X zMN$6fDz|&r=1hTq0I)?bRC=joy_1sa_iqSMBnq=U=S7};_a@Uz_x=NR_93LmW7qpE zP?I@tLI(lKB^9zPQrR*jmzoJVSiF@nxzJ)Cc`v>^mcYKHQwV9K*7Rp<1%Pdv?c zBs>T!{x9fx5YK43>sbSIaG|bI%B-=G41a!1|KO(T4+nD%kFo62Lw2q7n?~MOI0git zR`CMmC zg3S=PG0@Imbl;ot3cBxPf~(IiM_Y{X6HYbJ3-*x9g{_ncpYgzN<#&AcV-sDYq6=6R zpeaLK3i)-Gl~UUTMe#ObRiTBPU8VaNps<7kpaI-bjUJF!F@uI)ppJu9A84WG*ylXK z;TkOh_KbHRcY8VeUEc|R#@?qoo@)@gsrGlv@Wyqxsh9h>@}GI>o0WV%gT5=|Q=})j zD7~KOK|bXdCJ+QnurI+z^kg1-+I90q7O&@5LC+(9LVod=4KgIlKUhWRx$XlMyqOkv zk|0s+RXCiE-;2J(-#89^`Ax1NI^0j$`UvGcUA3`Gbinfl?x9-$-Ihp{Zq92PIJr?( zYNdRArE4hLzD8Gzm`vh6&l0KjwR;3~9-4rr7OHCZ+(%9$XtX@9-{)+yk{(~dSgByH zs^D~0!TGpnJntEO55BTezLa`^n3Zzumvfx-hS%OQO`#ZpB~_{#rK)t!e zewwpP5S=)WxD9>Q%kVgEM1ot+Pplv_YG>p3-+A~&hAusE!n27pzqYN;MXX*LfU$mhr%VRbun%P&z zS8#(=u;wmSfOUE)*RlerTRq{MwTc>m++NN_yp4%tgWpCZy$v_+&^Hd{4GT9cedGJL zpkCaN0{4RYUYPe5aA?8GIZfaDH}9pXdxzkhMity_%T9h@!Nyd@2%qFv$b4-!1gA z9D~layKXxSb2uSqnOumA(OK^Ln*G*opE~PC8$Zu6t)!FHvclD}aT*ryWxqc4NYg6V z!%Z-&_jm_vM5g_ejV(hq8P8*OezVNS-)WEBhJl}VUVz6mt?2+E`z-7cD!r4V!`ICURK%;3>2b?)`Ngs&9v zWe`3;;q$W<)D7u|)q&w-E`Xs4lKTnvMr@1D7sLW);(#6it0i4tI*Knn8F>j1=8^?| zz?HGmJ{1tP+#cWlxYZ2+gdo#aOMy;|U<*XU3Y|Us zSJ+Q20a@CrJtV={xl4?u>+ zHaZq4L^x;v_wa?rx#5#tVT7v!U*Un_8z}HSy7)lwb>x34PK)@SV~ppqg+7UZ;~TKD z3N)z$XC0q|P2mpP0wr4Xw3cvs3k=1A2Fo2@@i$73>K*O$2euQckx<^7tYF6=A*woK zor*r@#kUil*h+sHGwgZ?S2nYcO%a31)P;M&mQ%6=;@sVAd|d*f&ly_%5S!RKH7(=rqICuqDIyJ z8LS!+PD43Nl(cWx)GO;CNJ9G@IkPX2w*LJj+Ioa-iJZN{wwA@p7u%!1gA(K=KeHzvJb?!GZ%@vNmtTr)Fvfh)smkoo+u?^O*CMaEE_v+<6j~nd zP(MZ=MExgY!XG1=)Yzce{@Y(sJtSZKi`BndJFP#aKj4MyuvfqVDfq<;T9^(i27}p> z9tgVm40ePbvbqsSCaaE({b|5?20eA-eHZ`>Pl}1oD`=4G;*Ru8$ z8!fO8or^gGJimz3ngiIU1pOF5Ro)Hc9D%(a@_ON-PcJk3?FuAhW$N|_MHMa@^x5By zai(rQia{1LfpV?-CM;ssv{ST?0>t6MICkR@SIAEd;?R_{h@)bCdQ?07&Qkrg zQu?$K`m_>OP$}d?O0kOKg3kdnr=<}>W*Y1CZG_s+aDh|&de zk7v}pv3xl5wu?~-|4BkfPi?~(LlbUs3hjFS0^1Te#L|^IQzdQ_f7o%iJk2R8@53~s zJn`CByy7SaT7}YRDbSz$>?`z&aX+ETP%;mw9M0(xX5__}3K-6CAto+Lc}W~t_5+WB z37ikq-W~v`W|dz(kJ-XmJL;v1MQVbgrGG)dg}fii1)-b`F`~Mc&p{Mm`3`&`aT; z4Evdvw}}k`ZKx`k{aP!hZ2~0WKq)xz{$!nbtI!jO(K{0O zQGY6Hl{R&An+CYfk3gGRUW(1&1wJ!479-=n8Is79W4MCncvpAl!E}|5{8SMmh!s