From: wz Date: Thu, 13 Jun 2019 08:50:23 +0000 (+0800) Subject: add cancel vote (#172) X-Git-Tag: v1.0.5~208^2~32 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=ce85135aab7643cff4426cab11f1b822ad3ef264 add cancel vote (#172) * add cancel vote * fix review * modify name * fix review * fix test * fix test --- diff --git a/account/builder.go b/account/builder.go index af0c0a1c..fe96d747 100644 --- a/account/builder.go +++ b/account/builder.go @@ -313,7 +313,7 @@ func UtxoToInputs(signer *signers.Signer, u *UTXO) (*types.TxInput, *txbuilder.S if u.Vote == nil { txInput = types.NewSpendInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram) } else { - txInput = types.NewUnvoteInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram, u.Vote) + txInput = types.NewVetoInput(nil, u.SourceID, u.AssetID, u.Amount, u.SourcePos, u.ControlProgram, u.Vote) } sigInst := &txbuilder.SigningInstruction{} if signer == nil { diff --git a/blockchain/txfeed/txfeed.go b/blockchain/txfeed/txfeed.go index 01691eb8..63979904 100644 --- a/blockchain/txfeed/txfeed.go +++ b/blockchain/txfeed/txfeed.go @@ -358,6 +358,11 @@ func buildAnnotatedInput(tx *types.Tx, i uint32) *query.AnnotatedInput { in.Type = "cross_chain_in" in.ControlProgram = orig.ControlProgram() in.SpentOutputID = e.MainchainOutputId + + case *bc.VetoInput: + in.Type = "veto" + in.ControlProgram = orig.ControlProgram() + in.SpentOutputID = e.SpentOutputId } return in @@ -378,7 +383,16 @@ func buildAnnotatedOutput(tx *types.Tx, idx int) *query.AnnotatedOutput { if vmutil.IsUnspendable(out.ControlProgram) { out.Type = "retire" } else { - out.Type = "control" + e := tx.Entries[*outid] + switch e.(type) { + case *bc.CrossChainOutput: + out.Type = "crosschain_output" + case *bc.IntraChainOutput: + out.Type = "control" + case *bc.VoteOutput: + out.Type = "vote_control" + } } + return out } diff --git a/protocol/bc/bc.pb.go b/protocol/bc/bc.pb.go index 6b0a50ac..fbffe83b 100644 --- a/protocol/bc/bc.pb.go +++ b/protocol/bc/bc.pb.go @@ -23,6 +23,7 @@ It has these top-level messages: IntraChainOutput CrossChainOutput VoteOutput + VetoInput Retirement Spend CrossChainInput @@ -561,6 +562,46 @@ func (m *VoteOutput) GetVote() []byte { return nil } +type VetoInput struct { + SpentOutputId *Hash `protobuf:"bytes,1,opt,name=spent_output_id,json=spentOutputId" json:"spent_output_id,omitempty"` + WitnessDestination *ValueDestination `protobuf:"bytes,2,opt,name=witness_destination,json=witnessDestination" json:"witness_destination,omitempty"` + WitnessArguments [][]byte `protobuf:"bytes,3,rep,name=witness_arguments,json=witnessArguments,proto3" json:"witness_arguments,omitempty"` + Ordinal uint64 `protobuf:"varint,4,opt,name=ordinal" json:"ordinal,omitempty"` +} + +func (m *VetoInput) Reset() { *m = VetoInput{} } +func (m *VetoInput) String() string { return proto.CompactTextString(m) } +func (*VetoInput) ProtoMessage() {} +func (*VetoInput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } + +func (m *VetoInput) GetSpentOutputId() *Hash { + if m != nil { + return m.SpentOutputId + } + return nil +} + +func (m *VetoInput) GetWitnessDestination() *ValueDestination { + if m != nil { + return m.WitnessDestination + } + return nil +} + +func (m *VetoInput) GetWitnessArguments() [][]byte { + if m != nil { + return m.WitnessArguments + } + return nil +} + +func (m *VetoInput) GetOrdinal() uint64 { + if m != nil { + return m.Ordinal + } + return 0 +} + type Retirement struct { Source *ValueSource `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` Ordinal uint64 `protobuf:"varint,2,opt,name=ordinal" json:"ordinal,omitempty"` @@ -569,7 +610,7 @@ type Retirement struct { func (m *Retirement) Reset() { *m = Retirement{} } func (m *Retirement) String() string { return proto.CompactTextString(m) } func (*Retirement) ProtoMessage() {} -func (*Retirement) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } +func (*Retirement) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } func (m *Retirement) GetSource() *ValueSource { if m != nil { @@ -595,7 +636,7 @@ type Spend struct { func (m *Spend) Reset() { *m = Spend{} } func (m *Spend) String() string { return proto.CompactTextString(m) } func (*Spend) ProtoMessage() {} -func (*Spend) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } +func (*Spend) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } func (m *Spend) GetSpentOutputId() *Hash { if m != nil { @@ -637,7 +678,7 @@ type CrossChainInput struct { func (m *CrossChainInput) Reset() { *m = CrossChainInput{} } func (m *CrossChainInput) String() string { return proto.CompactTextString(m) } func (*CrossChainInput) ProtoMessage() {} -func (*CrossChainInput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } +func (*CrossChainInput) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } func (m *CrossChainInput) GetMainchainOutputId() *Hash { if m != nil { @@ -697,6 +738,7 @@ func init() { proto.RegisterType((*IntraChainOutput)(nil), "bc.IntraChainOutput") proto.RegisterType((*CrossChainOutput)(nil), "bc.CrossChainOutput") proto.RegisterType((*VoteOutput)(nil), "bc.VoteOutput") + proto.RegisterType((*VetoInput)(nil), "bc.VetoInput") proto.RegisterType((*Retirement)(nil), "bc.Retirement") proto.RegisterType((*Spend)(nil), "bc.Spend") proto.RegisterType((*CrossChainInput)(nil), "bc.CrossChainInput") @@ -705,61 +747,62 @@ func init() { func init() { proto.RegisterFile("bc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 886 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4f, 0x6f, 0xe3, 0x44, - 0x14, 0x57, 0x6c, 0x37, 0x49, 0x5f, 0xba, 0x4d, 0x33, 0xdd, 0x05, 0x6b, 0x05, 0xa2, 0xb2, 0xb4, - 0x74, 0x11, 0x52, 0xd5, 0x3f, 0x8b, 0xe0, 0xc0, 0x81, 0xd2, 0xb2, 0x6c, 0x0e, 0xab, 0x45, 0xd3, - 0xaa, 0x57, 0x6b, 0x62, 0x4f, 0x9b, 0x11, 0x8e, 0x27, 0xcc, 0x8c, 0x4d, 0xb7, 0x5f, 0x81, 0x33, - 0x07, 0xbe, 0x08, 0x5f, 0x81, 0x13, 0x9f, 0x09, 0x34, 0xcf, 0xe3, 0xc4, 0x69, 0xd2, 0x76, 0x57, - 0x08, 0xc1, 0xcd, 0xef, 0xdf, 0xef, 0xbd, 0xf7, 0x9b, 0xf7, 0x66, 0x0c, 0xdd, 0x51, 0xb2, 0x37, - 0x55, 0xd2, 0x48, 0xe2, 0x8d, 0x92, 0xe8, 0x25, 0x04, 0xaf, 0x98, 0x1e, 0x93, 0x4d, 0xf0, 0xca, - 0xfd, 0xb0, 0xb5, 0xd3, 0x7a, 0xde, 0xa6, 0x5e, 0xb9, 0x8f, 0xf2, 0x41, 0xe8, 0x39, 0xf9, 0x00, - 0xe5, 0xc3, 0xd0, 0x77, 0xf2, 0x21, 0xca, 0x47, 0x61, 0xe0, 0xe4, 0xa3, 0xe8, 0x6b, 0xe8, 0xfc, - 0xa0, 0xe4, 0x95, 0x62, 0x13, 0xf2, 0x31, 0x40, 0x39, 0x89, 0x4b, 0xae, 0xb4, 0x90, 0x39, 0x42, - 0x06, 0x74, 0xbd, 0x9c, 0x5c, 0x54, 0x0a, 0x42, 0x20, 0x48, 0x64, 0xca, 0x11, 0x7b, 0x83, 0xe2, - 0x77, 0x34, 0x84, 0xce, 0xb1, 0xd6, 0xdc, 0x0c, 0x4f, 0xff, 0x71, 0x21, 0xaf, 0xa1, 0x87, 0x50, - 0xc7, 0x13, 0x59, 0xe4, 0x86, 0x7c, 0x0a, 0x5d, 0x66, 0xc5, 0x58, 0xa4, 0x08, 0xda, 0x3b, 0xec, - 0xed, 0x8d, 0x92, 0x3d, 0x97, 0x8d, 0x76, 0xd0, 0x38, 0x4c, 0xc9, 0x07, 0xd0, 0x66, 0x18, 0x81, - 0xa9, 0x02, 0xea, 0xa4, 0x28, 0x83, 0xde, 0x05, 0xcb, 0x0a, 0x7e, 0x26, 0x0b, 0x95, 0x70, 0xf2, - 0x14, 0x7c, 0xc5, 0x2f, 0x1d, 0x52, 0xd7, 0x22, 0x59, 0xf6, 0xa8, 0x55, 0x92, 0x67, 0xb0, 0x56, - 0x5a, 0x57, 0x44, 0xe8, 0x1d, 0xf6, 0x67, 0x79, 0xaa, 0x52, 0x68, 0x65, 0x25, 0x4f, 0xa1, 0x3b, - 0x95, 0x5a, 0x18, 0x4b, 0x8e, 0x8f, 0xb9, 0x66, 0x72, 0xf4, 0x13, 0x6c, 0x61, 0xb6, 0x53, 0xae, - 0x8d, 0xc8, 0x99, 0xd5, 0xfd, 0xdb, 0x29, 0xff, 0xf2, 0xa0, 0xf7, 0x6d, 0x26, 0x93, 0x1f, 0x5f, - 0x71, 0x96, 0x72, 0x45, 0x42, 0xe8, 0x2c, 0x1e, 0x5d, 0x2d, 0x5a, 0x8a, 0xc6, 0x5c, 0x5c, 0x8d, - 0x67, 0x14, 0x55, 0x12, 0x79, 0x01, 0x83, 0xa9, 0xe2, 0xa5, 0x90, 0x85, 0x8e, 0x47, 0x16, 0xc9, - 0x72, 0xed, 0xdf, 0x2a, 0xb7, 0x5f, 0xbb, 0x60, 0xae, 0x61, 0x4a, 0x3e, 0x82, 0x75, 0x23, 0x26, - 0x5c, 0x1b, 0x36, 0x99, 0xe2, 0xf1, 0x05, 0x74, 0xae, 0x20, 0x5f, 0xc0, 0xc0, 0x28, 0x96, 0x6b, - 0x96, 0xd8, 0x22, 0x75, 0xac, 0xa4, 0x34, 0xe1, 0xda, 0x2d, 0xcc, 0xad, 0xa6, 0x0b, 0x95, 0xd2, - 0x90, 0x6f, 0xe0, 0xc3, 0x86, 0x2e, 0xd6, 0x86, 0x99, 0x42, 0xc7, 0x63, 0xa6, 0xc7, 0x61, 0xfb, - 0x56, 0xf0, 0x93, 0x86, 0xe3, 0x19, 0xfa, 0xe1, 0x1e, 0x9c, 0x02, 0x59, 0x46, 0x08, 0x3b, 0x18, - 0xfc, 0xc4, 0x06, 0x9f, 0xdf, 0x0e, 0xa3, 0x83, 0x25, 0x24, 0xf2, 0x39, 0x0c, 0x7e, 0x16, 0x26, - 0xe7, 0x5a, 0xc7, 0x4c, 0x5d, 0x15, 0x13, 0x9e, 0x1b, 0x1d, 0x76, 0x77, 0xfc, 0xe7, 0x1b, 0x74, - 0xcb, 0x19, 0x8e, 0x6b, 0x7d, 0xf4, 0x6b, 0x0b, 0xba, 0xe7, 0xd7, 0x0f, 0xd2, 0xbf, 0x0b, 0x7d, - 0xcd, 0x95, 0x60, 0x99, 0xb8, 0xe1, 0x69, 0xac, 0xc5, 0x0d, 0x77, 0xe7, 0xb0, 0x39, 0x57, 0x9f, - 0x89, 0x1b, 0x6e, 0xf7, 0xcf, 0x12, 0x19, 0x2b, 0x96, 0x5f, 0x71, 0x77, 0xde, 0x48, 0x2d, 0xb5, - 0x0a, 0xb2, 0x0b, 0xa0, 0xb8, 0x2e, 0x32, 0xbb, 0x12, 0x3a, 0x0c, 0x76, 0xfc, 0x05, 0x5a, 0xd6, - 0x2b, 0xdb, 0x30, 0xd5, 0xd1, 0x01, 0x6c, 0x9e, 0x5f, 0x5f, 0x70, 0x25, 0x2e, 0xdf, 0x52, 0x54, - 0x92, 0x4f, 0xa0, 0xe7, 0x28, 0xbd, 0x64, 0x22, 0xc3, 0x02, 0xbb, 0x14, 0x2a, 0xd5, 0x4b, 0x26, - 0xb2, 0xe8, 0x12, 0x06, 0x4b, 0xfc, 0xdc, 0xd3, 0xd2, 0x97, 0xf0, 0xa8, 0x44, 0xfc, 0x9a, 0x67, - 0x0f, 0xab, 0x21, 0xc8, 0xf3, 0x42, 0x6a, 0xba, 0x51, 0x39, 0x56, 0x90, 0xd1, 0x9f, 0x2d, 0xf0, - 0x5f, 0x17, 0xd7, 0xe4, 0x33, 0xe8, 0x68, 0x5c, 0x4c, 0x1d, 0xb6, 0x30, 0x14, 0x37, 0xa0, 0xb1, - 0xb0, 0xb4, 0xb6, 0x93, 0x67, 0xd0, 0x99, 0x56, 0x17, 0x94, 0x5b, 0x16, 0xbc, 0x07, 0xdc, 0x9d, - 0x45, 0x6b, 0x1b, 0xf9, 0x1e, 0x1e, 0xd7, 0x27, 0x97, 0xce, 0x97, 0x50, 0x87, 0x3e, 0xc2, 0x3f, - 0x9e, 0xc1, 0x37, 0x36, 0x94, 0x6e, 0xbb, 0x88, 0x86, 0xee, 0x8e, 0x11, 0x08, 0xee, 0x18, 0x01, - 0x09, 0xdd, 0x13, 0x29, 0xf2, 0x11, 0xd3, 0x9c, 0x7c, 0x07, 0xdb, 0x2b, 0x2a, 0x70, 0xfb, 0xbf, - 0xba, 0x00, 0xb2, 0x5c, 0x80, 0xdd, 0x2f, 0xa6, 0x46, 0xc2, 0x28, 0xa6, 0xde, 0xba, 0xbb, 0x76, - 0xae, 0x88, 0x7e, 0x69, 0xc1, 0xd6, 0x30, 0x37, 0x8a, 0x9d, 0x8c, 0x99, 0xc8, 0xdf, 0x14, 0x66, - 0x5a, 0x18, 0xb2, 0x0b, 0xed, 0x8a, 0x2d, 0x97, 0x6c, 0x89, 0x4c, 0x67, 0x26, 0x2f, 0xa0, 0x9f, - 0xc8, 0xdc, 0x28, 0x99, 0xc5, 0xf7, 0x70, 0xba, 0xe9, 0x7c, 0xea, 0x77, 0x21, 0x84, 0x8e, 0x54, - 0xa9, 0xc8, 0x59, 0xe6, 0x86, 0xb2, 0x16, 0xb1, 0x9a, 0x13, 0x25, 0xb5, 0xfe, 0x5f, 0x54, 0xf3, - 0x5b, 0x0b, 0xe0, 0x42, 0x1a, 0xfe, 0x1f, 0xd7, 0x61, 0x1f, 0xca, 0x52, 0x1a, 0x8e, 0x97, 0xe3, - 0x06, 0xc5, 0xef, 0xe8, 0x0d, 0x00, 0xe5, 0x46, 0x28, 0x6e, 0xe7, 0xe6, 0xdd, 0x4b, 0x6b, 0x24, - 0xf1, 0x16, 0x9b, 0xfd, 0xa3, 0x05, 0x6b, 0x67, 0x53, 0x9e, 0xa7, 0x64, 0x1f, 0xfa, 0x7a, 0xca, - 0x73, 0x13, 0x4b, 0xec, 0x7b, 0xfe, 0x60, 0xce, 0x2f, 0x87, 0x47, 0xe8, 0x50, 0xf1, 0x32, 0x4c, - 0xef, 0x9a, 0x54, 0xef, 0x3d, 0x27, 0x75, 0xe5, 0xa6, 0xf8, 0xab, 0x37, 0xa5, 0xd9, 0x49, 0xb0, - 0xd8, 0xc9, 0xef, 0x1e, 0xf4, 0xe7, 0x43, 0x34, 0xcc, 0xed, 0xd9, 0x7d, 0x05, 0xdb, 0x13, 0x26, - 0xf2, 0xc4, 0x6a, 0xee, 0xe9, 0x6b, 0x30, 0x73, 0x9a, 0xf5, 0xf6, 0x8e, 0x2f, 0xeb, 0x1d, 0x14, - 0xf8, 0xef, 0x49, 0xc1, 0x8a, 0xd1, 0x09, 0x1e, 0x1e, 0x9d, 0x95, 0xc4, 0xad, 0x3d, 0x4c, 0x5c, - 0x7b, 0x81, 0xb8, 0x51, 0x1b, 0xff, 0x06, 0x8f, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x41, - 0xe2, 0x4f, 0x19, 0x0a, 0x00, 0x00, + // 898 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x56, 0xdd, 0x6e, 0x23, 0x35, + 0x14, 0x56, 0x66, 0xa6, 0x49, 0x7a, 0xd2, 0x6d, 0x1a, 0x77, 0x17, 0x46, 0x2b, 0x10, 0xd5, 0x48, + 0x4b, 0x17, 0x21, 0x55, 0xfd, 0x59, 0x04, 0x17, 0x5c, 0x50, 0x5a, 0x96, 0xcd, 0xc5, 0x6a, 0x91, + 0x5b, 0xe5, 0x76, 0xe4, 0xcc, 0xb8, 0x8d, 0xc5, 0x64, 0x1c, 0x6c, 0xcf, 0xd0, 0xed, 0x2b, 0x70, + 0xcd, 0x05, 0x2f, 0xc2, 0x2b, 0x70, 0x81, 0x78, 0x26, 0x90, 0xcf, 0x78, 0xf2, 0xd3, 0xa4, 0xed, + 0x56, 0x08, 0x01, 0x77, 0x39, 0xc7, 0xc7, 0xdf, 0xf9, 0xfc, 0xf9, 0x7c, 0x9e, 0x40, 0x7b, 0x98, + 0xec, 0x4d, 0x94, 0x34, 0x92, 0x78, 0xc3, 0x24, 0x7a, 0x09, 0xc1, 0x2b, 0xa6, 0x47, 0x64, 0x13, + 0xbc, 0x72, 0x3f, 0x6c, 0xec, 0x34, 0x9e, 0x37, 0xa9, 0x57, 0xee, 0x63, 0x7c, 0x10, 0x7a, 0x2e, + 0x3e, 0xc0, 0xf8, 0x30, 0xf4, 0x5d, 0x7c, 0x88, 0xf1, 0x51, 0x18, 0xb8, 0xf8, 0x28, 0xfa, 0x12, + 0x5a, 0xdf, 0x29, 0x79, 0xa9, 0xd8, 0x98, 0x7c, 0x08, 0x50, 0x8e, 0xe3, 0x92, 0x2b, 0x2d, 0x64, + 0x8e, 0x90, 0x01, 0x5d, 0x2f, 0xc7, 0x83, 0x2a, 0x41, 0x08, 0x04, 0x89, 0x4c, 0x39, 0x62, 0x6f, + 0x50, 0xfc, 0x1d, 0xf5, 0xa1, 0x75, 0xac, 0x35, 0x37, 0xfd, 0xd3, 0xbf, 0x4d, 0xe4, 0x35, 0x74, + 0x10, 0xea, 0x78, 0x2c, 0x8b, 0xdc, 0x90, 0x8f, 0xa1, 0xcd, 0x6c, 0x18, 0x8b, 0x14, 0x41, 0x3b, + 0x87, 0x9d, 0xbd, 0x61, 0xb2, 0xe7, 0xba, 0xd1, 0x16, 0x2e, 0xf6, 0x53, 0xf2, 0x1e, 0x34, 0x19, + 0xee, 0xc0, 0x56, 0x01, 0x75, 0x51, 0x94, 0x41, 0x67, 0xc0, 0xb2, 0x82, 0x9f, 0xc9, 0x42, 0x25, + 0x9c, 0x3c, 0x05, 0x5f, 0xf1, 0x0b, 0x87, 0xd4, 0xb6, 0x48, 0x56, 0x3d, 0x6a, 0x93, 0xe4, 0x19, + 0xac, 0x95, 0xb6, 0x14, 0x11, 0x3a, 0x87, 0xdd, 0x69, 0x9f, 0x8a, 0x0a, 0xad, 0x56, 0xc9, 0x53, + 0x68, 0x4f, 0xa4, 0x16, 0xc6, 0x8a, 0xe3, 0x63, 0xaf, 0x69, 0x1c, 0xfd, 0x00, 0x5b, 0xd8, 0xed, + 0x94, 0x6b, 0x23, 0x72, 0x66, 0x73, 0xff, 0x74, 0xcb, 0x3f, 0x3d, 0xe8, 0x7c, 0x9d, 0xc9, 0xe4, + 0xfb, 0x57, 0x9c, 0xa5, 0x5c, 0x91, 0x10, 0x5a, 0x8b, 0x57, 0x57, 0x87, 0x56, 0xa2, 0x11, 0x17, + 0x97, 0xa3, 0xa9, 0x44, 0x55, 0x44, 0x5e, 0x40, 0x6f, 0xa2, 0x78, 0x29, 0x64, 0xa1, 0xe3, 0xa1, + 0x45, 0xb2, 0x5a, 0xfb, 0x37, 0xe8, 0x76, 0xeb, 0x12, 0xec, 0xd5, 0x4f, 0xc9, 0x07, 0xb0, 0x6e, + 0xc4, 0x98, 0x6b, 0xc3, 0xc6, 0x13, 0xbc, 0xbe, 0x80, 0xce, 0x12, 0xe4, 0x33, 0xe8, 0x19, 0xc5, + 0x72, 0xcd, 0x12, 0x4b, 0x52, 0xc7, 0x4a, 0x4a, 0x13, 0xae, 0xdd, 0xc0, 0xdc, 0x9a, 0x2f, 0xa1, + 0x52, 0x1a, 0xf2, 0x15, 0xbc, 0x3f, 0x97, 0x8b, 0xb5, 0x61, 0xa6, 0xd0, 0xf1, 0x88, 0xe9, 0x51, + 0xd8, 0xbc, 0xb1, 0xf9, 0xc9, 0x5c, 0xe1, 0x19, 0xd6, 0xa1, 0x0f, 0x4e, 0x81, 0x2c, 0x23, 0x84, + 0x2d, 0xdc, 0xfc, 0xc4, 0x6e, 0x3e, 0xbf, 0xb9, 0x8d, 0xf6, 0x96, 0x90, 0xc8, 0xa7, 0xd0, 0xfb, + 0x51, 0x98, 0x9c, 0x6b, 0x1d, 0x33, 0x75, 0x59, 0x8c, 0x79, 0x6e, 0x74, 0xd8, 0xde, 0xf1, 0x9f, + 0x6f, 0xd0, 0x2d, 0xb7, 0x70, 0x5c, 0xe7, 0xa3, 0x9f, 0x1b, 0xd0, 0x3e, 0xbf, 0xba, 0x57, 0xfe, + 0x5d, 0xe8, 0x6a, 0xae, 0x04, 0xcb, 0xc4, 0x35, 0x4f, 0x63, 0x2d, 0xae, 0xb9, 0xbb, 0x87, 0xcd, + 0x59, 0xfa, 0x4c, 0x5c, 0x73, 0xeb, 0x3f, 0x2b, 0x64, 0xac, 0x58, 0x7e, 0xc9, 0xdd, 0x7d, 0xa3, + 0xb4, 0xd4, 0x26, 0xc8, 0x2e, 0x80, 0xe2, 0xba, 0xc8, 0xac, 0x25, 0x74, 0x18, 0xec, 0xf8, 0x0b, + 0xb2, 0xac, 0x57, 0x6b, 0xfd, 0x54, 0x47, 0x07, 0xb0, 0x79, 0x7e, 0x35, 0xe0, 0x4a, 0x5c, 0xbc, + 0xa5, 0x98, 0x24, 0x1f, 0x41, 0xc7, 0x49, 0x7a, 0xc1, 0x44, 0x86, 0x04, 0xdb, 0x14, 0xaa, 0xd4, + 0x4b, 0x26, 0xb2, 0xe8, 0x02, 0x7a, 0x4b, 0xfa, 0xdc, 0x71, 0xa4, 0xcf, 0xe1, 0x51, 0x89, 0xf8, + 0xb5, 0xce, 0x1e, 0xb2, 0x21, 0xa8, 0xf3, 0x42, 0x6b, 0xba, 0x51, 0x15, 0x56, 0x90, 0xd1, 0x1f, + 0x0d, 0xf0, 0x5f, 0x17, 0x57, 0xe4, 0x13, 0x68, 0x69, 0x34, 0xa6, 0x0e, 0x1b, 0xb8, 0x15, 0x1d, + 0x30, 0x67, 0x58, 0x5a, 0xaf, 0x93, 0x67, 0xd0, 0x9a, 0x54, 0x0f, 0x94, 0x33, 0x0b, 0xbe, 0x03, + 0xee, 0xcd, 0xa2, 0xf5, 0x1a, 0xf9, 0x16, 0x1e, 0xd7, 0x37, 0x97, 0xce, 0x4c, 0xa8, 0x43, 0x1f, + 0xe1, 0x1f, 0x4f, 0xe1, 0xe7, 0x1c, 0x4a, 0xb7, 0xdd, 0x8e, 0xb9, 0xdc, 0x2d, 0x23, 0x10, 0xdc, + 0x32, 0x02, 0x12, 0xda, 0x27, 0x52, 0xe4, 0x43, 0xa6, 0x39, 0xf9, 0x06, 0xb6, 0x57, 0x30, 0x70, + 0xfe, 0x5f, 0x4d, 0x80, 0x2c, 0x13, 0xb0, 0xfe, 0x62, 0x6a, 0x28, 0x8c, 0x62, 0xea, 0xad, 0x7b, + 0x6b, 0x67, 0x89, 0xe8, 0xa7, 0x06, 0x6c, 0xf5, 0x73, 0xa3, 0xd8, 0xc9, 0x88, 0x89, 0xfc, 0x4d, + 0x61, 0x26, 0x85, 0x21, 0xbb, 0xd0, 0xac, 0xd4, 0x72, 0xcd, 0x96, 0xc4, 0x74, 0xcb, 0xe4, 0x05, + 0x74, 0x13, 0x99, 0x1b, 0x25, 0xb3, 0xf8, 0x0e, 0x4d, 0x37, 0x5d, 0x4d, 0xfd, 0x5d, 0x08, 0xa1, + 0x25, 0x55, 0x2a, 0x72, 0x96, 0xb9, 0xa1, 0xac, 0x43, 0x64, 0x73, 0xa2, 0xa4, 0xd6, 0xff, 0x09, + 0x36, 0xbf, 0x34, 0x00, 0x06, 0xd2, 0xf0, 0x7f, 0x99, 0x87, 0xfd, 0x50, 0x96, 0xd2, 0x70, 0x7c, + 0x1c, 0x37, 0x28, 0xfe, 0x8e, 0x7e, 0x6f, 0xc0, 0xfa, 0x80, 0x1b, 0xd9, 0xcf, 0x2d, 0xb5, 0x7d, + 0xe8, 0xea, 0x09, 0xcf, 0x4d, 0x2c, 0x91, 0xea, 0xec, 0x1b, 0x37, 0xf3, 0xf3, 0x23, 0x2c, 0xa8, + 0x8e, 0xd2, 0x4f, 0x6f, 0x1b, 0x2e, 0xef, 0x81, 0xc3, 0xb5, 0x72, 0xb8, 0xfd, 0xd5, 0xc3, 0x3d, + 0x7f, 0xc2, 0x60, 0x51, 0xe9, 0x37, 0x00, 0x94, 0x1b, 0xa1, 0xb8, 0x2d, 0x7c, 0x77, 0xa1, 0xe7, + 0x00, 0xbd, 0x45, 0xc0, 0xdf, 0x1a, 0xb0, 0x76, 0x36, 0xe1, 0x79, 0xfa, 0xbf, 0x97, 0xe6, 0x57, + 0x0f, 0xba, 0x33, 0x4b, 0x54, 0xd7, 0xfd, 0x05, 0x6c, 0x8f, 0x99, 0xc8, 0x13, 0x9b, 0xb9, 0xe3, + 0x5c, 0xbd, 0x69, 0xd1, 0xf4, 0x6c, 0xef, 0xf8, 0x3f, 0xe1, 0x16, 0x09, 0xfc, 0x07, 0x4a, 0xb0, + 0xc2, 0x08, 0xc1, 0xfd, 0x46, 0x58, 0x29, 0xdc, 0xda, 0xfd, 0xc2, 0x35, 0x17, 0x84, 0x1b, 0x36, + 0xf1, 0xbf, 0xed, 0xd1, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x80, 0xe2, 0xa6, 0xe7, 0x0a, + 0x00, 0x00, } diff --git a/protocol/bc/bc.proto b/protocol/bc/bc.proto index fd25c9e9..827100b6 100644 --- a/protocol/bc/bc.proto +++ b/protocol/bc/bc.proto @@ -101,6 +101,13 @@ message VoteOutput { bytes vote = 4; } +message VetoInput { + Hash spent_output_id = 1; + ValueDestination witness_destination = 2; + repeated bytes witness_arguments = 3; + uint64 ordinal = 4; +} + message Retirement { ValueSource source = 1; uint64 ordinal = 2; diff --git a/protocol/bc/tx.go b/protocol/bc/tx.go index fd76ddda..0702e4ce 100644 --- a/protocol/bc/tx.go +++ b/protocol/bc/tx.go @@ -82,6 +82,19 @@ func (tx *Tx) Spend(id Hash) (*Spend, error) { return sp, nil } +// VetoInput try to get the veto entry by given hash +func (tx *Tx) VetoInput(id Hash) (*VetoInput, error) { + e, ok := tx.Entries[id] + if !ok || e == nil { + return nil, errors.Wrapf(ErrMissingEntry, "id %x", id.Bytes()) + } + sp, ok := e.(*VetoInput) + if !ok { + return nil, errors.Wrapf(ErrEntryType, "entry %x has unexpected type %T", id.Bytes(), e) + } + return sp, nil +} + // VoteOutput try to get the vote output entry by given hash func (tx *Tx) VoteOutput(id Hash) (*VoteOutput, error) { e, ok := tx.Entries[id] diff --git a/protocol/bc/types/map.go b/protocol/bc/types/map.go index 1568119c..170b9f09 100644 --- a/protocol/bc/types/map.go +++ b/protocol/bc/types/map.go @@ -39,6 +39,13 @@ func MapTx(oldTx *TxData) *bc.Tx { tx.GasInputIDs = append(tx.GasInputIDs, id) } + case *bc.VetoInput: + ord = e.Ordinal + spentOutputIDs[*e.SpentOutputId] = true + if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID { + tx.GasInputIDs = append(tx.GasInputIDs, id) + } + case *bc.Coinbase: ord = 0 tx.GasInputIDs = append(tx.GasInputIDs, id) @@ -71,9 +78,10 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash } var ( - spends []*bc.Spend - crossIns []*bc.CrossChainInput - coinbase *bc.Coinbase + spends []*bc.Spend + vetoInputs []*bc.VetoInput + crossIns []*bc.CrossChainInput + coinbase *bc.Coinbase ) muxSources := make([]*bc.ValueSource, len(tx.Inputs)) @@ -111,7 +119,7 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash Value: &value, } - case *UnvoteInput: + case *VetoInput: prog := &bc.Program{VmVersion: inp.VMVersion, Code: inp.ControlProgram} src := &bc.ValueSource{ Ref: &inp.SourceID, @@ -120,16 +128,16 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash } prevout := bc.NewVoteOutput(src, prog, 0, inp.Vote) // ordinal doesn't matter for prevouts, only for result outputs prevoutID := addEntry(prevout) - // create entry for spend - spend := bc.NewSpend(&prevoutID, uint64(i)) - spend.WitnessArguments = inp.Arguments - spendID := addEntry(spend) + // create entry for VetoInput + vetoInput := bc.NewVetoInput(&prevoutID, uint64(i)) + vetoInput.WitnessArguments = inp.Arguments + vetoVoteID := addEntry(vetoInput) // setup mux muxSources[i] = &bc.ValueSource{ - Ref: &spendID, + Ref: &vetoVoteID, Value: &inp.AssetAmount, } - spends = append(spends, spend) + vetoInputs = append(vetoInputs, vetoInput) case *CrossChainInput: // TODO: fed peg script @@ -157,13 +165,13 @@ func mapTx(tx *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash // connect the inputs to the mux for _, spend := range spends { - switch spentOutput := entryMap[*spend.SpentOutputId].(type) { - case *bc.IntraChainOutput: - spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) + spentOutput := entryMap[*spend.SpentOutputId].(*bc.IntraChainOutput) + spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) + } - case *bc.VoteOutput: - spend.SetDestination(&muxID, spentOutput.Source.Value, spend.Ordinal) - } + for _, vetoInput := range vetoInputs { + voteOutput := entryMap[*vetoInput.SpentOutputId].(*bc.VoteOutput) + vetoInput.SetDestination(&muxID, voteOutput.Source.Value, vetoInput.Ordinal) } for _, crossIn := range crossIns { diff --git a/protocol/bc/types/transaction.go b/protocol/bc/types/transaction.go index 08e6f6c2..52f50a98 100644 --- a/protocol/bc/types/transaction.go +++ b/protocol/bc/types/transaction.go @@ -53,6 +53,8 @@ func (tx *Tx) SetInputArguments(n uint32, args [][]byte) { e.WitnessArguments = args case *bc.CrossChainInput: e.WitnessArguments = args + case *bc.VetoInput: + e.WitnessArguments = args } } diff --git a/protocol/bc/types/txinput.go b/protocol/bc/types/txinput.go index 7b9ba0ea..47831cca 100644 --- a/protocol/bc/types/txinput.go +++ b/protocol/bc/types/txinput.go @@ -14,7 +14,7 @@ const ( CrossChainInputType uint8 = iota SpendInputType CoinbaseInputType - UnvoteInputType + VetoInputType ) type ( @@ -43,7 +43,7 @@ func (t *TxInput) AssetAmount() bc.AssetAmount { case *CrossChainInput: return inp.AssetAmount - case *UnvoteInput: + case *VetoInput: return inp.AssetAmount } @@ -59,7 +59,7 @@ func (t *TxInput) AssetID() bc.AssetID { case *CrossChainInput: return *inp.AssetAmount.AssetId - case *UnvoteInput: + case *VetoInput: return *inp.AssetId } @@ -75,7 +75,7 @@ func (t *TxInput) Amount() uint64 { case *CrossChainInput: return inp.AssetAmount.Amount - case *UnvoteInput: + case *VetoInput: return inp.Amount } @@ -91,7 +91,7 @@ func (t *TxInput) ControlProgram() []byte { case *CrossChainInput: return inp.ControlProgram - case *UnvoteInput: + case *VetoInput: return inp.ControlProgram } @@ -108,7 +108,7 @@ func (t *TxInput) Arguments() [][]byte { case *CrossChainInput: return inp.Arguments - case *UnvoteInput: + case *VetoInput: return inp.Arguments } return nil @@ -123,7 +123,7 @@ func (t *TxInput) SetArguments(args [][]byte) { case *CrossChainInput: inp.Arguments = args - case *UnvoteInput: + case *VetoInput: inp.Arguments = args } } @@ -134,8 +134,8 @@ func (t *TxInput) SpentOutputID() (o bc.Hash, err error) { case *SpendInput: o, err = ComputeOutputID(&inp.SpendCommitment, SpendInputType, nil) - case *UnvoteInput: - o, err = ComputeOutputID(&inp.SpendCommitment, UnvoteInputType, inp.Vote) + case *VetoInput: + o, err = ComputeOutputID(&inp.SpendCommitment, VetoInputType, inp.Vote) } return o, err @@ -177,8 +177,8 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { return err } - case UnvoteInputType: - ui := new(UnvoteInput) + case VetoInputType: + ui := new(VetoInput) t.TypedInput = ui if ui.UnvoteCommitmentSuffix, err = ui.SpendCommitment.readFrom(r, 1); err != nil { @@ -210,7 +210,7 @@ func (t *TxInput) readFrom(r *blockchain.Reader) (err error) { return err } - case *UnvoteInput: + case *VetoInput: if inp.Arguments, err = blockchain.ReadVarstrList(r); err != nil { return err } @@ -284,8 +284,8 @@ func (t *TxInput) writeInputCommitment(w io.Writer) (err error) { return errors.Wrap(err, "writing coinbase arbitrary") } - case *UnvoteInput: - if _, err = w.Write([]byte{UnvoteInputType}); err != nil { + case *VetoInput: + if _, err = w.Write([]byte{VetoInputType}); err != nil { return err } return inp.SpendCommitment.writeExtensibleString(w, inp.UnvoteCommitmentSuffix, t.AssetVersion) @@ -306,7 +306,7 @@ func (t *TxInput) writeInputWitness(w io.Writer) error { case *CrossChainInput: _, err := blockchain.WriteVarstrList(w, inp.Arguments) return err - case *UnvoteInput: + case *VetoInput: if _, err := blockchain.WriteVarstrList(w, inp.Arguments); err != nil { return err } diff --git a/protocol/bc/types/txinput_test.go b/protocol/bc/types/txinput_test.go index 6ff94a93..884d6721 100644 --- a/protocol/bc/types/txinput_test.go +++ b/protocol/bc/types/txinput_test.go @@ -26,17 +26,17 @@ func TestSerializationSpend(t *testing.T) { "52", // spend commitment length "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID - "92c30f", // amount - "03", // source position - "01", // vm version - "0c", // spend program length + "92c30f", // amount + "03", // source position + "01", // vm version + "0c", // spend program length "7370656e6450726f6772616d", // spend program - "17", // witness length - "02", // argument array length - "0a", // first argument length - "617267756d656e747331", // first argument data - "0a", // second argument length - "617267756d656e747332", // second argument data + "17", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332", // second argument data }, "") // Test convert struct to hex @@ -80,19 +80,19 @@ func TestSerializationCrossIn(t *testing.T) { "54", // cross-chain input commitment length "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID - "92c30f", // amount - "03", // source position - "01", // vm version - "0e", // spend program length + "92c30f", // amount + "03", // source position + "01", // vm version + "0e", // spend program length "63726f7373496e50726f6772616d", // spend program - "17", // witness length - "02", // argument array length - "0a", // first argument length - "617267756d656e747331", // first argument data - "0a", // second argument length - "617267756d656e747332", // second argument data - "08", // asset definition length - "7768617465766572", // asset definition data + "17", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332", // second argument data + "08", // asset definition length + "7768617465766572", // asset definition data }, "") // Test convert struct to hex @@ -128,7 +128,7 @@ func TestSerializationUnvote(t *testing.T) { []byte("arguments2"), } - unvote := NewUnvoteInput(arguments, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), testutil.MustDecodeAsset("fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a"), 254354, 3, []byte("spendProgram"), []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269")) + vetoInput := NewVetoInput(arguments, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), testutil.MustDecodeAsset("fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a"), 254354, 3, []byte("spendProgram"), []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269")) wantHex := strings.Join([]string{ "01", // asset version @@ -137,24 +137,24 @@ func TestSerializationUnvote(t *testing.T) { "52", // unvote commitment length "fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // source id "fe9791d71b67ee62515e08723c061b5ccb952a80d804417c8aeedf7f633c524a", // assetID - "92c30f", // amount - "03", // source position - "01", // vm version - "0c", // unvote program length + "92c30f", // amount + "03", // source position + "01", // vm version + "0c", // unvote program length "7370656e6450726f6772616d", // unvote program - "9901", // witness length - "02", // argument array length - "0a", // first argument length - "617267756d656e747331", // first argument data - "0a", // second argument length - "617267756d656e747332", // second argument data - "8001", //xpub length + "9901", // witness length + "02", // argument array length + "0a", // first argument length + "617267756d656e747331", // first argument data + "0a", // second argument length + "617267756d656e747332", // second argument data + "8001", //xpub length "6166353934303036613430383337643966303238646161626236643538396466306239313338646165666164353638336535323333633236343632373932313732393461386435333265363038363362636631393636323561333566623863656566666133633039363130656239326463666236353561393437663133323639", //voter xpub }, "") // Test convert struct to hex var buffer bytes.Buffer - if err := unvote.writeTo(&buffer); err != nil { + if err := vetoInput.writeTo(&buffer); err != nil { t.Fatal(err) } @@ -164,18 +164,18 @@ func TestSerializationUnvote(t *testing.T) { } // Test convert hex to struct - var gotUnvote TxInput + var gotVeto TxInput decodeHex, err := hex.DecodeString(wantHex) if err != nil { t.Fatal(err) } - if err := gotUnvote.readFrom(blockchain.NewReader(decodeHex)); err != nil { + if err := gotVeto.readFrom(blockchain.NewReader(decodeHex)); err != nil { t.Fatal(err) } - if !testutil.DeepEqual(*unvote, gotUnvote) { - t.Errorf("expected marshaled/unmarshaled txinput to be:\n%sgot:\n%s", spew.Sdump(*unvote), spew.Sdump(gotUnvote)) + if !testutil.DeepEqual(*vetoInput, gotVeto) { + t.Errorf("expected marshaled/unmarshaled txinput to be:\n%sgot:\n%s", spew.Sdump(*vetoInput), spew.Sdump(gotVeto)) } } diff --git a/protocol/bc/types/txoutput.go b/protocol/bc/types/txoutput.go index aca99209..15f07e12 100644 --- a/protocol/bc/types/txoutput.go +++ b/protocol/bc/types/txoutput.go @@ -221,7 +221,7 @@ func ComputeOutputID(sc *SpendCommitment, inputType uint8, vote []byte) (h bc.Ha switch inputType { case SpendInputType: o = bc.NewIntraChainOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0) - case UnvoteInputType: + case VetoInputType: o = bc.NewVoteOutput(src, &bc.Program{VmVersion: sc.VMVersion, Code: sc.ControlProgram}, 0, vote) default: return h, fmt.Errorf("Input type error:[%v]", inputType) diff --git a/protocol/bc/types/txoutput_test.go b/protocol/bc/types/txoutput_test.go index 9dc854a8..0ae1f62f 100644 --- a/protocol/bc/types/txoutput_test.go +++ b/protocol/bc/types/txoutput_test.go @@ -185,9 +185,9 @@ func TestComputeOutputID(t *testing.T) { VMVersion: 1, ControlProgram: testutil.MustDecodeHexString("00145c47f3a0dd3e1e9956fe5b0f897072ed33f9efb9"), }, - inputType: UnvoteInputType, + inputType: VetoInputType, vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"), - wantOutputID: "c95701822db14f5c647158762e4d4b9bff270bfd3040f0ca32cb87c18e377429", + wantOutputID: "a4de5a81babc7949d6b38d1cd4bcbc83da340387e747b5f521af3e427c6b0132", }, { sc: &SpendCommitment{ @@ -197,9 +197,9 @@ func TestComputeOutputID(t *testing.T) { VMVersion: 1, ControlProgram: testutil.MustDecodeHexString("00145c47f3a0dd3e1e9956fe5b0f897072ed33f9efb9"), }, - inputType: UnvoteInputType, + inputType: VetoInputType, vote: []byte(""), - wantOutputID: "8f17b871f3fd07bfe778e92c272e26d4bb19258c90af08310ef32feb526eaf9c", + wantOutputID: "e42a48ef401b993c5e523b6a7b5456ad4b297c7aeda163405f265d8d00af983e", }, } diff --git a/protocol/bc/types/unvote.go b/protocol/bc/types/veto_input.go similarity index 61% rename from protocol/bc/types/unvote.go rename to protocol/bc/types/veto_input.go index 810a8f39..59517bd7 100644 --- a/protocol/bc/types/unvote.go +++ b/protocol/bc/types/veto_input.go @@ -4,16 +4,16 @@ import ( "github.com/vapor/protocol/bc" ) -// UnvoteInput satisfies the TypedInput interface and represents a unvote transaction. -type UnvoteInput struct { +// VetoInput satisfies the TypedInput interface and represents a unvote transaction. +type VetoInput struct { UnvoteCommitmentSuffix []byte // The unconsumed suffix of the output commitment Arguments [][]byte // Witness Vote []byte // voter xpub SpendCommitment } -// NewUnvoteInput create a new UnvoteInput struct. -func NewUnvoteInput(arguments [][]byte, sourceID bc.Hash, assetID bc.AssetID, amount, sourcePos uint64, controlProgram []byte, vote []byte) *TxInput { +// NewVetoInput create a new VetoInput struct. +func NewVetoInput(arguments [][]byte, sourceID bc.Hash, assetID bc.AssetID, amount, sourcePos uint64, controlProgram []byte, vote []byte) *TxInput { sc := SpendCommitment{ AssetAmount: bc.AssetAmount{ AssetId: &assetID, @@ -26,7 +26,7 @@ func NewUnvoteInput(arguments [][]byte, sourceID bc.Hash, assetID bc.AssetID, am } return &TxInput{ AssetVersion: 1, - TypedInput: &UnvoteInput{ + TypedInput: &VetoInput{ SpendCommitment: sc, Arguments: arguments, Vote: vote, @@ -35,4 +35,4 @@ func NewUnvoteInput(arguments [][]byte, sourceID bc.Hash, assetID bc.AssetID, am } // InputType is the interface function for return the input type. -func (ui *UnvoteInput) InputType() uint8 { return SpendInputType } +func (ui *VetoInput) InputType() uint8 { return VetoInputType } diff --git a/protocol/bc/veto_input.go b/protocol/bc/veto_input.go new file mode 100644 index 00000000..71975c5f --- /dev/null +++ b/protocol/bc/veto_input.go @@ -0,0 +1,25 @@ +package bc + +import "io" + +func (VetoInput) typ() string { return "vetoInput1" } +func (s *VetoInput) writeForHash(w io.Writer) { + mustWriteForHash(w, s.SpentOutputId) +} + +// SetDestination will link the spend to the output +func (s *VetoInput) SetDestination(id *Hash, val *AssetAmount, pos uint64) { + s.WitnessDestination = &ValueDestination{ + Ref: id, + Value: val, + Position: pos, + } +} + +// NewVetoInput creates a new VetoInput. +func NewVetoInput(spentOutputID *Hash, ordinal uint64) *VetoInput { + return &VetoInput{ + SpentOutputId: spentOutputID, + Ordinal: ordinal, + } +} diff --git a/protocol/bc/vote_output.go b/protocol/bc/vote_output.go index 9e574db0..2029ff0d 100644 --- a/protocol/bc/vote_output.go +++ b/protocol/bc/vote_output.go @@ -2,7 +2,7 @@ package bc import "io" -func (VoteOutput) typ() string { return "crosschainoutput1" } +func (VoteOutput) typ() string { return "voteoutput1" } func (o *VoteOutput) writeForHash(w io.Writer) { mustWriteForHash(w, o.Source) mustWriteForHash(w, o.ControlProgram) diff --git a/protocol/state/vote_result.go b/protocol/state/vote_result.go index 3ab12433..96ae36ff 100644 --- a/protocol/state/vote_result.go +++ b/protocol/state/vote_result.go @@ -58,7 +58,7 @@ func (v *VoteResult) ApplyBlock(block *types.Block) error { for _, tx := range block.Transactions { for _, input := range tx.Inputs { - unVoteInput, ok := input.TypedInput.(*types.UnvoteInput) + unVoteInput, ok := input.TypedInput.(*types.VetoInput) if !ok { continue } @@ -136,7 +136,7 @@ func (v *VoteResult) DetachBlock(block *types.Block) error { for i := len(block.Transactions) - 1; i >= 0; i-- { tx := block.Transactions[i] for _, input := range tx.Inputs { - unVoteInput, ok := input.TypedInput.(*types.UnvoteInput) + unVoteInput, ok := input.TypedInput.(*types.VetoInput) if !ok { continue } diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index 64fbde95..ce5feacf 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -265,30 +265,13 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { if e.SpentOutputId == nil { return errors.Wrap(ErrMissingField, "spend without spent output ID") } - var ( - controlProgram *bc.Program - value *bc.AssetAmount - ) - entryOutput, err := vs.tx.Entry(*e.SpentOutputId) + + spentOutput, err := vs.tx.IntraChainOutput(*e.SpentOutputId) if err != nil { return errors.Wrap(err, "getting spend prevout") } - switch output := entryOutput.(type) { - case *bc.IntraChainOutput: - controlProgram = output.ControlProgram - value = output.Source.Value - case *bc.VoteOutput: - if len(output.Vote) != 64 { - return ErrVotePubKey - } - controlProgram = output.ControlProgram - value = output.Source.Value - default: - return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", e.SpentOutputId.Bytes(), entryOutput) - } - - gasLeft, err := vm.Verify(NewTxVMContext(vs, e, controlProgram, e.WitnessArguments), vs.gasStatus.GasLeft) + gasLeft, err := vm.Verify(NewTxVMContext(vs, e, spentOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft) if err != nil { return errors.Wrap(err, "checking control program") } @@ -296,7 +279,7 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return err } - eq, err := value.Equal(e.WitnessDestination.Value) + eq, err := spentOutput.Source.Value.Equal(e.WitnessDestination.Value) if err != nil { return err } @@ -304,8 +287,8 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return errors.WithDetailf( ErrMismatchedValue, "previous output is for %d unit(s) of %x, spend wants %d unit(s) of %x", - value.Amount, - value.AssetId.Bytes(), + spentOutput.Source.Value.Amount, + spentOutput.Source.Value.AssetId.Bytes(), e.WitnessDestination.Value.Amount, e.WitnessDestination.Value.AssetId.Bytes(), ) @@ -316,6 +299,47 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return errors.Wrap(err, "checking spend destination") } + case *bc.VetoInput: + if e.SpentOutputId == nil { + return errors.Wrap(ErrMissingField, "vetoInput without vetoInput output ID") + } + + voteOutput, err := vs.tx.VoteOutput(*e.SpentOutputId) + if err != nil { + return errors.Wrap(err, "getting vetoInput prevout") + } + if len(voteOutput.Vote) != 64 { + return ErrVotePubKey + } + + gasLeft, err := vm.Verify(NewTxVMContext(vs, e, voteOutput.ControlProgram, e.WitnessArguments), vs.gasStatus.GasLeft) + if err != nil { + return errors.Wrap(err, "checking control program") + } + if err = vs.gasStatus.updateUsage(gasLeft); err != nil { + return err + } + + eq, err := voteOutput.Source.Value.Equal(e.WitnessDestination.Value) + if err != nil { + return err + } + if !eq { + return errors.WithDetailf( + ErrMismatchedValue, + "previous output is for %d unit(s) of %x, vetoInput wants %d unit(s) of %x", + voteOutput.Source.Value.Amount, + voteOutput.Source.Value.AssetId.Bytes(), + e.WitnessDestination.Value.Amount, + e.WitnessDestination.Value.AssetId.Bytes(), + ) + } + vs2 := *vs + vs2.destPos = 0 + if err = checkValidDest(&vs2, e.WitnessDestination); err != nil { + return errors.Wrap(err, "checking vetoInput destination") + } + case *bc.Coinbase: if vs.block == nil || len(vs.block.Transactions) == 0 || vs.block.Transactions[0] != vs.tx { return ErrWrongCoinbaseTransaction @@ -367,6 +391,12 @@ func checkValidSrc(vstate *validationState, vs *bc.ValueSource) error { var dest *bc.ValueDestination switch ref := e.(type) { + case *bc.VetoInput: + if vs.Position != 0 { + return errors.Wrapf(ErrPosition, "invalid position %d for veto-input source", vs.Position) + } + dest = ref.WitnessDestination + case *bc.Coinbase: if vs.Position != 0 { return errors.Wrapf(ErrPosition, "invalid position %d for coinbase source", vs.Position) diff --git a/protocol/validation/vmcontext.go b/protocol/validation/vmcontext.go index 10b77d8f..9815b2e3 100644 --- a/protocol/validation/vmcontext.go +++ b/protocol/validation/vmcontext.go @@ -32,23 +32,23 @@ func NewTxVMContext(vs *validationState, entry bc.Entry, prog *bc.Program, args destPos = &e.WitnessDestination.Position case *bc.Spend: - switch spentOutput := tx.Entries[*e.SpentOutputId].(type) { - case *bc.IntraChainOutput: - a1 := spentOutput.Source.Value.AssetId.Bytes() - assetID = &a1 - amount = &spentOutput.Source.Value.Amount - destPos = &e.WitnessDestination.Position - s := e.SpentOutputId.Bytes() - spentOutputID = &s + spentOutput := tx.Entries[*e.SpentOutputId].(*bc.IntraChainOutput) + a1 := spentOutput.Source.Value.AssetId.Bytes() + assetID = &a1 + amount = &spentOutput.Source.Value.Amount + destPos = &e.WitnessDestination.Position + s := e.SpentOutputId.Bytes() + spentOutputID = &s + + case *bc.VetoInput: + voteOutput := tx.Entries[*e.SpentOutputId].(*bc.VoteOutput) + a1 := voteOutput.Source.Value.AssetId.Bytes() + assetID = &a1 + amount = &voteOutput.Source.Value.Amount + destPos = &e.WitnessDestination.Position + s := e.SpentOutputId.Bytes() + spentOutputID = &s - case *bc.VoteOutput: - a1 := spentOutput.Source.Value.AssetId.Bytes() - assetID = &a1 - amount = &spentOutput.Source.Value.Amount - destPos = &e.WitnessDestination.Position - s := e.SpentOutputId.Bytes() - spentOutputID = &s - } } var txSigHash *[]byte @@ -173,6 +173,19 @@ func (ec *entryContext) checkOutput(index uint64, amount uint64, assetID []byte, return false, errors.Wrapf(vm.ErrBadValue, "index %d >= 1", index) } return checkEntry(d) + + case *bc.VetoInput: + d, ok := ec.entries[*e.WitnessDestination.Ref] + if !ok { + return false, errors.Wrapf(bc.ErrMissingEntry, "entry for vetoInput destination %x not found", e.WitnessDestination.Ref.Bytes()) + } + if m, ok := d.(*bc.Mux); ok { + return checkMux(m) + } + if index != 0 { + return false, errors.Wrapf(vm.ErrBadValue, "index %d >= 1", index) + } + return checkEntry(d) } return false, vm.ErrContext diff --git a/wallet/annotated.go b/wallet/annotated.go index 4bcc507d..66048769 100644 --- a/wallet/annotated.go +++ b/wallet/annotated.go @@ -174,6 +174,16 @@ func (w *Wallet) BuildAnnotatedInput(tx *types.Tx, i uint32) *query.AnnotatedInp in.InputID = id e := tx.Entries[id] switch e := e.(type) { + case *bc.VetoInput: + in.Type = "veto" + in.ControlProgram = orig.ControlProgram() + in.Address = w.getAddressFromControlProgram(in.ControlProgram, false) + in.SpentOutputID = e.SpentOutputId + arguments := orig.Arguments() + for _, arg := range arguments { + in.WitnessArguments = append(in.WitnessArguments, arg) + } + case *bc.CrossChainInput: in.Type = "cross_chain_in" in.ControlProgram = orig.ControlProgram() diff --git a/wallet/utxo.go b/wallet/utxo.go index e1373f52..491d98cf 100644 --- a/wallet/utxo.go +++ b/wallet/utxo.go @@ -174,38 +174,41 @@ func batchSaveUtxos(utxos []*account.UTXO, batch dbm.Batch) error { func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO { utxos := []*account.UTXO{} for _, inpID := range tx.Tx.InputIDs { - sp, err := tx.Spend(inpID) - if err != nil { - continue - } - entryOutput, err := tx.Entry(*sp.SpentOutputId) + e, err := tx.Entry(inpID) if err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get entryOutput") continue } - utxo := &account.UTXO{} - switch resOut := entryOutput.(type) { - case *bc.IntraChainOutput: + switch inp := e.(type) { + case *bc.Spend: + resOut, err := tx.IntraChainOutput(*inp.SpentOutputId) + if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get resOut for spedn") + continue + } if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID { continue } utxo = &account.UTXO{ - OutputID: *sp.SpentOutputId, + OutputID: *inp.SpentOutputId, AssetID: *resOut.Source.Value.AssetId, Amount: resOut.Source.Value.Amount, ControlProgram: resOut.ControlProgram.Code, SourceID: *resOut.Source.Ref, SourcePos: resOut.Source.Position, } - - case *bc.VoteOutput: + case *bc.VetoInput: + resOut, err := tx.VoteOutput(*inp.SpentOutputId) + if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get resOut for vetoInput") + continue + } if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID { continue } utxo = &account.UTXO{ - OutputID: *sp.SpentOutputId, + OutputID: *inp.SpentOutputId, AssetID: *resOut.Source.Value.AssetId, Amount: resOut.Source.Value.Amount, ControlProgram: resOut.ControlProgram.Code, @@ -213,12 +216,10 @@ func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO { SourcePos: resOut.Source.Position, Vote: resOut.Vote, } - default: - log.WithFields(log.Fields{"module": logModule}).Error("txInToUtxos fail on get resOut") + log.WithFields(log.Fields{"module": logModule, "err": errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", inpID.Bytes(), e)}).Error("txInToUtxos fail on get resOut") continue } - utxos = append(utxos, utxo) } return utxos diff --git a/wallet/utxo_test.go b/wallet/utxo_test.go index c5aad355..4f76dd55 100644 --- a/wallet/utxo_test.go +++ b/wallet/utxo_test.go @@ -484,7 +484,7 @@ func TestTxInToUtxos(t *testing.T) { { tx: types.NewTx(types.TxData{ Inputs: []*types.TxInput{ - types.NewUnvoteInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 1, 1, []byte{0x51}, []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269")), + types.NewVetoInput([][]byte{}, bc.Hash{V0: 1}, bc.AssetID{V0: 1}, 1, 1, []byte{0x51}, []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269")), }, Outputs: []*types.TxOutput{ types.NewIntraChainOutput(bc.AssetID{V0: 1}, 1, []byte{0x51}), @@ -493,7 +493,7 @@ func TestTxInToUtxos(t *testing.T) { statusFail: false, wantUtxos: []*account.UTXO{ &account.UTXO{ - OutputID: bc.NewHash([32]byte{0x95, 0x23, 0x06, 0xa5, 0x2f, 0xc4, 0xe2, 0x36, 0x03, 0x0f, 0xe3, 0xe6, 0xb8, 0x0b, 0xcc, 0x3c, 0x1e, 0x17, 0x3e, 0x25, 0x95, 0xd0, 0xbf, 0x08, 0x11, 0x73, 0x06, 0xd4, 0x64, 0x9c, 0xfb, 0x3b}), + OutputID: bc.NewHash([32]byte{0x7c, 0x75, 0x7f, 0x03, 0x67, 0x9b, 0xc2, 0x8f, 0x8f, 0xbd, 0x04, 0x25, 0x72, 0x42, 0x4b, 0x0b, 0x2a, 0xa4, 0x0e, 0x10, 0x0a, 0x6e, 0x99, 0x0e, 0x6d, 0x58, 0x92, 0x1d, 0xdd, 0xbe, 0xeb, 0x1a}), AssetID: bc.AssetID{V0: 1}, Amount: 1, ControlProgram: []byte{0x51},