add wallet send transaction
This commit is contained in:
parent
7de884b7e4
commit
d5e89c757d
@ -113,3 +113,39 @@ func (nc *NockchainClient) TxAccepted(txId string) (*nockchain.TransactionAccept
|
||||
return nil, fmt.Errorf("invalid result type")
|
||||
}
|
||||
}
|
||||
|
||||
func (nc *NockchainClient) WalletSendTransaction(tx *nockchain.RawTx) (*nockchain.WalletSendTransactionResponse, error) {
|
||||
inputs := []*nockchain.NamedInput{}
|
||||
for _, i := range tx.Inputs {
|
||||
input, err := ConvertInput(i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting input: %v", err)
|
||||
}
|
||||
inputs = append(inputs, input)
|
||||
}
|
||||
req := nockchain.WalletSendTransactionRequest{
|
||||
TxId: ParseHash(tx.TxId),
|
||||
RawTx: &nockchain.RawTransaction{
|
||||
NamedInputs: inputs,
|
||||
TotalFees: &nockchain.Nicks{Value: tx.TotalFees},
|
||||
TimelockRange: &nockchain.TimeLockRangeAbsolute{
|
||||
Min: (*nockchain.BlockHeight)(tx.TimelockRange.Min),
|
||||
Max: (*nockchain.BlockHeight)(tx.TimelockRange.Max),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := nc.client.WalletSendTransaction(context.Background(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch resp.Result.(type) {
|
||||
case *nockchain.WalletSendTransactionResponse_Ack:
|
||||
return resp, nil
|
||||
case *nockchain.WalletSendTransactionResponse_Error:
|
||||
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid result type")
|
||||
}
|
||||
}
|
||||
|
@ -313,109 +313,6 @@ func ComputeSig(m crypto.MasterKey, msg [5]uint64) ([8]uint64, [8]uint64, error)
|
||||
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: true,
|
||||
},
|
||||
Asset: entry.Note.Assets.Value,
|
||||
}
|
||||
}
|
||||
|
||||
func ParseTimelockIntent(timelock *nockchain.TimeLockIntent) *nockchain.TimelockIntent {
|
||||
if timelock == nil {
|
||||
return nil
|
||||
}
|
||||
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 {
|
||||
ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
|
||||
ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
|
||||
|
323
wallet/types.go
Normal file
323
wallet/types.go
Normal file
@ -0,0 +1,323 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/btcutil/base58"
|
||||
"github.com/phamminh0811/private-grpc/crypto"
|
||||
"github.com/phamminh0811/private-grpc/nockchain"
|
||||
)
|
||||
|
||||
func ParseBalanceEntry(entry *nockchain.BalanceEntry) nockchain.NockchainNote {
|
||||
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: true,
|
||||
},
|
||||
Asset: entry.Note.Assets.Value,
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertRawTx(rawTx *nockchain.RawTx) nockchain.RawTransaction {
|
||||
id := crypto.Base58ToTip5Hash(rawTx.TxId)
|
||||
|
||||
var timelockRange *nockchain.TimeLockRangeAbsolute
|
||||
if rawTx.TimelockRange != nil {
|
||||
timelockRange = &nockchain.TimeLockRangeAbsolute{
|
||||
Min: (*nockchain.BlockHeight)(rawTx.TimelockRange.Min),
|
||||
Max: (*nockchain.BlockHeight)(rawTx.TimelockRange.Max),
|
||||
}
|
||||
}
|
||||
|
||||
return nockchain.RawTransaction{
|
||||
Id: &nockchain.Hash{
|
||||
Belt_1: &nockchain.Belt{Value: id[0]},
|
||||
Belt_2: &nockchain.Belt{Value: id[1]},
|
||||
Belt_3: &nockchain.Belt{Value: id[2]},
|
||||
Belt_4: &nockchain.Belt{Value: id[3]},
|
||||
Belt_5: &nockchain.Belt{Value: id[4]},
|
||||
},
|
||||
TimelockRange: timelockRange,
|
||||
TotalFees: &nockchain.Nicks{
|
||||
Value: rawTx.TotalFees,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertInput(input *nockchain.NockchainInput) (*nockchain.NamedInput, error) {
|
||||
pks := []*nockchain.SchnorrPubkey{}
|
||||
|
||||
for _, i := range input.Note.Lock.Pubkeys {
|
||||
pk, err := ParseSchnorrPubkey(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pks = append(pks, pk)
|
||||
}
|
||||
seeds := []*nockchain.Seed{}
|
||||
for _, seed := range input.Spend.Seeds {
|
||||
seedPks := []*nockchain.SchnorrPubkey{}
|
||||
|
||||
for _, i := range input.Note.Lock.Pubkeys {
|
||||
pk, err := ParseSchnorrPubkey(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pks = append(seedPks, pk)
|
||||
}
|
||||
seeds = append(seeds, &nockchain.Seed{
|
||||
OutputSource: &nockchain.OutputSource{
|
||||
Source: &nockchain.Source{
|
||||
Hash: ParseHash(seed.OutputSource.Source),
|
||||
Coinbase: input.Note.Source.IsCoinbase,
|
||||
},
|
||||
},
|
||||
Recipient: &nockchain.Lock{
|
||||
KeysRequired: uint32(seed.Recipient.KeysRequired),
|
||||
SchnorrPubkeys: seedPks,
|
||||
},
|
||||
TimelockIntent: ConvertTimelockIntent(seed.TimelockIntent),
|
||||
Gift: &nockchain.Nicks{Value: seed.Gift},
|
||||
ParentHash: ParseHash(seed.ParentHash),
|
||||
})
|
||||
}
|
||||
|
||||
sigEntries := []*nockchain.SignatureEntry{}
|
||||
for _, sig := range input.Spend.Signatures {
|
||||
pk, err := ParseSchnorrPubkey(sig.Pubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigEntries = append(sigEntries, &nockchain.SignatureEntry{
|
||||
SchnorrPubkey: pk,
|
||||
Signature: &nockchain.SchnorrSignature{
|
||||
Chal: ParseEightBelt(sig.Chal),
|
||||
Sig: ParseEightBelt(sig.Sig),
|
||||
},
|
||||
})
|
||||
}
|
||||
return &nockchain.NamedInput{
|
||||
Name: ConvertName(input.Name),
|
||||
Input: &nockchain.Input{
|
||||
Note: &nockchain.Note{
|
||||
OriginPage: &nockchain.BlockHeight{
|
||||
Value: input.Note.BlockHeight,
|
||||
},
|
||||
Timelock: ConvertTimelockIntent(input.Note.Timelock),
|
||||
Name: ConvertName(input.Name),
|
||||
Lock: &nockchain.Lock{
|
||||
KeysRequired: uint32(input.Note.Lock.KeysRequired),
|
||||
SchnorrPubkeys: pks,
|
||||
},
|
||||
Source: &nockchain.Source{
|
||||
Hash: ParseHash(input.Note.Source.Source),
|
||||
Coinbase: input.Note.Source.IsCoinbase,
|
||||
},
|
||||
Assets: &nockchain.Nicks{Value: input.Note.Asset},
|
||||
Version: &nockchain.NoteVersion{Value: uint32(input.Note.Version)},
|
||||
},
|
||||
Spend: &nockchain.Spend{
|
||||
Signature: &nockchain.Signature{
|
||||
Entries: sigEntries,
|
||||
},
|
||||
Seeds: seeds,
|
||||
MinerFeeNicks: &nockchain.Nicks{Value: input.Spend.Fee},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ConvertName(name *nockchain.NockchainName) *nockchain.Name {
|
||||
return &nockchain.Name{
|
||||
First: ParseHash(name.First),
|
||||
Last: ParseHash(name.Last),
|
||||
}
|
||||
}
|
||||
func ConvertTimelockIntent(timelock *nockchain.TimelockIntent) *nockchain.TimeLockIntent {
|
||||
if timelock == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if timelock.Absolute != nil && timelock.Relative != nil {
|
||||
return &nockchain.TimeLockIntent{
|
||||
Value: &nockchain.TimeLockIntent_AbsoluteAndRelative{
|
||||
AbsoluteAndRelative: &nockchain.TimeLockRangeAbsoluteAndRelative{
|
||||
Absolute: &nockchain.TimeLockRangeAbsolute{
|
||||
Min: (*nockchain.BlockHeight)(timelock.Absolute.Min),
|
||||
Max: (*nockchain.BlockHeight)(timelock.Absolute.Max),
|
||||
},
|
||||
Relative: &nockchain.TimeLockRangeRelative{
|
||||
Min: (*nockchain.BlockHeightDelta)(timelock.Relative.Min),
|
||||
Max: (*nockchain.BlockHeightDelta)(timelock.Relative.Max),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if timelock.Absolute != nil {
|
||||
return &nockchain.TimeLockIntent{
|
||||
Value: &nockchain.TimeLockIntent_Absolute{
|
||||
Absolute: &nockchain.TimeLockRangeAbsolute{
|
||||
Min: (*nockchain.BlockHeight)(timelock.Absolute.Min),
|
||||
Max: (*nockchain.BlockHeight)(timelock.Absolute.Max),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if timelock.Relative != nil {
|
||||
return &nockchain.TimeLockIntent{
|
||||
Value: &nockchain.TimeLockIntent_Relative{
|
||||
Relative: &nockchain.TimeLockRangeRelative{
|
||||
Min: (*nockchain.BlockHeightDelta)(timelock.Relative.Min),
|
||||
Max: (*nockchain.BlockHeightDelta)(timelock.Relative.Max),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseHash(hash string) *nockchain.Hash {
|
||||
hashTip5 := crypto.Base58ToTip5Hash(hash)
|
||||
return &nockchain.Hash{
|
||||
Belt_1: &nockchain.Belt{Value: hashTip5[0]},
|
||||
Belt_2: &nockchain.Belt{Value: hashTip5[1]},
|
||||
Belt_3: &nockchain.Belt{Value: hashTip5[2]},
|
||||
Belt_4: &nockchain.Belt{Value: hashTip5[3]},
|
||||
Belt_5: &nockchain.Belt{Value: hashTip5[4]},
|
||||
}
|
||||
}
|
||||
|
||||
func ParseEightBelt(data []uint64) *nockchain.EightBelt {
|
||||
return &nockchain.EightBelt{
|
||||
Belt_1: &nockchain.Belt{Value: data[0]},
|
||||
Belt_2: &nockchain.Belt{Value: data[1]},
|
||||
Belt_3: &nockchain.Belt{Value: data[2]},
|
||||
Belt_4: &nockchain.Belt{Value: data[3]},
|
||||
Belt_5: &nockchain.Belt{Value: data[4]},
|
||||
Belt_6: &nockchain.Belt{Value: data[5]},
|
||||
Belt_7: &nockchain.Belt{Value: data[6]},
|
||||
Belt_8: &nockchain.Belt{Value: data[7]},
|
||||
}
|
||||
}
|
||||
func ParseSchnorrPubkey(key string) (*nockchain.SchnorrPubkey, error) {
|
||||
pk, err := crypto.CheetaPointFromBytes(base58.Decode(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &nockchain.SchnorrPubkey{
|
||||
Value: &nockchain.CheetahPoint{
|
||||
X: &nockchain.SixBelt{
|
||||
Belt_1: &nockchain.Belt{Value: pk.X[0].Value},
|
||||
Belt_2: &nockchain.Belt{Value: pk.X[1].Value},
|
||||
Belt_3: &nockchain.Belt{Value: pk.X[2].Value},
|
||||
Belt_4: &nockchain.Belt{Value: pk.X[3].Value},
|
||||
Belt_5: &nockchain.Belt{Value: pk.X[4].Value},
|
||||
Belt_6: &nockchain.Belt{Value: pk.X[5].Value},
|
||||
},
|
||||
Y: &nockchain.SixBelt{
|
||||
Belt_1: &nockchain.Belt{Value: pk.Y[0].Value},
|
||||
Belt_2: &nockchain.Belt{Value: pk.Y[1].Value},
|
||||
Belt_3: &nockchain.Belt{Value: pk.Y[2].Value},
|
||||
Belt_4: &nockchain.Belt{Value: pk.Y[3].Value},
|
||||
Belt_5: &nockchain.Belt{Value: pk.Y[4].Value},
|
||||
Belt_6: &nockchain.Belt{Value: pk.Y[5].Value},
|
||||
},
|
||||
Inf: pk.Inf,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
func ParseTimelockIntent(timelock *nockchain.TimeLockIntent) *nockchain.TimelockIntent {
|
||||
if timelock == nil {
|
||||
return nil
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user