fix: send tx with 2 notes
This commit is contained in:
parent
2816e5333b
commit
2d9185a5ec
@ -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}
|
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}
|
||||||
|
|||||||
@ -61,6 +61,24 @@ 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}})
|
||||||
@ -225,86 +243,36 @@ 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)
|
|
||||||
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)
|
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 {
|
} else {
|
||||||
seed1Hash, err := HashSeedWithoutSource(spend.Seeds[0])
|
return [5]uint64{}
|
||||||
if err != nil {
|
|
||||||
return [5]uint64{}, err
|
|
||||||
}
|
}
|
||||||
seed1HashVarLen, err := HashSeedVarLen(spend.Seeds[0])
|
},
|
||||||
if err != nil {
|
func(i interface{}) ([5]uint64, error) {
|
||||||
return [5]uint64{}, err
|
if seed, ok := i.(*nockchain.NockchainSeed); ok {
|
||||||
}
|
hash, err := HashSeedWithoutSource(seed)
|
||||||
seed1DoubleHash := crypto.Tip5RehashTenCell(seed1HashVarLen, seed1HashVarLen)
|
return hash, err
|
||||||
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 {
|
} else {
|
||||||
// seed2
|
return [5]uint64{}, fmt.Errorf("invalid input type")
|
||||||
// / \
|
}
|
||||||
// seed1 ~
|
},
|
||||||
// / \
|
)
|
||||||
// ~ ~
|
for _, seed := range spend.Seeds {
|
||||||
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
seedsTree.Insert(seed, seed)
|
||||||
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
}
|
||||||
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
finalSeedHash, err := seedsTree.Hash()
|
||||||
|
if err != nil {
|
||||||
|
return [5]uint64{}, err
|
||||||
}
|
}
|
||||||
} 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
|
||||||
@ -312,84 +280,33 @@ func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HashMsg(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
func HashMsg(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
||||||
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 := HashSeed(spend.Seeds[0])
|
seedHash, err := HashSeedVarLen(seed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return [5]uint64{}, err
|
return [5]uint64{}
|
||||||
}
|
}
|
||||||
|
return seedHash
|
||||||
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, crypto.Tip5ZeroZero)
|
|
||||||
} else {
|
} else {
|
||||||
seed1HashVarLen, err := HashSeedVarLen(spend.Seeds[0])
|
return [5]uint64{}
|
||||||
if err != nil {
|
|
||||||
return [5]uint64{}, err
|
|
||||||
}
|
}
|
||||||
seed1Hash, err := HashSeed(spend.Seeds[0])
|
},
|
||||||
if err != nil {
|
func(i interface{}) ([5]uint64, error) {
|
||||||
return [5]uint64{}, err
|
if seed, ok := i.(*nockchain.NockchainSeed); ok {
|
||||||
}
|
hash, err := HashSeed(seed)
|
||||||
seed1DoubleHash := crypto.Tip5RehashTenCell(seed1HashVarLen, seed1HashVarLen)
|
return hash, err
|
||||||
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 {
|
} else {
|
||||||
// seed2
|
return [5]uint64{}, fmt.Errorf("invalid input type")
|
||||||
// / \
|
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
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}})
|
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}})
|
||||||
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
|
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
|
||||||
@ -417,7 +334,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 HashName(name)
|
return HashNameVarLen(name)
|
||||||
} else {
|
} else {
|
||||||
return [5]uint64{}
|
return [5]uint64{}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 HashName(name)
|
return HashNameVarLen(name)
|
||||||
} else {
|
} else {
|
||||||
return [5]uint64{}
|
return [5]uint64{}
|
||||||
}
|
}
|
||||||
@ -297,16 +297,18 @@ 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)
|
||||||
}
|
}
|
||||||
nameLeftMost := nameTree.KeyLeftMost().(*nockchain.NockchainName)
|
nameList := nameTree.Tap()
|
||||||
idxLeftMost := -1
|
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 {
|
for i, name := range nnames {
|
||||||
if name.First == nameLeftMost.First && name.Last == nameLeftMost.Last {
|
if idx := slices.Index(nameKeys, name.First+" "+name.Last); idx != -1 {
|
||||||
idxLeftMost = i
|
indices[idx] = 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, "[") {
|
||||||
@ -411,40 +413,40 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs := []*nockchain.NockchainInput{}
|
inputs := make([]*nockchain.NockchainInput, len(names))
|
||||||
for i := 0; i < len(names); i++ {
|
isSpent := false
|
||||||
if notes[i] == nil {
|
for i := 0; i < len(nameKeys); i++ {
|
||||||
return nil, fmt.Errorf("notes scanned is missing at name: %s", names[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 {
|
if notes[idx].Asset < gifts[idx] {
|
||||||
return nil, fmt.Errorf("note not enough balance")
|
return nil, fmt.Errorf("note %s not enough balance", names[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
parentHash, err := HashNote(notes[i])
|
parentHash, err := HashNote(notes[idx])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
seeds := []*nockchain.NockchainSeed{
|
seeds := []*nockchain.NockchainSeed{
|
||||||
{
|
{
|
||||||
OutputSource: nil,
|
OutputSource: nil,
|
||||||
Recipient: recipents[i],
|
Recipient: recipents[idx],
|
||||||
TimelockIntent: req.TimelockIntent,
|
TimelockIntent: req.TimelockIntent,
|
||||||
Gift: gifts[i],
|
Gift: gifts[idx],
|
||||||
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if notes[i].Asset < gifts[i] {
|
|
||||||
return nil, fmt.Errorf("insufficient funds for notes %s", names[i])
|
assetLeft := notes[idx].Asset - gifts[idx]
|
||||||
}
|
fee := uint64(0)
|
||||||
assetLeft := notes[i].Asset - gifts[i]
|
if !isSpent && assetLeft >= req.Fee {
|
||||||
if i == idxLeftMost {
|
isSpent = true
|
||||||
if assetLeft > req.Fee {
|
fee = 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,
|
||||||
@ -457,19 +459,10 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
|||||||
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
var spend nockchain.NockchainSpend
|
spend := nockchain.NockchainSpend{
|
||||||
if i == idxLeftMost {
|
|
||||||
spend = nockchain.NockchainSpend{
|
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
Seeds: seeds,
|
Seeds: seeds,
|
||||||
Fee: req.Fee,
|
Fee: fee,
|
||||||
}
|
|
||||||
} else {
|
|
||||||
spend = nockchain.NockchainSpend{
|
|
||||||
Signatures: nil,
|
|
||||||
Seeds: seeds,
|
|
||||||
Fee: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, err := HashMsg(&spend)
|
msg, err := HashMsg(&spend)
|
||||||
@ -492,13 +485,16 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
|||||||
}
|
}
|
||||||
|
|
||||||
input := nockchain.NockchainInput{
|
input := nockchain.NockchainInput{
|
||||||
Name: nnames[i],
|
Name: nnames[idx],
|
||||||
Note: notes[i],
|
Note: notes[idx],
|
||||||
Spend: &spend,
|
Spend: &spend,
|
||||||
}
|
}
|
||||||
inputs = append(inputs, &input)
|
inputs[idx] = &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{
|
||||||
|
|||||||
@ -472,21 +472,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, "8gjTa6H1MrKXPWgNJCF9fsYE7PUfqhYzxetUoTftz7zyHCv24ZYHDM3")
|
assert.Equal(t, res.RawTx.TxId, "A8vSeRde61B4sZccSnNPEnkQgTe15EssoFwyhQXbkhtk4UNm5hyGSid")
|
||||||
|
|
||||||
_, err = nc.WalletSendTransaction(res.RawTx)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
txAccepted, err := nc.TxAccepted(res.RawTx.TxId)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("tx pass: ", res.RawTx.TxId)
|
|
||||||
if !txAccepted.GetAccepted() {
|
|
||||||
panic("tx not accepted")
|
|
||||||
}
|
|
||||||
// expected: A8vSeRde61B4sZccSnNPEnkQgTe15EssoFwyhQXbkhtk4UNm5hyGSid
|
|
||||||
}
|
}
|
||||||
|
|||||||
165
wallet/ztree.go
165
wallet/ztree.go
@ -1,8 +1,10 @@
|
|||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,6 +22,11 @@ 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,
|
||||||
@ -36,13 +43,13 @@ func (z *ZTree) Hash() ([5]uint64, error) {
|
|||||||
return z.Root.HashNode(z.HashValueFunc)
|
return z.Root.HashNode(z.HashValueFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *ZTree) KeyLeftMost() interface{} {
|
func (t *ZTree) Tap() []ZPair {
|
||||||
node := z.Root
|
tap := []ZPair{}
|
||||||
for node.Left != nil {
|
TapNode(t.Root, &tap)
|
||||||
node = node.Left
|
slices.Reverse(tap)
|
||||||
}
|
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{
|
||||||
@ -53,42 +60,18 @@ 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)
|
||||||
|
|
||||||
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
|
// key < node key
|
||||||
if slices.Compare(keyDoubleHash[:], nodeKeyDoubleHash[:]) == -1 {
|
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
|
|
||||||
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 {
|
|
||||||
// reinsert in right
|
// reinsert in right
|
||||||
node.Right = node.Right.InsertNode(hashFunc, key, value)
|
node.Right = node.Right.InsertNode(hashFunc, key, value)
|
||||||
} else {
|
} else {
|
||||||
@ -101,6 +84,92 @@ 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 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{
|
node = &ZNode{
|
||||||
Key: key,
|
Key: key,
|
||||||
Value: value,
|
Value: value,
|
||||||
@ -114,6 +183,8 @@ func (node *ZNode) InsertNode(hashFunc func(interface{}) [5]uint64, key, value i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,3 +209,25 @@ 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})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user