Compare commits
6 Commits
9e29f96dbd
...
16e47129f4
| Author | SHA1 | Date | |
|---|---|---|---|
| 16e47129f4 | |||
|
|
828628d82f | ||
|
|
2d9185a5ec | ||
| 2816e5333b | |||
|
|
262f7d3bc0 | ||
|
|
f91d39b943 |
@ -18,6 +18,7 @@ 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}
|
||||
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}
|
||||
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}
|
||||
Tip5One = [5]uint64{6727110957294540849, 15606243244732609007, 11887284596344881785, 10646863421881571398, 8146872807338919620}
|
||||
Tip5ZeroZero = [5]uint64{4372149332062030091, 17876920912185183887, 13348798570422431948, 8872865212694716527, 3385176510443841516}
|
||||
|
||||
@ -61,6 +61,24 @@ func HashName(name *nockchain.NockchainName) [5]uint64 {
|
||||
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) {
|
||||
versionHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Version)}})
|
||||
blockHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: note.BlockHeight}})
|
||||
@ -225,86 +243,36 @@ func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
||||
if err != nil {
|
||||
return [5]uint64{}, err
|
||||
}
|
||||
seedsCount := len(spend.Seeds)
|
||||
var finalSeedHash [5]uint64
|
||||
if seedsCount == 1 {
|
||||
seedHash, err := HashSeedWithoutSource(spend.Seeds[0])
|
||||
if err != nil {
|
||||
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)
|
||||
seedsTree := NewZTree(
|
||||
func(i interface{}) [5]uint64 {
|
||||
if seed, ok := i.(*nockchain.NockchainSeed); ok {
|
||||
seedHash, err := HashSeedVarLen(seed)
|
||||
if err != nil {
|
||||
return [5]uint64{}
|
||||
}
|
||||
return seedHash
|
||||
} else {
|
||||
// seed2
|
||||
// / \
|
||||
// seed1 ~
|
||||
// / \
|
||||
// ~ ~
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
||||
return [5]uint64{}
|
||||
}
|
||||
} 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)
|
||||
},
|
||||
func(i interface{}) ([5]uint64, error) {
|
||||
if seed, ok := i.(*nockchain.NockchainSeed); ok {
|
||||
hash, err := HashSeedWithoutSource(seed)
|
||||
return hash, err
|
||||
} else {
|
||||
// seed2
|
||||
// / \
|
||||
// ~ seed1
|
||||
// / \
|
||||
// ~ ~
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
||||
|
||||
return [5]uint64{}, fmt.Errorf("invalid input type")
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
for _, seed := range spend.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}})
|
||||
seedHashFee := crypto.Tip5RehashTenCell(finalSeedHash, feeHash)
|
||||
return crypto.Tip5RehashTenCell(sigHash, seedHashFee), nil
|
||||
@ -312,84 +280,33 @@ func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
||||
}
|
||||
|
||||
func HashMsg(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
||||
seedsCount := len(spend.Seeds)
|
||||
var finalSeedHash [5]uint64
|
||||
if seedsCount == 1 {
|
||||
seedHash, err := HashSeed(spend.Seeds[0])
|
||||
if err != nil {
|
||||
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)
|
||||
seedsTree := NewZTree(
|
||||
func(i interface{}) [5]uint64 {
|
||||
if seed, ok := i.(*nockchain.NockchainSeed); ok {
|
||||
seedHash, err := HashSeedVarLen(seed)
|
||||
if err != nil {
|
||||
return [5]uint64{}
|
||||
}
|
||||
return seedHash
|
||||
} else {
|
||||
// seed2
|
||||
// / \
|
||||
// seed1 ~
|
||||
// / \
|
||||
// ~ ~
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
||||
return [5]uint64{}
|
||||
}
|
||||
} 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)
|
||||
},
|
||||
func(i interface{}) ([5]uint64, error) {
|
||||
if seed, ok := i.(*nockchain.NockchainSeed); ok {
|
||||
hash, err := HashSeed(seed)
|
||||
return hash, err
|
||||
} else {
|
||||
// seed2
|
||||
// / \
|
||||
// ~ seed1
|
||||
// / \
|
||||
// ~ ~
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
|
||||
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
||||
return [5]uint64{}, fmt.Errorf("invalid input type")
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
for _, seed := range spend.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}})
|
||||
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
|
||||
@ -417,7 +334,7 @@ func ComputeTxId(inputs []*nockchain.NockchainInput, timelockRange *nockchain.Ti
|
||||
inputTree := NewZTree(
|
||||
func(i interface{}) [5]uint64 {
|
||||
if name, ok := i.(*nockchain.NockchainName); ok {
|
||||
return HashName(name)
|
||||
return HashNameVarLen(name)
|
||||
} else {
|
||||
return [5]uint64{}
|
||||
}
|
||||
|
||||
@ -287,7 +287,7 @@ 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 HashName(name)
|
||||
return HashNameVarLen(name)
|
||||
} else {
|
||||
return [5]uint64{}
|
||||
}
|
||||
@ -297,15 +297,17 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
||||
for _, name := range nnames {
|
||||
nameTree.Insert(name, nil)
|
||||
}
|
||||
nameLeftMost := nameTree.KeyLeftMost().(*nockchain.NockchainName)
|
||||
idxLeftMost := -1
|
||||
for i, name := range nnames {
|
||||
if name.First == nameLeftMost.First && name.Last == nameLeftMost.Last {
|
||||
idxLeftMost = i
|
||||
}
|
||||
nameList := nameTree.Tap()
|
||||
nameKeys := []string{}
|
||||
for _, nameKey := range nameList {
|
||||
name := nameKey.Key.(*nockchain.NockchainName)
|
||||
nameKeys = append(nameKeys, name.First+" "+name.Last)
|
||||
}
|
||||
if idxLeftMost == -1 {
|
||||
return nil, fmt.Errorf("unable to find left most node")
|
||||
indices := make([]int, len(nnames))
|
||||
for i, name := range nnames {
|
||||
if idx := slices.Index(nameKeys, name.First+" "+name.Last); idx != -1 {
|
||||
indices[idx] = i
|
||||
}
|
||||
}
|
||||
|
||||
recipents := []*nockchain.NockchainLock{}
|
||||
@ -411,40 +413,40 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
||||
}
|
||||
}
|
||||
|
||||
inputs := []*nockchain.NockchainInput{}
|
||||
for i := 0; i < len(names); i++ {
|
||||
if notes[i] == nil {
|
||||
return nil, fmt.Errorf("notes scanned is missing at name: %s", names[i])
|
||||
inputs := make([]*nockchain.NockchainInput, len(names))
|
||||
isSpent := false
|
||||
for i := 0; i < len(nameKeys); i++ {
|
||||
idx := indices[i]
|
||||
if notes[idx] == nil {
|
||||
return nil, fmt.Errorf("notes scanned is missing at name: %s", names[idx])
|
||||
}
|
||||
|
||||
if notes[i].Asset < gifts[i]+req.Fee {
|
||||
return nil, fmt.Errorf("note not enough balance")
|
||||
if notes[idx].Asset < gifts[idx] {
|
||||
return nil, fmt.Errorf("note %s not enough balance", names[idx])
|
||||
}
|
||||
|
||||
parentHash, err := HashNote(notes[i])
|
||||
parentHash, err := HashNote(notes[idx])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seeds := []*nockchain.NockchainSeed{
|
||||
{
|
||||
OutputSource: nil,
|
||||
Recipient: recipents[i],
|
||||
Recipient: recipents[idx],
|
||||
TimelockIntent: req.TimelockIntent,
|
||||
Gift: gifts[i],
|
||||
Gift: gifts[idx],
|
||||
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
||||
},
|
||||
}
|
||||
if notes[i].Asset < gifts[i] {
|
||||
return nil, fmt.Errorf("insufficient funds for notes %s", names[i])
|
||||
}
|
||||
assetLeft := notes[i].Asset - gifts[i]
|
||||
if i == idxLeftMost {
|
||||
if assetLeft > req.Fee {
|
||||
assetLeft -= req.Fee
|
||||
} else {
|
||||
return nil, fmt.Errorf("insufficient funds for notes %s", names[i])
|
||||
}
|
||||
|
||||
assetLeft := notes[idx].Asset - gifts[idx]
|
||||
fee := uint64(0)
|
||||
if !isSpent && assetLeft >= req.Fee {
|
||||
isSpent = true
|
||||
fee = req.Fee
|
||||
assetLeft -= req.Fee
|
||||
}
|
||||
|
||||
if assetLeft != 0 {
|
||||
seeds = append(seeds, &nockchain.NockchainSeed{
|
||||
OutputSource: nil,
|
||||
@ -457,19 +459,10 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
||||
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
||||
})
|
||||
}
|
||||
var spend nockchain.NockchainSpend
|
||||
if i == idxLeftMost {
|
||||
spend = nockchain.NockchainSpend{
|
||||
Signatures: nil,
|
||||
Seeds: seeds,
|
||||
Fee: req.Fee,
|
||||
}
|
||||
} else {
|
||||
spend = nockchain.NockchainSpend{
|
||||
Signatures: nil,
|
||||
Seeds: seeds,
|
||||
Fee: 0,
|
||||
}
|
||||
spend := nockchain.NockchainSpend{
|
||||
Signatures: nil,
|
||||
Seeds: seeds,
|
||||
Fee: fee,
|
||||
}
|
||||
|
||||
msg, err := HashMsg(&spend)
|
||||
@ -492,13 +485,16 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
||||
}
|
||||
|
||||
input := nockchain.NockchainInput{
|
||||
Name: nnames[i],
|
||||
Note: notes[i],
|
||||
Name: nnames[idx],
|
||||
Note: notes[idx],
|
||||
Spend: &spend,
|
||||
}
|
||||
inputs = append(inputs, &input)
|
||||
inputs[idx] = &input
|
||||
}
|
||||
|
||||
if !isSpent {
|
||||
return nil, fmt.Errorf("insufficient funds")
|
||||
}
|
||||
var timelockRange *nockchain.TimelockRange
|
||||
if req.TimelockIntent == nil {
|
||||
timelockRange = &nockchain.TimelockRange{
|
||||
|
||||
@ -428,21 +428,26 @@ func TestFullFlow(t *testing.T) {
|
||||
|
||||
// This test should be run with timeout 300s
|
||||
func TestCreateTx(t *testing.T) {
|
||||
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"
|
||||
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"
|
||||
|
||||
masterKey1, err := crypto.MasterKeyFromSeed(seed1)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println("masterKey1: ", base58.Encode(masterKey1.PublicKey))
|
||||
|
||||
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"
|
||||
// nockchain-wallet create-tx --names '[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 AmSjC3SDNtb7ZrUkTXc242BvGeimeL1nAV4CqV63HpLMryhom4L9W59],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 7oo4x3fuwcJ5DrbFY1yf715ctjtE6CqqPagJWT8d687Q6sgMVWc1SXz],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 8BrF9XAKwzvFdy8p7KAB8VEvcswPADhs2WamhWSLUErYN9z8U8cynaA]' --recipients '37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe,37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe,37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe' --gifts '50,50,50' --fee 100
|
||||
|
||||
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)
|
||||
assert.NoError(t, err)
|
||||
fmt.Println("masterKey2", base58.Encode(masterKey2.PublicKey))
|
||||
|
||||
nc, err := wallet.NewNockchainClient("nockchain-api.zorp.io:443")
|
||||
assert.NoError(t, err)
|
||||
handler := wallet.NewGprcHandler(*nc)
|
||||
|
||||
inputs := "[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 91z5muQKgHZDcChdnCSTEtvuN8dbbXp5wzNs5xrCkce2YvSX1q6fu3d],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 3a9VWigUM1TuS79yM4dAqkiUg6WJMUPGwVKJpQUHCLJcFZsCWM2q6pF],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 9RkPvHMtuYtjV2qvB86u7zcnr26SdVcKzFnHgfhUSEG1W3FgKgLpbBm]"
|
||||
inputs := "[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 AmSjC3SDNtb7ZrUkTXc242BvGeimeL1nAV4CqV63HpLMryhom4L9W59],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 7oo4x3fuwcJ5DrbFY1yf715ctjtE6CqqPagJWT8d687Q6sgMVWc1SXz],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 8BrF9XAKwzvFdy8p7KAB8VEvcswPADhs2WamhWSLUErYN9z8U8cynaA]"
|
||||
recipients := fmt.Sprintf("%s,%s,%s", base58.Encode(masterKey2.PublicKey), base58.Encode(masterKey2.PublicKey), base58.Encode(masterKey2.PublicKey))
|
||||
gifts := "100,100,100"
|
||||
gifts := "50,50,50"
|
||||
fee := 100
|
||||
|
||||
req := &nockchain.CreateTxRequest{
|
||||
@ -462,5 +467,5 @@ func TestCreateTx(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// the result is taken from create-tx scripts
|
||||
assert.Equal(t, res.RawTx.TxId, "8gjTa6H1MrKXPWgNJCF9fsYE7PUfqhYzxetUoTftz7zyHCv24ZYHDM3")
|
||||
assert.Equal(t, res.RawTx.TxId, "A8vSeRde61B4sZccSnNPEnkQgTe15EssoFwyhQXbkhtk4UNm5hyGSid")
|
||||
}
|
||||
|
||||
185
wallet/ztree.go
185
wallet/ztree.go
@ -1,8 +1,10 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"slices"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil/base58"
|
||||
"github.com/phamminh0811/private-grpc/crypto"
|
||||
)
|
||||
|
||||
@ -20,6 +22,11 @@ type ZTree struct {
|
||||
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 {
|
||||
return &ZTree{
|
||||
Root: nil,
|
||||
@ -36,13 +43,13 @@ func (z *ZTree) Hash() ([5]uint64, error) {
|
||||
return z.Root.HashNode(z.HashValueFunc)
|
||||
}
|
||||
|
||||
func (z *ZTree) KeyLeftMost() interface{} {
|
||||
node := z.Root
|
||||
for node.Left != nil {
|
||||
node = node.Left
|
||||
}
|
||||
return node.Key
|
||||
func (t *ZTree) Tap() []ZPair {
|
||||
tap := []ZPair{}
|
||||
TapNode(t.Root, &tap)
|
||||
slices.Reverse(tap)
|
||||
return tap
|
||||
}
|
||||
|
||||
func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value interface{}) *ZNode {
|
||||
if node == nil {
|
||||
node = &ZNode{
|
||||
@ -53,42 +60,18 @@ func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value i
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
keyHash := hashFunc(key)
|
||||
keyDoubleHash := crypto.Tip5RehashTenCell(keyHash, keyHash)
|
||||
nodeKeyHash := hashFunc(node.Key)
|
||||
nodeKeyDoubleHash := crypto.Tip5RehashTenCell(nodeKeyHash, nodeKeyHash)
|
||||
|
||||
if slices.Compare(keyHash[:], nodeKeyHash[:]) == -1 {
|
||||
keyHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(keyHash)))
|
||||
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
|
||||
if slices.Compare(keyDoubleHash[:], nodeKeyDoubleHash[:]) == -1 {
|
||||
// reinsert in left
|
||||
node.Left = node.Left.InsertNode(hashFunc, key, value)
|
||||
} else {
|
||||
// new key
|
||||
// / \
|
||||
// ~ old key
|
||||
// / \
|
||||
// ... ...
|
||||
nodeKey := node.Key
|
||||
nodeValue := node.Value
|
||||
leftNode := node.Left
|
||||
rightNode := node.Right
|
||||
node = &ZNode{
|
||||
Key: key,
|
||||
Value: value,
|
||||
Right: nil,
|
||||
Left: &ZNode{
|
||||
Key: nodeKey,
|
||||
Value: nodeValue,
|
||||
Left: leftNode,
|
||||
Right: rightNode,
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// key > node key
|
||||
if slices.Compare(keyDoubleHash[:], nodeKeyDoubleHash[:]) == -1 {
|
||||
if keyDoubleHashBigInt.Cmp(nodeKeyDoubleHashBigInt) == 1 {
|
||||
// reinsert in right
|
||||
node.Right = node.Right.InsertNode(hashFunc, key, value)
|
||||
} else {
|
||||
@ -101,16 +84,104 @@ func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value i
|
||||
nodeValue := node.Value
|
||||
leftNode := node.Left
|
||||
rightNode := node.Right
|
||||
node = &ZNode{
|
||||
Key: key,
|
||||
Value: value,
|
||||
Right: &ZNode{
|
||||
Key: nodeKey,
|
||||
Value: nodeValue,
|
||||
Left: leftNode,
|
||||
Right: rightNode,
|
||||
},
|
||||
Left: nil,
|
||||
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
|
||||
node.Left = node.Left.InsertNode(hashFunc, key, value)
|
||||
} else {
|
||||
// new key
|
||||
// / \
|
||||
// ~ old key
|
||||
// / \
|
||||
// ... ...
|
||||
nodeKey := node.Key
|
||||
nodeValue := node.Value
|
||||
leftNode := node.Left
|
||||
rightNode := node.Right
|
||||
if leftNode == nil {
|
||||
node = &ZNode{
|
||||
Key: key,
|
||||
Value: value,
|
||||
Right: &ZNode{
|
||||
Key: nodeKey,
|
||||
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,
|
||||
}
|
||||
} else {
|
||||
node = &ZNode{
|
||||
Key: key,
|
||||
Value: value,
|
||||
Right: &ZNode{
|
||||
Key: nodeKey,
|
||||
Value: nodeValue,
|
||||
Left: leftNode,
|
||||
Right: rightNode,
|
||||
},
|
||||
Left: nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,3 +209,25 @@ func (node *ZNode) HashNode(hashFunc func(interface{}) ([5]uint64, error)) ([5]u
|
||||
}
|
||||
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})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user