Compare commits

..

2 Commits

Author SHA1 Message Date
Chung Hoang Tuan Kiet (Lucky)
262f7d3bc0 feat: test submit tx 2025-10-20 09:35:25 +07:00
Chung Hoang Tuan Kiet (Lucky)
f91d39b943 feat: test submit tx 2025-10-16 16:15:48 +07:00
3 changed files with 108 additions and 100 deletions

View File

@ -13,8 +13,8 @@ import (
var ( var (
DomainSeparator = []byte("Nockchain seed") DomainSeparator = []byte("Nockchain seed")
PrivateKeyStart = []byte{1, 16, 99, 49} PrivateKeyStart = []byte{4, 178, 67, 11}
PublicKeyStart = []byte{12, 14, 187, 9} PublicKeyStart = []byte{234, 230, 92}
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}
@ -29,13 +29,6 @@ type MasterKey struct {
ChainCode []byte ChainCode []byte
} }
type KeyType int32
const (
KeyType_PRIVATE KeyType = 0
KeyType_PUBLIC KeyType = 1
)
func (m *MasterKey) DeriveChild(index uint64) (MasterKey, error) { func (m *MasterKey) DeriveChild(index uint64) (MasterKey, error) {
idxBytes := make([]byte, 4) idxBytes := make([]byte, 4)
binary.BigEndian.PutUint32(idxBytes, uint32(index)) binary.BigEndian.PutUint32(idxBytes, uint32(index))
@ -191,29 +184,18 @@ func BigIntToT8(data big.Int) [8]uint64 {
res := rip(data) res := rip(data)
return [8]uint64(res) return [8]uint64(res)
} }
func SerializeExtend(chainCode []byte, key []byte, keyType KeyType) []byte { func SerializeExtend(chainCode []byte, key []byte, version []byte) []byte {
data := []byte{} data := version
// dep: depth in chain // dep: depth in chain
// idx: index at depth // idx: index at depth
// pf: parent fingerprint // pf: parent fingerprint
// ver: version
ver := 0
depth := 0 depth := 0
idx := []byte{0, 0, 0, 0} idx := []byte{0, 0, 0, 0}
pf := []byte{0, 0, 0, 0} pf := []byte{0, 0, 0, 0}
var typ []byte data = append(data, byte(depth%256))
switch keyType { data = append(data, pf...)
case KeyType_PRIVATE: data = append(data, idx...)
typ = PrivateKeyStart data = append(data, chainCode...)
case KeyType_PUBLIC:
typ = PublicKeyStart
}
data = append(data, typ...) // 4 bytes
data = append(data, byte(ver)) // 1 byte
data = append(data, byte(depth%256)) // 1 byte
data = append(data, pf...) // 4 bytes
data = append(data, idx...) // 4 bytes
data = append(data, chainCode...) // 32 bytes
data = append(data, key...) data = append(data, key...)
return AddChecksum(data) return AddChecksum(data)
} }

View File

@ -54,8 +54,8 @@ func (h *GprcHandler) Keygen(ctx context.Context, req *nockchain.KeygenRequest)
PrivateKey: base58.Encode(masterKey.PrivateKey), PrivateKey: base58.Encode(masterKey.PrivateKey),
PublicKey: base58.Encode(masterKey.PublicKey), PublicKey: base58.Encode(masterKey.PublicKey),
ChainCode: base58.Encode(masterKey.ChainCode), ChainCode: base58.Encode(masterKey.ChainCode),
ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.KeyType_PRIVATE)), ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.PrivateKeyStart)),
ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.KeyType_PUBLIC)), ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.PublicKeyStart)),
}, nil }, nil
} }
@ -68,21 +68,21 @@ func (h *GprcHandler) ImportKeys(ctx context.Context, req *nockchain.ImportKeysR
data := base58.Decode(req.Key) data := base58.Decode(req.Key)
switch { switch {
case strings.HasPrefix(req.Key, "zprv"): case strings.HasPrefix(req.Key, "zprv"):
if len(data) != 83 { if len(data) != 82 {
return nil, fmt.Errorf("invalid extended private key length: %d (expected 83)", len(data)) return nil, fmt.Errorf("invalid extended private key length: %d (expected 82)", len(data))
} }
if data[46] != 0x00 { if data[45] != 0x00 {
return nil, fmt.Errorf("invalid private key prefix at byte 46: 0x%02x (expected 0x00)", data[46]) return nil, fmt.Errorf("invalid private key prefix at byte 45: 0x%02x (expected 0x00)", data[45])
} }
hash := sha256.Sum256(data[:79]) hash := sha256.Sum256(data[:78])
hash = sha256.Sum256(hash[:]) hash = sha256.Sum256(hash[:])
if !slices.Equal(hash[:4], data[79:]) { if !slices.Equal(hash[:4], data[78:]) {
return nil, fmt.Errorf("invalid checksum") return nil, fmt.Errorf("invalid checksum")
} }
chainCode := make([]byte, 32) chainCode := make([]byte, 32)
copy(chainCode, data[14:46]) copy(chainCode, data[13:45])
privateKey := make([]byte, 32) privateKey := make([]byte, 32)
copy(privateKey, data[47:79]) copy(privateKey, data[46:78])
masterKey, err := crypto.MasterKeyFromPrivKey(chainCode, privateKey) masterKey, err := crypto.MasterKeyFromPrivKey(chainCode, privateKey)
if err != nil { if err != nil {
return nil, err return nil, err
@ -93,31 +93,31 @@ func (h *GprcHandler) ImportKeys(ctx context.Context, req *nockchain.ImportKeysR
PrivateKey: base58.Encode(masterKey.PrivateKey), PrivateKey: base58.Encode(masterKey.PrivateKey),
PublicKey: base58.Encode(masterKey.PublicKey), PublicKey: base58.Encode(masterKey.PublicKey),
ChainCode: base58.Encode(masterKey.ChainCode), ChainCode: base58.Encode(masterKey.ChainCode),
ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.KeyType_PRIVATE)), ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.PrivateKeyStart)),
ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.KeyType_PUBLIC)), ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.PublicKeyStart)),
}, nil }, nil
case strings.HasPrefix(req.Key, "zpub"): case strings.HasPrefix(req.Key, "zpub"):
if len(data) != 147 { if len(data) != 145 {
return nil, fmt.Errorf("invalid extended public key length: %d (expected 147)", len(data)) return nil, fmt.Errorf("invalid extended public key length: %d (expected 145)", len(data))
} }
hash := sha256.Sum256(data[:143]) hash := sha256.Sum256(data[:141])
hash = sha256.Sum256(hash[:]) hash = sha256.Sum256(hash[:])
if !slices.Equal(hash[:4], data[143:]) { if !slices.Equal(hash[:4], data[141:]) {
return nil, fmt.Errorf("invalid checksum") return nil, fmt.Errorf("invalid checksum")
} }
chainCode := make([]byte, 32) chainCode := make([]byte, 32)
copy(chainCode, data[14:46]) copy(chainCode, data[12:44])
publicKey := make([]byte, 97) publicKey := make([]byte, 97)
copy(publicKey, data[46:143]) copy(publicKey, data[44:141])
return &nockchain.ImportKeysResponse{ return &nockchain.ImportKeysResponse{
Seed: "", Seed: "",
PrivateKey: "", PrivateKey: "",
PublicKey: base58.Encode(publicKey), PublicKey: base58.Encode(publicKey),
ChainCode: base58.Encode(chainCode), ChainCode: base58.Encode(chainCode),
ImportPrivateKey: "", ImportPrivateKey: "",
ImportPublicKey: base58.Encode(crypto.SerializeExtend(chainCode, publicKey, crypto.KeyType_PUBLIC)), ImportPublicKey: base58.Encode(crypto.SerializeExtend(chainCode, publicKey, crypto.PublicKeyStart)),
}, nil }, nil
default: default:
return nil, fmt.Errorf("invalid extended key") return nil, fmt.Errorf("invalid extended key")
@ -145,8 +145,8 @@ func (h *GprcHandler) ImportKeys(ctx context.Context, req *nockchain.ImportKeysR
PrivateKey: base58.Encode(masterKey.PrivateKey), PrivateKey: base58.Encode(masterKey.PrivateKey),
PublicKey: base58.Encode(masterKey.PublicKey), PublicKey: base58.Encode(masterKey.PublicKey),
ChainCode: base58.Encode(masterKey.ChainCode), ChainCode: base58.Encode(masterKey.ChainCode),
ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.KeyType_PRIVATE)), ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.PrivateKeyStart)),
ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.KeyType_PUBLIC)), ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.PublicKeyStart)),
}, nil }, nil
case nockchain.ImportType_SEEDPHRASE: case nockchain.ImportType_SEEDPHRASE:
masterKey, err := crypto.MasterKeyFromSeed(req.Key) masterKey, err := crypto.MasterKeyFromSeed(req.Key)
@ -159,8 +159,8 @@ func (h *GprcHandler) ImportKeys(ctx context.Context, req *nockchain.ImportKeysR
PrivateKey: base58.Encode(masterKey.PrivateKey), PrivateKey: base58.Encode(masterKey.PrivateKey),
PublicKey: base58.Encode(masterKey.PublicKey), PublicKey: base58.Encode(masterKey.PublicKey),
ChainCode: base58.Encode(masterKey.ChainCode), ChainCode: base58.Encode(masterKey.ChainCode),
ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.KeyType_PRIVATE)), ImportPrivateKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.PrivateKeyStart)),
ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.KeyType_PUBLIC)), ImportPublicKey: base58.Encode(crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.PublicKeyStart)),
}, nil }, nil
case nockchain.ImportType_WATCH_ONLY: case nockchain.ImportType_WATCH_ONLY:
pubKey := base58.Decode(req.Key) pubKey := base58.Decode(req.Key)
@ -188,21 +188,21 @@ func (h *GprcHandler) DeriveChild(ctx context.Context, req *nockchain.DeriveChil
} }
switch { switch {
case strings.HasPrefix(req.ImportedKey, "zprv"): case strings.HasPrefix(req.ImportedKey, "zprv"):
if len(data) != 83 { if len(data) != 82 {
return nil, fmt.Errorf("invalid extended private key length: %d (expected 83)", len(data)) return nil, fmt.Errorf("invalid extended private key length: %d (expected 82)", len(data))
} }
if data[46] != 0x00 { if data[45] != 0x00 {
return nil, fmt.Errorf("invalid private key prefix at byte 46: 0x%02x (expected 0x00)", data[46]) return nil, fmt.Errorf("invalid private key prefix at byte 45: 0x%02x (expected 0x00)", data[45])
} }
hash := sha256.Sum256(data[:79]) hash := sha256.Sum256(data[:78])
hash = sha256.Sum256(hash[:]) hash = sha256.Sum256(hash[:])
if !slices.Equal(hash[:4], data[79:]) { if !slices.Equal(hash[:4], data[78:]) {
return nil, fmt.Errorf("invalid checksum") return nil, fmt.Errorf("invalid checksum")
} }
chainCode := make([]byte, 32) chainCode := make([]byte, 32)
copy(chainCode, data[14:46]) copy(chainCode, data[13:45])
privateKey := make([]byte, 32) privateKey := make([]byte, 32)
copy(privateKey, data[47:79]) copy(privateKey, data[46:78])
masterKey, err := crypto.MasterKeyFromPrivKey(chainCode, privateKey) masterKey, err := crypto.MasterKeyFromPrivKey(chainCode, privateKey)
if err != nil { if err != nil {
return nil, err return nil, err
@ -219,20 +219,20 @@ func (h *GprcHandler) DeriveChild(ctx context.Context, req *nockchain.DeriveChil
}, nil }, nil
case strings.HasPrefix(req.ImportedKey, "zpub"): case strings.HasPrefix(req.ImportedKey, "zpub"):
if len(data) != 147 { if len(data) != 145 {
return nil, fmt.Errorf("invalid extended public key length: %d (expected 145)", len(data)) return nil, fmt.Errorf("invalid extended public key length: %d (expected 145)", len(data))
} }
hash := sha256.Sum256(data[:143]) hash := sha256.Sum256(data[:141])
hash = sha256.Sum256(hash[:]) hash = sha256.Sum256(hash[:])
if !slices.Equal(hash[:4], data[143:]) { if !slices.Equal(hash[:4], data[141:]) {
return nil, fmt.Errorf("invalid checksum") return nil, fmt.Errorf("invalid checksum")
} }
chainCode := make([]byte, 32) chainCode := make([]byte, 32)
copy(chainCode, data[14:46]) copy(chainCode, data[13:45])
publicKey := make([]byte, 97) publicKey := make([]byte, 97)
copy(publicKey, data[46:143]) copy(publicKey, data[45:141])
masterKey := crypto.MasterKey{ masterKey := crypto.MasterKey{
PublicKey: publicKey, PublicKey: publicKey,

View File

@ -17,13 +17,13 @@ import (
// The entropy, salt and result is taken from "nockchain-wallet keygen" command // The entropy, salt and result is taken from "nockchain-wallet keygen" command
func TestKeyGen(t *testing.T) { func TestKeyGen(t *testing.T) {
entropyBigInt, isOk := new(big.Int).SetString("37133536588676344913489312523941366110857274548479981512263368615793750653450", 10) entropyBigInt, isOk := new(big.Int).SetString("29615235796517918707367078072007441124337225858809749976291970867443501879006", 10)
assert.True(t, isOk) assert.True(t, isOk)
entropy := entropyBigInt.Bytes() entropy := entropyBigInt.Bytes()
assert.Len(t, entropy, 32) assert.Len(t, entropy, 32)
saltBigInt, isOk := new(big.Int).SetString("251632902249061493058993135304695174381", 10) saltBigInt, isOk := new(big.Int).SetString("212311808188922973323281316240858086116", 10)
assert.True(t, isOk) assert.True(t, isOk)
salt := saltBigInt.Bytes() salt := saltBigInt.Bytes()
@ -33,38 +33,38 @@ func TestKeyGen(t *testing.T) {
slices.Reverse(argonBytes) slices.Reverse(argonBytes)
mnemonic, err := bip39.NewMnemonic(argonBytes) mnemonic, err := bip39.NewMnemonic(argonBytes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, mnemonic, "include lounge salad chicken trumpet embrace grace mercy pulp submit alter weapon plastic welcome funny female palm satoshi open file knock sun fade match") assert.Equal(t, mnemonic, "brass vacuum stairs hurt brisk govern describe enforce fly exact rescue capable belt flavor lottery sauce easy frame orange legal injury border obey novel")
masterKey, err := crypto.MasterKeyFromSeed(mnemonic) masterKey, err := crypto.MasterKeyFromSeed(mnemonic)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, assert.Equal(t,
base58.Encode(masterKey.PublicKey), base58.Encode(masterKey.PublicKey),
"34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6", "39DL6YA1kSRCKMjzpFEtC8rmnxVuseUrP2LnViwY7YEhZYZkX2HmnAZ63Uwy1DwuXstmF1VeJDucg719xw49j9CKL3bsKq3A6SZN918CowcgQroHsgohj7dYgpGRWk41s42F",
) )
assert.Equal(t, assert.Equal(t,
base58.Encode(masterKey.PrivateKey), base58.Encode(masterKey.PrivateKey),
"3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg", "4SyUrsbGKPRknzvGakWmFbYefzHzb1r4LUmJpQD8WPcR",
) )
assert.Equal(t, assert.Equal(t,
base58.Encode(masterKey.ChainCode), base58.Encode(masterKey.ChainCode),
"2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8", "58SARPmADHvUcpq7XfBoCgwzy5QC8Kb3JrezpHqA85x2",
) )
// assert import priv/pubkey // assert import priv/pubkey
privBytes := append([]byte{0x00}, masterKey.PrivateKey...) privBytes := append([]byte{0x00}, masterKey.PrivateKey...)
importPrivKey := crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.KeyType_PRIVATE) importPrivKey := crypto.SerializeExtend(masterKey.ChainCode, privBytes, crypto.PrivateKeyStart)
assert.Len(t, importPrivKey, 83) assert.Len(t, importPrivKey, 82)
importPubKey := crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.KeyType_PUBLIC) importPubKey := crypto.SerializeExtend(masterKey.ChainCode, masterKey.PublicKey, crypto.PublicKeyStart)
assert.Len(t, importPubKey, 147) assert.Len(t, importPubKey, 145)
assert.Equal(t, assert.Equal(t,
base58.Encode(importPrivKey), base58.Encode(importPrivKey),
"zprvLpf3WSvYWmHRd3jj5oR8UXr7bi88pGnfJXj1dM9RnwJwu1MLo6fZzcKauqpxL2W7dk2fmjYKAUzavbyaGpnvqY5QndcrUzsBrPQAHXNnhiXx", "zprv2CyrSHEkzQzu4HCtJRFiP4t2rVMauZwLfJDFrNbqS8Pz3nsmXy5bAUx2HYUykaMuU4MiQTHsDcKYjLCjrPfpceNT9XBHgx1pUjKzBrF6Wdo",
) )
assert.Equal(t, assert.Equal(t,
base58.Encode(importPubKey), base58.Encode(importPubKey),
"zpub2jgndknkQprVYB4X4mqREyn7ZTUE5zp9qkSugdpiqhC5NSeNBceafoz6jGSLEpzJhaLryvY8MF6TokwZN627UXhsg5zd2U12woEL82UtZaLHRL8PZi8YiQnE41BiNJwkfpWjzAbq8mwbAHV3nXUEFgJW2BKCz4GmfoMCkCUDhJppYh5KFsMUkN41DzsfFZHuFrzo", "zpubUQwNTNE3hsCkMpBnD37W5QirkyVryokAVPLnPin1c6M13RRsq3yEJbwp5ies6qXF6DvJq5Woxw6ygT53PSVrmrsQgtHhbfMEixKNFm7qb4mELhpyoovpFEV1YPHFZx4xQGYBNF6qvXU6AHNh4TLrUdkYAdXKS2J5rPiSVPrXKGo8fLG6ZBCGBjJfPcwDb2VEJC",
) )
} }
@ -76,32 +76,32 @@ func TestImportKey(t *testing.T) {
errStr string errStr string
} }
correctImportPrivKey := base58.Decode("zprvLpf3WSvYWmHRd3jj5oR8UXr7bi88pGnfJXj1dM9RnwJwu1MLo6fZzcKauqpxL2W7dk2fmjYKAUzavbyaGpnvqY5QndcrUzsBrPQAHXNnhiXx") correctImportPrivKey := base58.Decode("zprv2CyrSHEkzQzu4HCtJRFiP4t2rVMauZwLfJDFrNbqS8Pz3nsmXy5bAUx2HYUykaMuU4MiQTHsDcKYjLCjrPfpceNT9XBHgx1pUjKzBrF6Wdo")
invalidImportPrivKeyPrefix := make([]byte, 83) invalidImportPrivKeyPrefix := make([]byte, 82)
copy(invalidImportPrivKeyPrefix[:], correctImportPrivKey) copy(invalidImportPrivKeyPrefix[:], correctImportPrivKey)
invalidImportPrivKeyPrefix[46] = 0x01 invalidImportPrivKeyPrefix[45] = 0x01
invalidImportPrivKeyChecksum := make([]byte, 83) invalidImportPrivKeyChecksum := make([]byte, 82)
copy(invalidImportPrivKeyChecksum[:], correctImportPrivKey) copy(invalidImportPrivKeyChecksum[:], correctImportPrivKey)
copy(invalidImportPrivKeyChecksum[79:], []byte{1, 2, 3, 4}) copy(invalidImportPrivKeyChecksum[78:], []byte{1, 2, 3, 4})
correctImportPubkey := base58.Decode("zpub2jgndknkQprVYB4X4mqREyn7ZTUE5zp9qkSugdpiqhC5NSeNBceafoz6jGSLEpzJhaLryvY8MF6TokwZN627UXhsg5zd2U12woEL82UtZaLHRL8PZi8YiQnE41BiNJwkfpWjzAbq8mwbAHV3nXUEFgJW2BKCz4GmfoMCkCUDhJppYh5KFsMUkN41DzsfFZHuFrzo") correctImportPubkey := base58.Decode("zpubUQwNTNE3hsCkMpBnD37W5QirkyVryokAVPLnPin1c6M13RRsq3yEJbwp5ies6qXF6DvJq5Woxw6ygT53PSVrmrsQgtHhbfMEixKNFm7qb4mELhpyoovpFEV1YPHFZx4xQGYBNF6qvXU6AHNh4TLrUdkYAdXKS2J5rPiSVPrXKGo8fLG6ZBCGBjJfPcwDb2VEJC")
invalidImportPubkeyChecksum := make([]byte, 147) invalidImportPubkeyChecksum := make([]byte, 145)
copy(invalidImportPubkeyChecksum[:], correctImportPubkey) copy(invalidImportPubkeyChecksum[:], correctImportPubkey)
copy(invalidImportPubkeyChecksum[143:], []byte{1, 2, 3, 4}) copy(invalidImportPubkeyChecksum[141:], []byte{1, 2, 3, 4})
response := &nockchain.ImportKeysResponse{ response := &nockchain.ImportKeysResponse{
PublicKey: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6", PublicKey: "39DL6YA1kSRCKMjzpFEtC8rmnxVuseUrP2LnViwY7YEhZYZkX2HmnAZ63Uwy1DwuXstmF1VeJDucg719xw49j9CKL3bsKq3A6SZN918CowcgQroHsgohj7dYgpGRWk41s42F",
PrivateKey: "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg", PrivateKey: "4SyUrsbGKPRknzvGakWmFbYefzHzb1r4LUmJpQD8WPcR",
ChainCode: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8", ChainCode: "58SARPmADHvUcpq7XfBoCgwzy5QC8Kb3JrezpHqA85x2",
ImportPrivateKey: base58.Encode(correctImportPrivKey), ImportPrivateKey: base58.Encode(correctImportPrivKey),
ImportPublicKey: base58.Encode(correctImportPubkey), ImportPublicKey: base58.Encode(correctImportPubkey),
} }
responseReadOnly := &nockchain.ImportKeysResponse{ responseReadOnly := &nockchain.ImportKeysResponse{
PublicKey: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6", PublicKey: "39DL6YA1kSRCKMjzpFEtC8rmnxVuseUrP2LnViwY7YEhZYZkX2HmnAZ63Uwy1DwuXstmF1VeJDucg719xw49j9CKL3bsKq3A6SZN918CowcgQroHsgohj7dYgpGRWk41s42F",
PrivateKey: "", PrivateKey: "",
ChainCode: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8", ChainCode: "58SARPmADHvUcpq7XfBoCgwzy5QC8Kb3JrezpHqA85x2",
ImportPrivateKey: "", ImportPrivateKey: "",
ImportPublicKey: base58.Encode(correctImportPubkey), ImportPublicKey: base58.Encode(correctImportPubkey),
} }
@ -142,7 +142,7 @@ func TestImportKey(t *testing.T) {
}, },
expectResp: nil, expectResp: nil,
isErr: true, isErr: true,
errStr: "invalid private key prefix at byte 46", errStr: "invalid private key prefix at byte 45",
}, },
{ {
req: &nockchain.ImportKeysRequest{ req: &nockchain.ImportKeysRequest{
@ -195,7 +195,7 @@ func TestImportKey(t *testing.T) {
// case missing chaincode when import master privkey // case missing chaincode when import master privkey
{ {
req: &nockchain.ImportKeysRequest{ req: &nockchain.ImportKeysRequest{
Key: "3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg", Key: "4SyUrsbGKPRknzvGakWmFbYefzHzb1r4LUmJpQD8WPcR",
ImportType: nockchain.ImportType_MASTER_PRIVKEY, ImportType: nockchain.ImportType_MASTER_PRIVKEY,
}, },
expectResp: nil, expectResp: nil,
@ -205,7 +205,7 @@ func TestImportKey(t *testing.T) {
// case invalid length // case invalid length
{ {
req: &nockchain.ImportKeysRequest{ req: &nockchain.ImportKeysRequest{
Key: "abcdxyz,3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg", Key: "abcdxyz,4SyUrsbGKPRknzvGakWmFbYefzHzb1r4LUmJpQD8WPcR",
ImportType: nockchain.ImportType_MASTER_PRIVKEY, ImportType: nockchain.ImportType_MASTER_PRIVKEY,
}, },
expectResp: nil, expectResp: nil,
@ -214,7 +214,7 @@ func TestImportKey(t *testing.T) {
}, },
{ {
req: &nockchain.ImportKeysRequest{ req: &nockchain.ImportKeysRequest{
Key: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8,abcdxyz", Key: "58SARPmADHvUcpq7XfBoCgwzy5QC8Kb3JrezpHqA85x2,abcdxyz",
ImportType: nockchain.ImportType_MASTER_PRIVKEY, ImportType: nockchain.ImportType_MASTER_PRIVKEY,
}, },
expectResp: nil, expectResp: nil,
@ -224,7 +224,7 @@ func TestImportKey(t *testing.T) {
// case success import master privkey // case success import master privkey
{ {
req: &nockchain.ImportKeysRequest{ req: &nockchain.ImportKeysRequest{
Key: "2ztGPxS8xYzMXoAHf3HMbMuyh4siew8X4Kz4KuTXvqX8,3B8Q5ZTHH63h9DT6WSwNZhea5zvtueuKpxk3qwZJEjsg", Key: "58SARPmADHvUcpq7XfBoCgwzy5QC8Kb3JrezpHqA85x2,4SyUrsbGKPRknzvGakWmFbYefzHzb1r4LUmJpQD8WPcR",
ImportType: nockchain.ImportType_MASTER_PRIVKEY, ImportType: nockchain.ImportType_MASTER_PRIVKEY,
}, },
expectResp: response, expectResp: response,
@ -234,7 +234,7 @@ func TestImportKey(t *testing.T) {
// case success import seed // case success import seed
{ {
req: &nockchain.ImportKeysRequest{ req: &nockchain.ImportKeysRequest{
Key: "include lounge salad chicken trumpet embrace grace mercy pulp submit alter weapon plastic welcome funny female palm satoshi open file knock sun fade match", Key: "brass vacuum stairs hurt brisk govern describe enforce fly exact rescue capable belt flavor lottery sauce easy frame orange legal injury border obey novel",
ImportType: nockchain.ImportType_SEEDPHRASE, ImportType: nockchain.ImportType_SEEDPHRASE,
}, },
expectResp: response, expectResp: response,
@ -244,11 +244,11 @@ func TestImportKey(t *testing.T) {
// case sucess import pubkey // case sucess import pubkey
{ {
req: &nockchain.ImportKeysRequest{ req: &nockchain.ImportKeysRequest{
Key: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6", Key: "39DL6YA1kSRCKMjzpFEtC8rmnxVuseUrP2LnViwY7YEhZYZkX2HmnAZ63Uwy1DwuXstmF1VeJDucg719xw49j9CKL3bsKq3A6SZN918CowcgQroHsgohj7dYgpGRWk41s42F",
ImportType: nockchain.ImportType_WATCH_ONLY, ImportType: nockchain.ImportType_WATCH_ONLY,
}, },
expectResp: &nockchain.ImportKeysResponse{ expectResp: &nockchain.ImportKeysResponse{
PublicKey: "34VqjU7ojQXWiFZz7kvXe1xfxhbdimmqqUAgp21XGESLqJSXxHkqrcquWirFcCPPj1pmSL4pRc8GndZoiiK8ijeYjgcJ3QR7fb2s4b2WdJhDao4Dx7gw3NRSt4RjXawqUQw6", PublicKey: "39DL6YA1kSRCKMjzpFEtC8rmnxVuseUrP2LnViwY7YEhZYZkX2HmnAZ63Uwy1DwuXstmF1VeJDucg719xw49j9CKL3bsKq3A6SZN918CowcgQroHsgohj7dYgpGRWk41s42F",
}, },
isErr: false, isErr: false,
errStr: "", errStr: "",
@ -428,21 +428,31 @@ 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 := "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) masterKey1, err := crypto.MasterKeyFromSeed(seed1)
assert.NoError(t, err) 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) 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 := "[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 91z5muQKgHZDcChdnCSTEtvuN8dbbXp5wzNs5xrCkce2YvSX1q6fu3d],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 3a9VWigUM1TuS79yM4dAqkiUg6WJMUPGwVKJpQUHCLJcFZsCWM2q6pF],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 9RkPvHMtuYtjV2qvB86u7zcnr26SdVcKzFnHgfhUSEG1W3FgKgLpbBm]" //inputs := "[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 91z5muQKgHZDcChdnCSTEtvuN8dbbXp5wzNs5xrCkce2YvSX1q6fu3d],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 3a9VWigUM1TuS79yM4dAqkiUg6WJMUPGwVKJpQUHCLJcFZsCWM2q6pF],[CxiTK4HjqPRebUkoy6rH89ZcNGuH4goHkmKgmgCJxZEFS2C3qrDoh4y 9RkPvHMtuYtjV2qvB86u7zcnr26SdVcKzFnHgfhUSEG1W3FgKgLpbBm]"
//inputs := "[7PGL7VUMmBBFLxBta9hxJy2yyPNyWww6mXB4B7L78CEM7vu8E1gZY6B 76WR3YEgKaPXN9YshstDhHo82yg7ghJwoYGy9hVoihdSogAMpb9Jbyb],[7PGL7VUMmBBFLxBta9hxJy2yyPNyWww6mXB4B7L78CEM7vu8E1gZY6B 4h3Y3RPn5oAuHEmVtysyxNfJgUiy1DsjfRn4GzgZvM7asPPgJ6Jb7iy]"
//inputs := "[7PGL7VUMmBBFLxBta9hxJy2yyPNyWww6mXB4B7L78CEM7vu8E1gZY6B 76WR3YEgKaPXN9YshstDhHo82yg7ghJwoYGy9hVoihdSogAMpb9Jbyb],[7PGL7VUMmBBFLxBta9hxJy2yyPNyWww6mXB4B7L78CEM7vu8E1gZY6B 4h3Y3RPn5oAuHEmVtysyxNfJgUiy1DsjfRn4GzgZvM7asPPgJ6Jb7iy]"
inputs := "[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 AmSjC3SDNtb7ZrUkTXc242BvGeimeL1nAV4CqV63HpLMryhom4L9W59],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 7oo4x3fuwcJ5DrbFY1yf715ctjtE6CqqPagJWT8d687Q6sgMVWc1SXz],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 8BrF9XAKwzvFdy8p7KAB8VEvcswPADhs2WamhWSLUErYN9z8U8cynaA]"
//inputs := "[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 4d5zzcHuc9spJ1k3ozKYc4SyGm3APeN8wjsg5RkN27FaFsa7oMoJCDf],[5bcr83LnCYyHqQh4ExK6metaf1cs7JYDqMYc92Awqhwc6VEpZJL9wj9 5ZgFvf8qt8YCa2Nru2VZG2FF7P82Xcj4EsM2EQKiddQ8C43ciG91276]"
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 := "100,100,100" //recipients := "37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe,37Ttw4d6Fq1WGis5qVz8SbeEtpqsbg2ihArBedi4ZeuhFFo8tbCNvwWNq9D8KFBc2qv7uzvPJmKmJg68aEHEh21FiXk9iJCmzyE3NqdSgpsPMCx7Q39yhUUrKkKvGnHUKzMe" //fmt.Sprintf("%s", base58.Encode(masterKey2.PublicKey))
gifts := "50,50,50"
fee := 100 fee := 100
req := &nockchain.CreateTxRequest{ req := &nockchain.CreateTxRequest{
@ -462,5 +472,21 @@ 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, "8gjTa6H1MrKXPWgNJCF9fsYE7PUfqhYzxetUoTftz7zyHCv24ZYHDM3")
_, 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
} }