Commit 619f4775 authored by heyubin's avatar heyubin Committed by vipwzw

add by hyb for get multisig account by owner

parent f5f0a308
......@@ -158,6 +158,9 @@ signType="secp256k1"
minerdisable=false
minerwhitelist=["*"]
[wallet.sub.multisig]
rescanMultisigAddr=false
[exec]
isFree=false
minExecFee=100000
......
......@@ -51,6 +51,7 @@ func MultiSigAccountCmd() *cobra.Command {
GetMultiSigAccUnSpentTodayCmd(),
GetMultiSigAccAssetsCmd(),
GetMultiSigAccAllAddressCmd(),
GetMultiSigAccByOwnerCmd(),
)
return cmd
}
......@@ -1100,3 +1101,30 @@ func isValidDailylimit(dailylimit float64) error {
}
return nil
}
//GetMultiSigAccByOwnerCmd 获取指定地址拥有的所有多重签名账户
func GetMultiSigAccByOwnerCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "owner",
Short: "get multisig accounts by the owner",
Run: getMultiSigAccByOwner,
}
getMultiSigAccByOwnerFlags(cmd)
return cmd
}
func getMultiSigAccByOwnerFlags(cmd *cobra.Command) {
cmd.Flags().StringP("addr", "a", "", "address of owner")
}
func getMultiSigAccByOwner(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ownerAddr, _ := cmd.Flags().GetString("addr")
params := &types.ReqString{
Data: ownerAddr,
}
var res mty.OwnerAttrs
ctx := jsonclient.NewRPCCtx(rpcLaddr, "multisig.MultiSigAddresList", params, &res)
ctx.Run()
}
......@@ -34,6 +34,7 @@ Available Commands:
creator get all multisig accounts created by the address
dailylimit Create a modify assets dailylimit transaction
info get multisig account info
owner get multisig accounts by the owner
unspent get assets unspent today amount
weight Create a modify required weight transaction
......@@ -194,4 +195,6 @@ cli send multisig tx confirm -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -i 8 -k "1
cli send multisig tx confirm -a "13q53Ga1kquDCqx7EWF8FU94tLUK18Zd47" -i 8 -k "1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK"
// 获取owner拥有的所有多重签名地址,不指定地址时返回的是本钱包拥有的所有多重签名地址
cli multisig account owner -a 166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf
*/
......@@ -192,6 +192,8 @@ func (m *MultiSig) Query_MultiSigTxInfo(in *mty.ReqMultiSigTxInfo) (types.Messag
}
if multiSigTx == nil {
multiSigTx = &mty.MultiSigTx{}
} else { //由于代码中使用hex.EncodeToString()接口转换的,没有加0x,为了方便上层统一处理再次返回时增加0x即可
multiSigTx.TxHash = "0x" + multiSigTx.TxHash
}
return multiSigTx, nil
}
......
......@@ -6,6 +6,7 @@ import (
"github.com/33cn/plugin/plugin/dapp/multisig/executor"
"github.com/33cn/plugin/plugin/dapp/multisig/rpc"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
_ "github.com/33cn/plugin/plugin/dapp/multisig/wallet" // register wallet package
)
func init() {
......
......@@ -338,4 +338,15 @@ message Assets {
//账户地址列表
message AccAddress {
repeated string address = 1;
}
//owner拥有的多重签名账户信息
message OwnerAttr {
string multiSigAddr = 1;
string ownerAddr = 2;
uint64 weight = 3;
}
message OwnerAttrs {
repeated OwnerAttr items = 1;
}
\ No newline at end of file
......@@ -91,3 +91,13 @@ func (c *Jrpc) MultiSigAccTransferOutTx(param *mty.MultiSigExecTransferFrom, res
*result = hex.EncodeToString(data)
return nil
}
// MultiSigAddresList 获取owner地址上的多重签名账户列表{multiSigAddr,owneraddr,weight}
func (c *Jrpc) MultiSigAddresList(in *types.ReqString, result *interface{}) error {
reply, err := c.cli.ExecWalletFunc(mty.MultiSigX, "MultiSigAddresList", in)
if err != nil {
return err
}
*result = reply
return nil
}
......@@ -193,6 +193,14 @@ func testAccCreateTx(t *testing.T, mocker *testnode.Chain33Mock, jrpcClient *jso
assert.Equal(t, rep3.Address[0], multiSigAccAddr)
//t.Log(rep3)
//获取owner拥有的多重签名账户地址
req4 := &types.ReqString{
Data: GenAddr,
}
var res4 mty.OwnerAttrs
err = jrpcClient.Call("multisig.MultiSigAddresList", req4, &res4)
assert.Nil(t, err)
assert.Equal(t, res4.Items[0].OwnerAddr, GenAddr)
return multiSigAccAddr
}
......
......@@ -5,10 +5,9 @@ package types
import (
fmt "fmt"
math "math"
types "github.com/33cn/chain33/types"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
......@@ -2561,6 +2560,101 @@ func (m *AccAddress) GetAddress() []string {
return nil
}
//owner拥有的多重签名账户信息
type OwnerAttr struct {
MultiSigAddr string `protobuf:"bytes,1,opt,name=multiSigAddr,proto3" json:"multiSigAddr,omitempty"`
OwnerAddr string `protobuf:"bytes,2,opt,name=ownerAddr,proto3" json:"ownerAddr,omitempty"`
Weight uint64 `protobuf:"varint,3,opt,name=weight,proto3" json:"weight,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *OwnerAttr) Reset() { *m = OwnerAttr{} }
func (m *OwnerAttr) String() string { return proto.CompactTextString(m) }
func (*OwnerAttr) ProtoMessage() {}
func (*OwnerAttr) Descriptor() ([]byte, []int) {
return fileDescriptor_62b8b91adf3febfa, []int{41}
}
func (m *OwnerAttr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_OwnerAttr.Unmarshal(m, b)
}
func (m *OwnerAttr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_OwnerAttr.Marshal(b, m, deterministic)
}
func (m *OwnerAttr) XXX_Merge(src proto.Message) {
xxx_messageInfo_OwnerAttr.Merge(m, src)
}
func (m *OwnerAttr) XXX_Size() int {
return xxx_messageInfo_OwnerAttr.Size(m)
}
func (m *OwnerAttr) XXX_DiscardUnknown() {
xxx_messageInfo_OwnerAttr.DiscardUnknown(m)
}
var xxx_messageInfo_OwnerAttr proto.InternalMessageInfo
func (m *OwnerAttr) GetMultiSigAddr() string {
if m != nil {
return m.MultiSigAddr
}
return ""
}
func (m *OwnerAttr) GetOwnerAddr() string {
if m != nil {
return m.OwnerAddr
}
return ""
}
func (m *OwnerAttr) GetWeight() uint64 {
if m != nil {
return m.Weight
}
return 0
}
type OwnerAttrs struct {
Items []*OwnerAttr `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *OwnerAttrs) Reset() { *m = OwnerAttrs{} }
func (m *OwnerAttrs) String() string { return proto.CompactTextString(m) }
func (*OwnerAttrs) ProtoMessage() {}
func (*OwnerAttrs) Descriptor() ([]byte, []int) {
return fileDescriptor_62b8b91adf3febfa, []int{42}
}
func (m *OwnerAttrs) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_OwnerAttrs.Unmarshal(m, b)
}
func (m *OwnerAttrs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_OwnerAttrs.Marshal(b, m, deterministic)
}
func (m *OwnerAttrs) XXX_Merge(src proto.Message) {
xxx_messageInfo_OwnerAttrs.Merge(m, src)
}
func (m *OwnerAttrs) XXX_Size() int {
return xxx_messageInfo_OwnerAttrs.Size(m)
}
func (m *OwnerAttrs) XXX_DiscardUnknown() {
xxx_messageInfo_OwnerAttrs.DiscardUnknown(m)
}
var xxx_messageInfo_OwnerAttrs proto.InternalMessageInfo
func (m *OwnerAttrs) GetItems() []*OwnerAttr {
if m != nil {
return m.Items
}
return nil
}
func init() {
proto.RegisterType((*MultiSig)(nil), "types.MultiSig")
proto.RegisterType((*ConfirmedOwner)(nil), "types.ConfirmedOwner")
......@@ -2603,106 +2697,111 @@ func init() {
proto.RegisterType((*AccAssets)(nil), "types.AccAssets")
proto.RegisterType((*Assets)(nil), "types.Assets")
proto.RegisterType((*AccAddress)(nil), "types.AccAddress")
proto.RegisterType((*OwnerAttr)(nil), "types.OwnerAttr")
proto.RegisterType((*OwnerAttrs)(nil), "types.OwnerAttrs")
}
func init() { proto.RegisterFile("multisig.proto", fileDescriptor_62b8b91adf3febfa) }
var fileDescriptor_62b8b91adf3febfa = []byte{
// 1535 bytes of a gzipped FileDescriptorProto
// 1572 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x18, 0xdd, 0x6e, 0xdc, 0x44,
0x37, 0xde, 0xbf, 0x64, 0xcf, 0x26, 0xdb, 0x64, 0xbe, 0x55, 0x3e, 0x13, 0x4a, 0x59, 0x8d, 0x4a,
0x37, 0xf6, 0xfe, 0x24, 0x7b, 0x92, 0x6c, 0x93, 0xf9, 0xa2, 0x7c, 0x26, 0x94, 0x12, 0x8d, 0x4a,
0xb5, 0xaa, 0x20, 0x42, 0x69, 0xa1, 0x14, 0x09, 0xd4, 0xa5, 0x69, 0x95, 0xaa, 0xa4, 0x29, 0xd3,
0xad, 0x2a, 0x21, 0x71, 0xe1, 0xd8, 0x93, 0xd4, 0x62, 0xd7, 0xde, 0xda, 0xde, 0x64, 0x17, 0x90,
0xca, 0x25, 0x2f, 0x00, 0x17, 0x5c, 0x20, 0x1e, 0x82, 0x0b, 0x9e, 0x00, 0x5e, 0x80, 0xb7, 0xe0,
0x1a, 0x71, 0x8b, 0xe6, 0xcf, 0x9e, 0xb1, 0x9d, 0xc8, 0x95, 0x0a, 0x42, 0xdc, 0xf9, 0x9c, 0x39,
0x73, 0xfe, 0xff, 0x3c, 0xd0, 0x9d, 0xcc, 0xc6, 0x89, 0x1f, 0xfb, 0xc7, 0xdb, 0xd3, 0x28, 0x4c,
0x42, 0xd4, 0x4c, 0x16, 0x53, 0x1a, 0x6f, 0xad, 0x39, 0xae, 0x1b, 0xce, 0x82, 0x44, 0x60, 0xf1,
0xef, 0x16, 0xac, 0xec, 0x33, 0xc2, 0x47, 0xfe, 0x31, 0xba, 0x04, 0xe0, 0x46, 0xd4, 0x49, 0xe8,
0xd0, 0xf3, 0x22, 0xdb, 0xea, 0x5b, 0x83, 0x36, 0xd1, 0x30, 0x08, 0xc3, 0xea, 0x44, 0xd2, 0x72,
0x8a, 0x1a, 0xa7, 0x30, 0x70, 0xe8, 0x32, 0xb4, 0xc2, 0xd3, 0x80, 0x46, 0xb1, 0x5d, 0xef, 0xd7,
0x07, 0x9d, 0x9d, 0xd5, 0x6d, 0x2e, 0x77, 0xfb, 0x80, 0x21, 0x89, 0x3c, 0x43, 0xd7, 0xa0, 0xe3,
0x39, 0xfe, 0x78, 0xf1, 0xb1, 0x3f, 0xf1, 0x93, 0xd8, 0x6e, 0x70, 0xd2, 0x0d, 0x49, 0xba, 0x9b,
0x9e, 0x10, 0x9d, 0x0a, 0xd9, 0xb0, 0x9c, 0xcc, 0x6f, 0x33, 0xe5, 0xed, 0x66, 0xdf, 0x1a, 0x34,
0x88, 0x02, 0xd1, 0x15, 0xe8, 0x46, 0xf4, 0xd9, 0xcc, 0x8f, 0xa8, 0xf7, 0x84, 0xfa, 0xc7, 0x4f,
0x13, 0xbb, 0xc5, 0x09, 0x72, 0x58, 0x7c, 0x17, 0xba, 0xb7, 0xc3, 0xe0, 0xc8, 0x8f, 0x26, 0xd4,
0xe3, 0x0a, 0xa1, 0xeb, 0xd0, 0x75, 0x0d, 0x8c, 0x6d, 0x95, 0xa8, 0x9d, 0xa3, 0xc1, 0xbf, 0x58,
0x00, 0xca, 0x6b, 0xa3, 0x39, 0x42, 0xd0, 0x48, 0xe6, 0xbe, 0xc7, 0x3d, 0xd6, 0x20, 0xfc, 0x1b,
0x6d, 0x42, 0x2b, 0x99, 0xef, 0x39, 0xf1, 0x53, 0xe9, 0x25, 0x09, 0xa1, 0x2d, 0x58, 0xa1, 0x73,
0xea, 0xce, 0x12, 0xea, 0xd9, 0xf5, 0xbe, 0x35, 0x58, 0x21, 0x29, 0x2c, 0xee, 0x8c, 0x16, 0x53,
0x6a, 0x37, 0x38, 0x27, 0x09, 0x15, 0xfc, 0xde, 0x2c, 0xf1, 0x7b, 0xd1, 0x90, 0x56, 0x05, 0x43,
0x3e, 0x80, 0xa6, 0xf0, 0xc3, 0x45, 0x68, 0xf3, 0xd0, 0x68, 0x91, 0xcf, 0x10, 0x4c, 0xb1, 0x53,
0xe1, 0xd7, 0x9a, 0x50, 0x4c, 0x40, 0xf8, 0x3b, 0x0b, 0x20, 0x8b, 0x16, 0x23, 0x8b, 0x17, 0x93,
0xc3, 0x70, 0x2c, 0x39, 0x48, 0x88, 0xe1, 0x99, 0x8d, 0x54, 0x65, 0x8c, 0x84, 0x58, 0xbe, 0x65,
0xf1, 0xe5, 0xde, 0x68, 0x10, 0x0d, 0xc3, 0xce, 0xe3, 0x29, 0x0d, 0x92, 0x51, 0xe8, 0x39, 0x0b,
0xe9, 0x13, 0x0d, 0xc3, 0x12, 0x62, 0xec, 0xc4, 0xc9, 0xae, 0xb3, 0xe0, 0x2e, 0xa9, 0x13, 0x05,
0xe2, 0x43, 0x58, 0x7f, 0xc4, 0x65, 0xff, 0x7d, 0xda, 0xe1, 0x6f, 0x1b, 0xd0, 0x55, 0x49, 0x30,
0x74, 0x13, 0x3f, 0x0c, 0xd0, 0x1e, 0x6c, 0xa4, 0x41, 0x71, 0xdd, 0xdb, 0xbc, 0x72, 0xb8, 0xb4,
0xce, 0x8e, 0x2d, 0xe3, 0xb0, 0x9f, 0x3f, 0xdf, 0x5b, 0x22, 0xc5, 0x4b, 0xe8, 0x13, 0xe8, 0x29,
0x24, 0x0f, 0xd0, 0xc1, 0x94, 0x46, 0x8c, 0x59, 0x8d, 0x33, 0x7b, 0x35, 0xc7, 0x4c, 0x27, 0xd9,
0x5b, 0x22, 0xa5, 0x57, 0xd1, 0x7d, 0x40, 0x9a, 0x1c, 0xc5, 0xb0, 0xce, 0x19, 0xbe, 0x52, 0xd4,
0x2e, 0x63, 0x57, 0x72, 0x4d, 0xb7, 0x54, 0x56, 0xd4, 0x68, 0xce, 0x23, 0x54, 0xb4, 0x34, 0x3d,
0xd7, 0x2d, 0x4d, 0x91, 0xe8, 0x09, 0x6c, 0x2a, 0xe4, 0x9d, 0x39, 0x75, 0x47, 0x91, 0x13, 0xc4,
0x47, 0x34, 0x1a, 0x85, 0x3c, 0xa6, 0x9d, 0x9d, 0xd7, 0x72, 0xec, 0x4c, 0xa2, 0xbd, 0x25, 0x72,
0xc6, 0x75, 0xf4, 0x19, 0xd8, 0x65, 0x27, 0x77, 0xa3, 0x70, 0xc2, 0xdb, 0x43, 0x67, 0xe7, 0xf5,
0x73, 0x58, 0x33, 0xb2, 0xbd, 0x25, 0x72, 0x26, 0x0b, 0xd4, 0x85, 0xda, 0x68, 0x61, 0x2f, 0xf7,
0xad, 0x41, 0x93, 0xd4, 0x46, 0x8b, 0x8f, 0x96, 0xa1, 0x79, 0xe2, 0x8c, 0x67, 0x14, 0x7f, 0x6f,
0xc1, 0x46, 0x21, 0xca, 0x5a, 0x5f, 0xb4, 0xce, 0xe9, 0x8b, 0xc5, 0x46, 0x56, 0x2b, 0x6b, 0x64,
0xe8, 0x46, 0x21, 0x37, 0x3b, 0x3b, 0xff, 0x97, 0x1c, 0xf3, 0x89, 0x6f, 0x24, 0xed, 0xcf, 0x16,
0xf4, 0xca, 0xb2, 0x06, 0x0d, 0xe0, 0x82, 0x16, 0x66, 0xad, 0x0d, 0xe4, 0xd1, 0xac, 0x83, 0x85,
0x63, 0xd9, 0x63, 0x44, 0xc5, 0xa4, 0x30, 0x3b, 0x0b, 0xe8, 0xa9, 0x38, 0xab, 0x8b, 0x33, 0x05,
0xb3, 0x16, 0x13, 0xd0, 0x53, 0x69, 0x96, 0x28, 0xe6, 0x0c, 0x81, 0xfa, 0xd0, 0x09, 0x85, 0x2a,
0x77, 0xc7, 0xce, 0xb1, 0x6c, 0xf0, 0x3a, 0x0a, 0xff, 0x6a, 0x01, 0x2a, 0xe6, 0xe7, 0x0b, 0x28,
0x6e, 0x3a, 0xad, 0x56, 0xd9, 0x69, 0xe8, 0x4d, 0xd8, 0x08, 0xe8, 0x29, 0x31, 0x03, 0x23, 0x1a,
0x42, 0xf1, 0x20, 0x6f, 0x49, 0x83, 0x37, 0x79, 0xc3, 0x92, 0x1f, 0x2c, 0xb0, 0xcf, 0xca, 0xb9,
0xf3, 0xda, 0x94, 0x33, 0xe1, 0xc3, 0xaf, 0xc6, 0x7b, 0x9d, 0x84, 0xd8, 0xf0, 0x09, 0x42, 0x59,
0xc8, 0x6d, 0xc2, 0xbf, 0xd5, 0x90, 0x09, 0x9c, 0x89, 0x18, 0x25, 0x6d, 0x92, 0xc2, 0x2c, 0x6f,
0x93, 0x50, 0x8e, 0x90, 0x5a, 0x12, 0xb2, 0xfb, 0x47, 0xaa, 0x24, 0xda, 0x84, 0x7f, 0xe3, 0x6f,
0x2c, 0xd8, 0x2c, 0xaf, 0xb7, 0x7f, 0x5a, 0x3d, 0xfc, 0x65, 0x56, 0x4c, 0x59, 0xcf, 0xa8, 0x1e,
0x73, 0x3e, 0x9a, 0xef, 0x79, 0xb2, 0x8c, 0xf8, 0x37, 0xbb, 0x2d, 0xc7, 0xe0, 0x41, 0x44, 0xe8,
0x49, 0xf8, 0x39, 0x95, 0x93, 0x38, 0x8f, 0xc6, 0x37, 0xe1, 0x02, 0xa1, 0xcf, 0xb4, 0xa4, 0x8b,
0x51, 0x0f, 0x9a, 0x71, 0xe2, 0x44, 0x09, 0x17, 0x58, 0x27, 0x02, 0x40, 0xeb, 0x50, 0xa7, 0x81,
0x27, 0x4d, 0x67, 0x9f, 0xf8, 0x2d, 0xd8, 0x20, 0x74, 0x3a, 0x5e, 0x18, 0x97, 0x6d, 0x58, 0x76,
0x3c, 0x2f, 0xa2, 0xb1, 0xe8, 0x02, 0x6d, 0xa2, 0x40, 0xfc, 0x21, 0x20, 0x53, 0xd2, 0xbd, 0xe0,
0x28, 0xac, 0x6e, 0x27, 0xfe, 0xd3, 0x82, 0x5e, 0x5e, 0x1e, 0x67, 0xf1, 0x9f, 0xdf, 0xe9, 0x7e,
0xb4, 0x60, 0x5d, 0x73, 0xdd, 0x68, 0xee, 0x7b, 0x71, 0xc1, 0x2a, 0xab, 0xc4, 0xaa, 0x2d, 0x58,
0x61, 0xc9, 0x3e, 0xca, 0xd2, 0x23, 0x85, 0xf9, 0x26, 0x16, 0xf2, 0x93, 0xba, 0xdc, 0xc4, 0x38,
0xc4, 0xd4, 0x9d, 0xd2, 0xc0, 0xf3, 0x03, 0x55, 0xd7, 0x0a, 0x34, 0xf6, 0xba, 0xa6, 0xb9, 0xd7,
0xe1, 0x07, 0x2c, 0xb8, 0x5a, 0x6c, 0xaa, 0xeb, 0xd8, 0x83, 0x26, 0xdb, 0x26, 0x63, 0xbb, 0xd6,
0xaf, 0x0f, 0x1a, 0x44, 0x00, 0xf8, 0x3e, 0xcb, 0x2d, 0xcd, 0x62, 0x1e, 0xe8, 0x2a, 0xec, 0x4a,
0xaa, 0x01, 0x3f, 0x84, 0xff, 0xe5, 0x94, 0xe3, 0xec, 0x6e, 0xca, 0x1f, 0x88, 0x14, 0x23, 0xf7,
0x98, 0x8d, 0xdc, 0xcc, 0x1c, 0xcd, 0x49, 0x8e, 0x10, 0x4f, 0x61, 0xcb, 0xcc, 0xe5, 0xc7, 0xc1,
0xa3, 0x6c, 0x69, 0xab, 0xa2, 0xe7, 0x59, 0x2b, 0x59, 0xd6, 0x7c, 0xea, 0x7a, 0xf3, 0xc1, 0x0f,
0xa5, 0x83, 0xa5, 0xa0, 0x61, 0x1c, 0xd3, 0x24, 0x46, 0xef, 0xc3, 0xda, 0x4c, 0x47, 0xc8, 0xec,
0xed, 0x49, 0x0b, 0x0c, 0x62, 0x62, 0x92, 0xe2, 0x07, 0xb0, 0x66, 0x32, 0x7b, 0x03, 0x5a, 0x8e,
0xe0, 0x22, 0xfc, 0xb0, 0x26, 0xb9, 0xc8, 0xeb, 0xf2, 0x30, 0xd7, 0x06, 0x1b, 0xaa, 0x0d, 0xe2,
0x77, 0x58, 0x27, 0x71, 0xa9, 0x3f, 0x4d, 0xd2, 0xbf, 0xad, 0x0a, 0x8e, 0xc0, 0x5f, 0xb0, 0xaa,
0xe6, 0xd7, 0x0e, 0xe4, 0x32, 0x7e, 0x10, 0xed, 0xd2, 0x71, 0x25, 0x27, 0x62, 0x68, 0x86, 0xe9,
0x90, 0xce, 0x17, 0xad, 0x38, 0x62, 0x59, 0xeb, 0x48, 0x9e, 0xea, 0x6f, 0x44, 0xc1, 0xf8, 0x27,
0xcb, 0x14, 0xbe, 0x1f, 0x7a, 0xac, 0x31, 0x4e, 0x2b, 0x09, 0xbf, 0x0a, 0xed, 0x69, 0x44, 0x4f,
0x0e, 0xce, 0x54, 0x20, 0x3b, 0x46, 0x6f, 0xc3, 0xaa, 0x3b, 0x8b, 0x22, 0x1a, 0x24, 0xd9, 0xe2,
0x90, 0x27, 0x37, 0x28, 0x98, 0xda, 0x13, 0xa9, 0x8d, 0xac, 0xc3, 0x14, 0xc6, 0xcf, 0x59, 0x3e,
0x73, 0xad, 0x45, 0x83, 0xd8, 0x0f, 0x3d, 0xff, 0xa8, 0x5a, 0xda, 0x5d, 0x02, 0x60, 0x5a, 0x19,
0x9b, 0x97, 0x86, 0x41, 0x97, 0x61, 0x4d, 0xaa, 0x61, 0xec, 0x00, 0x26, 0x12, 0xff, 0x66, 0x81,
0x2d, 0x35, 0xc8, 0xba, 0x9e, 0xda, 0x56, 0xaa, 0xa8, 0x71, 0x13, 0xba, 0x4c, 0xe8, 0x6e, 0x7e,
0x57, 0x29, 0xe9, 0xa5, 0x39, 0x42, 0x74, 0x83, 0x6b, 0xb8, 0x9b, 0x5f, 0x0d, 0x4b, 0x6e, 0x9a,
0x74, 0x6c, 0x69, 0xe1, 0x81, 0x17, 0xde, 0x52, 0x4b, 0x8b, 0x86, 0xc2, 0x5f, 0xf3, 0x3e, 0xcb,
0xcd, 0xca, 0x06, 0xf1, 0xad, 0x6c, 0x40, 0x8d, 0xe6, 0xea, 0xff, 0x99, 0x49, 0xdc, 0x2c, 0xb4,
0x09, 0x11, 0xc7, 0x3c, 0x39, 0xba, 0x0a, 0xeb, 0xea, 0x9f, 0x34, 0x9d, 0xc6, 0x35, 0x2e, 0xbd,
0x80, 0x67, 0x19, 0xb9, 0x25, 0x55, 0x18, 0xba, 0x6e, 0xa6, 0xfd, 0xe3, 0xa9, 0xf7, 0x2f, 0xf6,
0x2d, 0xfe, 0xc3, 0x62, 0xfd, 0xda, 0x28, 0xfe, 0x97, 0xe2, 0x3a, 0x0c, 0xab, 0x4c, 0xc5, 0x3b,
0x6a, 0xec, 0x08, 0xb7, 0x19, 0x38, 0x16, 0x57, 0x77, 0x16, 0xdd, 0x31, 0x5f, 0x1c, 0x74, 0x14,
0xdb, 0x31, 0xe2, 0xd9, 0x21, 0x4b, 0xd1, 0x48, 0xc6, 0x55, 0x46, 0x3f, 0x8f, 0xd6, 0x9e, 0x34,
0x9a, 0xc6, 0x93, 0x46, 0xf6, 0x6c, 0xd1, 0xd2, 0x9f, 0x2d, 0xf0, 0xa7, 0x69, 0xff, 0x18, 0x89,
0x99, 0xfe, 0x02, 0x71, 0x62, 0x6b, 0xcb, 0x2c, 0x92, 0xf7, 0x54, 0x29, 0x66, 0x18, 0xfc, 0x1c,
0x2e, 0xec, 0x17, 0xdd, 0x51, 0x6d, 0x00, 0xfa, 0xda, 0x00, 0xf4, 0xbd, 0x92, 0x97, 0x93, 0xb2,
0x06, 0x94, 0x7f, 0x39, 0xb9, 0x08, 0xad, 0xc7, 0x7e, 0x90, 0xbc, 0x7b, 0x9d, 0xf1, 0xf4, 0x9c,
0xc4, 0x51, 0xaf, 0x3f, 0xec, 0x1b, 0x47, 0xb0, 0x36, 0x14, 0xef, 0x6c, 0x72, 0x7c, 0x54, 0x51,
0x2e, 0x1b, 0x31, 0xb5, 0x6a, 0x23, 0xa6, 0xae, 0x6f, 0xda, 0x38, 0x84, 0x55, 0x42, 0x9f, 0xb1,
0x85, 0xf0, 0xa5, 0x8b, 0xec, 0x41, 0xd3, 0x8f, 0x87, 0x63, 0x35, 0x23, 0x04, 0x80, 0x6f, 0x41,
0x97, 0x4f, 0xdd, 0x4c, 0xe4, 0x36, 0xb4, 0x1d, 0x05, 0xc8, 0xff, 0xdc, 0x75, 0xc5, 0x51, 0xe1,
0x49, 0x46, 0x82, 0xbf, 0x82, 0x76, 0x76, 0xb9, 0xe2, 0x84, 0xbd, 0x04, 0x10, 0x51, 0xf7, 0x64,
0xa8, 0xff, 0x6c, 0x68, 0x18, 0x34, 0x80, 0x65, 0xf9, 0xc4, 0x29, 0xe3, 0xd8, 0xcd, 0x34, 0x60,
0x58, 0xa2, 0x8e, 0xf1, 0x7b, 0xd0, 0x1a, 0xa6, 0x2e, 0x95, 0xfb, 0x86, 0x75, 0xc6, 0xbe, 0x51,
0x33, 0xf6, 0x8d, 0x2b, 0x00, 0x72, 0xf1, 0xa6, 0xf1, 0x39, 0x5b, 0xfd, 0x61, 0x8b, 0x3f, 0xb2,
0x5e, 0xfb, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x6c, 0xd0, 0xe8, 0xee, 0x8c, 0x15, 0x00, 0x00,
0x1a, 0x71, 0x8b, 0xe6, 0xcf, 0x9e, 0xb1, 0xbd, 0x91, 0x2b, 0x15, 0x84, 0xb8, 0xf3, 0x39, 0x73,
0xe6, 0xfc, 0xff, 0x79, 0xa0, 0x3b, 0x9a, 0x0c, 0xd3, 0x20, 0x09, 0x4e, 0x76, 0xc6, 0x71, 0x94,
0x46, 0xa8, 0x95, 0xce, 0xc6, 0x34, 0xd9, 0x5a, 0x75, 0x3d, 0x2f, 0x9a, 0x84, 0xa9, 0xc0, 0xe2,
0xdf, 0x2d, 0x58, 0x3a, 0x60, 0x84, 0x8f, 0x82, 0x13, 0x74, 0x09, 0xc0, 0x8b, 0xa9, 0x9b, 0xd2,
0xbe, 0xef, 0xc7, 0x8e, 0xb5, 0x6d, 0xf5, 0x3a, 0x44, 0xc3, 0x20, 0x0c, 0x2b, 0x23, 0x49, 0xcb,
0x29, 0x6c, 0x4e, 0x61, 0xe0, 0xd0, 0x65, 0x68, 0x47, 0x67, 0x21, 0x8d, 0x13, 0xa7, 0xb1, 0xdd,
0xe8, 0x2d, 0xef, 0xae, 0xec, 0x70, 0xb9, 0x3b, 0x87, 0x0c, 0x49, 0xe4, 0x19, 0xba, 0x06, 0xcb,
0xbe, 0x1b, 0x0c, 0x67, 0x1f, 0x07, 0xa3, 0x20, 0x4d, 0x9c, 0x26, 0x27, 0x5d, 0x97, 0xa4, 0x7b,
0xd9, 0x09, 0xd1, 0xa9, 0x90, 0x03, 0x8b, 0xe9, 0xf4, 0x36, 0x53, 0xde, 0x69, 0x6d, 0x5b, 0xbd,
0x26, 0x51, 0x20, 0xba, 0x02, 0xdd, 0x98, 0x3e, 0x9b, 0x04, 0x31, 0xf5, 0x9f, 0xd0, 0xe0, 0xe4,
0x69, 0xea, 0xb4, 0x39, 0x41, 0x01, 0x8b, 0xef, 0x42, 0xf7, 0x76, 0x14, 0x1e, 0x07, 0xf1, 0x88,
0xfa, 0x5c, 0x21, 0x74, 0x1d, 0xba, 0x9e, 0x81, 0x71, 0xac, 0x0a, 0xb5, 0x0b, 0x34, 0xf8, 0x17,
0x0b, 0x40, 0x79, 0x6d, 0x30, 0x45, 0x08, 0x9a, 0xe9, 0x34, 0xf0, 0xb9, 0xc7, 0x9a, 0x84, 0x7f,
0xa3, 0x4d, 0x68, 0xa7, 0xd3, 0x7d, 0x37, 0x79, 0x2a, 0xbd, 0x24, 0x21, 0xb4, 0x05, 0x4b, 0x74,
0x4a, 0xbd, 0x49, 0x4a, 0x7d, 0xa7, 0xb1, 0x6d, 0xf5, 0x96, 0x48, 0x06, 0x8b, 0x3b, 0x83, 0xd9,
0x98, 0x3a, 0x4d, 0xce, 0x49, 0x42, 0x25, 0xbf, 0xb7, 0x2a, 0xfc, 0x5e, 0x36, 0xa4, 0x5d, 0xc3,
0x90, 0x0f, 0xa0, 0x25, 0xfc, 0x70, 0x11, 0x3a, 0x3c, 0x34, 0x5a, 0xe4, 0x73, 0x04, 0x53, 0xec,
0x4c, 0xf8, 0xd5, 0x16, 0x8a, 0x09, 0x08, 0x7f, 0x67, 0x01, 0xe4, 0xd1, 0x62, 0x64, 0xc9, 0x6c,
0x74, 0x14, 0x0d, 0x25, 0x07, 0x09, 0x31, 0x3c, 0xb3, 0x91, 0xaa, 0x8c, 0x91, 0x10, 0xcb, 0xb7,
0x3c, 0xbe, 0xdc, 0x1b, 0x4d, 0xa2, 0x61, 0xd8, 0x79, 0x32, 0xa6, 0x61, 0x3a, 0x88, 0x7c, 0x77,
0x26, 0x7d, 0xa2, 0x61, 0x58, 0x42, 0x0c, 0xdd, 0x24, 0xdd, 0x73, 0x67, 0xdc, 0x25, 0x0d, 0xa2,
0x40, 0x7c, 0x04, 0x6b, 0x8f, 0xb8, 0xec, 0xbf, 0x4f, 0x3b, 0xfc, 0x6d, 0x13, 0xba, 0x2a, 0x09,
0xfa, 0x5e, 0x1a, 0x44, 0x21, 0xda, 0x87, 0xf5, 0x2c, 0x28, 0x9e, 0x77, 0x9b, 0x57, 0x0e, 0x97,
0xb6, 0xbc, 0xeb, 0xc8, 0x38, 0x1c, 0x14, 0xcf, 0xf7, 0x17, 0x48, 0xf9, 0x12, 0xfa, 0x04, 0x36,
0x14, 0x92, 0x07, 0xe8, 0x70, 0x4c, 0x63, 0xc6, 0xcc, 0xe6, 0xcc, 0x5e, 0x2d, 0x30, 0xd3, 0x49,
0xf6, 0x17, 0x48, 0xe5, 0x55, 0x74, 0x1f, 0x90, 0x26, 0x47, 0x31, 0x6c, 0x70, 0x86, 0xaf, 0x94,
0xb5, 0xcb, 0xd9, 0x55, 0x5c, 0xd3, 0x2d, 0x95, 0x15, 0x35, 0x98, 0xf2, 0x08, 0x95, 0x2d, 0xcd,
0xce, 0x75, 0x4b, 0x33, 0x24, 0x7a, 0x02, 0x9b, 0x0a, 0x79, 0x67, 0x4a, 0xbd, 0x41, 0xec, 0x86,
0xc9, 0x31, 0x8d, 0x07, 0x11, 0x8f, 0xe9, 0xf2, 0xee, 0x6b, 0x05, 0x76, 0x26, 0xd1, 0xfe, 0x02,
0x99, 0x73, 0x1d, 0x7d, 0x06, 0x4e, 0xd5, 0xc9, 0xdd, 0x38, 0x1a, 0xf1, 0xf6, 0xb0, 0xbc, 0xfb,
0xfa, 0x39, 0xac, 0x19, 0xd9, 0xfe, 0x02, 0x99, 0xcb, 0x02, 0x75, 0xc1, 0x1e, 0xcc, 0x9c, 0xc5,
0x6d, 0xab, 0xd7, 0x22, 0xf6, 0x60, 0xf6, 0xd1, 0x22, 0xb4, 0x4e, 0xdd, 0xe1, 0x84, 0xe2, 0xef,
0x2d, 0x58, 0x2f, 0x45, 0x59, 0xeb, 0x8b, 0xd6, 0x39, 0x7d, 0xb1, 0xdc, 0xc8, 0xec, 0xaa, 0x46,
0x86, 0x6e, 0x94, 0x72, 0x73, 0x79, 0xf7, 0xff, 0x92, 0x63, 0x31, 0xf1, 0x8d, 0xa4, 0xfd, 0xd9,
0x82, 0x8d, 0xaa, 0xac, 0x41, 0x3d, 0xb8, 0xa0, 0x85, 0x59, 0x6b, 0x03, 0x45, 0x34, 0xeb, 0x60,
0xd1, 0x50, 0xf6, 0x18, 0x51, 0x31, 0x19, 0xcc, 0xce, 0x42, 0x7a, 0x26, 0xce, 0x1a, 0xe2, 0x4c,
0xc1, 0xac, 0xc5, 0x84, 0xf4, 0x4c, 0x9a, 0x25, 0x8a, 0x39, 0x47, 0xa0, 0x6d, 0x58, 0x8e, 0x84,
0x2a, 0x77, 0x87, 0xee, 0x89, 0x6c, 0xf0, 0x3a, 0x0a, 0xff, 0x6a, 0x01, 0x2a, 0xe7, 0xe7, 0x0b,
0x28, 0x6e, 0x3a, 0xcd, 0xae, 0xed, 0x34, 0xf4, 0x26, 0xac, 0x87, 0xf4, 0x8c, 0x98, 0x81, 0x11,
0x0d, 0xa1, 0x7c, 0x50, 0xb4, 0xa4, 0xc9, 0x9b, 0xbc, 0x61, 0xc9, 0x0f, 0x16, 0x38, 0xf3, 0x72,
0xee, 0xbc, 0x36, 0xe5, 0x8e, 0xf8, 0xf0, 0xb3, 0x79, 0xaf, 0x93, 0x10, 0x1b, 0x3e, 0x61, 0x24,
0x0b, 0xb9, 0x43, 0xf8, 0xb7, 0x1a, 0x32, 0xa1, 0x3b, 0x12, 0xa3, 0xa4, 0x43, 0x32, 0x98, 0xe5,
0x6d, 0x1a, 0xc9, 0x11, 0x62, 0xa7, 0x11, 0xbb, 0x7f, 0xac, 0x4a, 0xa2, 0x43, 0xf8, 0x37, 0xfe,
0xc6, 0x82, 0xcd, 0xea, 0x7a, 0xfb, 0xa7, 0xd5, 0xc3, 0x5f, 0xe6, 0xc5, 0x94, 0xf7, 0x8c, 0xfa,
0x31, 0xe7, 0xa3, 0xf9, 0x9e, 0x2f, 0xcb, 0x88, 0x7f, 0xb3, 0xdb, 0x72, 0x0c, 0x1e, 0xc6, 0x84,
0x9e, 0x46, 0x9f, 0x53, 0x39, 0x89, 0x8b, 0x68, 0x7c, 0x13, 0x2e, 0x10, 0xfa, 0x4c, 0x4b, 0xba,
0x04, 0x6d, 0x40, 0x2b, 0x49, 0xdd, 0x38, 0xe5, 0x02, 0x1b, 0x44, 0x00, 0x68, 0x0d, 0x1a, 0x34,
0xf4, 0xa5, 0xe9, 0xec, 0x13, 0xbf, 0x05, 0xeb, 0x84, 0x8e, 0x87, 0x33, 0xe3, 0xb2, 0x03, 0x8b,
0xae, 0xef, 0xc7, 0x34, 0x11, 0x5d, 0xa0, 0x43, 0x14, 0x88, 0x3f, 0x04, 0x64, 0x4a, 0xba, 0x17,
0x1e, 0x47, 0xf5, 0xed, 0xc4, 0x7f, 0x5a, 0xb0, 0x51, 0x94, 0xc7, 0x59, 0xfc, 0xe7, 0x77, 0xba,
0x1f, 0x2d, 0x58, 0xd3, 0x5c, 0x37, 0x98, 0x06, 0x7e, 0x52, 0xb2, 0xca, 0xaa, 0xb0, 0x6a, 0x0b,
0x96, 0x58, 0xb2, 0x0f, 0xf2, 0xf4, 0xc8, 0x60, 0xbe, 0x89, 0x45, 0xfc, 0xa4, 0x21, 0x37, 0x31,
0x0e, 0x31, 0x75, 0xc7, 0x34, 0xf4, 0x83, 0x50, 0xd5, 0xb5, 0x02, 0x8d, 0xbd, 0xae, 0x65, 0xee,
0x75, 0xf8, 0x01, 0x0b, 0xae, 0x16, 0x9b, 0xfa, 0x3a, 0x6e, 0x40, 0x8b, 0x6d, 0x93, 0x89, 0x63,
0x6f, 0x37, 0x7a, 0x4d, 0x22, 0x00, 0x7c, 0x9f, 0xe5, 0x96, 0x66, 0x31, 0x0f, 0x74, 0x1d, 0x76,
0x15, 0xd5, 0x80, 0x1f, 0xc2, 0xff, 0x0a, 0xca, 0x71, 0x76, 0x37, 0xe5, 0x0f, 0x44, 0x86, 0x91,
0x7b, 0xcc, 0x7a, 0x61, 0x66, 0x0e, 0xa6, 0xa4, 0x40, 0x88, 0xc7, 0xb0, 0x65, 0xe6, 0xf2, 0xe3,
0xf0, 0x51, 0xbe, 0xb4, 0xd5, 0xd1, 0x73, 0xde, 0x4a, 0x96, 0x37, 0x9f, 0x86, 0xde, 0x7c, 0xf0,
0x43, 0xe9, 0x60, 0x29, 0xa8, 0x9f, 0x24, 0x34, 0x4d, 0xd0, 0xfb, 0xb0, 0x3a, 0xd1, 0x11, 0x32,
0x7b, 0x37, 0xa4, 0x05, 0x06, 0x31, 0x31, 0x49, 0xf1, 0x03, 0x58, 0x35, 0x99, 0xbd, 0x01, 0x6d,
0x57, 0x70, 0x11, 0x7e, 0x58, 0x95, 0x5c, 0xe4, 0x75, 0x79, 0x58, 0x68, 0x83, 0x4d, 0xd5, 0x06,
0xf1, 0x3b, 0xac, 0x93, 0x78, 0x34, 0x18, 0xa7, 0xd9, 0xdf, 0x56, 0x0d, 0x47, 0xe0, 0x2f, 0x58,
0x55, 0xf3, 0x6b, 0x87, 0x72, 0x19, 0x3f, 0x8c, 0xf7, 0xe8, 0xb0, 0x96, 0x13, 0x31, 0xb4, 0xa2,
0x6c, 0x48, 0x17, 0x8b, 0x56, 0x1c, 0xb1, 0xac, 0x75, 0x25, 0x4f, 0xf5, 0x37, 0xa2, 0x60, 0xfc,
0x93, 0x65, 0x0a, 0x3f, 0x88, 0x7c, 0xd6, 0x18, 0xc7, 0xb5, 0x84, 0x5f, 0x85, 0xce, 0x38, 0xa6,
0xa7, 0x87, 0x73, 0x15, 0xc8, 0x8f, 0xd1, 0xdb, 0xb0, 0xe2, 0x4d, 0xe2, 0x98, 0x86, 0x69, 0xbe,
0x38, 0x14, 0xc9, 0x0d, 0x0a, 0xa6, 0xf6, 0x48, 0x6a, 0x23, 0xeb, 0x30, 0x83, 0xf1, 0x73, 0x96,
0xcf, 0x5c, 0x6b, 0xd1, 0x20, 0x0e, 0x22, 0x3f, 0x38, 0xae, 0x97, 0x76, 0x97, 0x00, 0x98, 0x56,
0xc6, 0xe6, 0xa5, 0x61, 0xd0, 0x65, 0x58, 0x95, 0x6a, 0x18, 0x3b, 0x80, 0x89, 0xc4, 0xbf, 0x59,
0xe0, 0x48, 0x0d, 0xf2, 0xae, 0xa7, 0xb6, 0x95, 0x3a, 0x6a, 0xdc, 0x84, 0x2e, 0x13, 0xba, 0x57,
0xdc, 0x55, 0x2a, 0x7a, 0x69, 0x81, 0x10, 0xdd, 0xe0, 0x1a, 0xee, 0x15, 0x57, 0xc3, 0x8a, 0x9b,
0x26, 0x1d, 0x5b, 0x5a, 0x78, 0xe0, 0x85, 0xb7, 0xd4, 0xd2, 0xa2, 0xa1, 0xf0, 0xd7, 0xbc, 0xcf,
0x72, 0xb3, 0xf2, 0x41, 0x7c, 0x2b, 0x1f, 0x50, 0x83, 0xa9, 0xfa, 0x7f, 0x66, 0x12, 0x37, 0x4b,
0x6d, 0x42, 0xc4, 0xb1, 0x48, 0x8e, 0xae, 0xc2, 0x9a, 0xfa, 0x27, 0xcd, 0xa6, 0xb1, 0xcd, 0xa5,
0x97, 0xf0, 0x2c, 0x23, 0xb7, 0xa4, 0x0a, 0x7d, 0xcf, 0xcb, 0xb5, 0x7f, 0x3c, 0xf6, 0xff, 0xc5,
0xbe, 0xc5, 0x7f, 0x58, 0xac, 0x5f, 0x1b, 0xc5, 0xff, 0x52, 0x5c, 0x87, 0x61, 0x85, 0xa9, 0x78,
0x47, 0x8d, 0x1d, 0xe1, 0x36, 0x03, 0xc7, 0xe2, 0xea, 0x4d, 0xe2, 0x3b, 0xe6, 0x8b, 0x83, 0x8e,
0x62, 0x3b, 0x46, 0x32, 0x39, 0x62, 0x29, 0x1a, 0xcb, 0xb8, 0xca, 0xe8, 0x17, 0xd1, 0xda, 0x93,
0x46, 0xcb, 0x78, 0xd2, 0xc8, 0x9f, 0x2d, 0xda, 0xfa, 0xb3, 0x05, 0xfe, 0x34, 0xeb, 0x1f, 0x03,
0x31, 0xd3, 0x5f, 0x20, 0x4e, 0x6c, 0x6d, 0x99, 0xc4, 0xf2, 0x9e, 0x2a, 0xc5, 0x1c, 0x83, 0x9f,
0xc3, 0x85, 0x83, 0xb2, 0x3b, 0xea, 0x0d, 0xc0, 0x40, 0x1b, 0x80, 0x81, 0x5f, 0xf1, 0x72, 0x52,
0xd5, 0x80, 0x8a, 0x2f, 0x27, 0x17, 0xa1, 0xfd, 0x38, 0x08, 0xd3, 0x77, 0xaf, 0x33, 0x9e, 0xbe,
0x9b, 0xba, 0xea, 0xf5, 0x87, 0x7d, 0xe3, 0x18, 0x56, 0xfb, 0xe2, 0x9d, 0x4d, 0x8e, 0x8f, 0x3a,
0xca, 0xe5, 0x23, 0xc6, 0xae, 0x37, 0x62, 0x1a, 0xfa, 0xa6, 0x8d, 0x23, 0x58, 0x21, 0xf4, 0x19,
0x5b, 0x08, 0x5f, 0xba, 0xc8, 0x0d, 0x68, 0x05, 0x49, 0x7f, 0xa8, 0x66, 0x84, 0x00, 0xf0, 0x2d,
0xe8, 0xf2, 0xa9, 0x9b, 0x8b, 0xdc, 0x81, 0x8e, 0xab, 0x00, 0xf9, 0x9f, 0xbb, 0xa6, 0x38, 0x2a,
0x3c, 0xc9, 0x49, 0xf0, 0x57, 0xd0, 0xc9, 0x2f, 0xd7, 0x9c, 0xb0, 0x97, 0x00, 0x62, 0xea, 0x9d,
0xf6, 0xf5, 0x9f, 0x0d, 0x0d, 0x83, 0x7a, 0xb0, 0x28, 0x9f, 0x38, 0x65, 0x1c, 0xbb, 0xb9, 0x06,
0x0c, 0x4b, 0xd4, 0x31, 0x7e, 0x0f, 0xda, 0xfd, 0xcc, 0xa5, 0x72, 0xdf, 0xb0, 0xe6, 0xec, 0x1b,
0xb6, 0xb1, 0x6f, 0x5c, 0x01, 0x90, 0x8b, 0x37, 0x4d, 0xce, 0xdb, 0xea, 0x29, 0x74, 0xc4, 0xdc,
0x4e, 0xd3, 0x7a, 0xf9, 0x69, 0x3c, 0xc3, 0xd9, 0xf3, 0x9f, 0xe1, 0x1a, 0xc6, 0x33, 0xdc, 0x75,
0x80, 0x4c, 0x4c, 0x82, 0xae, 0x40, 0x2b, 0x48, 0xe9, 0xa8, 0x18, 0x80, 0x8c, 0x82, 0x88, 0xe3,
0xa3, 0x36, 0x7f, 0x01, 0xbe, 0xf6, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0e, 0x1b, 0x43, 0x0b,
0x29, 0x16, 0x00, 0x00,
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wallet
const (
MaxCountPerTime int64 = 100
)
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wallet
import (
"github.com/33cn/chain33/types"
)
//On_MultiSigAddresList 获取owner对应的多重签名地址列表
func (policy *multisigPolicy) On_MultiSigAddresList(req *types.ReqString) (types.Message, error) {
policy.getWalletOperate().GetMutex().Lock()
defer policy.getWalletOperate().GetMutex().Unlock()
//获取本钱包中记录的所有多重签名地址
if req.Data == "" {
reply, err := policy.store.listOwnerAttrs()
if err != nil {
bizlog.Error("On_MultiSigAddresList listOwnerAttrs", "err", err)
}
return reply, err
}
//值查询指定owner地址拥有的多重签名地址列表
reply, err := policy.store.listOwnerAttrsByAddr(req.Data)
if err != nil {
bizlog.Error("On_MultiSigAddresList listOwnerAttrsByAddr", "owneraddr", req.Data, "err", err)
}
return reply, err
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wallet_test
import (
"fmt"
"testing"
"github.com/33cn/chain33/common"
// "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
_ "github.com/33cn/chain33/system"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util/testnode"
_ "github.com/33cn/plugin/plugin"
mty "github.com/33cn/plugin/plugin/dapp/multisig/types"
"github.com/stretchr/testify/assert"
)
var (
Symbol = "BTY"
Asset = "coins"
PrivKeyA = "0x06c0fa653c719275d1baa365c7bc0b9306447287499a715b541b930482eaa504" // 1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK
PrivKeyB = "0x4c8663cded61093af20339ae038b3c6bfa58a33e65874a655022f82eaf3f2fa0" // 1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj
PrivKeyC = "0x9abcf378b397682109c174b37a45bfc8a459c9514dd2ef719e22a9815373047d" // 1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd
PrivKeyD = "0xbf8f865a03fec64f30d2243847807e88d2dbc8104e77925e4fc11c4d4380f3da" // 166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf
PrivKeyE = "0x5b8ca316cf073aa94f1056a9e3f6e0b9a9ec11ae45862d58c7a09640b4d55302" // 1KHwX7ZadNeQDjBGpnweb4k2dqj2CWtAYo
PrivKeyGen = "CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944"
AddrA = "1C5xK2ytuoFqxmVGMcyz9XFKFWcDA8T3rK"
AddrB = "1LDGrokrZjo1HtSmSnw8ef3oy5Vm1nctbj"
AddrC = "1DkrXbz2bK6XMpY4v9z2YUnhwWTXT6V5jd"
AddrD = "166po3ghRbRu53hu8jBBQzddp7kUJ9Ynyf"
AddrE = "1KHwX7ZadNeQDjBGpnweb4k2dqj2CWtAYo"
GenAddr = "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
)
//TestPrivkeyHex :
var TestPrivkeyHex = []string{
"0x06c0fa653c719275d1baa365c7bc0b9306447287499a715b541b930482eaa504",
"0x4c8663cded61093af20339ae038b3c6bfa58a33e65874a655022f82eaf3f2fa0",
"0x9abcf378b397682109c174b37a45bfc8a459c9514dd2ef719e22a9815373047d",
"0xbf8f865a03fec64f30d2243847807e88d2dbc8104e77925e4fc11c4d4380f3da",
"0x5b8ca316cf073aa94f1056a9e3f6e0b9a9ec11ae45862d58c7a09640b4d55302",
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName(mty.MultiSigX, signType))
if err != nil {
return tx, err
}
bytes, err := common.FromHex(hexPrivKey[:])
if err != nil {
return tx, err
}
privKey, err := c.PrivKeyFromBytes(bytes)
if err != nil {
return tx, err
}
tx.Sign(int32(signType), privKey)
return tx, nil
}
func getRPCClient(t *testing.T, mocker *testnode.Chain33Mock) *jsonclient.JSONClient {
jrpcClient := mocker.GetJSONC()
assert.NotNil(t, jrpcClient)
return jrpcClient
}
func getTx(t *testing.T, hex string) *types.Transaction {
data, err := common.FromHex(hex)
assert.Nil(t, err)
var tx types.Transaction
err = types.Decode(data, &tx)
assert.Nil(t, err)
return &tx
}
func TestMultiSigAccount(t *testing.T) {
mocker := testnode.New("--free--", nil)
defer mocker.Close()
mocker.Listen()
jrpcClient := getRPCClient(t, mocker)
//导入私钥到钱包
for i, priv := range TestPrivkeyHex {
privkey := &types.ReqWalletImportPrivkey{Privkey: priv, Label: fmt.Sprintf("heyubin%d", i)}
_, err := mocker.GetAPI().WalletImportprivkey(privkey)
if err != nil {
panic(err)
}
//t.Log("import", "index", i, "addr", acc.Acc.Addr)
}
//创建多重签名账户,owner:AddrA,AddrB,GenAddr,weight:20,10,30;coins:BTY 1000000000 RequestWeight:15
multiSigAccAddr := testAccCreateTx(t, mocker, jrpcClient)
//owner add AddrE
testAddOwner(t, mocker, jrpcClient, multiSigAccAddr)
//owner del AddrE
testDelOwner(t, mocker, jrpcClient, multiSigAccAddr)
//owner AddrA modify weight to 30
testModifyOwnerWeight(t, mocker, jrpcClient, multiSigAccAddr)
//owner AddrA replace by AddrE
testReplaceOwner(t, mocker, jrpcClient, multiSigAccAddr)
}
//创建多重签名账户
func testAccCreateTx(t *testing.T, mocker *testnode.Chain33Mock, jrpcClient *jsonclient.JSONClient) string {
gen := mocker.GetGenesisKey()
var params rpctypes.Query4Jrpc
//1. MultiSigAccCreateTx 创建交易
var owners []*mty.Owner
owmer1 := &mty.Owner{OwnerAddr: AddrA, Weight: 20}
owmer2 := &mty.Owner{OwnerAddr: AddrB, Weight: 10}
owmer3 := &mty.Owner{OwnerAddr: GenAddr, Weight: 30}
owners = append(owners, owmer1)
owners = append(owners, owmer2)
owners = append(owners, owmer3)
symboldailylimit := &mty.SymbolDailyLimit{
Symbol: Symbol,
Execer: Asset,
DailyLimit: 1000000000,
}
req := &mty.MultiSigAccCreate{
Owners: owners,
RequiredWeight: 15,
DailyLimit: symboldailylimit,
}
var res string
err := jrpcClient.Call("multisig.MultiSigAccCreateTx", req, &res)
assert.Nil(t, err)
tx := getTx(t, res)
tx.Sign(types.SECP256K1, gen)
reply, err := mocker.GetAPI().SendTx(tx)
assert.Nil(t, err)
_, err = mocker.WaitTx(reply.GetMsg())
assert.Nil(t, err)
//查询account 计数
params.Execer = mty.MultiSigX
params.FuncName = "MultiSigAccCount"
params.Payload = types.MustPBToJSON(&types.ReqNil{})
rep := &types.Int64{}
err = jrpcClient.Call("Chain33.Query", &params, rep)
assert.Nil(t, err)
assert.Equal(t, int64(1), rep.Data)
//查询account addr
//t.Log("MultiSigAccounts ")
req1 := mty.ReqMultiSigAccs{
Start: 0,
End: 0,
}
params.Execer = mty.MultiSigX
params.FuncName = "MultiSigAccounts"
params.Payload = types.MustPBToJSON(&req1)
rep1 := &mty.ReplyMultiSigAccs{}
err = jrpcClient.Call("Chain33.Query", params, rep1)
assert.Nil(t, err)
//t.Log(rep1)
multiSigAccAddr := rep1.Address[0]
//获取owner拥有的多重签名账户地址
req4 := &types.ReqString{
Data: GenAddr,
}
var res4 mty.OwnerAttrs
err = jrpcClient.Call("multisig.MultiSigAddresList", req4, &res4)
assert.Nil(t, err)
assert.Equal(t, res4.Items[0].OwnerAddr, GenAddr)
return multiSigAccAddr
}
//owner add AddrE
func testAddOwner(t *testing.T, mocker *testnode.Chain33Mock, jrpcClient *jsonclient.JSONClient, multiSigAccAddr string) {
gen := mocker.GetGenesisKey()
params9 := &mty.MultiSigOwnerOperate{
MultiSigAccAddr: multiSigAccAddr,
NewOwner: AddrE,
NewWeight: 8,
OperateFlag: mty.OwnerAdd,
}
var res9 string
err := jrpcClient.Call("multisig.MultiSigOwnerOperateTx", params9, &res9)
assert.Nil(t, err)
tx := getTx(t, res9)
tx.Sign(types.SECP256K1, gen)
reply, err := mocker.GetAPI().SendTx(tx)
assert.Nil(t, err)
_, err = mocker.WaitTx(reply.GetMsg())
assert.Nil(t, err)
//获取owner拥有的多重签名账户地址
req4 := &types.ReqString{
Data: AddrE,
}
var res4 mty.OwnerAttrs
err = jrpcClient.Call("multisig.MultiSigAddresList", req4, &res4)
assert.Nil(t, err)
//t.Log(res4)
assert.Equal(t, res4.Items[0].OwnerAddr, AddrE)
assert.Equal(t, res4.Items[0].MultiSigAddr, multiSigAccAddr)
assert.Equal(t, res4.Items[0].Weight, uint64(8))
}
//owner del AddrE
func testDelOwner(t *testing.T, mocker *testnode.Chain33Mock, jrpcClient *jsonclient.JSONClient, multiSigAccAddr string) {
gen := mocker.GetGenesisKey()
param := &mty.MultiSigOwnerOperate{
MultiSigAccAddr: multiSigAccAddr,
OldOwner: AddrE,
OperateFlag: mty.OwnerDel,
}
var res string
err := jrpcClient.Call("multisig.MultiSigOwnerOperateTx", param, &res)
assert.Nil(t, err)
tx := getTx(t, res)
tx.Sign(types.SECP256K1, gen)
reply, err := mocker.GetAPI().SendTx(tx)
assert.Nil(t, err)
_, err = mocker.WaitTx(reply.GetMsg())
assert.Nil(t, err)
//获取owner拥有的多重签名账户地址
req4 := &types.ReqString{
Data: AddrE,
}
var res4 mty.OwnerAttrs
err = jrpcClient.Call("multisig.MultiSigAddresList", req4, &res4)
//t.Log(res4)
assert.Equal(t, err, types.ErrNotFound)
}
//ModifyOwnerWeight
func testModifyOwnerWeight(t *testing.T, mocker *testnode.Chain33Mock, jrpcClient *jsonclient.JSONClient, multiSigAccAddr string) {
gen := mocker.GetGenesisKey()
param := &mty.MultiSigOwnerOperate{
MultiSigAccAddr: multiSigAccAddr,
OldOwner: AddrA,
NewWeight: 30,
OperateFlag: mty.OwnerModify,
}
var res string
err := jrpcClient.Call("multisig.MultiSigOwnerOperateTx", param, &res)
assert.Nil(t, err)
tx := getTx(t, res)
tx.Sign(types.SECP256K1, gen)
reply, err := mocker.GetAPI().SendTx(tx)
assert.Nil(t, err)
_, err = mocker.WaitTx(reply.GetMsg())
assert.Nil(t, err)
//获取owner拥有的多重签名账户地址
req4 := &types.ReqString{
Data: AddrA,
}
var res4 mty.OwnerAttrs
err = jrpcClient.Call("multisig.MultiSigAddresList", req4, &res4)
assert.Nil(t, err)
assert.Equal(t, res4.Items[0].OwnerAddr, AddrA)
assert.Equal(t, res4.Items[0].MultiSigAddr, multiSigAccAddr)
assert.Equal(t, res4.Items[0].Weight, uint64(30))
}
//testReplaceOwner owner AddrA replace by AddrE
func testReplaceOwner(t *testing.T, mocker *testnode.Chain33Mock, jrpcClient *jsonclient.JSONClient, multiSigAccAddr string) {
gen := mocker.GetGenesisKey()
param := &mty.MultiSigOwnerOperate{
MultiSigAccAddr: multiSigAccAddr,
OldOwner: AddrA,
NewOwner: AddrE,
OperateFlag: mty.OwnerReplace,
}
var res string
err := jrpcClient.Call("multisig.MultiSigOwnerOperateTx", param, &res)
assert.Nil(t, err)
tx := getTx(t, res)
tx.Sign(types.SECP256K1, gen)
reply, err := mocker.GetAPI().SendTx(tx)
assert.Nil(t, err)
_, err = mocker.WaitTx(reply.GetMsg())
assert.Nil(t, err)
//获取owner AddrE 拥有的多重签名账户地址
req4 := &types.ReqString{
Data: AddrE,
}
var res4 mty.OwnerAttrs
err = jrpcClient.Call("multisig.MultiSigAddresList", req4, &res4)
assert.Nil(t, err)
assert.Equal(t, res4.Items[0].OwnerAddr, AddrE)
assert.Equal(t, res4.Items[0].MultiSigAddr, multiSigAccAddr)
assert.Equal(t, res4.Items[0].Weight, uint64(30))
//获取owner AddrA 拥有的多重签名账户地址 没有
req5 := &types.ReqString{
Data: AddrA,
}
var res5 mty.OwnerAttrs
err = jrpcClient.Call("multisig.MultiSigAddresList", req5, &res5)
assert.Equal(t, err, types.ErrNotFound)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wallet
import "fmt"
const (
// MultisigAddr 记录本钱包owner地址拥有的多重签名地址,key:"multisig-addr-owneraddr, value [](multisigaddr,owneraddr,weight)
MultisigAddr = "multisig-addr-"
)
func calcMultisigAddr(ownerAddr string) []byte {
return []byte(fmt.Sprintf("%s%s", MultisigAddr, ownerAddr))
}
func calcPrefixMultisigAddr() []byte {
return []byte(MultisigAddr)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of policy source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wallet
import (
"sync"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
wcom "github.com/33cn/chain33/wallet/common"
mtypes "github.com/33cn/plugin/plugin/dapp/multisig/types"
)
var (
bizlog = log15.New("module", "wallet.multisig")
)
func init() {
wcom.RegisterPolicy(mtypes.MultiSigX, New())
}
// New 创建一个钱包业务策略
func New() wcom.WalletBizPolicy {
return &multisigPolicy{
mtx: &sync.Mutex{},
rescanwg: &sync.WaitGroup{},
}
}
type multisigPolicy struct {
mtx *sync.Mutex
store *multisigStore
walletOperate wcom.WalletOperate
rescanwg *sync.WaitGroup
cfg *subConfig
}
type subConfig struct {
RescanMultisigAddr bool `json:"rescanMultisigAddr"`
}
func (policy *multisigPolicy) setWalletOperate(walletBiz wcom.WalletOperate) {
policy.mtx.Lock()
defer policy.mtx.Unlock()
policy.walletOperate = walletBiz
}
func (policy *multisigPolicy) getWalletOperate() wcom.WalletOperate {
policy.mtx.Lock()
defer policy.mtx.Unlock()
return policy.walletOperate
}
func (policy *multisigPolicy) getRescanMultisigAddr() bool {
policy.mtx.Lock()
defer policy.mtx.Unlock()
return policy.cfg.RescanMultisigAddr
}
// Init 初始化处理
func (policy *multisigPolicy) Init(walletOperate wcom.WalletOperate, sub []byte) {
policy.setWalletOperate(walletOperate)
policy.store = newStore(walletOperate.GetDBStore())
var subcfg subConfig
if sub != nil {
types.MustDecode(sub, &subcfg)
}
policy.cfg = &subcfg
}
// OnCreateNewAccount 创建账户时需要扫描此账户拥有的多重签名账户信息
func (policy *multisigPolicy) OnCreateNewAccount(acc *types.Account) {
if policy.getRescanMultisigAddr() {
policy.rescanwg.Add(1)
go policy.rescanOwnerAttrByAddr(acc.Addr)
}
}
// OnImportPrivateKey 在私钥导入时需要扫描此账户拥有的多重签名账户信息
func (policy *multisigPolicy) OnImportPrivateKey(acc *types.Account) {
if policy.getRescanMultisigAddr() {
policy.rescanwg.Add(1)
go policy.rescanOwnerAttrByAddr(acc.Addr)
}
}
// OnAddBlockTx 响应区块交易添加的处理
func (policy *multisigPolicy) OnAddBlockTx(block *types.BlockDetail, tx *types.Transaction, index int32, dbbatch db.Batch) *types.WalletTxDetail {
policy.filterMultisigTxsFromBlock(tx, index, block, dbbatch, true)
return nil
}
// OnDeleteBlockTx 响应删除区块交易的处理
func (policy *multisigPolicy) OnDeleteBlockTx(block *types.BlockDetail, tx *types.Transaction, index int32, dbbatch db.Batch) *types.WalletTxDetail {
policy.filterMultisigTxsFromBlock(tx, index, block, dbbatch, false)
return nil
}
// OnAddBlockFinish 在区块被添加成功时做一些处理
func (policy *multisigPolicy) OnAddBlockFinish(block *types.BlockDetail) {
}
// OnDeleteBlockFinish 在区块被删除成功时做一些处理
func (policy *multisigPolicy) OnDeleteBlockFinish(block *types.BlockDetail) {
}
// OnClose 在钱包关闭时做一些处理
func (policy *multisigPolicy) OnClose() {
}
// OnSetQueueClient 在钱包消息队列初始化时做一些处理
func (policy *multisigPolicy) OnSetQueueClient() {
}
// OnWalletLocked 在钱包加锁时做一些处理
func (policy *multisigPolicy) OnWalletLocked() {
}
// OnWalletUnlocked 在钱包解锁时做一些处理
func (policy *multisigPolicy) OnWalletUnlocked(WalletUnLock *types.WalletUnLock) {
}
// Call 调用隐私的方法
func (policy *multisigPolicy) Call(funName string, in types.Message) (ret types.Message, err error) {
err = types.ErrNotSupport
return
}
// SignTransaction :
func (policy *multisigPolicy) SignTransaction(key crypto.PrivKey, req *types.ReqSignRawTx) (needSysSign bool, signtxhex string, err error) {
needSysSign = true
return
}
func (policy *multisigPolicy) filterMultisigTxsFromBlock(tx *types.Transaction, index int32, block *types.BlockDetail, newbatch db.Batch, addOrRollback bool) {
receiptData := block.Receipts[index]
if receiptData.GetTy() != types.ExecOk {
return
}
for _, log := range receiptData.Logs {
bizlog.Debug("filterMultisigTxsFromBlock", "Ty", log.Ty)
switch log.Ty {
case mtypes.TyLogMultiSigAccCreate:
{
var receipt mtypes.MultiSig
err := types.Decode(log.Log, &receipt)
if err != nil {
bizlog.Error("filterMultisigTxsFromBlock Decode err", "Ty", log.Ty, "err", err)
return
}
policy.saveMultiSigAccCreate(&receipt, newbatch, addOrRollback)
}
case mtypes.TyLogMultiSigOwnerAdd,
mtypes.TyLogMultiSigOwnerDel:
{
var receipt mtypes.ReceiptOwnerAddOrDel
err := types.Decode(log.Log, &receipt)
if err != nil {
bizlog.Error("filterMultisigTxsFromBlock Decode err", "Ty", log.Ty, "err", err)
return
}
policy.saveMultiSigOwnerAddOrDel(&receipt, newbatch, addOrRollback)
}
case mtypes.TyLogMultiSigOwnerModify,
mtypes.TyLogMultiSigOwnerReplace:
{
var receipt mtypes.ReceiptOwnerModOrRep
err := types.Decode(log.Log, &receipt)
if err != nil {
bizlog.Error("filterMultisigTxsFromBlock Decode err", "Ty", log.Ty, "err", err)
return
}
policy.saveMultiSigOwnerModOrRep(&receipt, newbatch, addOrRollback)
}
default:
continue
}
}
}
//需要区分执行的是add/Rollback
func (policy *multisigPolicy) saveMultiSigAccCreate(multiSig *mtypes.MultiSig, newbatch db.Batch, addOrRollback bool) {
wallet := policy.getWalletOperate()
for _, owner := range multiSig.Owners {
if wallet.AddrInWallet(owner.OwnerAddr) {
ownerAttrs, err := policy.store.listOwnerAttrsByAddr(owner.OwnerAddr)
if err != nil && err != types.ErrNotFound {
bizlog.Error("saveMultiSigAccCreate ", "owner.OwnerAddr", owner.OwnerAddr, "err", err)
continue
}
//add tx
if addOrRollback {
ownerAttr := &mtypes.OwnerAttr{
MultiSigAddr: multiSig.MultiSigAddr,
OwnerAddr: owner.OwnerAddr,
Weight: owner.Weight,
}
//第一次添加owner
if err == types.ErrNotFound {
AddOwnerAttr(true, nil, ownerAttr, newbatch)
} else if ownerAttrs != nil {
AddOwnerAttr(false, ownerAttrs, ownerAttr, newbatch)
}
} else if ownerAttrs != nil && !addOrRollback {
DelOwnerAttr(ownerAttrs, owner.OwnerAddr, multiSig.MultiSigAddr, newbatch)
}
}
}
}
//账户owner的add/del操作.需要区分add/del 交易
func (policy *multisigPolicy) saveMultiSigOwnerAddOrDel(ownerOp *mtypes.ReceiptOwnerAddOrDel, newbatch db.Batch, addOrRollback bool) {
wallet := policy.getWalletOperate()
owner := ownerOp.Owner
if wallet.AddrInWallet(owner.OwnerAddr) {
ownerAttrs, err := policy.store.listOwnerAttrsByAddr(owner.OwnerAddr)
if err != nil && err != types.ErrNotFound {
bizlog.Error("saveMultiSigOwnerAddOrDel ", "owner.OwnerAddr", owner.OwnerAddr, "err", err)
return
}
ownerAttr := &mtypes.OwnerAttr{
MultiSigAddr: ownerOp.MultiSigAddr,
OwnerAddr: owner.OwnerAddr,
Weight: owner.Weight,
}
//add tx
if addOrRollback {
if ownerOp.AddOrDel {
if err == types.ErrNotFound {
AddOwnerAttr(true, nil, ownerAttr, newbatch)
} else {
AddOwnerAttr(false, ownerAttrs, ownerAttr, newbatch)
}
} else if ownerAttrs != nil {
DelOwnerAttr(ownerAttrs, owner.OwnerAddr, ownerOp.MultiSigAddr, newbatch)
}
} else {
//回滚add owner
if ownerOp.AddOrDel && ownerAttrs != nil {
DelOwnerAttr(ownerAttrs, owner.OwnerAddr, ownerOp.MultiSigAddr, newbatch)
} else if !ownerOp.AddOrDel { //回滚 del owner
if err == types.ErrNotFound {
AddOwnerAttr(true, nil, ownerAttr, newbatch)
} else if ownerAttrs != nil {
AddOwnerAttr(false, ownerAttrs, ownerAttr, newbatch)
}
}
}
}
}
//账户owner的mod/replace操作
func (policy *multisigPolicy) saveMultiSigOwnerModOrRep(ownerOp *mtypes.ReceiptOwnerModOrRep, newbatch db.Batch, addOrRollback bool) {
wallet := policy.getWalletOperate()
prevOwner := ownerOp.PrevOwner
curOwner := ownerOp.CurrentOwner
multiSigAddr := ownerOp.MultiSigAddr
//首先处理prevOwner
if wallet.AddrInWallet(prevOwner.OwnerAddr) {
ownerAttrs, err := policy.store.listOwnerAttrsByAddr(prevOwner.OwnerAddr)
if err != nil && err != types.ErrNotFound {
bizlog.Error("saveMultiSigOwnerModOrRep ", "prevOwner.OwnerAddr", prevOwner.OwnerAddr, "err", err)
return
}
ownerAttr := &mtypes.OwnerAttr{
MultiSigAddr: multiSigAddr,
OwnerAddr: prevOwner.OwnerAddr,
Weight: prevOwner.Weight,
}
//add tx
if addOrRollback && ownerAttrs != nil {
if ownerOp.ModOrRep {
ModOwnerAttr(ownerAttrs, prevOwner.OwnerAddr, multiSigAddr, curOwner.Weight, newbatch)
} else {
DelOwnerAttr(ownerAttrs, prevOwner.OwnerAddr, multiSigAddr, newbatch)
}
} else if !addOrRollback { //交易Rollback的处理
if ownerOp.ModOrRep && ownerAttrs != nil {
ModOwnerAttr(ownerAttrs, prevOwner.OwnerAddr, multiSigAddr, prevOwner.Weight, newbatch)
} else {
if err == types.ErrNotFound {
AddOwnerAttr(true, nil, ownerAttr, newbatch)
} else if ownerAttrs != nil {
AddOwnerAttr(false, ownerAttrs, ownerAttr, newbatch)
}
}
}
}
//接着处理curOwner,replace时的情况
if wallet.AddrInWallet(curOwner.OwnerAddr) && !ownerOp.ModOrRep {
ownerAttrs, err := policy.store.listOwnerAttrsByAddr(curOwner.OwnerAddr)
if err != nil && err != types.ErrNotFound {
bizlog.Error("saveMultiSigOwnerModOrRep ", "curOwner.OwnerAddr", curOwner.OwnerAddr, "err", err)
return
}
ownerAttr := &mtypes.OwnerAttr{
MultiSigAddr: multiSigAddr,
OwnerAddr: curOwner.OwnerAddr,
Weight: curOwner.Weight,
}
if addOrRollback {
if err == types.ErrNotFound {
AddOwnerAttr(true, nil, ownerAttr, newbatch)
} else if ownerAttrs != nil {
AddOwnerAttr(false, ownerAttrs, ownerAttr, newbatch)
}
} else if ownerAttrs != nil {
DelOwnerAttr(ownerAttrs, curOwner.OwnerAddr, multiSigAddr, newbatch)
}
}
}
//AddOwnerAttr : 添加owmer属性
func AddOwnerAttr(firstAdd bool, ownerAttrs *mtypes.OwnerAttrs, ownerAttr *mtypes.OwnerAttr, newbatch db.Batch) {
if firstAdd {
var firstownerAttrs mtypes.OwnerAttrs
addOwnerAttr(&firstownerAttrs, ownerAttr)
batchSet(&firstownerAttrs, ownerAttr.OwnerAddr, newbatch)
return
}
addOwnerAttr(ownerAttrs, ownerAttr)
batchSet(ownerAttrs, ownerAttr.OwnerAddr, newbatch)
}
//DelOwnerAttr :删除owner属性
func DelOwnerAttr(ownerAttrs *mtypes.OwnerAttrs, ownerAddr string, multiSigAddr string, newbatch db.Batch) {
index, find := getOwnerAttr(ownerAttrs, multiSigAddr)
if find {
//删除最后一个需要将value值设置成空
if len(ownerAttrs.Items) == 1 && index == 0 {
newbatch.Delete(calcMultisigAddr(ownerAddr))
} else {
ownerAttrs = delOwnerAttr(ownerAttrs, index)
batchSet(ownerAttrs, ownerAddr, newbatch)
}
}
}
//ModOwnerAttr :修改owner weight属性
func ModOwnerAttr(ownerAttrs *mtypes.OwnerAttrs, ownerAddr string, multiSigAddr string, weight uint64, newbatch db.Batch) {
index, find := getOwnerAttr(ownerAttrs, multiSigAddr)
if find {
ownerAttrs.Items[index].Weight = weight
batchSet(ownerAttrs, ownerAddr, newbatch)
}
}
//batchSet :
func batchSet(ownerAttrs *mtypes.OwnerAttrs, addr string, newbatch db.Batch) {
ownerAttrsbyte := types.Encode(ownerAttrs)
newbatch.Set(calcMultisigAddr(addr), ownerAttrsbyte)
}
//delOwnerAttr :
func delOwnerAttr(ownerAttrs *mtypes.OwnerAttrs, index int) *mtypes.OwnerAttrs {
ownerSize := len(ownerAttrs.Items)
//删除第一个owner
if index == 0 {
ownerAttrs.Items = ownerAttrs.Items[1:]
} else if (ownerSize) == index+1 { //删除最后一个owner
ownerAttrs.Items = ownerAttrs.Items[0 : ownerSize-1]
} else {
ownerAttrs.Items = append(ownerAttrs.Items[0:index], ownerAttrs.Items[index+1:]...)
}
return ownerAttrs
}
//addOwnerAttr :
func addOwnerAttr(ownerAttrs *mtypes.OwnerAttrs, ownerAttr *mtypes.OwnerAttr) *mtypes.OwnerAttrs {
ownerAttrs.Items = append(ownerAttrs.Items, ownerAttr)
return ownerAttrs
}
// getOwnerAttr :
func getOwnerAttr(ownerAttrs *mtypes.OwnerAttrs, multiSigAddr string) (int, bool) {
for index, owner := range ownerAttrs.Items {
if owner.MultiSigAddr == multiSigAddr {
return index, true
}
}
return 0, false
}
// 创建账户或者导入私钥时,从blockchain模块遍历所有多重签名地址,过滤出此地址拥有的多重签名账户
func (policy *multisigPolicy) rescanOwnerAttrByAddr(addr string) {
beg := types.Now()
defer func() {
bizlog.Info("rescanOwnerAttrByAddr", "addr", addr, "cost", types.Since(beg))
}()
defer policy.rescanwg.Done()
if len(addr) == 0 {
bizlog.Error("rescanOwnerAttrByAddr input addr is nil!")
return
}
operater := policy.getWalletOperate()
//获取全网中多重签名账户数量
msg, err := operater.GetAPI().Query(types.ExecName(mtypes.MultiSigX), "MultiSigAccCount", &types.ReqNil{})
if err != nil {
bizlog.Error("rescanOwnerAttrByAddr Query MultiSigAccCount err", "MultiSigX", mtypes.MultiSigX, "addr", addr, "err", err)
return
}
replay := msg.(*types.Int64)
if replay == nil {
bizlog.Error("rescanOwnerAttrByAddr Query MultiSigAccCount is nil")
return
}
totalCount := replay.Data
bizlog.Info("rescanOwnerAttrByAddr MultiSigAccCount ", "totalCount", totalCount, "addr", addr)
if totalCount <= 0 {
return
}
var curCount int64
for {
var req mtypes.ReqMultiSigAccs
if totalCount <= MaxCountPerTime || (curCount+MaxCountPerTime) >= totalCount {
req.Start = curCount
req.End = totalCount - 1
curCount = req.End
} else if curCount+MaxCountPerTime < totalCount {
req.Start = curCount
req.End = req.Start + MaxCountPerTime
curCount = req.End
}
msg, err := operater.GetAPI().Query(types.ExecName(mtypes.MultiSigX), "MultiSigAccounts", &req)
if err != nil {
bizlog.Error("rescanOwnerAttrByAddr", "MultiSigAccounts error", err, "addr", addr)
return
}
replay := msg.(*mtypes.ReplyMultiSigAccs)
if replay == nil {
bizlog.Error("rescanOwnerAttrByAddr Query MultiSigAccounts is nil")
return
}
policy.proceMultiSigAcc(replay, addr)
if curCount >= totalCount-1 {
return
}
curCount = curCount + 1
}
}
func (policy *multisigPolicy) proceMultiSigAcc(multiSigAccs *mtypes.ReplyMultiSigAccs, owneraddr string) {
operater := policy.getWalletOperate()
for _, multiSigaddr := range multiSigAccs.Address {
req := mtypes.ReqMultiSigAccInfo{
MultiSigAccAddr: multiSigaddr,
}
msg, err := operater.GetAPI().Query(types.ExecName(mtypes.MultiSigX), "MultiSigAccountInfo", &req)
if err != nil {
bizlog.Error("ProceMultiSigAcc", "MultiSigAccountInfo error", err, "multiSigaddr", multiSigaddr)
continue
}
replay := msg.(*mtypes.MultiSig)
if replay == nil {
bizlog.Error("ProceMultiSigAcc Query MultiSigAccountInfo is nil", "multiSigaddr", multiSigaddr)
continue
}
for _, owner := range replay.Owners {
if owner.OwnerAddr == owneraddr {
ownerAttrs, err := policy.store.listOwnerAttrsByAddr(owneraddr)
if err != nil && err != types.ErrNotFound {
bizlog.Error("ProceMultiSigAcc ", "owneraddr", owneraddr, "err", err)
break
}
ownerAttr := &mtypes.OwnerAttr{
MultiSigAddr: multiSigaddr,
OwnerAddr: owner.OwnerAddr,
Weight: owner.Weight,
}
newbatch := policy.store.NewBatch(true)
if err == types.ErrNotFound {
AddOwnerAttr(true, nil, ownerAttr, newbatch)
} else if ownerAttrs != nil {
AddOwnerAttr(false, ownerAttrs, ownerAttr, newbatch)
}
newbatch.Write()
break
}
}
}
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wallet
import (
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
wcom "github.com/33cn/chain33/wallet/common"
mtypes "github.com/33cn/plugin/plugin/dapp/multisig/types"
)
func newStore(db db.DB) *multisigStore {
return &multisigStore{Store: wcom.NewStore(db)}
}
// multisigStore 多重签名数据库存储操作类
type multisigStore struct {
*wcom.Store
}
//获取指定owner拥有的多重签名地址
func (store *multisigStore) listOwnerAttrsByAddr(addr string) (*mtypes.OwnerAttrs, error) {
if len(addr) == 0 {
bizlog.Error("listMultisigAddrByOwnerAddr addr is nil")
return nil, types.ErrInvalidParam
}
ownerAttrByte, err := store.Get(calcMultisigAddr(addr))
if err != nil {
bizlog.Error("listMultisigAddrByOwnerAddr", "addr", addr, "db Get error ", err)
if err == db.ErrNotFoundInDb {
return nil, types.ErrNotFound
}
return nil, err
}
if nil == ownerAttrByte || len(ownerAttrByte) == 0 {
return nil, types.ErrNotFound
}
var ownerAttrs mtypes.OwnerAttrs
err = types.Decode(ownerAttrByte, &ownerAttrs)
if err != nil {
bizlog.Error("listMultisigAddrByOwnerAddr", "proto.Unmarshal err:", err)
return nil, types.ErrUnmarshal
}
return &ownerAttrs, nil
}
//获取本钱包地址拥有的所有多重签名地址
func (store *multisigStore) listOwnerAttrs() (*mtypes.OwnerAttrs, error) {
list := store.NewListHelper()
ownerbytes := list.PrefixScan(calcPrefixMultisigAddr())
if len(ownerbytes) == 0 {
bizlog.Error("listOwnerAttrs is null")
return nil, types.ErrNotFound
}
var replayOwnerAttrs mtypes.OwnerAttrs
for _, ownerattrbytes := range ownerbytes {
var ownerAttrs mtypes.OwnerAttrs
err := types.Decode(ownerattrbytes, &ownerAttrs)
if err != nil {
bizlog.Error("listOwnerAttrs", "Decode err", err)
continue
}
for _, ownerAttr := range ownerAttrs.Items {
replayOwnerAttrs.Items = append(replayOwnerAttrs.Items, ownerAttr)
}
}
return &replayOwnerAttrs, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment