+ openssl version
OpenSSL 1.1.0h 27 Mar 2018
+ openssl ecparam -name secp256k1 -genkey -text -out ./key.priv.pem
+ cat ./key.priv.pem
ASN1 OID: secp256k1
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEID/VMb8FeEUT25fMlECFXFFmrlN2JyIaAq8wCurYix/LoAcGBSuBBAAK
oUQDQgAEc9EfjNOS77aPvokdhShEXfJinwQ3dOqZp9YOVdegIIXz0uYvt+VY08nG
0o2127zrMVETlRG4/qJT8zz1hOMBGA==
-----END EC PRIVATE KEY-----
+ openssl ec -in ./key.priv.pem -pubout -out ./key.pub.pem
read EC key
writing EC key
+ cat ./key.pub.pem
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc9EfjNOS77aPvokdhShEXfJinwQ3dOqZ
p9YOVdegIIXz0uYvt+VY08nG0o2127zrMVETlRG4/qJT8zz1hOMBGA==
-----END PUBLIC KEY-----
echo 'test123' >textfile.txt
openssl dgst -sha256 -sign ./key.priv.pem -out ./sign.bin textfile.txt
openssl base64 -in ./sign.bin -out ./sign.txt
+ cat ./sign.txt
MEUCIQDYso2HZkuQHw82FT8PtYa8Qf832tWLTk9KYfzUlxa0ZQIgLS6ljjr0y5Mj
SEwTQt5biOLb+dsLhbv4SxbTIQPeiO0=
openssl dgst -sha256 -verify ./key.pub.pem -signature ./sign.bin ./textfile.txt
Verified OK
#! /bin/sh -x
openssl version
openssl ecparam -name secp256k1 -genkey -text -out ./key.priv.pem
cat ./key.priv.pem
openssl ec -in ./key.priv.pem -pubout -out ./key.pub.pem
cat ./key.pub.pem
echo 'test123' >textfile.txt
openssl dgst -sha256 -sign ./key.priv.pem -out ./sign.bin textfile.txt
openssl base64 -in ./sign.bin -out ./sign.txt
cat ./sign.txt
openssl dgst -sha256 -verify ./key.pub.pem -signature ./sign.bin ./textfile.txt
+ openssl version
OpenSSL 1.1.0h 27 Mar 2018
+ openssl ecparam -name secp256k1 -genkey -text -out ./key.priv.pem
+ cat ./key.priv.pem
ASN1 OID: secp256k1
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIA8XwLgEqy+WW9shqLrT2zrp4B4kSqC7RA6QrQLyXltsoAcGBSuBBAAK
oUQDQgAEIBSsyL1UjQlmML9w7ecF6fhnEaQgqXkyrgjdhYXgcNovMeWwoIp+SxQv
jNgdaTCr/dq5IlznxMaoBlHnqwKS2A==
-----END EC PRIVATE KEY-----
+ openssl ec -in ./key.priv.pem -pubout -out ./key.pub.pem
read EC key
writing EC key
+ cat ./key.pub.pem
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIBSsyL1UjQlmML9w7ecF6fhnEaQgqXky
rgjdhYXgcNovMeWwoIp+SxQvjNgdaTCr/dq5IlznxMaoBlHnqwKS2A==
-----END PUBLIC KEY-----
+ echo test123
+ openssl dgst -sha256 -sign ./key.priv.pem -out ./sign.bin textfile.txt
+ openssl base64 -in ./sign.bin -out ./sign.txt
+ cat ./sign.txt
MEQCIGfvYyBggaT0f3B1GxNxbJnYXciSfJFgi5J5UaWx7TnVAiBAnFmgAj1R/kni
dcXQU+3MEiN67owdK2aIaTQpVRDHWA==
+ openssl dgst -sha256 -verify ./key.pub.pem -signature ./sign.bin ./textfile.txt
Verified OK
openssl ec -in key.priv.pem -conv_form compressed -outform DER | dd bs=1 skip=53 > key.raw.bin
100GGGGG GGGGGGGG GGGBBBBB BBBBBBBB BBBBBBBB AAAAAAAA AAAAAAAA AAAAAAAA
101BBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB AAAAAAAA AAAAAAAA AAAAAAAA
AADDLLLLLLLLLLLLLLCC
AA100000001677722412
decimal bin
AA10 = 10 = 1010
00000016777224 = 16777224 = 1000000000000000000001000
100 00000 00000001 010 00000 00000000 00000001 00000000 00000000 00001000
0x80 0x01 0x40 0x00 0x01 0x00 0x00 0x08
HHHHHHHHHHHHHHHHCC
Address: 00000000FE00007DF0
00000000FE00007D - address itself
F0 - checksum
It's needed to change high bits of address to 101 (this is a private address) and convert it to hexadecimal:
A0000000FE00007D
function der2pem($der_data, $type='PUBLIC KEY') {
$der_data = hex2bin('3036301006072a8648ce3d020106052b8104000a032200') . $der_data;
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN ".$type."-----\n".
trim($pem) .
"\n-----END ".$type."-----\n";
return $pem;
}
curl http://127.0.0.1/api/tx/new -d '{"tx":"g6R0eXBlo … 2MjI4X8TfA5gc"}'
{
"body": BinaryBody (binary),
"sig": Array (array of binary),
"ver": 2 (unsigned integer)
}
{
"purpose": {
"0": "transfer",
"1": "srcfee",
"2": "dstfee",
"3": "gas"
},
"kind": {
"16": ["generic", 2],
"17": ["register", 2],
"18": ["deploy", 2],
"19": ["patch", 2],
"20": ["block", 2]
}
}
{
"k": 0x11,
"t": 1530106891372,
"nonce": "T1umkWY=",
"h": "Y6dVG5CvZacwlbf21oybiIHh/4h+8d2EJwF7Qp/GpCA=",
"e": {}
}
[
"025348F9AD2BDC8E394B7C3C69FDD221F8C7F95B458D56AACD677C4C9ABF8E1AE7",
"0234326DF0BDF60DA3E6D203B73C0D0C4DEE518BD60717C3B20C0D27812C7DADEB",
"02266C9DAA52F9BB5AD73B77A703437E27A3344F36F1D4FF0C0267C3DEA2BC91D7"
]
[
"02266C9DAA52F9BB5AD73B77A703437E27A3344F36F1D4FF0C0267C3DEA2BC91D7",
"0234326DF0BDF60DA3E6D203B73C0D0C4DEE518BD60717C3B20C0D27812C7DADEB",
"025348F9AD2BDC8E394B7C3C69FDD221F8C7F95B458D56AACD677C4C9ABF8E1AE7"
]
02266C9DAA52F9BB5AD73B77A703437E27A3344F36F1D4FF0C0267C3DEA2BC91D70234326DF0BDF60DA3E6D203B73C0D0C4DEE518BD60717C3B20C0D27812C7DADEB025348F9AD2BDC8E394B7C3C69FDD221F8C7F95B458D56AACD677C4C9ABF8E1AE7
CB32960606B0E3846D763B8DA8FE5EF7379D89A227C2B6DBDA499F4ECEA0B071
{
"k":17,
"t":1541067579755,
"nonce":0,
"h":"957216f45873f7d09466610b887f1634359b000820bc91119e0efea70d2de64d"
}
84a16b11a174cf00000166cec9216ba56e6f6e636500a168c420957216f45873f7d09466610b887f1634359b000820bc91119e0efea70d2de64d
3890c8e314282271d4050d049adf70722210e4147551b76edfc74e2fb9977bbf
5ef41f4cc83d38144adc6bc52c93d3d1fb30473b043bf2f3b91c05dfcb6835a0
{
"k":17,
"t":1541067579755,
"nonce":210,
"h":"957216f45873f7d09466610b887f1634359b000820bc91119e0efea70d2de64d"
}
84a16b11a174cf00000166cec9216ba56e6f6e6365ccd2a168c420957216f458
73f7d09466610b887f1634359b000820bc91119e0efea70d2de64d
0014e384d970d49feb87c476720f52942dc09ee086a57e2505a32a00b1747135
1872ea751e6b323c5d319a0fb5eb2f28c1fb2f8cad4e7d1b6ff8debbc52eb78f
00000000 00010100
0x00 0x14
02 21 02B1912FABA80FCECD2A64C574FEFE422C61106001EC588AF1BD9D7548B81064CB
01 08 00000164B250D800
tag 0x02 (public key), length of data 0x21, public key data
tag 0x01 (timestamp), length of data 0x08, current unixtime as microseconds in unsigned int 64 format
# tag 0x02 (public key), length of data 0x21, public key data
02 21 02B1912FABA80FCECD2A64C574FEFE422C61106001EC588AF1BD9D7548B81064CB
# tag 0x01 (timestamp), length of data 0x08, current unixtime as microseconds in unsigned int 64 format
01 08 00000164B250D800
# 'Hello, world!' string added to the end of BSig container
48656C6C6F2C20776F726C6421
022102B1912FABA80FCECD2A64C574FEFE422C61106001EC588AF1BD9D
7548B81064CB010800000164B250D80048656C6C6F2C20776F726C6421
304402205250D827749F285CE174137EC88B394092E43B9E6C6774045EE5E6ED502322520
2204D1628F019E57BF19C1A0FE37193355A059F22CF8203D85E112FF3B4873D46FE
FF 46 304402205250D827749F285CE174137EC88B394092E43B9E6C6774045EE5E6ED5023225202204D1628F019E57BF19C1A0FE37193355A059F22CF8203D85E112FF3B4873D46FE
02 21 02B1912FABA80FCECD2A64C574FEFE422C61106001EC588AF1BD9D7548B81064CB
01 08 00000164B250D800
tag 0xFF (signature), length of data 0x46, binary data of signature (NOT it's ASCII)
tag 0x02 (public key), length of data 0x21, binary data of public key (NOT it's ASCII)
tag 0x01 (timestamp), length of data 0x08, current unixtime as microseconds in unsigned int 64 format
[
[ purpose, "currency name", amount ],
[ purpose, "currency name", amount ],
[ 0x00, "SK", 10 ],
[ 0x01, "SK", 3 ]
]
g6Rib2R5xFCHoWsQoWbECIAAIAACAAADonRvxAiAACAAAgAABaFzzwAFeYouTBkw
oXTPAAABZstPb6ShcJKTAKJTSxGTAaNGRUUDoWWBo21zZ6VoZWxsb6NzaWeRxHb/
RzBFAiBSpsU9BM3tcsK+7lAFUdgOiHsZlvw90gwM9mKIMtMVvQIhAM4K0Qn6jgm8
2czyso2LupaosplS6eJ7Su2jpxMujOj7AiECsZEvq6gPzs0qZMV0/v5CLGEQYAHs
WIrxvZ11SLgQZMsBCAAAAWbLT2+ko3ZlcgI=
# 83 = fixmap of 3 elements
83
# body
a4 626f6479 c45087a16b10a166c4088000200002000003a2746fc408800020
0002000005a173cf0005798a2e4c1930a174cf00000166cb4f6f
a4a170929300a2534b119301a346454503a16581a36d7367a568
656c6c6f
# sig
a3 736967 91c476ff473045022052a6c53d04cded72c2beee500551d80e88
7b1996fc3dd20c0cf6628832d315bd022100ce0ad109fa8e09bc
d9ccf2b28d8bba96a8b29952e9e27b4aeda3a7132e8ce8fb0221
02b1912faba80fcecd2a64c574fefe422c61106001ec588af1bd
9d7548b81064cb010800000166cb4f6fa4a
# ver
37 66572 02
{
"body":
c45087a16b10a166c4088000200002000003a2746fc4088000200002000005a1
73cf0005798a2e4c1930a174cf00000166cb4f6fa4a170929300a2534b119301
a346454503a16581a36d7367a568656c6c6f,
"sig":
ff473045022052a6c53d04cded72c2beee500551d80e887b1996fc3dd20c0cf6
628832d315bd022100ce0ad109fa8e09bcd9ccf2b28d8bba96a8b29952e9e27b
4aeda3a7132e8ce8fb022102b1912faba80fcecd2a64c574fefe422c61106001
ec588af1bd9d7548b81064cb010800000166cb4f6fa4,
"ver": 2
}
c450 # binary, length 0x50 bytes
87 # fixmap of 7 elements
# a1 = fixstr of 1 symbol, 6b = 'k' (this is the map key name), the value is 0x10
a16b10
# a1 = fixstr of 1 symbol, 66 = 'f', c408 = binary of 8 bytes,
# the value is 8000200002000003 (encoded AA010000003355443516 wallet address)
a166c4088000200002000003
# a2 = fixstr of 2 symbols, 746f = 'to', c408 = binary of 8 bytes,
# the value is 8000200002000005 (encoded AA010000003355443737 wallet address)
a2746fc4088000200002000005
# a1 = fixstr of 1 symbol, 73 = 's', cf = uint64,
# 0005798a2e4c1930 = 1541009272740144 = 2018-10-31 18:07:52.740144
a173cf0005798a2e4c1930
# a1 = fixstr of 1 symbol, 74 = 't', cf = uint64,
# 00000166cb4f6fa4 = 1541009272740 = 2018-10-31 18:07:52.740
a174cf00000166cb4f6fa4
# a1 = fixstr of 1 symbol, 70 = 'p', 92 = fixarray of 2 elements
a17092
# 93 = fixarray of 3 elements, 00 = 0 (transfer), a2 = fixstr of 2 symbols,
# 534b = 'SK', 11 = 0x11 = 17 (amount)
9300a2534b11
# 93 = fixarray of 3 elements, 01 = 1 (srcfee), a3 = fixstr of 3 symbols,
# 464545 = 'FEE', 03 = 3 (amount)
9301a346454503
# a1 = fixstr of 1 symbol, 65 = 'e', 81 = fixmap of 1 element
a16581
# a3 = fixstr of 3 symbols, 6d7367 = 'msg'
a36d7367
# a5 = fixstr of 5 symbols, 68656c6c6f = 'hello'
a568656c6c6f
# 91 = fixarray of 1 element
91
# c476 = binary of 0x76 bytes
c476
# below this point goes bsig
# ff47 = signature, length 0x47 bytes ( = 71 in decimal)
ff47
# 71 bytes of signature
3045022052a6c53d04cded72c2beee500551d80e887b1996fc3dd20c0cf6628
832d315bd022100ce0ad109fa8e09bcd9ccf2b28d8bba96a8b29952e9e27b4a
eda3a7132e8ce8fb
# 0221 = public key, length 0x21 bytes ( = 33 in decimal)
0221
# 33 bytes of public key
02b1912faba80fcecd2a64c574fefe422c61106001ec588af1bd9d7548b81064cb
# 0108 = timestamp, length 8 bytes,
# 00000166cb4f6fa4 = 1541009272740 = 2018-10-31 18:07:52.740
010800000166cb4f6fa4
<?php
// some code for data encoding to messagepack format was taken from https://github.com/rybakit/msgpack.php
// constants of binary signature container tags
const TAG_TIMESTAMP = 0x01;
const TAG_PUBLIC_KEY = 0x02;
const TAG_CREATE_DURATION = 0x03;
const TAG_OTHER = 0xF0;
const TAG_PURPOSE = 0xFE;
const TAG_SIGNATURE = 0xFF;
const PURPOSE_TRANSFER = 0x00;
const PURPOSE_SRCFEE = 0x01;
const PURPOSE_DSTFEE = 0x02;
const PURPOSE_GAS = 0x03;
const KIND_GENERIC = 0x10;
const KIND_REGISTER = 0x11;
const KIND_DEPLOY = 0x12;
const KIND_PATCH = 0x13;
const KIND_BLOCK = 0x14;
// non-repeating increasing numbers generator
function get_nonce()
{
list($usec, $sec) = explode(" ", microtime());
return intval($sec.substr($usec, 2, 6));
}
// current time in milliseconds
function now()
{
list($usec, $sec) = explode(" ", microtime());
return intval(($sec + $usec) * 1000);
}
// convert key from der format (used by API) to pem format (used by openssl)
function der2pem($der_data, $type = 'PUBLIC KEY')
{
if ($type == 'EC PRIVATE KEY') {
$der_data = hex2bin('302e0201010420').$der_data.hex2bin('a00706052b8104000a');
} else {
$der_data = hex2bin('3036301006072a8648ce3d020106052b8104000a032200').$der_data;
}
$pem = chunk_split(base64_encode($der_data), 64, "\n");
$pem = "-----BEGIN ".$type."-----\n".
trim($pem).
"\n-----END ".$type."-----\n";
return $pem;
}
// encode non negative int to messagepack format
function encode_uint($uint)
{
if ($uint < 0) {
throw new Exception("uint must be non negative integer");
}
if ($uint <= 0x7f) {
return \chr($uint);
}
if ($uint <= 0xff) {
return "\xcc".\chr($uint);
}
if ($uint <= 0xffff) {
return "\xcd".\chr($uint >> 8).\chr($uint);
}
if ($uint <= 0xffffffff) {
return \pack('CN', 0xce, $uint);
}
return \pack('CJ', 0xcf, $uint);
}
// encode string to messagepack format
function encode_str($str)
{
$length = strlen($str);
if ($length < 32) {
return chr(0xa0 | $length).$str;
}
if ($length <= 0xff) {
return "\xd9".chr($length).$str;
}
if ($length <= 0xffff) {
return "\xda".chr($length >> 8).chr($length).$str;
}
return pack('CN', 0xdb, $length).$str;
}
// encode binary to messagepack format
function encode_bin($str)
{
$length = strlen($str);
if ($length <= 0xff) {
return "\xc4".chr($length).$str;
}
if ($length <= 0xffff) {
return "\xc5".chr($length >> 8).chr($length).$str;
}
return pack('CN', 0xc6, $length).$str;
}
// return messagepack header of array of $size elements
function encode_array_header($size)
{
if ($size <= 0xf) {
return chr(0x90 | $size);
}
if ($size <= 0xffff) {
return "\xdc".chr($size >> 8).chr($size);
}
return pack('CN', 0xdd, $size);
}
// return messagepack header of map of $size elements
function encode_map_header($size)
{
if ($size <= 0xf) {
return \chr(0x80 | $size);
}
if ($size <= 0xffff) {
return "\xde".\chr($size >> 8).\chr($size);
}
return \pack('CN', 0xdf, $size);
}
// encode array of binary to messagepack format
function encode_bin_array($arr)
{
$data = encode_array_header(sizeof($arr));
foreach ($arr as $element) {
$data .= encode_bin($element);
}
return $data;
}
// generic encode uint, string or array to messagepack format
function encode_generic($val)
{
if (is_string($val)) {
return encode_str($val);
}
if (is_integer($val) && $val >= 0) {
return encode_uint($val);
}
if (is_array($val)) {
return encode_array($val);
}
throw new Exception("Unsupported type: " . gettype($val));
}
// encode generic array of uints or strings
function encode_array($arr)
{
$data = encode_array_header(sizeof($arr));
foreach ($arr as $element) {
$data .= encode_generic($element);
}
return $data;
}
// compute hash of array of keys
function hash_keys_array($keys)
{
if (!is_array($keys)) {
throw new Exception("Keys have a wrong type. You have to pass array of keys");
}
sort($keys);
return hash('sha256', implode("", $keys));
}
// encode timestamp to put it in binary signature container
function tlv_add_timestamp($timestamp)
{
$len = 8;
return pack('CCJ', TAG_TIMESTAMP, $len, $timestamp);
}
// encode public key to put it in binary signature container
function tlv_add_pub_key($pub_key)
{
$len = strlen($pub_key);
if ($len > 0xFF) {
throw new Exception("pub_key is too long");
}
if ($len < 1) {
throw new Exception("invalid pub_key");
}
return pack('CC', TAG_PUBLIC_KEY, $len).$pub_key;
}
// encode signature to put it in binary signature container
function tlv_add_sign($sign)
{
$len = strlen($sign);
if ($len > 0xFF) {
throw new Exception("signature is too long");
}
if ($len < 1) {
throw new Exception("invalid signature");
}
return pack('CC', TAG_SIGNATURE, $len).$sign;
}
// sign transaction body
function sign_data($data, $options)
{
$mandatory_options = ['pub_key', 'priv_key'];
foreach ($mandatory_options as $option_name) {
if (empty($options[$option_name])) {
throw new Exception($option_name." option is missing");
}
}
$priv_pem = der2pem($options['priv_key'], 'EC PRIVATE KEY');
$priv_key_handle = openssl_pkey_get_private($priv_pem);
if ($priv_key_handle === false) {
throw new Exception("Can't import private key. Openssl error");
}
$container = [];
foreach ($options as $option_name => $option_data) {
switch ($option_name) {
case 'pub_key':
array_push($container, tlv_add_pub_key($option_data));
break;
case 'timestamp':
array_push($container, tlv_add_timestamp($option_data));
break;
default:
break;
}
}
$meta_info = implode("", $container);
if (openssl_sign($meta_info.$data, $sign, $priv_key_handle, OPENSSL_ALGO_SHA256) === false) {
throw new Exception("Can't sign data. Openssl error");
}
return tlv_add_sign($sign).$meta_info;
}
// encode transaction body map to messagepack format
function encode_map($body, $types)
{
$data = encode_map_header(sizeof($body)); // fixmap of sizeof($body) elements
foreach ($body as $key => $value) {
$data .= encode_str($key);
if (!isset($types[$key])) {
throw new Exception("Unknown type of key " . $key);
}
switch ($types[$key]) {
case 'uint':
$data .= encode_uint($value);
break;
case 'binary':
$data .= encode_bin($value);
break;
case 'bin_array':
$data .= encode_bin_array($value);
break;
case 'array':
$data .= encode_array($value);
break;
case 'auto':
$data .= msgpack_pack($value); // use external msgpack library to encode this type
break;
default:
throw new Exception($types[$key]." is unsupported type of key ".$key);
break;
}
}
return $data;
}
// check difficulty for registration transaction
function is_difficulty_not_enough($data, $difficulty)
{
if ($difficulty == 0) {
return false; // false = difficulty is enough
}
$hash = hash('sha512', $data);
$nibbles = intval($difficulty/4);
for ($i=0; $i<$nibbles; $i++) {
if ($hash[$i] != '0') {
return true; // true = difficulty is not enough
}
}
$last_nibble = unpack("C", pack("h",$hash[$nibbles]))[1];
$bits_of_last_byte = $difficulty - $nibbles*4;
for($i=0; $i<$bits_of_last_byte; $i++) {
if (($last_nibble >> (3-$i)) & 0x01 != 0) {
return true; // true = difficulty is not enough
}
}
return false; // false = difficulty is enough
}
// get data for registration transaction body in msgpack format
function registration_tx_body($public_keys, $difficulty)
{
if (!is_array($public_keys)) {
throw new Exception("You chose wrong type for 'keys'. You must pass array of public keys.");
}
$current_nonce = 0;
$body = [
"k" => KIND_REGISTER,
"t" => now(),
"nonce" => $current_nonce,
"h" => hex2bin(hash_keys_array($public_keys)),
];
$types = [
"k" => "uint",
"t" => "uint",
"nonce" => "uint",
"h" => "binary"
];
$body_bin = encode_map($body, $types);
while ( is_difficulty_not_enough($body_bin, $difficulty) ) {
$current_nonce++;
$body['nonce'] = $current_nonce;
$body_bin = encode_map($body, $types);
}
return $body_bin;
}
// get data for generic money transfer transaction body in msgpack format
function money_transfer_tx_body($options)
{
$mandatory_options = ['from', 'to', 'money'];
foreach ($mandatory_options as $option_name) {
if (empty($options[$option_name])) {
throw new Exception($option_name." option is missing");
}
}
$body = [
'k' => KIND_GENERIC,
'f' => $options['from'],
'to' => $options['to'],
's' => get_nonce(),
't' => now(),
'p' => $options['money'],
'e' => [ 'msg' => 'hello']
];
$types = [
'k' => 'uint',
'f' => 'binary',
'to' => 'binary',
's' => 'uint',
't' => 'uint',
'p' => 'array',
'e' => 'auto'
];
return encode_map($body, $types);
}
// pack and sign transaction
function pack_tx($packed_body, $keys)
{
if (!is_array($keys)) {
throw new Exception("You must pass array of keys.");
}
$sigs = [];
foreach ($keys as $pub_key => $priv_key) {
$options = [
'pub_key' => $pub_key,
'priv_key' => $priv_key,
'timestamp' => now(),
];
$sigs[] = sign_data($packed_body, $options);
}
$body = [
'body' => $packed_body,
'sig' => $sigs,
'ver' => 2
];
$types = [
'body' => 'binary',
'sig' => 'bin_array',
'ver' => 'uint'
];
return encode_map($body, $types);
}
// endpoint settings used in curlify_transaction
function get_endpoint_settings()
{
return [
'url' => 'http://127.0.0.1:49841',
'new_tx' => 'tx/new'
];
}
// prints curl command with all nessesary parameter
function curlify_transaction($transaction)
{
$data = json_encode(
[
"tx" => base64_encode($transaction),
]
);
$settings = get_endpoint_settings();
printf("playground:\n");
printf(
"curl -s %s/api/playground/tx/validate -d '%s' | jq .\n\n",
$settings['url'],
$data
);
printf("apply transaction:\n");
printf(
"curl -s %s/api/%s -d '%s' | jq .\n\n",
$settings['url'],
$settings['new_tx'],
$data
);
}
// private key in der format
$priv_key = hex2bin('0102030405060708090001020304050607080900010203040506070809000102');
// public key in der format (as stored in blockchain)
$pub_key = hex2bin('02B1912FABA80FCECD2A64C574FEFE422C61106001EC588AF1BD9D7548B81064CB');
printf("## registration transaction:\n");
curlify_transaction(
pack_tx(
registration_tx_body([$pub_key], 10),
[$pub_key => $priv_key]
)
);
printf("\n\n");
$from = hex2bin("8000200002000003"); // AA010000003355443516
$to = hex2bin("8000200002000005"); // AA010000003355443737
$money = [
[PURPOSE_TRANSFER, "SK", 17],
[PURPOSE_SRCFEE, "FEE", 3],
];
printf("## money transfer transaction:\n");
curlify_transaction(
pack_tx(
money_transfer_tx_body([
'from' => $from,
'to' => $to,
'money' => $money
]),
[$pub_key => $priv_key]
)
);
<pre>
{
"block":
{
"bals": {...},
"hash": "...",
"child": "...",
"header": {...},
"outbound": [...],
"settings": [...],
"sign": [...],
"txs": {...},
},
"result": "ok"
}
</pre>
{
"8001400002000001":
{
"amount": {...},
"lastblk": "...",
"seq": Х,
"t": Х
}
}
{ "balroot":"...",
{
"balroot":"...",
"chain":Х,
"height":Х,
"ledger_hash":"...",
"settings_hash":"...",
"parent":"...",
"txroot":"..."
}
{
"15190FBE2E428790-XUkvyU3JvUoMPyHEhkCKnsbD7jT-03":
{
"amount":Х,
"cur":"...",
"extradata":"{...}",
"from":"...",
"seq":Х,
"sig": {...},
"sigverify":
{
"invalid":Х,
"valid":Х
},
"timestamp":Х,
"to":"...",
"type":"tx"
{ "binextra": "...",
"extra": {
"pubkey": "...",
"timestamp": Х,
"createduration": Х
},
"nodeid": "...",
"signature": "..."
}
% curl http://127.0.0.1:49841/api/status -s |jq
{
"client": "127.0.0.1",
"ok": true
}
% curl http://127.0.0.1:49841/api/node/status -s |jq .
{
"result": "ok",
"status": {
"blockchain": {
"chain": 4,
"hash": "W91YU1ES85Z82j5zz2Hj9cXtfR0ckyhMW5gBpP№v45k=",
"header": {
"balroot": "NxwuY3kb2kIYtiqbjjXujgKPQsScdgONaqkAaPHF170=”, "chain": 4,
"height": 134,
"ledger_hash": "HRVRerlRWYM3rk9L4RA7KZX2YHWIN15dbyOp0FmMsxs=", "parent": "/lmFP73bpwU79UVUGYGnlDfW:v8qGK9j3oCGOPN0YX8=", "setroot": "x74U0qmRSg+kLQASxuxjx+9P+xx/vXgM9ThG9LIIN]g=", "txroot": "Ii/0ubdnnLMkVk724EGkd5n3YXnC3FaPNS5qmPxmHqk="
>
b
"nodeid": "287nRpYVitpiYzHbjyt7YefngcoC",
"public_key": ”AganOY4DcSMZ078U9tR9+p0PkwDzwnoKZH2SW17Io9Xb", "sync_peers": [
"28AFpshz4W4YD7tbLjliu4ytpPzQ",
"3NBx74EdmT2PyYexBSrg7xcht998"
],
"tpic_peers": [
{
"auth": "ok",
"node": "28AFpshz4W4YD7tbLjliu4ytpPzQ",
"state": "working"
{
"auth": "ok",
"node": "3NBx74EdmT2PyYexBSrg7xcht998",
"state": "working"
>
],
"ver": "v0.5.3-l-g3ff2986",
"xchaininbound": {},
"xchainoutbound": {}
"ok": true
>
% curl http://127.0.0.1:49841/api/where/0x8001400004000041 -s |jq
{
"chain": 4,
"result": "found",
"address": "0x8001400004000041",
"ok": true,
"txtaddress": "AA100000006710892962"
}
% curl http://121.0.0.1:49841/api/address/0x8001400004000011 -s |jq .
{
"info": {
"amount": {
"FTT": 61306,
"SK": l
},
"lastblk": "550C89CAF76B6D075A5B1948F8D6D77C45C27E7E50BF885CD0AD77A5EC253EDD",
"preblk": "17836B6466E7FB0D3BB3C9977D10CF4DEDE1981C35AB2E2D18B4834DB952D801",
"pubkey": "036A21F068BE92697268B60D96C4CA93052EC104E49E003AE2C404F916864372F4",
"seq": 1,
"t": 1528979142839,
"usk": 1
},
"result": "ok",
"address": "0x8001400004000011",
"ok": true,
"txtaddress": "AA100000006710888182"
}
% curl http://127.0.0.1:49841/api/blockinfo/last -s |jq .
{
"block": {
"extdata": {
"prevnodes": [
"node_287nRpYV",
"node_28AFpshz"
]
},
"hash": "5BD958525112F3967CDA3E73CF61E3F5C5ED7D139C93284C5B9801A4F366E399",
"header": {
"balroot": "371C2E63791BDA4218B62A9B8E35EE8E028F42C49C76038D6AA90068F1C597BD",
"chain": 4,
"height": 134,
"ledger_hash": "1D15517ABD51598337AE4F4BE1103B2995F6607588375E5D6F23A9D0598CB31B",
"parent": "FE59853FBDDBA7053BF545541981A7D437D47EFF2A18AF6326808638F374617F",
"setroot": "C7BE143AA9914A0FA42D0012C6EC63C7EF4FFB1C7FBD780CF53846F4B2083498",
"txroot": "222FCEB9B7679CB324564EF6E041A47799C96179C2DC568F352E6A98FC661EA9"
},
"outbound": [],
"settings": {
"aalloc": {
"patch": [
{
"P": [
"current",
"allocblock",
"last"
],
"t": "set",
"v": 65
}
],
"sig": []
}
},
"sign": [
{
"_nodeid": "28AFpshz4W4YD7tbLjliu4ytpPzQ",
"_nodename": "node_28AFpshz",
"blnextra": "022102E8C7DB1B129CE0952799AD572ECC40F7027CD1049CA8215F43FD57E13E55FA",
"extra": {
"pubkey": "02E8C7DB1B129CE0952799AD572ECC40F7027CD1049CA8215F43FD57E13E55FA3F",
"timestamp": 1530007642203,
"createduration": 2690705
},
"signature": "3046022100C73B5838078D6C15B3726E36E328C3BB474BDD8C479C68932D4855598D074C70022100DF8DCF91D1E6DBA5F1769A6F4E15C05945956A588F4CB2CB8BF6B8D8A2B68167"
},
{
"_nodeid": "287nRpWitpiYzHbjyt7YefngcoC",
"_nodename": "node_287nRpYV",
"extra": {
"pubkey": "0206A7398E03712319D3BF14F6D47DFA9D0F9300F3C27A0A647D925A5EC8A3D5DB",
"timestamp": 1530007642203,
"createduration": 4786972
},
"signature": "3046022100DB94193056C30E8913B75C221CA5198698994D4E44894FABCFC6CBF33DC945FD022100C5976316966494BCC0CB8E40BA5A236FEA99B42AED784844F1BAEF75074C4753"
}
],
"txs_count": 1
},
"result": "ok",
"ok": true
}
%|
% curl http://127.0.0.1:49841/api/blockinfo/last -s |jq .
{
"block": {
"bals": {
"8001400004000041": {
"amount": {},
"pubkey": "036A21F068BE92697268B60D96C4CA93052EC104E49E003AE2C404F916864372F4"
},
"A000000000000000": {
"amount": {
"FTT": 0,
"SK": 0
},
"lastblk": "FE59853FBDDBA7053BF545541981A7D437D47EFF2A18AF6326808638F374617F"
},
"extdata": {
"prevnodes": [
" node_287nRpW",
"node 28AFpshz"
],
"hash": "5BD958525112F3967CDA3E73CF61E3F5C5ED7D139C93284C5B9801A4F366E399",
"header": {
"balroot": "371C2E63791BDA4218B62A9B8E35EE8E028F42C49C76038D6AA90068F1C597BD",
"chain": 4,
"height": 134,
"ledgerjiash": "1D15517ABDS1598337AE4F4BE1103B2995F6607588375E5D6F23A9D0598CB31B",
"parent": "FE59853FBDDBA7053BF545541981A7D437D47EFF2A18AF6326808638F374617F",
"setroot": "C7BE143AA9914A0FA42D0012C6EC63C7EF4FFB1C7FBD780CF53846F4B2083498",
"txroot": "222FCEB9B7679CB324564EF6E041A47799C96179C2DC568F352E6A98FC661EA9"
},
"outbound": [],
"settings": {
"aalloc": {
"patch": [
{
"p": [
"current",
"allocblock",
"last"
],
"t": "set",
"v": 65
}
],
"sig": []
},
"sign": [
{
"_nodeid": "28AFpshz4W4YD7tbLjliu4ytpPzQ",
"_nodename": "node_28AFpshz",
"binextra": "022102E8C7DB1B129CE0952799AD572ECC40F7027CD1049CA8215F43FD57E13E55FA3F0108000001643B8FE05B03080000000000290E91",
"extra": {
"pubkey": "02E8C7DB1B129CE0952799AD572ECC40F7027CD1049CA8215F43FD57E13E55FA3F",
"timestamp": 1530007642203,
"createduration": 2690705
},
"signature": "3046022100C73B5838078D6C15B3726E36E328C3BB474BDD8C479C68932D4855598D074C70022100DF8DCF91D1E6DBA5F1769A6F4E15C05945956A5 88F4CB2CB8BF6B8D8A2B68167"
},
{
"_nodeid": "287nRpYVitpiYzHbjyt7YefngcoC",
"_nodename": "node_287nRpYV",
"binextra": "02210206A7398E03712319D3BF14F6D47DFA9D0F9300F3C27A0A647D925A5EC8A3D5DB0108000001643B8FE05B03080000000000490B1C",
"extra": {
"pubkey": "0206A7398E03712319D3BF14F6D47DFA9D0F9300F3C27A0A647D925A5EC8A3D5DB",
"timestamp": 1530007642203,
"createduration": 4786972
},
"signature": "3046022100DB94193056C30E8913B75C221CA5198698994D4E44894FABCFC6CBF33DC945FD022100C5976316966494BCC0CB8E40BA5A236FEA99B42AED784844F1BAEF75074C4753"
},
"txs": {
"153BADD7D908919C-287nRpYVitpiYzHbjyt7YefngcoC-72": {
"address": "8001400004000041",
"extdata": {
"origin": "node_287nRpYV"
},
"pow": "54455354352031353330303037363430203533",
"register": "036A21F068BE92697268B60D96C4CA93052EC104E49E003AE2C404F916864372F4",
"timestamp": 1530007640,
"type": "register"
}
}
},
"result": "ok",
"ok": true
}
%|