compute tx id
This commit is contained in:
parent
65ccf9157c
commit
a5ceedeb6c
@ -1,7 +1,6 @@
|
|||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil/base58"
|
"github.com/btcsuite/btcd/btcutil/base58"
|
||||||
@ -153,6 +152,23 @@ func HashSource(source *nockchain.NockchainSource) [5]uint64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HashParent(note *nockchain.NockchainNote) ([5]uint64, error) {
|
||||||
|
nameHash := HashName(note.Name)
|
||||||
|
lockHash, err := HashLock(note.Lock)
|
||||||
|
if err != nil {
|
||||||
|
return [5]uint64{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceHash := HashSource(note.Source)
|
||||||
|
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Asset)}})
|
||||||
|
|
||||||
|
hashSourceAsset := crypto.Tip5RehashTenCell(sourceHash, assetHash)
|
||||||
|
|
||||||
|
q := crypto.Tip5RehashTenCell(nameHash, crypto.Tip5RehashTenCell(lockHash, hashSourceAsset))
|
||||||
|
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
func HashSeedWithoutSource(seed *nockchain.NockchainSeed) ([5]uint64, error) {
|
func HashSeedWithoutSource(seed *nockchain.NockchainSeed) ([5]uint64, error) {
|
||||||
lockHash, err := HashLock(seed.Recipient)
|
lockHash, err := HashLock(seed.Recipient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -217,7 +233,6 @@ func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return [5]uint64{}, err
|
return [5]uint64{}, err
|
||||||
}
|
}
|
||||||
fmt.Println("")
|
|
||||||
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, finalSeedHash)
|
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, finalSeedHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,6 +242,29 @@ func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HashMsg(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
||||||
|
seedsCount := len(spend.Seeds)
|
||||||
|
finalSeedHash, err := HashSeed(spend.Seeds[seedsCount-1])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return [5]uint64{}, err
|
||||||
|
}
|
||||||
|
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5ZeroZero)
|
||||||
|
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
||||||
|
|
||||||
|
if seedsCount != 1 {
|
||||||
|
for i := 1; i < seedsCount; i++ {
|
||||||
|
seedHash, err := HashSeed(spend.Seeds[seedsCount-1-i])
|
||||||
|
if err != nil {
|
||||||
|
return [5]uint64{}, err
|
||||||
|
}
|
||||||
|
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, finalSeedHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}})
|
||||||
|
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
|
||||||
|
}
|
||||||
|
|
||||||
func HashInput(input *nockchain.NockchainInput) ([5]uint64, error) {
|
func HashInput(input *nockchain.NockchainInput) ([5]uint64, error) {
|
||||||
nameHash := HashName(input.Name)
|
nameHash := HashName(input.Name)
|
||||||
|
|
||||||
@ -287,6 +325,106 @@ func ComputeSig(m crypto.MasterKey, msg [5]uint64) ([8]uint64, [8]uint64, error)
|
|||||||
return chalT8, sigT8, nil
|
return chalT8, sigT8, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
|
||||||
|
version := nockchain.Version(entry.Note.Version.Value)
|
||||||
|
pubkeys := []string{}
|
||||||
|
for _, pk := range entry.Note.Lock.SchnorrPubkeys {
|
||||||
|
pkPoint := crypto.CheetahPoint{
|
||||||
|
X: [6]crypto.Belt{
|
||||||
|
{Value: pk.Value.X.Belt_1.Value},
|
||||||
|
{Value: pk.Value.X.Belt_2.Value},
|
||||||
|
{Value: pk.Value.X.Belt_3.Value},
|
||||||
|
{Value: pk.Value.X.Belt_4.Value},
|
||||||
|
{Value: pk.Value.X.Belt_5.Value},
|
||||||
|
{Value: pk.Value.X.Belt_6.Value},
|
||||||
|
},
|
||||||
|
Y: [6]crypto.Belt{
|
||||||
|
{Value: pk.Value.Y.Belt_1.Value},
|
||||||
|
{Value: pk.Value.Y.Belt_2.Value},
|
||||||
|
{Value: pk.Value.Y.Belt_3.Value},
|
||||||
|
{Value: pk.Value.Y.Belt_4.Value},
|
||||||
|
{Value: pk.Value.Y.Belt_5.Value},
|
||||||
|
{Value: pk.Value.Y.Belt_6.Value},
|
||||||
|
},
|
||||||
|
Inf: pk.Value.Inf,
|
||||||
|
}
|
||||||
|
|
||||||
|
pkStr := base58.Encode(pkPoint.Bytes())
|
||||||
|
pubkeys = append(pubkeys, pkStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceHash := [5]uint64{
|
||||||
|
entry.Note.Source.Hash.Belt_1.Value,
|
||||||
|
entry.Note.Source.Hash.Belt_2.Value,
|
||||||
|
entry.Note.Source.Hash.Belt_3.Value,
|
||||||
|
entry.Note.Source.Hash.Belt_4.Value,
|
||||||
|
entry.Note.Source.Hash.Belt_5.Value,
|
||||||
|
}
|
||||||
|
return nockchain.NockchainNote{
|
||||||
|
Version: version,
|
||||||
|
BlockHeight: entry.Note.OriginPage.Value,
|
||||||
|
Timelock: ParseTimelockIntent(entry.Note.Timelock),
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Lock: &nockchain.NockchainLock{
|
||||||
|
KeysRequired: uint64(entry.Note.Lock.KeysRequired),
|
||||||
|
Pubkeys: pubkeys,
|
||||||
|
},
|
||||||
|
Source: &nockchain.NockchainSource{
|
||||||
|
Source: crypto.Tip5HashToBase58(sourceHash),
|
||||||
|
IsCoinbase: entry.Note.Source.Coinbase,
|
||||||
|
},
|
||||||
|
Asset: entry.Note.Assets.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseTimelockIntent(timelock *nockchain.TimeLockIntent) *nockchain.TimelockIntent {
|
||||||
|
switch timelock.Value.(type) {
|
||||||
|
case *nockchain.TimeLockIntent_Absolute:
|
||||||
|
return &nockchain.TimelockIntent{
|
||||||
|
Absolute: &nockchain.TimelockRange{
|
||||||
|
Min: (*nockchain.Timelock)(timelock.GetAbsolute().Min),
|
||||||
|
Max: (*nockchain.Timelock)(timelock.GetAbsolute().Max),
|
||||||
|
},
|
||||||
|
Relative: nil,
|
||||||
|
}
|
||||||
|
case *nockchain.TimeLockIntent_Relative:
|
||||||
|
return &nockchain.TimelockIntent{
|
||||||
|
Absolute: nil,
|
||||||
|
Relative: &nockchain.TimelockRange{
|
||||||
|
Min: (*nockchain.Timelock)(timelock.GetRelative().Min),
|
||||||
|
Max: (*nockchain.Timelock)(timelock.GetRelative().Max),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case *nockchain.TimeLockIntent_AbsoluteAndRelative:
|
||||||
|
return &nockchain.TimelockIntent{
|
||||||
|
Absolute: &nockchain.TimelockRange{
|
||||||
|
Min: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Absolute.Min),
|
||||||
|
Max: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Absolute.Max),
|
||||||
|
},
|
||||||
|
Relative: &nockchain.TimelockRange{
|
||||||
|
Min: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Relative.Min),
|
||||||
|
Max: (*nockchain.Timelock)(timelock.GetAbsoluteAndRelative().Relative.Max),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
func first(ownerHash [5]uint64) [5]uint64 {
|
func first(ownerHash [5]uint64) [5]uint64 {
|
||||||
ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
|
ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
|
||||||
ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
|
ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
|
||||||
|
@ -263,7 +263,9 @@ func (h *GprcHandler) DeriveChild(ctx context.Context, req *nockchain.DeriveChil
|
|||||||
func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxRequest) (*nockchain.CreateTxResponse, error) {
|
func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxRequest) (*nockchain.CreateTxResponse, error) {
|
||||||
firstNames := [][5]uint64{}
|
firstNames := [][5]uint64{}
|
||||||
lastNames := [][5]uint64{}
|
lastNames := [][5]uint64{}
|
||||||
for _, name := range strings.Split(req.Names, ",") {
|
names := strings.Split(req.Names, ",")
|
||||||
|
notes := make([]*nockchain.NockchainNote, len(names))
|
||||||
|
for _, name := range names {
|
||||||
name = strings.TrimSpace(name)
|
name = strings.TrimSpace(name)
|
||||||
if strings.HasPrefix(name, "[") && strings.HasSuffix(name, "]") {
|
if strings.HasPrefix(name, "[") && strings.HasSuffix(name, "]") {
|
||||||
inner := name[1 : len(name)-1]
|
inner := name[1 : len(name)-1]
|
||||||
@ -275,11 +277,7 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Recipent struct {
|
recipents := []*nockchain.NockchainLock{}
|
||||||
index uint64
|
|
||||||
pubkeys [][]byte
|
|
||||||
}
|
|
||||||
recipents := []Recipent{}
|
|
||||||
if strings.Contains(req.Recipients, "[") {
|
if strings.Contains(req.Recipients, "[") {
|
||||||
pairs := strings.Split(req.Recipients, ",")
|
pairs := strings.Split(req.Recipients, ",")
|
||||||
for _, pair := range pairs {
|
for _, pair := range pairs {
|
||||||
@ -295,13 +293,9 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkeyStrs := strings.Split(parts[1], ",")
|
pubkeysStr := strings.Split(parts[1], ",")
|
||||||
var pubkeys [][]byte
|
|
||||||
for _, s := range pubkeyStrs {
|
|
||||||
pubkeys = append(pubkeys, base58.Decode(strings.TrimSpace(s)))
|
|
||||||
}
|
|
||||||
|
|
||||||
recipents = append(recipents, Recipent{index: number, pubkeys: pubkeys})
|
recipents = append(recipents, &nockchain.NockchainLock{KeysRequired: number, Pubkeys: pubkeysStr})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +304,7 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
|||||||
addrs := strings.Split(req.Recipients, ",")
|
addrs := strings.Split(req.Recipients, ",")
|
||||||
|
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
recipents = append(recipents, Recipent{index: uint64(1), pubkeys: [][]byte{base58.Decode(strings.TrimSpace(addr))}})
|
recipents = append(recipents, &nockchain.NockchainLock{KeysRequired: uint64(1), Pubkeys: []string{strings.TrimSpace(addr)}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gifts := []uint64{}
|
gifts := []uint64{}
|
||||||
@ -372,9 +366,130 @@ func (h *GprcHandler) CreateTx(ctx context.Context, req *nockchain.CreateTxReque
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(masterKeyScan.Notes) != 0 {
|
if len(masterKeyScan.Notes) != 0 {
|
||||||
// TODO: check notes by first and last name
|
for _, note := range masterKeyScan.Notes {
|
||||||
|
firstName := crypto.Tip5HashToBase58([5]uint64{
|
||||||
|
note.Name.First.Belt_1.Value,
|
||||||
|
note.Name.First.Belt_2.Value,
|
||||||
|
note.Name.First.Belt_3.Value,
|
||||||
|
note.Name.First.Belt_4.Value,
|
||||||
|
note.Name.First.Belt_5.Value,
|
||||||
|
})
|
||||||
|
lastName := crypto.Tip5HashToBase58([5]uint64{
|
||||||
|
note.Name.Last.Belt_1.Value,
|
||||||
|
note.Name.Last.Belt_2.Value,
|
||||||
|
note.Name.Last.Belt_3.Value,
|
||||||
|
note.Name.Last.Belt_4.Value,
|
||||||
|
note.Name.Last.Belt_5.Value,
|
||||||
|
})
|
||||||
|
name := "[" + firstName + " " + lastName + "]"
|
||||||
|
if i := slices.Index(names, name); i != -1 {
|
||||||
|
balanceEntry := ParseBalanceEntry(note)
|
||||||
|
notes[i] = &balanceEntry
|
||||||
}
|
}
|
||||||
return nil, nil
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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])
|
||||||
|
}
|
||||||
|
|
||||||
|
if notes[i].Asset < gifts[i]+req.Fee {
|
||||||
|
return nil, fmt.Errorf("note not enough balance")
|
||||||
|
}
|
||||||
|
|
||||||
|
parentHash, err := HashParent(notes[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
seeds := []*nockchain.NockchainSeed{
|
||||||
|
{
|
||||||
|
OutputSource: nil,
|
||||||
|
Recipient: recipents[i],
|
||||||
|
TimelockIntent: req.TimelockIntent,
|
||||||
|
Gift: gifts[i],
|
||||||
|
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if notes[i].Asset < gifts[i]+req.Fee {
|
||||||
|
seeds = append(seeds, &nockchain.NockchainSeed{
|
||||||
|
OutputSource: nil,
|
||||||
|
Recipient: &nockchain.NockchainLock{
|
||||||
|
KeysRequired: 1,
|
||||||
|
Pubkeys: []string{base58.Encode(masterKey.PublicKey)},
|
||||||
|
},
|
||||||
|
TimelockIntent: req.TimelockIntent,
|
||||||
|
Gift: notes[i].Asset - gifts[i] - req.Fee,
|
||||||
|
ParentHash: crypto.Tip5HashToBase58(parentHash),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
spend := nockchain.NockchainSpend{
|
||||||
|
Signatures: nil,
|
||||||
|
Seeds: seeds,
|
||||||
|
Fee: req.Fee,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := HashMsg(&spend)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(masterKey.PrivateKey) != 0 {
|
||||||
|
// sign
|
||||||
|
chalT8, sigT8, err := ComputeSig(*masterKey, msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
spend.Signatures = []*nockchain.NockchainSignature{
|
||||||
|
{
|
||||||
|
Pubkey: base58.Encode(masterKey.PublicKey),
|
||||||
|
Chal: chalT8[:],
|
||||||
|
Sig: sigT8[:],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input := nockchain.NockchainInput{
|
||||||
|
Name: &nockchain.NockchainName{
|
||||||
|
First: crypto.Tip5HashToBase58(firstNames[i]),
|
||||||
|
Last: crypto.Tip5HashToBase58(lastNames[i]),
|
||||||
|
},
|
||||||
|
Note: notes[i],
|
||||||
|
Spend: &spend,
|
||||||
|
}
|
||||||
|
inputs = append(inputs, &input)
|
||||||
|
}
|
||||||
|
|
||||||
|
var timelockRange *nockchain.TimelockRange
|
||||||
|
if req.TimelockIntent == nil {
|
||||||
|
timelockRange = nil
|
||||||
|
} else {
|
||||||
|
if req.TimelockIntent.Absolute != nil {
|
||||||
|
timelockRange = req.TimelockIntent.Absolute
|
||||||
|
}
|
||||||
|
if req.TimelockIntent.Relative != nil {
|
||||||
|
timelockRange = req.TimelockIntent.Relative
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rawTx := nockchain.RawTx{
|
||||||
|
TxId: "",
|
||||||
|
Inputs: inputs,
|
||||||
|
TimelockRange: timelockRange,
|
||||||
|
TotalFees: req.Fee,
|
||||||
|
}
|
||||||
|
txId, err := ComputeTxId(inputs, timelockRange, req.Fee)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rawTx.TxId = crypto.Tip5HashToBase58(txId)
|
||||||
|
return &nockchain.CreateTxResponse{
|
||||||
|
RawTx: &rawTx,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *GprcHandler) Scan(ctx context.Context, req *nockchain.ScanRequest) (*nockchain.ScanResponse, error) {
|
func (h *GprcHandler) Scan(ctx context.Context, req *nockchain.ScanRequest) (*nockchain.ScanResponse, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user