complete transfer v1 -> v1

This commit is contained in:
Trinity 2025-11-07 11:16:19 +07:00
parent 3a9d132f8d
commit 3ab2b57835
7 changed files with 818 additions and 400 deletions

View File

@ -478,7 +478,7 @@ func (*NockchainNamedSpend_Witness) isNockchainNamedSpend_SpendKind() {}
type NockchainSpendV0 struct { type NockchainSpendV0 struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Signatures []*NockchainSignature `protobuf:"bytes,1,rep,name=signatures,proto3" json:"signatures,omitempty"` Signatures []*NockchainSignature `protobuf:"bytes,1,rep,name=signatures,proto3" json:"signatures,omitempty"`
Seeds []*NockchainSeedV0 `protobuf:"bytes,2,rep,name=seeds,proto3" json:"seeds,omitempty"` Seeds []*NockchainSeed `protobuf:"bytes,2,rep,name=seeds,proto3" json:"seeds,omitempty"`
Fee uint64 `protobuf:"varint,3,opt,name=fee,proto3" json:"fee,omitempty"` Fee uint64 `protobuf:"varint,3,opt,name=fee,proto3" json:"fee,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -521,7 +521,7 @@ func (x *NockchainSpendV0) GetSignatures() []*NockchainSignature {
return nil return nil
} }
func (x *NockchainSpendV0) GetSeeds() []*NockchainSeedV0 { func (x *NockchainSpendV0) GetSeeds() []*NockchainSeed {
if x != nil { if x != nil {
return x.Seeds return x.Seeds
} }
@ -537,6 +537,9 @@ func (x *NockchainSpendV0) GetFee() uint64 {
type NockchainSpendV1 struct { type NockchainSpendV1 struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Witness []*NockchainWitness `protobuf:"bytes,1,rep,name=witness,proto3" json:"witness,omitempty"`
Seeds []*NockchainSeed `protobuf:"bytes,2,rep,name=seeds,proto3" json:"seeds,omitempty"`
Fee uint64 `protobuf:"varint,3,opt,name=fee,proto3" json:"fee,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -571,6 +574,27 @@ func (*NockchainSpendV1) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{7} return file_types_proto_rawDescGZIP(), []int{7}
} }
func (x *NockchainSpendV1) GetWitness() []*NockchainWitness {
if x != nil {
return x.Witness
}
return nil
}
func (x *NockchainSpendV1) GetSeeds() []*NockchainSeed {
if x != nil {
return x.Seeds
}
return nil
}
func (x *NockchainSpendV1) GetFee() uint64 {
if x != nil {
return x.Fee
}
return 0
}
type NockchainNote struct { type NockchainNote struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Note: // Types that are valid to be assigned to Note:
@ -658,9 +682,9 @@ type NockchainNoteV0 struct {
Version Version `protobuf:"varint,1,opt,name=version,proto3,enum=nockchain.public.v2.Version" json:"version,omitempty"` Version Version `protobuf:"varint,1,opt,name=version,proto3,enum=nockchain.public.v2.Version" json:"version,omitempty"`
OriginPage uint64 `protobuf:"varint,2,opt,name=origin_page,json=originPage,proto3" json:"origin_page,omitempty"` OriginPage uint64 `protobuf:"varint,2,opt,name=origin_page,json=originPage,proto3" json:"origin_page,omitempty"`
Name *NockchainName `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` Name *NockchainName `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
Lock *NockchainLock `protobuf:"bytes,5,opt,name=lock,proto3" json:"lock,omitempty"` Lock *NockchainLock `protobuf:"bytes,4,opt,name=lock,proto3" json:"lock,omitempty"`
Source *NockchainSource `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"` Source *NockchainSource `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"`
Asset uint64 `protobuf:"varint,7,opt,name=asset,proto3" json:"asset,omitempty"` Asset uint64 `protobuf:"varint,6,opt,name=asset,proto3" json:"asset,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -739,6 +763,11 @@ func (x *NockchainNoteV0) GetAsset() uint64 {
type NockchainNoteV1 struct { type NockchainNoteV1 struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Version Version `protobuf:"varint,1,opt,name=version,proto3,enum=nockchain.public.v2.Version" json:"version,omitempty"`
OriginPage uint64 `protobuf:"varint,2,opt,name=origin_page,json=originPage,proto3" json:"origin_page,omitempty"`
Name *NockchainName `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
NoteData *NockchainLock `protobuf:"bytes,4,opt,name=note_data,json=noteData,proto3" json:"note_data,omitempty"`
Assets uint64 `protobuf:"varint,5,opt,name=assets,proto3" json:"assets,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -773,6 +802,41 @@ func (*NockchainNoteV1) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{10} return file_types_proto_rawDescGZIP(), []int{10}
} }
func (x *NockchainNoteV1) GetVersion() Version {
if x != nil {
return x.Version
}
return Version_V0
}
func (x *NockchainNoteV1) GetOriginPage() uint64 {
if x != nil {
return x.OriginPage
}
return 0
}
func (x *NockchainNoteV1) GetName() *NockchainName {
if x != nil {
return x.Name
}
return nil
}
func (x *NockchainNoteV1) GetNoteData() *NockchainLock {
if x != nil {
return x.NoteData
}
return nil
}
func (x *NockchainNoteV1) GetAssets() uint64 {
if x != nil {
return x.Assets
}
return 0
}
type NockchainName struct { type NockchainName struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
First string `protobuf:"bytes,1,opt,name=first,proto3" json:"first,omitempty"` First string `protobuf:"bytes,1,opt,name=first,proto3" json:"first,omitempty"`
@ -885,31 +949,28 @@ func (x *NockchainSignature) GetSig() []uint64 {
return nil return nil
} }
type NockchainSeedV0 struct { type NockchainWitness struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
OutputSource *NockchainSource `protobuf:"bytes,1,opt,name=output_source,json=outputSource,proto3,oneof" json:"output_source,omitempty"` Lmp *NockchainLockMerkleProof `protobuf:"bytes,1,opt,name=lmp,proto3" json:"lmp,omitempty"`
LockRoot string `protobuf:"bytes,2,opt,name=lock_root,json=lockRoot,proto3" json:"lock_root,omitempty"` Pkh []*NockchainSignature `protobuf:"bytes,2,rep,name=pkh,proto3" json:"pkh,omitempty"`
NoteData *NockchainLock `protobuf:"bytes,3,opt,name=note_data,json=noteData,proto3" json:"note_data,omitempty"`
Gift uint64 `protobuf:"varint,4,opt,name=gift,proto3" json:"gift,omitempty"`
ParentHash string `protobuf:"bytes,5,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
func (x *NockchainSeedV0) Reset() { func (x *NockchainWitness) Reset() {
*x = NockchainSeedV0{} *x = NockchainWitness{}
mi := &file_types_proto_msgTypes[13] mi := &file_types_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
func (x *NockchainSeedV0) String() string { func (x *NockchainWitness) String() string {
return protoimpl.X.MessageStringOf(x) return protoimpl.X.MessageStringOf(x)
} }
func (*NockchainSeedV0) ProtoMessage() {} func (*NockchainWitness) ProtoMessage() {}
func (x *NockchainSeedV0) ProtoReflect() protoreflect.Message { func (x *NockchainWitness) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[13] mi := &file_types_proto_msgTypes[13]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -921,40 +982,155 @@ func (x *NockchainSeedV0) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x) return mi.MessageOf(x)
} }
// Deprecated: Use NockchainSeedV0.ProtoReflect.Descriptor instead. // Deprecated: Use NockchainWitness.ProtoReflect.Descriptor instead.
func (*NockchainSeedV0) Descriptor() ([]byte, []int) { func (*NockchainWitness) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{13} return file_types_proto_rawDescGZIP(), []int{13}
} }
func (x *NockchainSeedV0) GetOutputSource() *NockchainSource { func (x *NockchainWitness) GetLmp() *NockchainLockMerkleProof {
if x != nil {
return x.Lmp
}
return nil
}
func (x *NockchainWitness) GetPkh() []*NockchainSignature {
if x != nil {
return x.Pkh
}
return nil
}
type NockchainLockMerkleProof struct {
state protoimpl.MessageState `protogen:"open.v1"`
SpendCondition *NockchainLock `protobuf:"bytes,1,opt,name=spend_condition,json=spendCondition,proto3" json:"spend_condition,omitempty"`
Axis uint64 `protobuf:"varint,2,opt,name=axis,proto3" json:"axis,omitempty"`
MerkleRoot string `protobuf:"bytes,3,opt,name=merkle_root,json=merkleRoot,proto3" json:"merkle_root,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NockchainLockMerkleProof) Reset() {
*x = NockchainLockMerkleProof{}
mi := &file_types_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NockchainLockMerkleProof) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NockchainLockMerkleProof) ProtoMessage() {}
func (x *NockchainLockMerkleProof) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NockchainLockMerkleProof.ProtoReflect.Descriptor instead.
func (*NockchainLockMerkleProof) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{14}
}
func (x *NockchainLockMerkleProof) GetSpendCondition() *NockchainLock {
if x != nil {
return x.SpendCondition
}
return nil
}
func (x *NockchainLockMerkleProof) GetAxis() uint64 {
if x != nil {
return x.Axis
}
return 0
}
func (x *NockchainLockMerkleProof) GetMerkleRoot() string {
if x != nil {
return x.MerkleRoot
}
return ""
}
type NockchainSeed struct {
state protoimpl.MessageState `protogen:"open.v1"`
OutputSource *NockchainSource `protobuf:"bytes,1,opt,name=output_source,json=outputSource,proto3,oneof" json:"output_source,omitempty"`
LockRoot string `protobuf:"bytes,2,opt,name=lock_root,json=lockRoot,proto3" json:"lock_root,omitempty"`
NoteData *NockchainLock `protobuf:"bytes,3,opt,name=note_data,json=noteData,proto3" json:"note_data,omitempty"`
Gift uint64 `protobuf:"varint,4,opt,name=gift,proto3" json:"gift,omitempty"`
ParentHash string `protobuf:"bytes,5,opt,name=parent_hash,json=parentHash,proto3" json:"parent_hash,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NockchainSeed) Reset() {
*x = NockchainSeed{}
mi := &file_types_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NockchainSeed) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NockchainSeed) ProtoMessage() {}
func (x *NockchainSeed) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NockchainSeed.ProtoReflect.Descriptor instead.
func (*NockchainSeed) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{15}
}
func (x *NockchainSeed) GetOutputSource() *NockchainSource {
if x != nil { if x != nil {
return x.OutputSource return x.OutputSource
} }
return nil return nil
} }
func (x *NockchainSeedV0) GetLockRoot() string { func (x *NockchainSeed) GetLockRoot() string {
if x != nil { if x != nil {
return x.LockRoot return x.LockRoot
} }
return "" return ""
} }
func (x *NockchainSeedV0) GetNoteData() *NockchainLock { func (x *NockchainSeed) GetNoteData() *NockchainLock {
if x != nil { if x != nil {
return x.NoteData return x.NoteData
} }
return nil return nil
} }
func (x *NockchainSeedV0) GetGift() uint64 { func (x *NockchainSeed) GetGift() uint64 {
if x != nil { if x != nil {
return x.Gift return x.Gift
} }
return 0 return 0
} }
func (x *NockchainSeedV0) GetParentHash() string { func (x *NockchainSeed) GetParentHash() string {
if x != nil { if x != nil {
return x.ParentHash return x.ParentHash
} }
@ -971,7 +1147,7 @@ type NockchainLock struct {
func (x *NockchainLock) Reset() { func (x *NockchainLock) Reset() {
*x = NockchainLock{} *x = NockchainLock{}
mi := &file_types_proto_msgTypes[14] mi := &file_types_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -983,7 +1159,7 @@ func (x *NockchainLock) String() string {
func (*NockchainLock) ProtoMessage() {} func (*NockchainLock) ProtoMessage() {}
func (x *NockchainLock) ProtoReflect() protoreflect.Message { func (x *NockchainLock) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[14] mi := &file_types_proto_msgTypes[16]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -996,7 +1172,7 @@ func (x *NockchainLock) ProtoReflect() protoreflect.Message {
// Deprecated: Use NockchainLock.ProtoReflect.Descriptor instead. // Deprecated: Use NockchainLock.ProtoReflect.Descriptor instead.
func (*NockchainLock) Descriptor() ([]byte, []int) { func (*NockchainLock) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{14} return file_types_proto_rawDescGZIP(), []int{16}
} }
func (x *NockchainLock) GetKeysRequired() uint64 { func (x *NockchainLock) GetKeysRequired() uint64 {
@ -1023,7 +1199,7 @@ type NockchainSource struct {
func (x *NockchainSource) Reset() { func (x *NockchainSource) Reset() {
*x = NockchainSource{} *x = NockchainSource{}
mi := &file_types_proto_msgTypes[15] mi := &file_types_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1035,7 +1211,7 @@ func (x *NockchainSource) String() string {
func (*NockchainSource) ProtoMessage() {} func (*NockchainSource) ProtoMessage() {}
func (x *NockchainSource) ProtoReflect() protoreflect.Message { func (x *NockchainSource) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[15] mi := &file_types_proto_msgTypes[17]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1048,7 +1224,7 @@ func (x *NockchainSource) ProtoReflect() protoreflect.Message {
// Deprecated: Use NockchainSource.ProtoReflect.Descriptor instead. // Deprecated: Use NockchainSource.ProtoReflect.Descriptor instead.
func (*NockchainSource) Descriptor() ([]byte, []int) { func (*NockchainSource) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{15} return file_types_proto_rawDescGZIP(), []int{17}
} }
func (x *NockchainSource) GetSource() string { func (x *NockchainSource) GetSource() string {
@ -1094,14 +1270,17 @@ const file_types_proto_rawDesc = "" +
"\x06legacy\x18\x02 \x01(\v2%.nockchain.public.v2.NockchainSpendV0H\x00R\x06legacy\x12A\n" + "\x06legacy\x18\x02 \x01(\v2%.nockchain.public.v2.NockchainSpendV0H\x00R\x06legacy\x12A\n" +
"\awitness\x18\x03 \x01(\v2%.nockchain.public.v2.NockchainSpendV1H\x00R\awitnessB\f\n" + "\awitness\x18\x03 \x01(\v2%.nockchain.public.v2.NockchainSpendV1H\x00R\awitnessB\f\n" +
"\n" + "\n" +
"spend_kind\"\xa9\x01\n" + "spend_kind\"\xa7\x01\n" +
"\x10NockchainSpendV0\x12G\n" + "\x10NockchainSpendV0\x12G\n" +
"\n" + "\n" +
"signatures\x18\x01 \x03(\v2'.nockchain.public.v2.NockchainSignatureR\n" + "signatures\x18\x01 \x03(\v2'.nockchain.public.v2.NockchainSignatureR\n" +
"signatures\x12:\n" + "signatures\x128\n" +
"\x05seeds\x18\x02 \x03(\v2$.nockchain.public.v2.NockchainSeedV0R\x05seeds\x12\x10\n" + "\x05seeds\x18\x02 \x03(\v2\".nockchain.public.v2.NockchainSeedR\x05seeds\x12\x10\n" +
"\x03fee\x18\x03 \x01(\x04R\x03fee\"\x12\n" + "\x03fee\x18\x03 \x01(\x04R\x03fee\"\x9f\x01\n" +
"\x10NockchainSpendV1\"\x87\x01\n" + "\x10NockchainSpendV1\x12?\n" +
"\awitness\x18\x01 \x03(\v2%.nockchain.public.v2.NockchainWitnessR\awitness\x128\n" +
"\x05seeds\x18\x02 \x03(\v2\".nockchain.public.v2.NockchainSeedR\x05seeds\x12\x10\n" +
"\x03fee\x18\x03 \x01(\x04R\x03fee\"\x87\x01\n" +
"\rNockchainNote\x126\n" + "\rNockchainNote\x126\n" +
"\x02v0\x18\x01 \x01(\v2$.nockchain.public.v2.NockchainNoteV0H\x00R\x02v0\x126\n" + "\x02v0\x18\x01 \x01(\v2$.nockchain.public.v2.NockchainNoteV0H\x00R\x02v0\x126\n" +
"\x02v1\x18\x02 \x01(\v2$.nockchain.public.v2.NockchainNoteV1H\x00R\x02v1B\x06\n" + "\x02v1\x18\x02 \x01(\v2$.nockchain.public.v2.NockchainNoteV1H\x00R\x02v1B\x06\n" +
@ -1111,18 +1290,32 @@ const file_types_proto_rawDesc = "" +
"\vorigin_page\x18\x02 \x01(\x04R\n" + "\vorigin_page\x18\x02 \x01(\x04R\n" +
"originPage\x126\n" + "originPage\x126\n" +
"\x04name\x18\x03 \x01(\v2\".nockchain.public.v2.NockchainNameR\x04name\x126\n" + "\x04name\x18\x03 \x01(\v2\".nockchain.public.v2.NockchainNameR\x04name\x126\n" +
"\x04lock\x18\x05 \x01(\v2\".nockchain.public.v2.NockchainLockR\x04lock\x12<\n" + "\x04lock\x18\x04 \x01(\v2\".nockchain.public.v2.NockchainLockR\x04lock\x12<\n" +
"\x06source\x18\x06 \x01(\v2$.nockchain.public.v2.NockchainSourceR\x06source\x12\x14\n" + "\x06source\x18\x05 \x01(\v2$.nockchain.public.v2.NockchainSourceR\x06source\x12\x14\n" +
"\x05asset\x18\a \x01(\x04R\x05asset\"\x11\n" + "\x05asset\x18\x06 \x01(\x04R\x05asset\"\xfb\x01\n" +
"\x0fNockchainNoteV1\"9\n" + "\x0fNockchainNoteV1\x126\n" +
"\aversion\x18\x01 \x01(\x0e2\x1c.nockchain.public.v2.VersionR\aversion\x12\x1f\n" +
"\vorigin_page\x18\x02 \x01(\x04R\n" +
"originPage\x126\n" +
"\x04name\x18\x03 \x01(\v2\".nockchain.public.v2.NockchainNameR\x04name\x12?\n" +
"\tnote_data\x18\x04 \x01(\v2\".nockchain.public.v2.NockchainLockR\bnoteData\x12\x16\n" +
"\x06assets\x18\x05 \x01(\x04R\x06assets\"9\n" +
"\rNockchainName\x12\x14\n" + "\rNockchainName\x12\x14\n" +
"\x05first\x18\x01 \x01(\tR\x05first\x12\x12\n" + "\x05first\x18\x01 \x01(\tR\x05first\x12\x12\n" +
"\x04last\x18\x02 \x01(\tR\x04last\"R\n" + "\x04last\x18\x02 \x01(\tR\x04last\"R\n" +
"\x12NockchainSignature\x12\x16\n" + "\x12NockchainSignature\x12\x16\n" +
"\x06pubkey\x18\x01 \x01(\tR\x06pubkey\x12\x12\n" + "\x06pubkey\x18\x01 \x01(\tR\x06pubkey\x12\x12\n" +
"\x04chal\x18\x02 \x03(\x04R\x04chal\x12\x10\n" + "\x04chal\x18\x02 \x03(\x04R\x04chal\x12\x10\n" +
"\x03sig\x18\x03 \x03(\x04R\x03sig\"\x86\x02\n" + "\x03sig\x18\x03 \x03(\x04R\x03sig\"\x8e\x01\n" +
"\x0fNockchainSeedV0\x12N\n" + "\x10NockchainWitness\x12?\n" +
"\x03lmp\x18\x01 \x01(\v2-.nockchain.public.v2.NockchainLockMerkleProofR\x03lmp\x129\n" +
"\x03pkh\x18\x02 \x03(\v2'.nockchain.public.v2.NockchainSignatureR\x03pkh\"\x9c\x01\n" +
"\x18NockchainLockMerkleProof\x12K\n" +
"\x0fspend_condition\x18\x01 \x01(\v2\".nockchain.public.v2.NockchainLockR\x0espendCondition\x12\x12\n" +
"\x04axis\x18\x02 \x01(\x04R\x04axis\x12\x1f\n" +
"\vmerkle_root\x18\x03 \x01(\tR\n" +
"merkleRoot\"\x84\x02\n" +
"\rNockchainSeed\x12N\n" +
"\routput_source\x18\x01 \x01(\v2$.nockchain.public.v2.NockchainSourceH\x00R\foutputSource\x88\x01\x01\x12\x1b\n" + "\routput_source\x18\x01 \x01(\v2$.nockchain.public.v2.NockchainSourceH\x00R\foutputSource\x88\x01\x01\x12\x1b\n" +
"\tlock_root\x18\x02 \x01(\tR\blockRoot\x12?\n" + "\tlock_root\x18\x02 \x01(\tR\blockRoot\x12?\n" +
"\tnote_data\x18\x03 \x01(\v2\".nockchain.public.v2.NockchainLockR\bnoteData\x12\x12\n" + "\tnote_data\x18\x03 \x01(\v2\".nockchain.public.v2.NockchainLockR\bnoteData\x12\x12\n" +
@ -1164,7 +1357,7 @@ func file_types_proto_rawDescGZIP() []byte {
} }
var file_types_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_types_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
var file_types_proto_goTypes = []any{ var file_types_proto_goTypes = []any{
(ImportType)(0), // 0: nockchain.public.v2.ImportType (ImportType)(0), // 0: nockchain.public.v2.ImportType
(Version)(0), // 1: nockchain.public.v2.Version (Version)(0), // 1: nockchain.public.v2.Version
@ -1181,13 +1374,15 @@ var file_types_proto_goTypes = []any{
(*NockchainNoteV1)(nil), // 12: nockchain.public.v2.NockchainNoteV1 (*NockchainNoteV1)(nil), // 12: nockchain.public.v2.NockchainNoteV1
(*NockchainName)(nil), // 13: nockchain.public.v2.NockchainName (*NockchainName)(nil), // 13: nockchain.public.v2.NockchainName
(*NockchainSignature)(nil), // 14: nockchain.public.v2.NockchainSignature (*NockchainSignature)(nil), // 14: nockchain.public.v2.NockchainSignature
(*NockchainSeedV0)(nil), // 15: nockchain.public.v2.NockchainSeedV0 (*NockchainWitness)(nil), // 15: nockchain.public.v2.NockchainWitness
(*NockchainLock)(nil), // 16: nockchain.public.v2.NockchainLock (*NockchainLockMerkleProof)(nil), // 16: nockchain.public.v2.NockchainLockMerkleProof
(*NockchainSource)(nil), // 17: nockchain.public.v2.NockchainSource (*NockchainSeed)(nil), // 17: nockchain.public.v2.NockchainSeed
(*Balance)(nil), // 18: nockchain.public.v2.Balance (*NockchainLock)(nil), // 18: nockchain.public.v2.NockchainLock
(*NockchainSource)(nil), // 19: nockchain.public.v2.NockchainSource
(*Balance)(nil), // 20: nockchain.public.v2.Balance
} }
var file_types_proto_depIdxs = []int32{ var file_types_proto_depIdxs = []int32{
18, // 0: nockchain.public.v2.ScanData.data:type_name -> nockchain.public.v2.Balance 20, // 0: nockchain.public.v2.ScanData.data:type_name -> nockchain.public.v2.Balance
4, // 1: nockchain.public.v2.TimelockIntent.absolute:type_name -> nockchain.public.v2.TimelockRange 4, // 1: nockchain.public.v2.TimelockIntent.absolute:type_name -> nockchain.public.v2.TimelockRange
4, // 2: nockchain.public.v2.TimelockIntent.relative:type_name -> nockchain.public.v2.TimelockRange 4, // 2: nockchain.public.v2.TimelockIntent.relative:type_name -> nockchain.public.v2.TimelockRange
5, // 3: nockchain.public.v2.TimelockRange.min:type_name -> nockchain.public.v2.Timelock 5, // 3: nockchain.public.v2.TimelockRange.min:type_name -> nockchain.public.v2.Timelock
@ -1198,20 +1393,28 @@ var file_types_proto_depIdxs = []int32{
8, // 8: nockchain.public.v2.NockchainNamedSpend.legacy:type_name -> nockchain.public.v2.NockchainSpendV0 8, // 8: nockchain.public.v2.NockchainNamedSpend.legacy:type_name -> nockchain.public.v2.NockchainSpendV0
9, // 9: nockchain.public.v2.NockchainNamedSpend.witness:type_name -> nockchain.public.v2.NockchainSpendV1 9, // 9: nockchain.public.v2.NockchainNamedSpend.witness:type_name -> nockchain.public.v2.NockchainSpendV1
14, // 10: nockchain.public.v2.NockchainSpendV0.signatures:type_name -> nockchain.public.v2.NockchainSignature 14, // 10: nockchain.public.v2.NockchainSpendV0.signatures:type_name -> nockchain.public.v2.NockchainSignature
15, // 11: nockchain.public.v2.NockchainSpendV0.seeds:type_name -> nockchain.public.v2.NockchainSeedV0 17, // 11: nockchain.public.v2.NockchainSpendV0.seeds:type_name -> nockchain.public.v2.NockchainSeed
11, // 12: nockchain.public.v2.NockchainNote.v0:type_name -> nockchain.public.v2.NockchainNoteV0 15, // 12: nockchain.public.v2.NockchainSpendV1.witness:type_name -> nockchain.public.v2.NockchainWitness
12, // 13: nockchain.public.v2.NockchainNote.v1:type_name -> nockchain.public.v2.NockchainNoteV1 17, // 13: nockchain.public.v2.NockchainSpendV1.seeds:type_name -> nockchain.public.v2.NockchainSeed
1, // 14: nockchain.public.v2.NockchainNoteV0.version:type_name -> nockchain.public.v2.Version 11, // 14: nockchain.public.v2.NockchainNote.v0:type_name -> nockchain.public.v2.NockchainNoteV0
13, // 15: nockchain.public.v2.NockchainNoteV0.name:type_name -> nockchain.public.v2.NockchainName 12, // 15: nockchain.public.v2.NockchainNote.v1:type_name -> nockchain.public.v2.NockchainNoteV1
16, // 16: nockchain.public.v2.NockchainNoteV0.lock:type_name -> nockchain.public.v2.NockchainLock 1, // 16: nockchain.public.v2.NockchainNoteV0.version:type_name -> nockchain.public.v2.Version
17, // 17: nockchain.public.v2.NockchainNoteV0.source:type_name -> nockchain.public.v2.NockchainSource 13, // 17: nockchain.public.v2.NockchainNoteV0.name:type_name -> nockchain.public.v2.NockchainName
17, // 18: nockchain.public.v2.NockchainSeedV0.output_source:type_name -> nockchain.public.v2.NockchainSource 18, // 18: nockchain.public.v2.NockchainNoteV0.lock:type_name -> nockchain.public.v2.NockchainLock
16, // 19: nockchain.public.v2.NockchainSeedV0.note_data:type_name -> nockchain.public.v2.NockchainLock 19, // 19: nockchain.public.v2.NockchainNoteV0.source:type_name -> nockchain.public.v2.NockchainSource
20, // [20:20] is the sub-list for method output_type 1, // 20: nockchain.public.v2.NockchainNoteV1.version:type_name -> nockchain.public.v2.Version
20, // [20:20] is the sub-list for method input_type 13, // 21: nockchain.public.v2.NockchainNoteV1.name:type_name -> nockchain.public.v2.NockchainName
20, // [20:20] is the sub-list for extension type_name 18, // 22: nockchain.public.v2.NockchainNoteV1.note_data:type_name -> nockchain.public.v2.NockchainLock
20, // [20:20] is the sub-list for extension extendee 16, // 23: nockchain.public.v2.NockchainWitness.lmp:type_name -> nockchain.public.v2.NockchainLockMerkleProof
0, // [0:20] is the sub-list for field type_name 14, // 24: nockchain.public.v2.NockchainWitness.pkh:type_name -> nockchain.public.v2.NockchainSignature
18, // 25: nockchain.public.v2.NockchainLockMerkleProof.spend_condition:type_name -> nockchain.public.v2.NockchainLock
19, // 26: nockchain.public.v2.NockchainSeed.output_source:type_name -> nockchain.public.v2.NockchainSource
18, // 27: nockchain.public.v2.NockchainSeed.note_data:type_name -> nockchain.public.v2.NockchainLock
28, // [28:28] is the sub-list for method output_type
28, // [28:28] is the sub-list for method input_type
28, // [28:28] is the sub-list for extension type_name
28, // [28:28] is the sub-list for extension extendee
0, // [0:28] is the sub-list for field type_name
} }
func init() { file_types_proto_init() } func init() { file_types_proto_init() }
@ -1230,14 +1433,14 @@ func file_types_proto_init() {
(*NockchainNote_V0)(nil), (*NockchainNote_V0)(nil),
(*NockchainNote_V1)(nil), (*NockchainNote_V1)(nil),
} }
file_types_proto_msgTypes[13].OneofWrappers = []any{} file_types_proto_msgTypes[15].OneofWrappers = []any{}
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),
NumEnums: 2, NumEnums: 2,
NumMessages: 16, NumMessages: 18,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@ -46,11 +46,14 @@ message NockchainNamedSpend {
message NockchainSpendV0 { message NockchainSpendV0 {
repeated NockchainSignature signatures = 1; repeated NockchainSignature signatures = 1;
repeated NockchainSeedV0 seeds = 2; repeated NockchainSeed seeds = 2;
uint64 fee = 3; uint64 fee = 3;
} }
message NockchainSpendV1 { message NockchainSpendV1 {
repeated NockchainWitness witness = 1;
repeated NockchainSeed seeds = 2;
uint64 fee = 3;
} }
message NockchainNote { message NockchainNote {
@ -63,12 +66,17 @@ message NockchainNoteV0 {
Version version = 1; Version version = 1;
uint64 origin_page = 2; uint64 origin_page = 2;
NockchainName name = 3; NockchainName name = 3;
NockchainLock lock = 5; NockchainLock lock = 4;
NockchainSource source = 6; NockchainSource source = 5;
uint64 asset =7; uint64 asset =6;
} }
message NockchainNoteV1 { message NockchainNoteV1 {
Version version = 1;
uint64 origin_page = 2;
NockchainName name = 3;
NockchainLock note_data = 4;
uint64 assets = 5;
} }
message NockchainName { message NockchainName {
@ -82,7 +90,18 @@ message NockchainSignature {
repeated uint64 sig = 3; repeated uint64 sig = 3;
} }
message NockchainSeedV0 { message NockchainWitness {
NockchainLockMerkleProof lmp = 1;
repeated NockchainSignature pkh = 2;
}
message NockchainLockMerkleProof {
NockchainLock spend_condition = 1;
uint64 axis = 2;
string merkle_root = 3;
}
message NockchainSeed {
optional NockchainSource output_source = 1; optional NockchainSource output_source = 1;
string lock_root = 2; string lock_root = 2;
NockchainLock note_data = 3; NockchainLock note_data = 3;

View File

@ -9,7 +9,9 @@ import (
"github.com/phamminh0811/private-grpc/nockchain" "github.com/phamminh0811/private-grpc/nockchain"
) )
var LastName = [5]uint64{9541855607561054508, 12383849149342406623, 11220017934615522559, 678840671137489369, 8985908938884028381} var (
MerkleHash = [5]uint64{7971649669803894685, 16663670492333541326, 11038715785817710450, 18178011379925321681, 17049062282971338707}
)
func HashPubkey(pkPoint crypto.CheetahPoint) [5]uint64 { func HashPubkey(pkPoint crypto.CheetahPoint) [5]uint64 {
belts := []crypto.Belt{{Value: 13}} belts := []crypto.Belt{{Value: 13}}
@ -22,7 +24,7 @@ func HashPubkey(pkPoint crypto.CheetahPoint) [5]uint64 {
return crypto.Tip5HashBelts(belts) return crypto.Tip5HashBelts(belts)
} }
func HashSignature(signature *nockchain.NockchainSignature) ([5]uint64, error) { func HashSignatureV0(signature *nockchain.NockchainSignature) ([5]uint64, error) {
belts := []crypto.Belt{{Value: 16}} belts := []crypto.Belt{{Value: 16}}
for _, i := range signature.Chal { for _, i := range signature.Chal {
belts = append(belts, crypto.Belt{Value: i}) belts = append(belts, crypto.Belt{Value: i})
@ -43,6 +45,42 @@ func HashSignature(signature *nockchain.NockchainSignature) ([5]uint64, error) {
return crypto.Tip5RehashTenCell(sigHash, crypto.Tip5ZeroZero), nil return crypto.Tip5RehashTenCell(sigHash, crypto.Tip5ZeroZero), nil
} }
func HashSignatureV1(signature *nockchain.NockchainSignature) ([5]uint64, error) {
belts := []crypto.Belt{{Value: 16}}
for _, i := range signature.Chal {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range signature.Sig {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range crypto.MagicDyckForT8 {
belts = append(belts, crypto.Belt{Value: i})
}
sigHash := crypto.Tip5HashBelts(belts)
pkPoint, err := crypto.CheetaPointFromBytes(base58.Decode(signature.Pubkey))
if err != nil {
return [5]uint64{}, err
}
pkHash := HashPubkey(pkPoint)
sigHash = crypto.Tip5RehashTenCell(pkHash, sigHash)
pkHashSig := crypto.Tip5RehashTenCell(pkHash, sigHash)
return crypto.Tip5RehashTenCell(pkHashSig, crypto.Tip5ZeroZero), nil
}
func HashWitness(witness *nockchain.NockchainWitness) ([5]uint64, error) {
spendConditionHash := HashLock(witness.Lmp.SpendCondition)
rootHash := crypto.Base58ToTip5Hash(witness.Lmp.MerkleRoot)
rootHashZero := crypto.Tip5RehashTenCell(rootHash, crypto.Tip5Zero)
axisHashRoot := crypto.Tip5RehashTenCell(MerkleHash, rootHashZero)
lmpHash := crypto.Tip5RehashTenCell(spendConditionHash, axisHashRoot)
sigHash, err := HashSignatureV1(witness.Pkh[0])
if err != nil {
return [5]uint64{}, err
}
sigHashZeroZero := crypto.Tip5RehashTenCell(sigHash, crypto.Tip5ZeroZero)
return crypto.Tip5RehashTenCell(lmpHash, sigHashZeroZero), nil
}
func HashNoteData(lock *nockchain.NockchainLock) [5]uint64 { func HashNoteData(lock *nockchain.NockchainLock) [5]uint64 {
keysRequiredHash := crypto.Tip5HashLeaf(lock.KeysRequired) keysRequiredHash := crypto.Tip5HashLeaf(lock.KeysRequired)
// TODO: handle multisig // TODO: handle multisig
@ -67,9 +105,10 @@ func HashOwner(pkPoint crypto.CheetahPoint) [5]uint64 {
return crypto.Tip5RehashTenCell(crypto.Tip5One, pkHashedZeroZero) return crypto.Tip5RehashTenCell(crypto.Tip5One, pkHashedZeroZero)
} }
func NockName(ownerHash [5]uint64) ([5]uint64, [5]uint64) { func NockFirstName(ownerHash [5]uint64) [5]uint64 {
firstName := first(ownerHash) ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
return firstName, LastName ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
return crypto.Tip5RehashTenCell(crypto.Tip5Zero, ownerHashZeroOne)
} }
func HashName(name *nockchain.NockchainName) [5]uint64 { func HashName(name *nockchain.NockchainName) [5]uint64 {
@ -117,6 +156,19 @@ func HashNoteV0(note *nockchain.NockchainNoteV0) ([5]uint64, error) {
return crypto.Tip5RehashTenCell(p, q), nil return crypto.Tip5RehashTenCell(p, q), nil
} }
func HashNoteV1(note *nockchain.NockchainNoteV1) [5]uint64 {
versionHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Version)}})
blockHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: note.OriginPage}})
nameHash := HashName(note.Name)
noteDataHash := HashNoteData(note.NoteData)
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Assets)}})
hashNoteDataAsset := crypto.Tip5RehashTenCell(noteDataHash, assetHash)
hashNameNoteDataAsset := crypto.Tip5RehashTenCell(nameHash, hashNoteDataAsset)
q := crypto.Tip5RehashTenCell(blockHash, hashNameNoteDataAsset)
return crypto.Tip5RehashTenCell(versionHash, q)
}
func HashTimelockIntent(timelock *nockchain.TimelockIntent) [5]uint64 { func HashTimelockIntent(timelock *nockchain.TimelockIntent) [5]uint64 {
if timelock == nil { if timelock == nil {
return crypto.Tip5Zero return crypto.Tip5Zero
@ -201,29 +253,26 @@ func HashSource(source *nockchain.NockchainSource) [5]uint64 {
return crypto.Tip5RehashTenCell(sourceHash, crypto.Tip5One) return crypto.Tip5RehashTenCell(sourceHash, crypto.Tip5One)
} }
func HashSeedWithoutSource(seed *nockchain.NockchainSeedV0) [5]uint64 { func HashSeedWithoutSource(seed *nockchain.NockchainSeed) [5]uint64 {
lockRoot := crypto.Base58ToTip5Hash(seed.LockRoot) lockRoot := crypto.Base58ToTip5Hash(seed.LockRoot)
fmt.Println("lockRoot:", lockRoot)
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: seed.Gift}}) assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: seed.Gift}})
parentHash := crypto.Base58ToTip5Hash(seed.ParentHash) parentHash := crypto.Base58ToTip5Hash(seed.ParentHash)
fmt.Println("parentHash:", parentHash)
assetHashparentHash := crypto.Tip5RehashTenCell(assetHash, parentHash) assetHashparentHash := crypto.Tip5RehashTenCell(assetHash, parentHash)
noteDataHash := HashNoteData(seed.NoteData) noteDataHash := HashNoteData(seed.NoteData)
fmt.Println("noteDataHash:", noteDataHash)
noteDataHashAssetParentHash := crypto.Tip5RehashTenCell(noteDataHash, assetHashparentHash) noteDataHashAssetParentHash := crypto.Tip5RehashTenCell(noteDataHash, assetHashparentHash)
seedHash := crypto.Tip5RehashTenCell(lockRoot, noteDataHashAssetParentHash) seedHash := crypto.Tip5RehashTenCell(lockRoot, noteDataHashAssetParentHash)
return seedHash return seedHash
} }
func HashSeed(seed *nockchain.NockchainSeedV0) [5]uint64 { func HashSeed(seed *nockchain.NockchainSeed) [5]uint64 {
seedHash := HashSeedWithoutSource(seed) seedHash := HashSeedWithoutSource(seed)
sourceHash := HashSource(seed.OutputSource) sourceHash := HashSource(seed.OutputSource)
return crypto.Tip5RehashTenCell(sourceHash, seedHash) return crypto.Tip5RehashTenCell(sourceHash, seedHash)
} }
func HashSeedVarLen(seed *nockchain.NockchainSeedV0) [5]uint64 { func HashSeedVarLen(seed *nockchain.NockchainSeed) [5]uint64 {
belts := []crypto.Belt{{Value: 0}} belts := []crypto.Belt{{Value: 0}}
lockRoot := crypto.Base58ToTip5Hash(seed.LockRoot) lockRoot := crypto.Base58ToTip5Hash(seed.LockRoot)
for _, i := range lockRoot { for _, i := range lockRoot {
@ -284,85 +333,91 @@ func HashSpendV0(spend *nockchain.NockchainSpendV0) ([5]uint64, error) {
return [5]uint64{}, fmt.Errorf("signatures can not be empty") return [5]uint64{}, fmt.Errorf("signatures can not be empty")
} }
sigHash, err := HashSignature(spend.Signatures[0]) sigHash, err := HashSignatureV0(spend.Signatures[0])
if err != nil { if err != nil {
return [5]uint64{}, err return [5]uint64{}, err
} }
seedsTree := NewZTree( seedHashFee, err := HashSeedsAndFee(spend.Seeds, spend.Fee)
func(i interface{}) [5]uint64 {
if seed, ok := i.(*nockchain.NockchainSeedV0); ok {
return HashSeedVarLen(seed)
} else {
return [5]uint64{}
}
},
func(i interface{}) ([5]uint64, error) {
if seed, ok := i.(*nockchain.NockchainSeedV0); ok {
return HashSeedWithoutSource(seed), nil
} else {
return [5]uint64{}, fmt.Errorf("invalid input type")
}
},
)
for _, seed := range spend.Seeds {
seedsTree.Insert(seed, seed)
}
finalSeedHash, err := seedsTree.Hash()
if err != nil { if err != nil {
return [5]uint64{}, err return [5]uint64{}, err
} }
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}})
seedHashFee := crypto.Tip5RehashTenCell(finalSeedHash, feeHash)
return crypto.Tip5RehashTenCell(sigHash, seedHashFee), nil return crypto.Tip5RehashTenCell(sigHash, seedHashFee), nil
} }
func HashMsg(spend *nockchain.NockchainSpendV0) ([5]uint64, error) { func HashSpendV1(spend *nockchain.NockchainSpendV1) ([5]uint64, error) {
if len(spend.Witness) == 0 {
return [5]uint64{}, fmt.Errorf("witness can not be empty")
}
witnessHash, err := HashWitness(spend.Witness[0])
if err != nil {
return [5]uint64{}, err
}
seedHashFee, err := HashSeedsAndFee(spend.Seeds, spend.Fee)
if err != nil {
return [5]uint64{}, err
}
return crypto.Tip5RehashTenCell(witnessHash, seedHashFee), nil
}
func HashMsg(seeds []*nockchain.NockchainSeed, fee uint64) ([5]uint64, error) {
seedsTree := NewZTree( seedsTree := NewZTree(
func(i interface{}) [5]uint64 { func(i interface{}) [5]uint64 {
if seed, ok := i.(*nockchain.NockchainSeedV0); ok { if seed, ok := i.(*nockchain.NockchainSeed); ok {
return HashSeedVarLen(seed) return HashSeedVarLen(seed)
} else { } else {
return [5]uint64{} return [5]uint64{}
} }
}, },
func(i interface{}) ([5]uint64, error) { func(i interface{}) ([5]uint64, error) {
if seed, ok := i.(*nockchain.NockchainSeedV0); ok { if seed, ok := i.(*nockchain.NockchainSeed); ok {
return HashSeed(seed), nil return HashSeed(seed), nil
} else { } else {
return [5]uint64{}, fmt.Errorf("invalid input type") return [5]uint64{}, fmt.Errorf("invalid input type")
} }
}, },
) )
for _, seed := range spend.Seeds { for _, seed := range seeds {
seedsTree.Insert(seed, seed) seedsTree.Insert(seed, seed)
} }
finalSeedHash, err := seedsTree.Hash() finalSeedHash, err := seedsTree.Hash()
if err != nil { if err != nil {
return [5]uint64{}, err return [5]uint64{}, err
} }
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}}) feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: fee}})
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
} }
// func HashInput(input *nockchain.NockchainInput) ([5]uint64, error) { func HashSeedsAndFee(seeds []*nockchain.NockchainSeed, fee uint64) ([5]uint64, error) {
// nameHash := HashName(input.Name) seedsTree := NewZTree(
func(i interface{}) [5]uint64 {
if seed, ok := i.(*nockchain.NockchainSeed); ok {
return HashSeedVarLen(seed)
} else {
return [5]uint64{}
}
},
func(i interface{}) ([5]uint64, error) {
if seed, ok := i.(*nockchain.NockchainSeed); ok {
return HashSeedWithoutSource(seed), nil
} else {
return [5]uint64{}, fmt.Errorf("invalid input type")
}
},
)
for _, seed := range seeds {
seedsTree.Insert(seed, seed)
}
finalSeedHash, err := seedsTree.Hash()
if err != nil {
return [5]uint64{}, err
}
// noteHash, err := HashNote(input.Note) feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: fee}})
// if err != nil { return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
// return [5]uint64{}, err }
// }
// spendHash, err := HashSpend(input.Spend)
// if err != nil {
// return [5]uint64{}, err
// }
// hashNoteSpend := crypto.Tip5RehashTenCell(noteHash, spendHash)
// return crypto.Tip5RehashTenCell(nameHash, hashNoteSpend), nil
// }
func ComputeTxId(spends []*nockchain.NockchainNamedSpend, version uint64) ([5]uint64, error) { func ComputeTxId(spends []*nockchain.NockchainNamedSpend, version uint64) ([5]uint64, error) {
var spendHash [5]uint64 var spendHash [5]uint64
@ -399,7 +454,37 @@ func ComputeTxId(spends []*nockchain.NockchainNamedSpend, version uint64) ([5]ui
if err != nil { if err != nil {
return [5]uint64{}, fmt.Errorf("error hashing spends: %v", err) return [5]uint64{}, fmt.Errorf("error hashing spends: %v", err)
} }
fmt.Println("spendHash:", spendHash) case 1:
spendTree := NewZTree(
func(i interface{}) [5]uint64 {
if name, ok := i.(*nockchain.NockchainName); ok {
return HashNameVarLen(name)
} else {
return [5]uint64{}
}
},
func(i interface{}) ([5]uint64, error) {
if spendEntry, ok := i.(*nockchain.NockchainNamedSpend); ok {
nameHash := HashName(spendEntry.Name)
spendV1Hash, err := HashSpendV1(spendEntry.GetWitness())
if err != nil {
return [5]uint64{}, fmt.Errorf("error hashing spend: %v", err)
}
oneHashspend := crypto.Tip5RehashTenCell(crypto.Tip5One, spendV1Hash)
return crypto.Tip5RehashTenCell(nameHash, oneHashspend), nil
} else {
return [5]uint64{}, fmt.Errorf("invalid input type")
}
},
)
for _, spend := range spends {
spendTree.Insert(spend.Name, spend)
}
spendHash, err = spendTree.Hash()
if err != nil {
return [5]uint64{}, fmt.Errorf("error hashing spends: %v", err)
}
default: default:
return [5]uint64{}, fmt.Errorf("unsupported version %d", version) return [5]uint64{}, fmt.Errorf("unsupported version %d", version)
} }
@ -431,9 +516,3 @@ func ComputeSig(m crypto.MasterKey, msg [5]uint64) ([8]uint64, [8]uint64, error)
sigT8 := crypto.BigIntToT8(*sig) sigT8 := crypto.BigIntToT8(*sig)
return chalT8, sigT8, nil return chalT8, sigT8, nil
} }
func first(ownerHash [5]uint64) [5]uint64 {
ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
return crypto.Tip5RehashTenCell(crypto.Tip5Zero, ownerHashZeroOne)
}

View File

@ -24,6 +24,16 @@ func Uint64ToBitsLSB0(x uint64) []bool {
return bits return bits
} }
func BitsToUint64LSB0(bits []bool, start, sz int) uint64 {
var data uint64
for i := 0; i < sz; i++ {
if bits[start+i] {
data |= 1 << i // LSB0: bit 0 = least significant
}
}
return data
}
func BoolsToBytesLSB0(bits []bool) []byte { func BoolsToBytesLSB0(bits []bool) []byte {
if len(bits) == 0 { if len(bits) == 0 {
return nil return nil
@ -40,6 +50,16 @@ func BoolsToBytesLSB0(bits []bool) []byte {
return bytes return bytes
} }
func BytesToBoolsLSB0(data []byte) []bool {
bools := make([]bool, len(data)*8)
for i, b := range data {
for j := 0; j < 8; j++ {
bools[i*8+j] = ((b >> j) & 1) == 1 // LSB0 order
}
}
return bools
}
func EncodeNoteData(noteData *nockchain.NockchainLock) []byte { func EncodeNoteData(noteData *nockchain.NockchainLock) []byte {
bits := InitialBits bits := InitialBits
@ -89,3 +109,48 @@ func EncodeNoteData(noteData *nockchain.NockchainLock) []byte {
bits = append(bits, []bool{true, false, false, true, false, true, false, true}...) bits = append(bits, []bool{true, false, false, true, false, true, false, true}...)
return BoolsToBytesLSB0(bits) return BoolsToBytesLSB0(bits)
} }
func DecodeNoteData(blob []byte) *nockchain.NockchainLock {
bits := BytesToBoolsLSB0(blob)
start := len(InitialBits) + 1
count := 0
for !bits[start] {
start += 1
count += 1
}
start += 1
numPksSz := uint64(1)
if count > 1 {
numPksSz = BitsToUint64LSB0(bits, start, count-1)
start += count - 1
}
numPks := BitsToUint64LSB0(bits, start, int(numPksSz))
start += int(numPksSz)
start += 2
pkHash := [5]uint64{}
for i := 0; i < 5; i++ {
if i != 4 {
start += 2
}
start += 1
count := 0
for !bits[start] {
start += 1
count += 1
}
start += 1
hashSz := uint64(count)
if count > 1 {
hashSz = BitsToUint64LSB0(bits, start, count-1) + 1<<(count-1)
start += count - 1
}
hash := BitsToUint64LSB0(bits, start, int(hashSz))
start += int(hashSz)
pkHash[i] = hash
}
return &nockchain.NockchainLock{
KeysRequired: numPks,
Pubkeys: []string{crypto.Tip5HashToBase58(pkHash)},
}
}

View File

@ -17,7 +17,7 @@ import (
) )
const ( const (
WitnessWordsCount = 0 WitnessWordsCount = 55
SignatureWordsCount = 31 SignatureWordsCount = 31
SeedWordsCount = 13 SeedWordsCount = 13
BaseFee = 1 << 15 BaseFee = 1 << 15
@ -390,32 +390,6 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
} }
} }
nameTree := NewZTree(
func(i interface{}) [5]uint64 {
if name, ok := i.(*nockchain.NockchainName); ok {
return HashNameVarLen(name)
} else {
return [5]uint64{}
}
},
nil,
)
for _, name := range nnames {
nameTree.Insert(name, nil)
}
nameList := nameTree.Tap()
nameKeys := []string{}
for _, nameKey := range nameList {
name := nameKey.Key.(*nockchain.NockchainName)
nameKeys = append(nameKeys, name.First+" "+name.Last)
}
indices := make([]int, len(nnames))
for i, name := range nnames {
if idx := slices.Index(nameKeys, name.First+" "+name.Last); idx != -1 {
indices[idx] = i
}
}
specs := strings.Split(req.Recipients, ",") specs := strings.Split(req.Recipients, ",")
if len(specs) == 0 { if len(specs) == 0 {
return nil, fmt.Errorf("at least one output must be provided") return nil, fmt.Errorf("at least one output must be provided")
@ -454,6 +428,11 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
} }
masterKey = &childKey masterKey = &childKey
} }
masterPkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey)
if err != nil {
return nil, err
}
pkHash := HashPubkey(masterPkPoint)
recipent := &nockchain.NockchainLock{ recipent := &nockchain.NockchainLock{
KeysRequired: 1, KeysRequired: 1,
@ -464,23 +443,40 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
} }
refundAddr := req.RefundAddress refundAddr := req.RefundAddress
if refundAddr == "" { if refundAddr == "" {
masterPkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey)
if err != nil {
return nil, err
}
pkHash := HashPubkey(masterPkPoint)
refundAddr = crypto.Tip5HashToBase58(pkHash) refundAddr = crypto.Tip5HashToBase58(pkHash)
} }
refundLock := &nockchain.NockchainLock{ refundLock := &nockchain.NockchainLock{
KeysRequired: 1, KeysRequired: 1,
Pubkeys: []string{refundAddr}, Pubkeys: []string{refundAddr},
} }
ownerLock := &nockchain.NockchainLock{
KeysRequired: 1,
Pubkeys: []string{crypto.Tip5HashToBase58(pkHash)},
}
ownerHash := HashLock(ownerLock)
// Scan key to get notes // Scan key to get notes
masterKeyScan, err := h.client.WalletGetBalance(&nockchain.GetBalanceRequest{ var scanReq *nockchain.GetBalanceRequest
switch req.Version {
case 0:
scanReq = &nockchain.GetBalanceRequest{
Selector: &nockchain.GetBalanceRequest_Address{ Selector: &nockchain.GetBalanceRequest_Address{
Address: base58.Encode(masterKey.PublicKey), Address: base58.Encode(masterKey.PublicKey),
}, },
}) }
case 1:
firstName := crypto.Tip5RehashTenCell(crypto.Tip5Zero, ownerHash)
scanReq = &nockchain.GetBalanceRequest{
Selector: &nockchain.GetBalanceRequest_FirstName{
FirstName: crypto.Tip5HashToBase58(firstName),
},
}
default:
return nil, fmt.Errorf("unsuport version")
}
masterKeyScan, err := h.client.WalletGetBalance(scanReq)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -535,23 +531,30 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
notesV1Sort := make([]*nockchain.NockchainNoteV1, len(notesV1)) notesV1Sort := make([]*nockchain.NockchainNoteV1, len(notesV1))
copy(notesV1Sort, notesV1) copy(notesV1Sort, notesV1)
switch req.Version {
case 0:
slices.SortFunc(notesV0Sort, func(note1, note2 *nockchain.NockchainNoteV0) int { slices.SortFunc(notesV0Sort, func(note1, note2 *nockchain.NockchainNoteV0) int {
return cmp.Compare(note1.Asset, note2.Asset) return cmp.Compare(note2.Asset, note1.Asset)
}) })
// TODO: sort V1 notes case 1:
slices.SortFunc(notesV1Sort, func(note1, note2 *nockchain.NockchainNoteV1) int {
return cmp.Compare(note2.Assets, note1.Assets)
})
}
spends := []*nockchain.NockchainNamedSpend{} spends := []*nockchain.NockchainNamedSpend{}
for _, note := range notesV0Sort { for i := 0; i < len(names); i++ {
giftPortion := uint64(0) asset := uint64(0)
feePortion := uint64(0) switch req.Version {
if giftRemaining != 0 { case 0:
giftPortion = min(giftRemaining, note.Asset) asset = notesV0Sort[i].Asset
case 1:
asset = notesV1Sort[i].Assets
} }
giftPortion := min(giftRemaining, asset)
feeAvailable := note.Asset - giftPortion feeAvailable := asset - giftPortion
if feeRemaining != 0 { feePortion := min(feeRemaining, feeAvailable)
feePortion = min(feeRemaining, feeAvailable)
}
if giftPortion == 0 && feePortion == 0 { if giftPortion == 0 && feePortion == 0 {
continue continue
@ -560,32 +563,38 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
giftRemaining = giftRemaining - giftPortion giftRemaining = giftRemaining - giftPortion
feeRemaining = feeRemaining - feePortion feeRemaining = feeRemaining - feePortion
refund := note.Asset - giftPortion - feePortion refund := asset - giftPortion - feePortion
if refund == 0 && giftPortion == 0 { if refund == 0 && giftPortion == 0 {
continue continue
} }
parentHash, err := HashNoteV0(note) var parentHash [5]uint64
switch req.Version {
case 0:
parentHash, err = HashNoteV0(notesV0Sort[i])
if err != nil { if err != nil {
return nil, err return nil, err
} }
case 1:
if req.Version == 0 { parentHash = HashNoteV1(notesV1Sort[i])
}
lockRoot := HashLock(recipent) lockRoot := HashLock(recipent)
seeds := []*nockchain.NockchainSeed{}
if giftPortion != 0 {
wordCount += SeedWordsCount wordCount += SeedWordsCount
seeds := []*nockchain.NockchainSeedV0{ seeds = append(seeds, &nockchain.NockchainSeed{
{
OutputSource: nil, OutputSource: nil,
LockRoot: crypto.Tip5HashToBase58(lockRoot), LockRoot: crypto.Tip5HashToBase58(lockRoot),
NoteData: recipent, NoteData: recipent,
Gift: giftPortion, Gift: giftPortion,
ParentHash: crypto.Tip5HashToBase58(parentHash), ParentHash: crypto.Tip5HashToBase58(parentHash),
}, })
} }
if refund != 0 { if refund != 0 {
wordCount += SeedWordsCount wordCount += SeedWordsCount
lockRoot := HashLock(refundLock) lockRoot := HashLock(refundLock)
seeds = append(seeds, &nockchain.NockchainSeedV0{ seeds = append(seeds, &nockchain.NockchainSeed{
OutputSource: nil, OutputSource: nil,
LockRoot: crypto.Tip5HashToBase58(lockRoot), LockRoot: crypto.Tip5HashToBase58(lockRoot),
NoteData: refundLock, NoteData: refundLock,
@ -594,17 +603,10 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
}) })
} }
spend := nockchain.NockchainSpendV0{ msg, err := HashMsg(seeds, feePortion)
Signatures: nil,
Seeds: seeds,
Fee: feePortion,
}
msg, err := HashMsg(&spend)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmt.Println("msg:", msg)
// sign // sign
chalT8, sigT8, err := ComputeSig(*masterKey, msg) chalT8, sigT8, err := ComputeSig(*masterKey, msg)
@ -612,27 +614,73 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
return nil, err return nil, err
} }
masterPkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey) sigs := []*nockchain.NockchainSignature{
if err != nil {
return nil, err
}
fmt.Println("master pk point:", masterPkPoint)
spend.Signatures = []*nockchain.NockchainSignature{
{ {
Pubkey: base58.Encode(masterKey.PublicKey), Pubkey: base58.Encode(masterKey.PublicKey),
Chal: chalT8[:], Chal: chalT8[:],
Sig: sigT8[:], Sig: sigT8[:],
}, },
} }
switch req.Version {
case 0:
spend := nockchain.NockchainSpendV0{
Signatures: nil,
Seeds: seeds,
Fee: feePortion,
}
spend.Signatures = sigs
wordCount += SignatureWordsCount wordCount += SignatureWordsCount
nameIdx := -1
for j := 0; j < len(names); j++ {
if nnames[j].Last == notesV0Sort[i].Name.Last {
nameIdx = j
break
}
}
spends = append(spends, &nockchain.NockchainNamedSpend{ spends = append(spends, &nockchain.NockchainNamedSpend{
Name: note.Name, Name: nnames[nameIdx],
SpendKind: &nockchain.NockchainNamedSpend_Legacy{ SpendKind: &nockchain.NockchainNamedSpend_Legacy{
Legacy: &spend, Legacy: &spend,
}, },
}) })
case 1:
spend := nockchain.NockchainSpendV1{
Witness: nil,
Seeds: seeds,
Fee: feePortion,
} }
spend.Witness = []*nockchain.NockchainWitness{
{
Lmp: &nockchain.NockchainLockMerkleProof{
SpendCondition: ownerLock,
Axis: 1,
MerkleRoot: crypto.Tip5HashToBase58(ownerHash),
},
Pkh: sigs,
},
}
wordCount += WitnessWordsCount
nameIdx := -1
for j := 0; j < len(names); j++ {
if nnames[j].Last == notesV1Sort[i].Name.Last {
nameIdx = j
break
}
}
spends = append(spends, &nockchain.NockchainNamedSpend{
Name: nnames[nameIdx],
SpendKind: &nockchain.NockchainNamedSpend_Witness{
Witness: &spend,
},
})
}
}
if giftRemaining != 0 || feeRemaining != 0 {
return nil, fmt.Errorf("insufficient funds to pay fee and gift")
} }
if wordCount*BaseFee > int(req.Fee) { if wordCount*BaseFee > int(req.Fee) {

View File

@ -435,7 +435,7 @@ func TestScan(t *testing.T) {
assert.NotEmpty(t, masterKey1Scan.Notes) assert.NotEmpty(t, masterKey1Scan.Notes)
} }
func TestEncodeNoun(t *testing.T) { func TestEncodeDecodeNoun(t *testing.T) {
lock1 := &nockchain.NockchainLock{ lock1 := &nockchain.NockchainLock{
KeysRequired: 1, KeysRequired: 1,
Pubkeys: []string{"5wef35rKxbJDJRAtzGG1VwbMQK9jF3Wr5e6fyMsh2hxnCQZDZJV1YNQ"}, Pubkeys: []string{"5wef35rKxbJDJRAtzGG1VwbMQK9jF3Wr5e6fyMsh2hxnCQZDZJV1YNQ"},
@ -444,143 +444,22 @@ func TestEncodeNoun(t *testing.T) {
lock1Encode := wallet.EncodeNoteData(lock1) lock1Encode := wallet.EncodeNoteData(lock1)
assert.Equal(t, lock1Encode, []byte{89, 192, 131, 91, 67, 199, 5, 16, 32, 24, 199, 52, 39, 171, 121, 6, 15, 240, 167, 243, 69, 34, 254, 110, 4, 78, 3, 8, 44, 245, 128, 176, 69, 72, 150, 253, 6, 232, 167, 34, 133, 115, 154, 56, 106, 106, 192, 175, 176, 88, 89, 160, 208, 117, 55, 78, 5}) assert.Equal(t, lock1Encode, []byte{89, 192, 131, 91, 67, 199, 5, 16, 32, 24, 199, 52, 39, 171, 121, 6, 15, 240, 167, 243, 69, 34, 254, 110, 4, 78, 3, 8, 44, 245, 128, 176, 69, 72, 150, 253, 6, 232, 167, 34, 133, 115, 154, 56, 106, 106, 192, 175, 176, 88, 89, 160, 208, 117, 55, 78, 5})
lock1Decode := wallet.DecodeNoteData(lock1Encode)
assert.Equal(t, lock1Decode.KeysRequired, lock1.KeysRequired)
assert.Equal(t, lock1Decode.Pubkeys, lock1.Pubkeys)
lock2 := lock1 lock2 := lock1
lock2.Pubkeys = []string{"7UXNF2HXzEaPUvLDVDgGJyriKqpd2974Kj7U2RnLuBPeRGa7ZezhGmK"} lock2.Pubkeys = []string{"7UXNF2HXzEaPUvLDVDgGJyriKqpd2974Kj7U2RnLuBPeRGa7ZezhGmK"}
lock2Encode := wallet.EncodeNoteData(lock2) lock2Encode := wallet.EncodeNoteData(lock2)
assert.Equal(t, lock2Encode, []byte{89, 192, 131, 91, 67, 199, 5, 248, 151, 186, 241, 213, 183, 156, 103, 181, 1, 254, 206, 33, 184, 3, 142, 3, 99, 101, 0, 1, 246, 168, 22, 252, 21, 155, 53, 205, 0, 2, 172, 67, 150, 149, 228, 139, 80, 206, 0, 1, 203, 54, 188, 141, 54, 21, 39, 193, 84}) assert.Equal(t, lock2Encode, []byte{89, 192, 131, 91, 67, 199, 5, 248, 151, 186, 241, 213, 183, 156, 103, 181, 1, 254, 206, 33, 184, 3, 142, 3, 99, 101, 0, 1, 246, 168, 22, 252, 21, 155, 53, 205, 0, 2, 172, 67, 150, 149, 228, 139, 80, 206, 0, 1, 203, 54, 188, 141, 54, 21, 39, 193, 84})
lock2Decode := wallet.DecodeNoteData(lock2Encode)
assert.Equal(t, lock2Decode.KeysRequired, lock2.KeysRequired)
assert.Equal(t, lock2Decode.Pubkeys, lock2.Pubkeys)
} }
// // This test should be run with timeout 120s
// func TestFullFlow(t *testing.T) {
// mnemonic1 := "rail nurse smile angle uphold gun kitten spoon quick frozen trigger cable decorate episode blame tray off bag arena taxi approve breeze job letter"
// masterKey1, err := crypto.MasterKeyFromSeed(mnemonic1)
// assert.NoError(t, err)
// fmt.Println(base58.Encode(masterKey1.PublicKey))
// mnemonic2 := "brass vacuum stairs hurt brisk govern describe enforce fly exact rescue capable belt flavor lottery sauce easy frame orange legal injury border obey novel"
// masterKey2, err := crypto.MasterKeyFromSeed(mnemonic2)
// assert.NoError(t, err)
// inputName := "[4taoqkpysafnp64WBQyzHDKVrqkMeNrdAiVSbWdzZmj7yQYZgQtCq4W 9cjUFbdtaFHeXNWCAKjsTphBchHmCoUU6a1aDbJAFz9qHqeG8osh4wF]"
// nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
// assert.NoError(t, err)
// masterKeyScan, err := nc.WalletGetBalance(base58.Encode(masterKey1.PublicKey))
// assert.NoError(t, err)
// var note *nockchain.NockchainNote
// for _, balanceEntry := range masterKeyScan.Notes {
// firstName := crypto.Tip5HashToBase58([5]uint64{
// balanceEntry.Name.First.Belt_1.Value,
// balanceEntry.Name.First.Belt_2.Value,
// balanceEntry.Name.First.Belt_3.Value,
// balanceEntry.Name.First.Belt_4.Value,
// balanceEntry.Name.First.Belt_5.Value,
// })
// lastName := crypto.Tip5HashToBase58([5]uint64{
// balanceEntry.Name.Last.Belt_1.Value,
// balanceEntry.Name.Last.Belt_2.Value,
// balanceEntry.Name.Last.Belt_3.Value,
// balanceEntry.Name.Last.Belt_4.Value,
// balanceEntry.Name.Last.Belt_5.Value,
// })
// nname := "[" + firstName + " " + lastName + "]"
// if nname == inputName {
// nnote := wallet.ParseBalanceEntry(balanceEntry)
// note = &nnote
// break
// }
// }
// assert.NotNil(t, note)
// parentHash, err := wallet.HashNote(note)
// assert.NoError(t, err)
// gift := uint64(100000)
// seed1 := &nockchain.NockchainSeed{
// OutputSource: nil,
// Recipient: &nockchain.NockchainLock{
// KeysRequired: 1,
// Pubkeys: []string{base58.Encode(masterKey2.PublicKey)},
// },
// TimelockIntent: nil,
// Gift: gift,
// ParentHash: crypto.Tip5HashToBase58(parentHash),
// }
// gift = note.Asset - gift - 100
// seed2 := &nockchain.NockchainSeed{
// OutputSource: nil,
// Recipient: &nockchain.NockchainLock{
// KeysRequired: 1,
// Pubkeys: []string{base58.Encode(masterKey1.PublicKey)},
// },
// TimelockIntent: nil,
// Gift: gift,
// ParentHash: crypto.Tip5HashToBase58(parentHash),
// }
// spend := nockchain.NockchainSpend{
// Signatures: nil,
// Seeds: []*nockchain.NockchainSeed{
// seed1, seed2,
// },
// Fee: 100,
// }
// msg, err := wallet.HashMsg(&spend)
// assert.NoError(t, err)
// chalT8, sigT8, err := wallet.ComputeSig(*masterKey1, msg)
// assert.NoError(t, err)
// spend.Signatures = []*nockchain.NockchainSignature{
// {
// Pubkey: base58.Encode(masterKey1.PublicKey),
// Chal: chalT8[:],
// Sig: sigT8[:],
// },
// }
// input := nockchain.NockchainInput{
// Name: &nockchain.NockchainName{
// First: "4taoqkpysafnp64WBQyzHDKVrqkMeNrdAiVSbWdzZmj7yQYZgQtCq4W",
// Last: "9cjUFbdtaFHeXNWCAKjsTphBchHmCoUU6a1aDbJAFz9qHqeG8osh4wF",
// },
// Note: note,
// Spend: &spend,
// }
// id, err := wallet.ComputeTxId([]*nockchain.NockchainInput{&input}, &nockchain.TimelockRange{
// Min: nil,
// Max: nil,
// }, 100)
// assert.NoError(t, err)
// rawTx := nockchain.RawTx{
// TxId: crypto.Tip5HashToBase58(id),
// Inputs: []*nockchain.NockchainInput{&input},
// TimelockRange: &nockchain.TimelockRange{
// Min: nil,
// Max: nil,
// },
// TotalFees: 100,
// }
// resp, err := nc.WalletSendTransaction(&rawTx)
// assert.NoError(t, err)
// assert.Equal(t, resp.Result, &nockchain.WalletSendTransactionResponse_Ack{
// Ack: &nockchain.Acknowledged{},
// })
// txAcceptedResp, err := nc.TxAccepted(rawTx.TxId)
// assert.NoError(t, err)
// assert.Equal(t, txAcceptedResp.Result, &nockchain.TransactionAcceptedResponse_Accepted{
// Accepted: true,
// })
// }
// This test should be run with timeout 300s // This test should be run with timeout 300s
func TestCreateTx(t *testing.T) { func TestCreateTxV0(t *testing.T) {
seed1 := "rail nurse smile angle uphold gun kitten spoon quick frozen trigger cable decorate episode blame tray off bag arena taxi approve breeze job letter" seed1 := "rail nurse smile angle uphold gun kitten spoon quick frozen trigger cable decorate episode blame tray off bag arena taxi approve breeze job letter"
masterKey1, err := crypto.MasterKeyFromSeed(seed1) masterKey1, err := crypto.MasterKeyFromSeed(seed1)
assert.NoError(t, err) assert.NoError(t, err)
@ -626,3 +505,34 @@ func TestCreateTx(t *testing.T) {
// the result is taken from create-tx scripts // the result is taken from create-tx scripts
assert.Equal(t, res.RawTx.TxId, "6oDgTWnk6sL98yK49hcQTRAfCdFfgKh58U6TDTKmGPirhoxkMii2D6E") assert.Equal(t, res.RawTx.TxId, "6oDgTWnk6sL98yK49hcQTRAfCdFfgKh58U6TDTKmGPirhoxkMii2D6E")
} }
func TestCreateTxV1(t *testing.T) {
seed := "pledge vessel toilet sunny hockey skirt spend wire disorder attitude crumble lecture problem bundle bone rather address over suit ancient primary gospel silent repair"
_, err := crypto.MasterKeyFromSeed(seed)
assert.NoError(t, err)
nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
assert.NoError(t, err)
handler := wallet.NewGprcHandler(*nc)
inputs := "[9McQZWZzqFCLwsF37gUHLHt3cxWVbLA64SabN3AMMSgNuSM2b9SmMsj 88uZqY63kneffJnVAEYpb67W96sk3xsdFYTjzj8DSBiigL9AZd9pHsC],[9McQZWZzqFCLwsF37gUHLHt3cxWVbLA64SabN3AMMSgNuSM2b9SmMsj 2JLcp5oXBTtgTCKN4na9Dnk2YuHJCXuDAkk5qT8n9iP1d4iz1c3Amfo]"
recipients := fmt.Sprintf("%s:747336", "D6NUb9HC4ursvZzYdMAtWAMSyyJWwtdqnsyRXxsADsyqQwh5dcDsTRm")
fee := 4456448
req := &nockchain.CreateTxRequest{
Names: inputs,
Recipients: recipients,
Fee: uint64(fee),
IsMasterKey: true,
Seed: seed,
Index: 0,
Hardened: false,
Version: 1,
}
resp, err := handler.CreateTx(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, resp.RawTx.TxId, "9DfaTJgtsGU8Fs2mAPhGpiMMw5RcRXjEVfnmFcTTxoSFMLWpv2Ae4eG")
}

View File

@ -1,14 +1,28 @@
package wallet package wallet
import ( import (
"fmt"
"github.com/btcsuite/btcd/btcutil/base58" "github.com/btcsuite/btcd/btcutil/base58"
"github.com/phamminh0811/private-grpc/crypto" "github.com/phamminh0811/private-grpc/crypto"
"github.com/phamminh0811/private-grpc/nockchain" "github.com/phamminh0811/private-grpc/nockchain"
) )
func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote { func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
name := &nockchain.NockchainName{
First: crypto.Tip5HashToBase58([5]uint64{
entry.Name.First.Belt_1.Value,
entry.Name.First.Belt_2.Value,
entry.Name.First.Belt_3.Value,
entry.Name.First.Belt_4.Value,
entry.Name.First.Belt_5.Value,
}),
Last: crypto.Tip5HashToBase58([5]uint64{
entry.Name.Last.Belt_1.Value,
entry.Name.Last.Belt_2.Value,
entry.Name.Last.Belt_3.Value,
entry.Name.Last.Belt_4.Value,
entry.Name.Last.Belt_5.Value,
}),
}
switch entry.Note.NoteVersion.(type) { switch entry.Note.NoteVersion.(type) {
case *nockchain.Note_Legacy: case *nockchain.Note_Legacy:
note := entry.Note.GetLegacy() note := entry.Note.GetLegacy()
@ -50,22 +64,7 @@ func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
V0: &nockchain.NockchainNoteV0{ V0: &nockchain.NockchainNoteV0{
Version: version, Version: version,
OriginPage: note.OriginPage.Value, OriginPage: note.OriginPage.Value,
Name: &nockchain.NockchainName{ Name: name,
First: crypto.Tip5HashToBase58([5]uint64{
entry.Name.First.Belt_1.Value,
entry.Name.First.Belt_2.Value,
entry.Name.First.Belt_3.Value,
entry.Name.First.Belt_4.Value,
entry.Name.First.Belt_5.Value,
}),
Last: crypto.Tip5HashToBase58([5]uint64{
entry.Name.Last.Belt_1.Value,
entry.Name.Last.Belt_2.Value,
entry.Name.Last.Belt_3.Value,
entry.Name.Last.Belt_4.Value,
entry.Name.Last.Belt_5.Value,
}),
},
Lock: &nockchain.NockchainLock{ Lock: &nockchain.NockchainLock{
KeysRequired: uint64(note.Lock.KeysRequired), KeysRequired: uint64(note.Lock.KeysRequired),
Pubkeys: pubkeys, Pubkeys: pubkeys,
@ -79,11 +78,22 @@ func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
}, },
} }
case *nockchain.Note_V1: case *nockchain.Note_V1:
fmt.Println("go here???") note := entry.Note.GetV1()
// Handle V1 notes if needed version := nockchain.Version(note.Version.Value)
if len(note.NoteData.Entries) != 1 || note.NoteData.Entries[0].Key != "lock" {
panic("invalid note data")
}
lock := DecodeNoteData(note.NoteData.Entries[0].Blob)
return nockchain.NockchainNote{ return nockchain.NockchainNote{
Note: &nockchain.NockchainNote_V1{ Note: &nockchain.NockchainNote_V1{
V1: &nockchain.NockchainNoteV1{}, V1: &nockchain.NockchainNoteV1{
Version: version,
OriginPage: note.OriginPage.Value,
Name: name,
NoteData: lock,
Assets: note.Assets.Value,
},
}, },
} }
default: default:
@ -134,7 +144,91 @@ func ConvertNamedSpend(spend *nockchain.NockchainNamedSpend) (*nockchain.SpendEn
}, },
} }
case *nockchain.NockchainNamedSpend_Witness: case *nockchain.NockchainNamedSpend_Witness:
// TODO: handle v1 witnessSpend := spend.GetWitness()
seeds := []*nockchain.Seed{}
for _, seed := range witnessSpend.Seeds {
seeds = append(seeds, &nockchain.Seed{
OutputSource: &nockchain.Source{
Hash: ParseHash(seed.OutputSource.Source),
Coinbase: seed.OutputSource.IsCoinbase,
},
LockRoot: ParseHash(seed.LockRoot),
NoteData: &nockchain.NoteData{
Entries: []*nockchain.NoteDataEntry{
{
Key: "lock",
Blob: EncodeNoteData(seed.NoteData),
},
},
},
Gift: &nockchain.Nicks{
Value: seed.Gift,
},
ParentHash: ParseHash(seed.ParentHash),
})
}
witness := witnessSpend.Witness[0]
lockHashes := []*nockchain.Hash{}
for i := 0; i < len(witness.Lmp.SpendCondition.Pubkeys); i++ {
lockHashes = append(lockHashes, ParseHash(witness.Lmp.SpendCondition.Pubkeys[i]))
}
pkhSigs := []*nockchain.PkhSignatureEntry{}
for _, pkh := range witness.Pkh {
pk, err := crypto.CheetaPointFromBytes(base58.Decode(pkh.Pubkey))
if err != nil {
return nil, err
}
schnorrPk, err := ParseSchnorrPubkey(pkh.Pubkey)
if err != nil {
return nil, err
}
pkHash := HashPubkey(pk)
pkhSigs = append(pkhSigs, &nockchain.PkhSignatureEntry{
Hash: ParseHash(crypto.Tip5HashToBase58(pkHash)),
Pubkey: schnorrPk,
Signature: &nockchain.SchnorrSignature{
Chal: ParseEightBelt(pkh.Chal),
Sig: ParseEightBelt(pkh.Sig),
},
})
}
convertedSpend = &nockchain.Spend{
SpendKind: &nockchain.Spend_Witness{
Witness: &nockchain.WitnessSpend{
Witness: &nockchain.Witness{
LockMerkleProof: &nockchain.LockMerkleProof{
SpendCondition: &nockchain.SpendCondition{
Primitives: []*nockchain.LockPrimitive{
{
Primitive: &nockchain.LockPrimitive_Pkh{
Pkh: &nockchain.PkhLock{
M: witness.Lmp.SpendCondition.KeysRequired,
Hashes: lockHashes,
},
},
},
},
},
Axis: witness.Lmp.Axis,
Proof: &nockchain.MerkleProof{
Root: ParseHash(witness.Lmp.MerkleRoot),
Path: []*nockchain.Hash{},
},
},
PkhSignature: &nockchain.PkhSignature{
Entries: pkhSigs,
},
},
Seeds: seeds,
Fee: &nockchain.Nicks{
Value: witnessSpend.Fee,
},
},
},
}
} }
// Conversion logic here // Conversion logic here
return &nockchain.SpendEntry{ return &nockchain.SpendEntry{