Compare commits

..

No commits in common. "16e47129f4aade9554e956ea5e6c9905e2fc71e4" and "9e29f96dbdaf47d75913d729eb12d416ab129f60" have entirely different histories.

5 changed files with 247 additions and 259 deletions

View File

@ -18,7 +18,6 @@ var (
MagicDyckForPoint = []uint64{0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1} MagicDyckForPoint = []uint64{0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1}
MagicDyckForT8 = []uint64{0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1} MagicDyckForT8 = []uint64{0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}
MagicDyckForSeed = []uint64{0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1} MagicDyckForSeed = []uint64{0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}
MagicDyckForName = []uint64{0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1}
Tip5Zero = [5]uint64{1730770831742798981, 2676322185709933211, 8329210750824781744, 16756092452590401876, 3547445316740171466} Tip5Zero = [5]uint64{1730770831742798981, 2676322185709933211, 8329210750824781744, 16756092452590401876, 3547445316740171466}
Tip5One = [5]uint64{6727110957294540849, 15606243244732609007, 11887284596344881785, 10646863421881571398, 8146872807338919620} Tip5One = [5]uint64{6727110957294540849, 15606243244732609007, 11887284596344881785, 10646863421881571398, 8146872807338919620}
Tip5ZeroZero = [5]uint64{4372149332062030091, 17876920912185183887, 13348798570422431948, 8872865212694716527, 3385176510443841516} Tip5ZeroZero = [5]uint64{4372149332062030091, 17876920912185183887, 13348798570422431948, 8872865212694716527, 3385176510443841516}

View File

@ -61,24 +61,6 @@ func HashName(name *nockchain.NockchainName) [5]uint64 {
return crypto.Tip5RehashTenCell(firstNameHash, crypto.Tip5RehashTenCell(lastNameHash, crypto.Tip5Zero)) return crypto.Tip5RehashTenCell(firstNameHash, crypto.Tip5RehashTenCell(lastNameHash, crypto.Tip5Zero))
} }
func HashNameVarLen(name *nockchain.NockchainName) [5]uint64 {
belts := []crypto.Belt{}
for _, i := range crypto.Base58ToTip5Hash(name.First) {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range crypto.Base58ToTip5Hash(name.Last) {
belts = append(belts, crypto.Belt{Value: i})
}
belts = append(belts, crypto.BELT_ZERO)
size := len(belts)
belts = append([]crypto.Belt{{Value: uint64(size)}}, belts...)
for _, i := range crypto.MagicDyckForName {
belts = append(belts, crypto.Belt{Value: i})
}
res := crypto.Tip5HashBelts(belts)
return res
}
func HashNote(note *nockchain.NockchainNote) ([5]uint64, error) { func HashNote(note *nockchain.NockchainNote) ([5]uint64, error) {
versionHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Version)}}) versionHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Version)}})
blockHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: note.BlockHeight}}) blockHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: note.BlockHeight}})
@ -243,36 +225,86 @@ func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
if err != nil { if err != nil {
return [5]uint64{}, err return [5]uint64{}, err
} }
seedsCount := len(spend.Seeds)
seedsTree := NewZTree( var finalSeedHash [5]uint64
func(i interface{}) [5]uint64 { if seedsCount == 1 {
if seed, ok := i.(*nockchain.NockchainSeed); ok { seedHash, err := HashSeedWithoutSource(spend.Seeds[0])
seedHash, err := HashSeedVarLen(seed)
if err != nil {
return [5]uint64{}
}
return seedHash
} else {
return [5]uint64{}
}
},
func(i interface{}) ([5]uint64, error) {
if seed, ok := i.(*nockchain.NockchainSeed); ok {
hash, err := HashSeedWithoutSource(seed)
return hash, err
} 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
} }
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, crypto.Tip5ZeroZero)
} else {
seed1Hash, err := HashSeedWithoutSource(spend.Seeds[0])
if err != nil {
return [5]uint64{}, err
}
seed1HashVarLen, err := HashSeedVarLen(spend.Seeds[0])
if err != nil {
return [5]uint64{}, err
}
seed1DoubleHash := crypto.Tip5RehashTenCell(seed1HashVarLen, seed1HashVarLen)
seed2Hash, err := HashSeedWithoutSource(spend.Seeds[1])
if err != nil {
return [5]uint64{}, err
}
seed2HashVarLen, err := HashSeedVarLen(spend.Seeds[1])
if err != nil {
return [5]uint64{}, err
}
seed2DoubleHash := crypto.Tip5RehashTenCell(seed2HashVarLen, seed2HashVarLen)
seedHash1BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1HashVarLen)))
seed1DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1DoubleHash)))
seedHash2BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2HashVarLen)))
seed2DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2DoubleHash)))
if seedHash1BigInt.Cmp(seedHash2BigInt) == -1 {
// seed 1 < seed 2
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
// seed1
// / \
// ~ seed2
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
} else {
// seed2
// / \
// seed1 ~
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
}
} else {
// seed 1 > seed 2
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
// seed1
// / \
// seed2 ~
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
} else {
// seed2
// / \
// ~ seed1
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
}
}
}
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}}) feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}})
seedHashFee := crypto.Tip5RehashTenCell(finalSeedHash, feeHash) seedHashFee := crypto.Tip5RehashTenCell(finalSeedHash, feeHash)
return crypto.Tip5RehashTenCell(sigHash, seedHashFee), nil return crypto.Tip5RehashTenCell(sigHash, seedHashFee), nil
@ -280,34 +312,85 @@ func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
} }
func HashMsg(spend *nockchain.NockchainSpend) ([5]uint64, error) { func HashMsg(spend *nockchain.NockchainSpend) ([5]uint64, error) {
seedsTree := NewZTree( seedsCount := len(spend.Seeds)
func(i interface{}) [5]uint64 { var finalSeedHash [5]uint64
if seed, ok := i.(*nockchain.NockchainSeed); ok { if seedsCount == 1 {
seedHash, err := HashSeedVarLen(seed) seedHash, err := HashSeed(spend.Seeds[0])
if err != nil {
return [5]uint64{}
}
return seedHash
} else {
return [5]uint64{}
}
},
func(i interface{}) ([5]uint64, error) {
if seed, ok := i.(*nockchain.NockchainSeed); ok {
hash, err := HashSeed(seed)
return hash, err
} 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
} }
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, crypto.Tip5ZeroZero)
} else {
seed1HashVarLen, err := HashSeedVarLen(spend.Seeds[0])
if err != nil {
return [5]uint64{}, err
}
seed1Hash, err := HashSeed(spend.Seeds[0])
if err != nil {
return [5]uint64{}, err
}
seed1DoubleHash := crypto.Tip5RehashTenCell(seed1HashVarLen, seed1HashVarLen)
seed2HashVarLen, err := HashSeedVarLen(spend.Seeds[1])
if err != nil {
return [5]uint64{}, err
}
seed2Hash, err := HashSeed(spend.Seeds[1])
if err != nil {
return [5]uint64{}, err
}
seed2DoubleHash := crypto.Tip5RehashTenCell(seed2HashVarLen, seed2HashVarLen)
seedHash1BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1HashVarLen)))
seed1DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1DoubleHash)))
seedHash2BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2HashVarLen)))
seed2DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2DoubleHash)))
if seedHash1BigInt.Cmp(seedHash2BigInt) == -1 {
// seed 1 < seed 2
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
// seed1
// / \
// ~ seed2
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
} else {
// seed2
// / \
// seed1 ~
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
}
} else {
// seed 1 > seed 2
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
// seed1
// / \
// seed2 ~
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
} else {
// seed2
// / \
// ~ seed1
// / \
// ~ ~
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
}
}
}
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}}) feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}})
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
} }
@ -334,7 +417,7 @@ func ComputeTxId(inputs []*nockchain.NockchainInput, timelockRange *nockchain.Ti
inputTree := NewZTree( inputTree := NewZTree(
func(i interface{}) [5]uint64 { func(i interface{}) [5]uint64 {
if name, ok := i.(*nockchain.NockchainName); ok { if name, ok := i.(*nockchain.NockchainName); ok {
return HashNameVarLen(name) return HashName(name)
} else { } else {
return [5]uint64{} return [5]uint64{}
} }

View File

@ -287,7 +287,7 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
nameTree := NewZTree( nameTree := NewZTree(
func(i interface{}) [5]uint64 { func(i interface{}) [5]uint64 {
if name, ok := i.(*nockchain.NockchainName); ok { if name, ok := i.(*nockchain.NockchainName); ok {
return HashNameVarLen(name) return HashName(name)
} else { } else {
return [5]uint64{} return [5]uint64{}
} }
@ -297,18 +297,16 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
for _, name := range nnames { for _, name := range nnames {
nameTree.Insert(name, nil) nameTree.Insert(name, nil)
} }
nameList := nameTree.Tap() nameLeftMost := nameTree.KeyLeftMost().(*nockchain.NockchainName)
nameKeys := []string{} idxLeftMost := -1
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 { for i, name := range nnames {
if idx := slices.Index(nameKeys, name.First+" "+name.Last); idx != -1 { if name.First == nameLeftMost.First && name.Last == nameLeftMost.Last {
indices[idx] = i idxLeftMost = i
} }
} }
if idxLeftMost == -1 {
return nil, fmt.Errorf("unable to find left most node")
}
recipents := []*nockchain.NockchainLock{} recipents := []*nockchain.NockchainLock{}
if strings.Contains(req.Recipients, "[") { if strings.Contains(req.Recipients, "[") {
@ -413,40 +411,40 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
} }
} }
inputs := make([]*nockchain.NockchainInput, len(names)) inputs := []*nockchain.NockchainInput{}
isSpent := false for i := 0; i < len(names); i++ {
for i := 0; i < len(nameKeys); i++ { if notes[i] == nil {
idx := indices[i] return nil, fmt.Errorf("notes scanned is missing at name: %s", names[i])
if notes[idx] == nil {
return nil, fmt.Errorf("notes scanned is missing at name: %s", names[idx])
} }
if notes[idx].Asset < gifts[idx] { if notes[i].Asset < gifts[i]+req.Fee {
return nil, fmt.Errorf("note %s not enough balance", names[idx]) return nil, fmt.Errorf("note not enough balance")
} }
parentHash, err := HashNote(notes[idx]) parentHash, err := HashNote(notes[i])
if err != nil { if err != nil {
return nil, err return nil, err
} }
seeds := []*nockchain.NockchainSeed{ seeds := []*nockchain.NockchainSeed{
{ {
OutputSource: nil, OutputSource: nil,
Recipient: recipents[idx], Recipient: recipents[i],
TimelockIntent: req.TimelockIntent, TimelockIntent: req.TimelockIntent,
Gift: gifts[idx], Gift: gifts[i],
ParentHash: crypto.Tip5HashToBase58(parentHash), ParentHash: crypto.Tip5HashToBase58(parentHash),
}, },
} }
if notes[i].Asset < gifts[i] {
assetLeft := notes[idx].Asset - gifts[idx] return nil, fmt.Errorf("insufficient funds for notes %s", names[i])
fee := uint64(0) }
if !isSpent && assetLeft >= req.Fee { assetLeft := notes[i].Asset - gifts[i]
isSpent = true if i == idxLeftMost {
fee = req.Fee if assetLeft > req.Fee {
assetLeft -= req.Fee assetLeft -= req.Fee
} else {
return nil, fmt.Errorf("insufficient funds for notes %s", names[i])
}
} }
if assetLeft != 0 { if assetLeft != 0 {
seeds = append(seeds, &nockchain.NockchainSeed{ seeds = append(seeds, &nockchain.NockchainSeed{
OutputSource: nil, OutputSource: nil,
@ -459,10 +457,19 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
ParentHash: crypto.Tip5HashToBase58(parentHash), ParentHash: crypto.Tip5HashToBase58(parentHash),
}) })
} }
spend := nockchain.NockchainSpend{ var spend nockchain.NockchainSpend
if i == idxLeftMost {
spend = nockchain.NockchainSpend{
Signatures: nil, Signatures: nil,
Seeds: seeds, Seeds: seeds,
Fee: fee, Fee: req.Fee,
}
} else {
spend = nockchain.NockchainSpend{
Signatures: nil,
Seeds: seeds,
Fee: 0,
}
} }
msg, err := HashMsg(&spend) msg, err := HashMsg(&spend)
@ -485,16 +492,13 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
} }
input := nockchain.NockchainInput{ input := nockchain.NockchainInput{
Name: nnames[idx], Name: nnames[i],
Note: notes[idx], Note: notes[i],
Spend: &spend, Spend: &spend,
} }
inputs[idx] = &input inputs = append(inputs, &input)
} }
if !isSpent {
return nil, fmt.Errorf("insufficient funds")
}
var timelockRange *nockchain.TimelockRange var timelockRange *nockchain.TimelockRange
if req.TimelockIntent == nil { if req.TimelockIntent == nil {
timelockRange = &nockchain.TimelockRange{ timelockRange = &nockchain.TimelockRange{

View File

@ -428,26 +428,21 @@ func TestFullFlow(t *testing.T) {
// This test should be run with timeout 300s // This test should be run with timeout 300s
func TestCreateTx(t *testing.T) { func TestCreateTx(t *testing.T) {
seed1 := "brass vacuum stairs hurt brisk govern describe enforce fly exact rescue capable belt flavor lottery sauce easy frame orange legal injury border obey novel" seed1 := "pledge vessel toilet sunny hockey skirt spend wire disorder attitude crumble lecture problem bundle bone rather address over suit ancient primary gospel silent repair"
masterKey1, err := crypto.MasterKeyFromSeed(seed1) masterKey1, err := crypto.MasterKeyFromSeed(seed1)
assert.NoError(t, err) assert.NoError(t, err)
fmt.Println("masterKey1: ", base58.Encode(masterKey1.PublicKey))
// nockchain-wallet create-tx --names '[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 AmSjC3SDNtb7ZrUkTXc242BvGeimeL1nAV4CqV63HpLMryhom4L9W59],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 7oo4x3fuwcJ5DrbFY1yf715ctjtE6CqqPagJWT8d687Q6sgMVWc1SXz],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 8BrF9XAKwzvFdy8p7KAB8VEvcswPADhs2WamhWSLUErYN9z8U8cynaA]' --recipients '37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe,37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe,37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe' --gifts '50,50,50' --fee 100 seed2 := "brass vacuum stairs hurt brisk govern describe enforce fly exact rescue capable belt flavor lottery sauce easy frame orange legal injury border obey novel"
seed2 := "chimney endorse scan ramp cheap harvest mother ball winter way barrel foil tissue pupil answer worth right undo one chimney element grape image unlock"
masterKey2, err := crypto.MasterKeyFromSeed(seed2) masterKey2, err := crypto.MasterKeyFromSeed(seed2)
assert.NoError(t, err) assert.NoError(t, err)
fmt.Println("masterKey2", base58.Encode(masterKey2.PublicKey))
nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443") nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
assert.NoError(t, err) assert.NoError(t, err)
handler := wallet.NewGprcHandler(*nc) handler := wallet.NewGprcHandler(*nc)
inputs := "[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 AmSjC3SDNtb7ZrUkTXc242BvGeimeL1nAV4CqV63HpLMryhom4L9W59],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 7oo4x3fuwcJ5DrbFY1yf715ctjtE6CqqPagJWT8d687Q6sgMVWc1SXz],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 8BrF9XAKwzvFdy8p7KAB8VEvcswPADhs2WamhWSLUErYN9z8U8cynaA]" inputs := "[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 91z5muQKgHZDcChdnCSTEtvuN8dbbXp5wzNs5xrCkce2YvSX1q6fu3d],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 3a9VWigUM1TuS79yM4dAqkiUg6WJMUPGwVKJpQUHCLJcFZsCWM2q6pF],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 9RkPvHMtuYtjV2qvB86u7zcnr26SdVcKzFnHgfhUSEG1W3FgKgLpbBm]"
recipients := fmt.Sprintf("%s,%s,%s", base58.Encode(masterKey2.PublicKey), base58.Encode(masterKey2.PublicKey), base58.Encode(masterKey2.PublicKey)) recipients := fmt.Sprintf("%s,%s,%s", base58.Encode(masterKey2.PublicKey), base58.Encode(masterKey2.PublicKey), base58.Encode(masterKey2.PublicKey))
gifts := "50,50,50" gifts := "100,100,100"
fee := 100 fee := 100
req := &nockchain.CreateTxRequest{ req := &nockchain.CreateTxRequest{
@ -467,5 +462,5 @@ func TestCreateTx(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// the result is taken from create-tx scripts // the result is taken from create-tx scripts
assert.Equal(t, res.RawTx.TxId, "A8vSeRde61B4sZccSnNPEnkQgTe15EssoFwyhQXbkhtk4UNm5hyGSid") assert.Equal(t, res.RawTx.TxId, "8gjTa6H1MrKXPWgNJCF9fsYE7PUfqhYzxetUoTftz7zyHCv24ZYHDM3")
} }

View File

@ -1,10 +1,8 @@
package wallet package wallet
import ( import (
"math/big"
"slices" "slices"
"github.com/btcsuite/btcd/btcutil/base58"
"github.com/phamminh0811/private-grpc/crypto" "github.com/phamminh0811/private-grpc/crypto"
) )
@ -22,11 +20,6 @@ type ZTree struct {
HashValueFunc func(interface{}) ([5]uint64, error) HashValueFunc func(interface{}) ([5]uint64, error)
} }
type ZPair struct {
Key interface{}
Value interface{}
}
func NewZTree(hashKeyFunc func(interface{}) [5]uint64, hashValueFunc func(interface{}) ([5]uint64, error)) *ZTree { func NewZTree(hashKeyFunc func(interface{}) [5]uint64, hashValueFunc func(interface{}) ([5]uint64, error)) *ZTree {
return &ZTree{ return &ZTree{
Root: nil, Root: nil,
@ -43,13 +36,13 @@ func (z *ZTree) Hash() ([5]uint64, error) {
return z.Root.HashNode(z.HashValueFunc) return z.Root.HashNode(z.HashValueFunc)
} }
func (t *ZTree) Tap() []ZPair { func (z *ZTree) KeyLeftMost() interface{} {
tap := []ZPair{} node := z.Root
TapNode(t.Root, &tap) for node.Left != nil {
slices.Reverse(tap) node = node.Left
return tap }
return node.Key
} }
func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value interface{}) *ZNode { func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value interface{}) *ZNode {
if node == nil { if node == nil {
node = &ZNode{ node = &ZNode{
@ -60,76 +53,15 @@ func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value i
} }
return node return node
} }
keyHash := hashFunc(key) keyHash := hashFunc(key)
keyDoubleHash := crypto.Tip5RehashTenCell(keyHash, keyHash) keyDoubleHash := crypto.Tip5RehashTenCell(keyHash, keyHash)
nodeKeyHash := hashFunc(node.Key) nodeKeyHash := hashFunc(node.Key)
nodeKeyDoubleHash := crypto.Tip5RehashTenCell(nodeKeyHash, nodeKeyHash) nodeKeyDoubleHash := crypto.Tip5RehashTenCell(nodeKeyHash, nodeKeyHash)
keyHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(keyHash))) if slices.Compare(keyHash[:], nodeKeyHash[:]) == -1 {
nodeKeyHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(nodeKeyHash)))
keyDoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(keyDoubleHash)))
nodeKeyDoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(nodeKeyDoubleHash)))
if keyHashBigInt.Cmp(nodeKeyHashBigInt) == 1 {
// key < node key // key < node key
if keyDoubleHashBigInt.Cmp(nodeKeyDoubleHashBigInt) == 1 { if slices.Compare(keyDoubleHash[:], nodeKeyDoubleHash[:]) == -1 {
// reinsert in right
node.Right = node.Right.InsertNode(hashFunc, key, value)
} else {
// new key
// / \
// old key ~
// / \
// ... ...
nodeKey := node.Key
nodeValue := node.Value
leftNode := node.Left
rightNode := node.Right
if rightNode == nil {
node = &ZNode{
Key: key,
Value: value,
Right: nil,
Left: &ZNode{
Key: nodeKey,
Value: nodeValue,
Left: leftNode,
Right: nil,
},
}
} else {
rightNodeKeyHash := hashFunc(rightNode.Key)
rightNodeKeyHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(rightNodeKeyHash)))
if rightNodeKeyHashBigInt.Cmp(keyHashBigInt) == -1 {
node = &ZNode{
Key: key,
Value: value,
Right: nil,
Left: &ZNode{
Key: nodeKey,
Value: nodeValue,
Left: leftNode,
Right: rightNode,
},
}
} else {
node = &ZNode{
Key: key,
Value: value,
Right: rightNode,
Left: &ZNode{
Key: nodeKey,
Value: nodeValue,
Left: leftNode,
Right: nil,
},
}
}
}
}
} else {
// key > node key
if keyDoubleHashBigInt.Cmp(nodeKeyDoubleHashBigInt) == 1 {
// reinsert in left // reinsert in left
node.Left = node.Left.InsertNode(hashFunc, key, value) node.Left = node.Left.InsertNode(hashFunc, key, value)
} else { } else {
@ -142,34 +74,33 @@ func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value i
nodeValue := node.Value nodeValue := node.Value
leftNode := node.Left leftNode := node.Left
rightNode := node.Right rightNode := node.Right
if leftNode == nil {
node = &ZNode{ node = &ZNode{
Key: key, Key: key,
Value: value, Value: value,
Right: &ZNode{ Right: nil,
Left: &ZNode{
Key: nodeKey, Key: nodeKey,
Value: nodeValue, Value: nodeValue,
Left: nil,
Right: rightNode,
},
Left: nil,
}
} else {
leftNodeKeyHash := hashFunc(leftNode.Key)
leftNodeKeyHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(leftNodeKeyHash)))
if leftNodeKeyHashBigInt.Cmp(keyHashBigInt) == -1 {
node = &ZNode{
Key: key,
Value: value,
Right: &ZNode{
Key: nodeKey,
Value: nodeValue,
Left: nil,
Right: rightNode,
},
Left: leftNode, Left: leftNode,
Right: rightNode,
},
}
} }
} else { } else {
// key > node key
if slices.Compare(keyDoubleHash[:], nodeKeyDoubleHash[:]) == -1 {
// reinsert in right
node.Right = node.Right.InsertNode(hashFunc, key, value)
} else {
// new key
// / \
// old key ~
// / \
// ... ...
nodeKey := node.Key
nodeValue := node.Value
leftNode := node.Left
rightNode := node.Right
node = &ZNode{ node = &ZNode{
Key: key, Key: key,
Value: value, Value: value,
@ -183,8 +114,6 @@ func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value i
} }
} }
} }
}
}
return node return node
} }
@ -209,25 +138,3 @@ func (node *ZNode) HashNode(hashFunc func(interface{}) ([5]uint64, error)) ([5]u
} }
return crypto.Tip5RehashTenCell(valHash, hashLeftRight), nil return crypto.Tip5RehashTenCell(valHash, hashLeftRight), nil
} }
func TapNode(node *ZNode, acc *[]ZPair) {
if node == nil {
return
}
stored := false
if node.Right != nil {
TapNode(node.Right, acc)
} else {
*acc = append(*acc, ZPair{Key: node.Key, Value: node.Value})
stored = true
}
if node.Left != nil {
TapNode(node.Left, acc)
}
if !stored {
*acc = append(*acc, ZPair{Key: node.Key, Value: node.Value})
}
}