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 {
state protoimpl.MessageState `protogen:"open.v1"`
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"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
@ -521,7 +521,7 @@ func (x *NockchainSpendV0) GetSignatures() []*NockchainSignature {
return nil
}
func (x *NockchainSpendV0) GetSeeds() []*NockchainSeedV0 {
func (x *NockchainSpendV0) GetSeeds() []*NockchainSeed {
if x != nil {
return x.Seeds
}
@ -537,6 +537,9 @@ func (x *NockchainSpendV0) GetFee() uint64 {
type NockchainSpendV1 struct {
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
sizeCache protoimpl.SizeCache
}
@ -571,6 +574,27 @@ func (*NockchainSpendV1) Descriptor() ([]byte, []int) {
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 {
state protoimpl.MessageState `protogen:"open.v1"`
// 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"`
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"`
Lock *NockchainLock `protobuf:"bytes,5,opt,name=lock,proto3" json:"lock,omitempty"`
Source *NockchainSource `protobuf:"bytes,6,opt,name=source,proto3" json:"source,omitempty"`
Asset uint64 `protobuf:"varint,7,opt,name=asset,proto3" json:"asset,omitempty"`
Lock *NockchainLock `protobuf:"bytes,4,opt,name=lock,proto3" json:"lock,omitempty"`
Source *NockchainSource `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"`
Asset uint64 `protobuf:"varint,6,opt,name=asset,proto3" json:"asset,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -739,6 +763,11 @@ func (x *NockchainNoteV0) GetAsset() uint64 {
type NockchainNoteV1 struct {
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
sizeCache protoimpl.SizeCache
}
@ -773,6 +802,41 @@ func (*NockchainNoteV1) Descriptor() ([]byte, []int) {
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 {
state protoimpl.MessageState `protogen:"open.v1"`
First string `protobuf:"bytes,1,opt,name=first,proto3" json:"first,omitempty"`
@ -885,31 +949,28 @@ func (x *NockchainSignature) GetSig() []uint64 {
return nil
}
type NockchainSeedV0 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"`
type NockchainWitness struct {
state protoimpl.MessageState `protogen:"open.v1"`
Lmp *NockchainLockMerkleProof `protobuf:"bytes,1,opt,name=lmp,proto3" json:"lmp,omitempty"`
Pkh []*NockchainSignature `protobuf:"bytes,2,rep,name=pkh,proto3" json:"pkh,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NockchainSeedV0) Reset() {
*x = NockchainSeedV0{}
func (x *NockchainWitness) Reset() {
*x = NockchainWitness{}
mi := &file_types_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NockchainSeedV0) String() string {
func (x *NockchainWitness) String() string {
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]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -921,40 +982,155 @@ func (x *NockchainSeedV0) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use NockchainSeedV0.ProtoReflect.Descriptor instead.
func (*NockchainSeedV0) Descriptor() ([]byte, []int) {
// Deprecated: Use NockchainWitness.ProtoReflect.Descriptor instead.
func (*NockchainWitness) Descriptor() ([]byte, []int) {
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 {
return x.OutputSource
}
return nil
}
func (x *NockchainSeedV0) GetLockRoot() string {
func (x *NockchainSeed) GetLockRoot() string {
if x != nil {
return x.LockRoot
}
return ""
}
func (x *NockchainSeedV0) GetNoteData() *NockchainLock {
func (x *NockchainSeed) GetNoteData() *NockchainLock {
if x != nil {
return x.NoteData
}
return nil
}
func (x *NockchainSeedV0) GetGift() uint64 {
func (x *NockchainSeed) GetGift() uint64 {
if x != nil {
return x.Gift
}
return 0
}
func (x *NockchainSeedV0) GetParentHash() string {
func (x *NockchainSeed) GetParentHash() string {
if x != nil {
return x.ParentHash
}
@ -971,7 +1147,7 @@ type NockchainLock struct {
func (x *NockchainLock) Reset() {
*x = NockchainLock{}
mi := &file_types_proto_msgTypes[14]
mi := &file_types_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -983,7 +1159,7 @@ func (x *NockchainLock) String() string {
func (*NockchainLock) ProtoMessage() {}
func (x *NockchainLock) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[14]
mi := &file_types_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -996,7 +1172,7 @@ func (x *NockchainLock) ProtoReflect() protoreflect.Message {
// Deprecated: Use NockchainLock.ProtoReflect.Descriptor instead.
func (*NockchainLock) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{14}
return file_types_proto_rawDescGZIP(), []int{16}
}
func (x *NockchainLock) GetKeysRequired() uint64 {
@ -1023,7 +1199,7 @@ type NockchainSource struct {
func (x *NockchainSource) Reset() {
*x = NockchainSource{}
mi := &file_types_proto_msgTypes[15]
mi := &file_types_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -1035,7 +1211,7 @@ func (x *NockchainSource) String() string {
func (*NockchainSource) ProtoMessage() {}
func (x *NockchainSource) ProtoReflect() protoreflect.Message {
mi := &file_types_proto_msgTypes[15]
mi := &file_types_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -1048,7 +1224,7 @@ func (x *NockchainSource) ProtoReflect() protoreflect.Message {
// Deprecated: Use NockchainSource.ProtoReflect.Descriptor instead.
func (*NockchainSource) Descriptor() ([]byte, []int) {
return file_types_proto_rawDescGZIP(), []int{15}
return file_types_proto_rawDescGZIP(), []int{17}
}
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" +
"\awitness\x18\x03 \x01(\v2%.nockchain.public.v2.NockchainSpendV1H\x00R\awitnessB\f\n" +
"\n" +
"spend_kind\"\xa9\x01\n" +
"spend_kind\"\xa7\x01\n" +
"\x10NockchainSpendV0\x12G\n" +
"\n" +
"signatures\x18\x01 \x03(\v2'.nockchain.public.v2.NockchainSignatureR\n" +
"signatures\x12:\n" +
"\x05seeds\x18\x02 \x03(\v2$.nockchain.public.v2.NockchainSeedV0R\x05seeds\x12\x10\n" +
"\x03fee\x18\x03 \x01(\x04R\x03fee\"\x12\n" +
"\x10NockchainSpendV1\"\x87\x01\n" +
"signatures\x128\n" +
"\x05seeds\x18\x02 \x03(\v2\".nockchain.public.v2.NockchainSeedR\x05seeds\x12\x10\n" +
"\x03fee\x18\x03 \x01(\x04R\x03fee\"\x9f\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" +
"\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" +
@ -1111,18 +1290,32 @@ const file_types_proto_rawDesc = "" +
"\vorigin_page\x18\x02 \x01(\x04R\n" +
"originPage\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" +
"\x06source\x18\x06 \x01(\v2$.nockchain.public.v2.NockchainSourceR\x06source\x12\x14\n" +
"\x05asset\x18\a \x01(\x04R\x05asset\"\x11\n" +
"\x0fNockchainNoteV1\"9\n" +
"\x04lock\x18\x04 \x01(\v2\".nockchain.public.v2.NockchainLockR\x04lock\x12<\n" +
"\x06source\x18\x05 \x01(\v2$.nockchain.public.v2.NockchainSourceR\x06source\x12\x14\n" +
"\x05asset\x18\x06 \x01(\x04R\x05asset\"\xfb\x01\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" +
"\x05first\x18\x01 \x01(\tR\x05first\x12\x12\n" +
"\x04last\x18\x02 \x01(\tR\x04last\"R\n" +
"\x12NockchainSignature\x12\x16\n" +
"\x06pubkey\x18\x01 \x01(\tR\x06pubkey\x12\x12\n" +
"\x04chal\x18\x02 \x03(\x04R\x04chal\x12\x10\n" +
"\x03sig\x18\x03 \x03(\x04R\x03sig\"\x86\x02\n" +
"\x0fNockchainSeedV0\x12N\n" +
"\x03sig\x18\x03 \x03(\x04R\x03sig\"\x8e\x01\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" +
"\tlock_root\x18\x02 \x01(\tR\blockRoot\x12?\n" +
"\tnote_data\x18\x03 \x01(\v2\".nockchain.public.v2.NockchainLockR\bnoteData\x12\x12\n" +
@ -1164,30 +1357,32 @@ func file_types_proto_rawDescGZIP() []byte {
}
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{
(ImportType)(0), // 0: nockchain.public.v2.ImportType
(Version)(0), // 1: nockchain.public.v2.Version
(*ScanData)(nil), // 2: nockchain.public.v2.ScanData
(*TimelockIntent)(nil), // 3: nockchain.public.v2.TimelockIntent
(*TimelockRange)(nil), // 4: nockchain.public.v2.TimelockRange
(*Timelock)(nil), // 5: nockchain.public.v2.Timelock
(*RawTx)(nil), // 6: nockchain.public.v2.RawTx
(*NockchainNamedSpend)(nil), // 7: nockchain.public.v2.NockchainNamedSpend
(*NockchainSpendV0)(nil), // 8: nockchain.public.v2.NockchainSpendV0
(*NockchainSpendV1)(nil), // 9: nockchain.public.v2.NockchainSpendV1
(*NockchainNote)(nil), // 10: nockchain.public.v2.NockchainNote
(*NockchainNoteV0)(nil), // 11: nockchain.public.v2.NockchainNoteV0
(*NockchainNoteV1)(nil), // 12: nockchain.public.v2.NockchainNoteV1
(*NockchainName)(nil), // 13: nockchain.public.v2.NockchainName
(*NockchainSignature)(nil), // 14: nockchain.public.v2.NockchainSignature
(*NockchainSeedV0)(nil), // 15: nockchain.public.v2.NockchainSeedV0
(*NockchainLock)(nil), // 16: nockchain.public.v2.NockchainLock
(*NockchainSource)(nil), // 17: nockchain.public.v2.NockchainSource
(*Balance)(nil), // 18: nockchain.public.v2.Balance
(ImportType)(0), // 0: nockchain.public.v2.ImportType
(Version)(0), // 1: nockchain.public.v2.Version
(*ScanData)(nil), // 2: nockchain.public.v2.ScanData
(*TimelockIntent)(nil), // 3: nockchain.public.v2.TimelockIntent
(*TimelockRange)(nil), // 4: nockchain.public.v2.TimelockRange
(*Timelock)(nil), // 5: nockchain.public.v2.Timelock
(*RawTx)(nil), // 6: nockchain.public.v2.RawTx
(*NockchainNamedSpend)(nil), // 7: nockchain.public.v2.NockchainNamedSpend
(*NockchainSpendV0)(nil), // 8: nockchain.public.v2.NockchainSpendV0
(*NockchainSpendV1)(nil), // 9: nockchain.public.v2.NockchainSpendV1
(*NockchainNote)(nil), // 10: nockchain.public.v2.NockchainNote
(*NockchainNoteV0)(nil), // 11: nockchain.public.v2.NockchainNoteV0
(*NockchainNoteV1)(nil), // 12: nockchain.public.v2.NockchainNoteV1
(*NockchainName)(nil), // 13: nockchain.public.v2.NockchainName
(*NockchainSignature)(nil), // 14: nockchain.public.v2.NockchainSignature
(*NockchainWitness)(nil), // 15: nockchain.public.v2.NockchainWitness
(*NockchainLockMerkleProof)(nil), // 16: nockchain.public.v2.NockchainLockMerkleProof
(*NockchainSeed)(nil), // 17: nockchain.public.v2.NockchainSeed
(*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{
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, // 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
@ -1198,20 +1393,28 @@ var file_types_proto_depIdxs = []int32{
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
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
11, // 12: nockchain.public.v2.NockchainNote.v0:type_name -> nockchain.public.v2.NockchainNoteV0
12, // 13: nockchain.public.v2.NockchainNote.v1:type_name -> nockchain.public.v2.NockchainNoteV1
1, // 14: nockchain.public.v2.NockchainNoteV0.version:type_name -> nockchain.public.v2.Version
13, // 15: nockchain.public.v2.NockchainNoteV0.name:type_name -> nockchain.public.v2.NockchainName
16, // 16: nockchain.public.v2.NockchainNoteV0.lock:type_name -> nockchain.public.v2.NockchainLock
17, // 17: nockchain.public.v2.NockchainNoteV0.source:type_name -> nockchain.public.v2.NockchainSource
17, // 18: nockchain.public.v2.NockchainSeedV0.output_source:type_name -> nockchain.public.v2.NockchainSource
16, // 19: nockchain.public.v2.NockchainSeedV0.note_data:type_name -> nockchain.public.v2.NockchainLock
20, // [20:20] is the sub-list for method output_type
20, // [20:20] is the sub-list for method input_type
20, // [20:20] is the sub-list for extension type_name
20, // [20:20] is the sub-list for extension extendee
0, // [0:20] is the sub-list for field type_name
17, // 11: nockchain.public.v2.NockchainSpendV0.seeds:type_name -> nockchain.public.v2.NockchainSeed
15, // 12: nockchain.public.v2.NockchainSpendV1.witness:type_name -> nockchain.public.v2.NockchainWitness
17, // 13: nockchain.public.v2.NockchainSpendV1.seeds:type_name -> nockchain.public.v2.NockchainSeed
11, // 14: nockchain.public.v2.NockchainNote.v0:type_name -> nockchain.public.v2.NockchainNoteV0
12, // 15: nockchain.public.v2.NockchainNote.v1:type_name -> nockchain.public.v2.NockchainNoteV1
1, // 16: nockchain.public.v2.NockchainNoteV0.version:type_name -> nockchain.public.v2.Version
13, // 17: nockchain.public.v2.NockchainNoteV0.name:type_name -> nockchain.public.v2.NockchainName
18, // 18: nockchain.public.v2.NockchainNoteV0.lock:type_name -> nockchain.public.v2.NockchainLock
19, // 19: nockchain.public.v2.NockchainNoteV0.source:type_name -> nockchain.public.v2.NockchainSource
1, // 20: nockchain.public.v2.NockchainNoteV1.version:type_name -> nockchain.public.v2.Version
13, // 21: nockchain.public.v2.NockchainNoteV1.name:type_name -> nockchain.public.v2.NockchainName
18, // 22: nockchain.public.v2.NockchainNoteV1.note_data:type_name -> nockchain.public.v2.NockchainLock
16, // 23: nockchain.public.v2.NockchainWitness.lmp:type_name -> nockchain.public.v2.NockchainLockMerkleProof
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() }
@ -1230,14 +1433,14 @@ func file_types_proto_init() {
(*NockchainNote_V0)(nil),
(*NockchainNote_V1)(nil),
}
file_types_proto_msgTypes[13].OneofWrappers = []any{}
file_types_proto_msgTypes[15].OneofWrappers = []any{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),
NumEnums: 2,
NumMessages: 16,
NumMessages: 18,
NumExtensions: 0,
NumServices: 0,
},

View File

@ -46,11 +46,14 @@ message NockchainNamedSpend {
message NockchainSpendV0 {
repeated NockchainSignature signatures = 1;
repeated NockchainSeedV0 seeds = 2;
repeated NockchainSeed seeds = 2;
uint64 fee = 3;
}
message NockchainSpendV1 {
repeated NockchainWitness witness = 1;
repeated NockchainSeed seeds = 2;
uint64 fee = 3;
}
message NockchainNote {
@ -63,12 +66,17 @@ message NockchainNoteV0 {
Version version = 1;
uint64 origin_page = 2;
NockchainName name = 3;
NockchainLock lock = 5;
NockchainSource source = 6;
uint64 asset =7;
NockchainLock lock = 4;
NockchainSource source = 5;
uint64 asset =6;
}
message NockchainNoteV1 {
Version version = 1;
uint64 origin_page = 2;
NockchainName name = 3;
NockchainLock note_data = 4;
uint64 assets = 5;
}
message NockchainName {
@ -82,7 +90,18 @@ message NockchainSignature {
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;
string lock_root = 2;
NockchainLock note_data = 3;

View File

@ -9,7 +9,9 @@ import (
"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 {
belts := []crypto.Belt{{Value: 13}}
@ -22,7 +24,7 @@ func HashPubkey(pkPoint crypto.CheetahPoint) [5]uint64 {
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}}
for _, i := range signature.Chal {
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
}
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 {
keysRequiredHash := crypto.Tip5HashLeaf(lock.KeysRequired)
// TODO: handle multisig
@ -67,9 +105,10 @@ func HashOwner(pkPoint crypto.CheetahPoint) [5]uint64 {
return crypto.Tip5RehashTenCell(crypto.Tip5One, pkHashedZeroZero)
}
func NockName(ownerHash [5]uint64) ([5]uint64, [5]uint64) {
firstName := first(ownerHash)
return firstName, LastName
func NockFirstName(ownerHash [5]uint64) [5]uint64 {
ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
return crypto.Tip5RehashTenCell(crypto.Tip5Zero, ownerHashZeroOne)
}
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
}
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 {
if timelock == nil {
return crypto.Tip5Zero
@ -201,29 +253,26 @@ func HashSource(source *nockchain.NockchainSource) [5]uint64 {
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)
fmt.Println("lockRoot:", lockRoot)
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: seed.Gift}})
parentHash := crypto.Base58ToTip5Hash(seed.ParentHash)
fmt.Println("parentHash:", parentHash)
assetHashparentHash := crypto.Tip5RehashTenCell(assetHash, parentHash)
noteDataHash := HashNoteData(seed.NoteData)
fmt.Println("noteDataHash:", noteDataHash)
noteDataHashAssetParentHash := crypto.Tip5RehashTenCell(noteDataHash, assetHashparentHash)
seedHash := crypto.Tip5RehashTenCell(lockRoot, noteDataHashAssetParentHash)
return seedHash
}
func HashSeed(seed *nockchain.NockchainSeedV0) [5]uint64 {
func HashSeed(seed *nockchain.NockchainSeed) [5]uint64 {
seedHash := HashSeedWithoutSource(seed)
sourceHash := HashSource(seed.OutputSource)
return crypto.Tip5RehashTenCell(sourceHash, seedHash)
}
func HashSeedVarLen(seed *nockchain.NockchainSeedV0) [5]uint64 {
func HashSeedVarLen(seed *nockchain.NockchainSeed) [5]uint64 {
belts := []crypto.Belt{{Value: 0}}
lockRoot := crypto.Base58ToTip5Hash(seed.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")
}
sigHash, err := HashSignature(spend.Signatures[0])
sigHash, err := HashSignatureV0(spend.Signatures[0])
if err != nil {
return [5]uint64{}, err
}
seedsTree := NewZTree(
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()
seedHashFee, err := HashSeedsAndFee(spend.Seeds, spend.Fee)
if err != nil {
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
}
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(
func(i interface{}) [5]uint64 {
if seed, ok := i.(*nockchain.NockchainSeedV0); ok {
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.NockchainSeedV0); ok {
if seed, ok := i.(*nockchain.NockchainSeed); ok {
return HashSeed(seed), nil
} else {
return [5]uint64{}, fmt.Errorf("invalid input type")
}
},
)
for _, seed := range spend.Seeds {
for _, seed := range seeds {
seedsTree.Insert(seed, seed)
}
finalSeedHash, err := seedsTree.Hash()
if err != nil {
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
}
// func HashInput(input *nockchain.NockchainInput) ([5]uint64, error) {
// nameHash := HashName(input.Name)
func HashSeedsAndFee(seeds []*nockchain.NockchainSeed, fee uint64) ([5]uint64, error) {
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)
// if err != 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
// }
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: fee}})
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
}
func ComputeTxId(spends []*nockchain.NockchainNamedSpend, version uint64) ([5]uint64, error) {
var spendHash [5]uint64
@ -399,7 +454,37 @@ func ComputeTxId(spends []*nockchain.NockchainNamedSpend, version uint64) ([5]ui
if err != nil {
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:
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)
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
}
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 {
if len(bits) == 0 {
return nil
@ -40,6 +50,16 @@ func BoolsToBytesLSB0(bits []bool) []byte {
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 {
bits := InitialBits
@ -89,3 +109,48 @@ func EncodeNoteData(noteData *nockchain.NockchainLock) []byte {
bits = append(bits, []bool{true, false, false, true, false, true, false, true}...)
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 (
WitnessWordsCount = 0
WitnessWordsCount = 55
SignatureWordsCount = 31
SeedWordsCount = 13
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, ",")
if len(specs) == 0 {
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
}
masterPkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey)
if err != nil {
return nil, err
}
pkHash := HashPubkey(masterPkPoint)
recipent := &nockchain.NockchainLock{
KeysRequired: 1,
@ -464,23 +443,40 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
}
refundAddr := req.RefundAddress
if refundAddr == "" {
masterPkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey)
if err != nil {
return nil, err
}
pkHash := HashPubkey(masterPkPoint)
refundAddr = crypto.Tip5HashToBase58(pkHash)
}
refundLock := &nockchain.NockchainLock{
KeysRequired: 1,
Pubkeys: []string{refundAddr},
}
ownerLock := &nockchain.NockchainLock{
KeysRequired: 1,
Pubkeys: []string{crypto.Tip5HashToBase58(pkHash)},
}
ownerHash := HashLock(ownerLock)
// Scan key to get notes
masterKeyScan, err := h.client.WalletGetBalance(&nockchain.GetBalanceRequest{
Selector: &nockchain.GetBalanceRequest_Address{
Address: base58.Encode(masterKey.PublicKey),
},
})
var scanReq *nockchain.GetBalanceRequest
switch req.Version {
case 0:
scanReq = &nockchain.GetBalanceRequest{
Selector: &nockchain.GetBalanceRequest_Address{
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 {
return nil, err
}
@ -535,23 +531,30 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
notesV1Sort := make([]*nockchain.NockchainNoteV1, len(notesV1))
copy(notesV1Sort, notesV1)
slices.SortFunc(notesV0Sort, func(note1, note2 *nockchain.NockchainNoteV0) int {
return cmp.Compare(note1.Asset, note2.Asset)
})
// TODO: sort V1 notes
switch req.Version {
case 0:
slices.SortFunc(notesV0Sort, func(note1, note2 *nockchain.NockchainNoteV0) int {
return cmp.Compare(note2.Asset, note1.Asset)
})
case 1:
slices.SortFunc(notesV1Sort, func(note1, note2 *nockchain.NockchainNoteV1) int {
return cmp.Compare(note2.Assets, note1.Assets)
})
}
spends := []*nockchain.NockchainNamedSpend{}
for _, note := range notesV0Sort {
giftPortion := uint64(0)
feePortion := uint64(0)
if giftRemaining != 0 {
giftPortion = min(giftRemaining, note.Asset)
for i := 0; i < len(names); i++ {
asset := uint64(0)
switch req.Version {
case 0:
asset = notesV0Sort[i].Asset
case 1:
asset = notesV1Sort[i].Assets
}
giftPortion := min(giftRemaining, asset)
feeAvailable := note.Asset - giftPortion
if feeRemaining != 0 {
feePortion = min(feeRemaining, feeAvailable)
}
feeAvailable := asset - giftPortion
feePortion := min(feeRemaining, feeAvailable)
if giftPortion == 0 && feePortion == 0 {
continue
@ -560,81 +563,126 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
giftRemaining = giftRemaining - giftPortion
feeRemaining = feeRemaining - feePortion
refund := note.Asset - giftPortion - feePortion
refund := asset - giftPortion - feePortion
if refund == 0 && giftPortion == 0 {
continue
}
parentHash, err := HashNoteV0(note)
var parentHash [5]uint64
switch req.Version {
case 0:
parentHash, err = HashNoteV0(notesV0Sort[i])
if err != nil {
return nil, err
}
case 1:
parentHash = HashNoteV1(notesV1Sort[i])
}
lockRoot := HashLock(recipent)
seeds := []*nockchain.NockchainSeed{}
if giftPortion != 0 {
wordCount += SeedWordsCount
seeds = append(seeds, &nockchain.NockchainSeed{
OutputSource: nil,
LockRoot: crypto.Tip5HashToBase58(lockRoot),
NoteData: recipent,
Gift: giftPortion,
ParentHash: crypto.Tip5HashToBase58(parentHash),
})
}
if refund != 0 {
wordCount += SeedWordsCount
lockRoot := HashLock(refundLock)
seeds = append(seeds, &nockchain.NockchainSeed{
OutputSource: nil,
LockRoot: crypto.Tip5HashToBase58(lockRoot),
NoteData: refundLock,
Gift: refund,
ParentHash: crypto.Tip5HashToBase58(parentHash),
})
}
msg, err := HashMsg(seeds, feePortion)
if err != nil {
return nil, err
}
if req.Version == 0 {
lockRoot := HashLock(recipent)
wordCount += SeedWordsCount
seeds := []*nockchain.NockchainSeedV0{
{
OutputSource: nil,
LockRoot: crypto.Tip5HashToBase58(lockRoot),
NoteData: recipent,
Gift: giftPortion,
ParentHash: crypto.Tip5HashToBase58(parentHash),
},
}
if refund != 0 {
wordCount += SeedWordsCount
lockRoot := HashLock(refundLock)
seeds = append(seeds, &nockchain.NockchainSeedV0{
OutputSource: nil,
LockRoot: crypto.Tip5HashToBase58(lockRoot),
NoteData: refundLock,
Gift: refund,
ParentHash: crypto.Tip5HashToBase58(parentHash),
})
}
// sign
chalT8, sigT8, err := ComputeSig(*masterKey, msg)
if err != nil {
return nil, err
}
sigs := []*nockchain.NockchainSignature{
{
Pubkey: base58.Encode(masterKey.PublicKey),
Chal: chalT8[:],
Sig: sigT8[:],
},
}
switch req.Version {
case 0:
spend := nockchain.NockchainSpendV0{
Signatures: nil,
Seeds: seeds,
Fee: feePortion,
}
msg, err := HashMsg(&spend)
if err != nil {
return nil, err
}
fmt.Println("msg:", msg)
// sign
chalT8, sigT8, err := ComputeSig(*masterKey, msg)
if err != nil {
return nil, err
}
masterPkPoint, err := crypto.CheetaPointFromBytes(masterKey.PublicKey)
if err != nil {
return nil, err
}
fmt.Println("master pk point:", masterPkPoint)
spend.Signatures = []*nockchain.NockchainSignature{
{
Pubkey: base58.Encode(masterKey.PublicKey),
Chal: chalT8[:],
Sig: sigT8[:],
},
}
spend.Signatures = sigs
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{
Name: note.Name,
Name: nnames[nameIdx],
SpendKind: &nockchain.NockchainNamedSpend_Legacy{
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) {
return nil, fmt.Errorf("min fee not met, this transaction requires at least: %d", wordCount*BaseFee)
}

View File

@ -435,7 +435,7 @@ func TestScan(t *testing.T) {
assert.NotEmpty(t, masterKey1Scan.Notes)
}
func TestEncodeNoun(t *testing.T) {
func TestEncodeDecodeNoun(t *testing.T) {
lock1 := &nockchain.NockchainLock{
KeysRequired: 1,
Pubkeys: []string{"5wef35rKxbJDJRAtzGG1VwbMQK9jF3Wr5e6fyMsh2hxnCQZDZJV1YNQ"},
@ -444,143 +444,22 @@ func TestEncodeNoun(t *testing.T) {
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})
lock1Decode := wallet.DecodeNoteData(lock1Encode)
assert.Equal(t, lock1Decode.KeysRequired, lock1.KeysRequired)
assert.Equal(t, lock1Decode.Pubkeys, lock1.Pubkeys)
lock2 := lock1
lock2.Pubkeys = []string{"7UXNF2HXzEaPUvLDVDgGJyriKqpd2974Kj7U2RnLuBPeRGa7ZezhGmK"}
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})
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
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"
masterKey1, err := crypto.MasterKeyFromSeed(seed1)
assert.NoError(t, err)
@ -626,3 +505,34 @@ func TestCreateTx(t *testing.T) {
// the result is taken from create-tx scripts
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
import (
"fmt"
"github.com/btcsuite/btcd/btcutil/base58"
"github.com/phamminh0811/private-grpc/crypto"
"github.com/phamminh0811/private-grpc/nockchain"
)
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) {
case *nockchain.Note_Legacy:
note := entry.Note.GetLegacy()
@ -50,22 +64,7 @@ func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
V0: &nockchain.NockchainNoteV0{
Version: version,
OriginPage: note.OriginPage.Value,
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,
}),
},
Name: name,
Lock: &nockchain.NockchainLock{
KeysRequired: uint64(note.Lock.KeysRequired),
Pubkeys: pubkeys,
@ -79,11 +78,22 @@ func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
},
}
case *nockchain.Note_V1:
fmt.Println("go here???")
// Handle V1 notes if needed
note := entry.Note.GetV1()
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{
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:
@ -134,7 +144,91 @@ func ConvertNamedSpend(spend *nockchain.NockchainNamedSpend) (*nockchain.SpendEn
},
}
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
return &nockchain.SpendEntry{