08_transactions_v2

Andrew Beyond edited this page Nov 29, 2018 · 6 revisions

Transactions v2

Any changes you want to make in the state of the blockchain can be done using transactions. There are two main types of transactions: registration transaction and generic (financial) transaction (sending token from one wallet to another). In the future, more types of transactions will be added.

Transaction related API description

Url Request Type Description of parameters
/api/tx/new POST Input parameters: {"tx": " ... packed and signed transaction ... "}
Response: {"txid": "153B7614F8051F79-3RGPJnQuajxy1r9zj5Jb9JUr4skE-6BC2"} - transaction identifier
/api/tx/status/{txid} GET Input parameters: {txid} - transaction identifier you've received from the call /api/tx/new
Response:
{"Res": null} - the transaction has not yet included into the block (no information yet)
{"Res": {"ok": true}} - the transaction has included into the block

Example of sending a transaction using curl (the transaction body has been shortened):

curl http://127.0.0.1/api/tx/new -d '{"tx":"g6R0eXBlo … 2MjI4X8TfA5gc"}'

Dive into transaction format

In order to make a new transaction, you should send an HTTP POST request to the server. Request data should be in JSON format and contain the key 'tx' with base64-encoded transaction container.

transacton_v2_general

The transaction container is a MessagePack fixmap (first byte 0x80 - 0x8f) with the following structure:

{
  "body": BinaryBody (binary),
  "sig": Array (array of binary),
  "ver": 2 (unsigned integer)
}

The keys of this fixmap should be encoded as a string.

The value of the 'body' is a MessagePack binary (0xc4 the first byte) with MessagePack encoded transaction payload (we referring it as a transaction body).

The transaction body is a MessagePack map (0xde, 0x80-0x8f) with one mandatory key 'k' which value indicates transaction kind and other keys depending on transaction purpose.

For the best extendability transaction kind number is unique for each kind with each transaction version. Headers with constants should be generated by scripts from supplied JSON file (priv/tx_const.json):

{
  "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]
  }
}

The value of the 'sig' key is MessagePack array (types 0x90-0x9f or 0xdc-0xdc). Each array item contains signature for one key. Signature format (BSig) described below. A transaction might have multiple signatures.

The value of the 'ver' key is an integer, which indicates a version of transaction format to specify which body decoder should be used. As for now it has to be 2 (0x02 in MessagePack).

Registration Transaction

For registration of a new wallet there is the 'register' transaction type. As we mentioned before, the transaction body is MessagePack map (or fixmap) type. The first byte of this type is the 0xDE or from a range 0x80-0x8F.

transacton_v2_registration

Here is an example of registration transaction body content (shown as json, binary data represented as base64-encoded strings):

{
  "k": 0x11,
  "t": 1530106891372,
  "nonce": "T1umkWY=",
  "h": "Y6dVG5CvZacwlbf21oybiIHh/4h+8d2EJwF7Qp/GpCA=",
  "e": {}
}

The value of the 'k' key should always be 0x11 for registration transactions (MessagePack positive fixint type, 0x11).

The value of the 't' key is a transaction creation timestamp (unixtime in milliseconds, MessagePack uint 64 type, 0xcf).

The value of the 'nonce' key can be any type and should be used to change the transaction hash (see comment about difficulty below).

The value of the 'h' key is sha256 hash of concatenated public keys sorted ascending (MessagePack binary type, 0xc4).

The value of the 'e' key is user defined extra data included into transaction (MessagePack map or fixmap type, 0xde, 0x80-0x8f).

Example of calculating the value of the 'h' key.

Let's take 3 arbitrary public keys (shown as json array, binary data represented as hex string):

[
  "025348F9AD2BDC8E394B7C3C69FDD221F8C7F95B458D56AACD677C4C9ABF8E1AE7",
  "0234326DF0BDF60DA3E6D203B73C0D0C4DEE518BD60717C3B20C0D27812C7DADEB",
  "02266C9DAA52F9BB5AD73B77A703437E27A3344F36F1D4FF0C0267C3DEA2BC91D7"
]

Please note, keys should be represented as binary data (i.e. for string 02 you should take 0x02 byte of binary data).

After sorting the keys we'll get the following order:

[
  "02266C9DAA52F9BB5AD73B77A703437E27A3344F36F1D4FF0C0267C3DEA2BC91D7",
  "0234326DF0BDF60DA3E6D203B73C0D0C4DEE518BD60717C3B20C0D27812C7DADEB",
  "025348F9AD2BDC8E394B7C3C69FDD221F8C7F95B458D56AACD677C4C9ABF8E1AE7"
]

After concatenation step we'll get the following data:

02266C9DAA52F9BB5AD73B77A703437E27A3344F36F1D4FF0C0267C3DEA2BC91D70234
326DF0BDF60DA3E6D203B73C0D0C4DEE518BD60717C3B20C0D27812C7DADEB025348F9
AD2BDC8E394B7C3C69FDD221F8C7F95B458D56AACD677C4C9ABF8E1AE7

The next step is calculating the sha256 hash of this data. Please note, we should deal with binary data (i.e. string E7 in the example should be byte 0xE7 of binary data). We calculate the hash of binary data, NOT the string of ASCII symbols.

For the data in this example the sha256 hash is CB32960606B0E3846D763B8DA8FE5EF7379D89A227C2B6DBDA499F4ECEA0B071.

PoW difficulty of the registration transaction

In order to prevent mass wallets registration, we require a PoW calculation for every registration transaction. In our case, the PoW means you should change the transaction data to get a sha512 hash which meets special requirements. These requirements usually called difficulty.

You can get the current difficulty of the shard by API call (GET) /api/settings. By this API call you'll get a JSON object. The value of the key settings.current.register.diff is the difficulty of this shard.

For example, if difficulty was 16 you should get a sha265 hash of the transaction with 16 leading bits of 0 (i.e. two leading bytes should be equal to 0). You should change the value of the 'nonce' key of the registration transaction to get a hash with 16 leading 0 bits.

Please note, the hash of the transaction body doesn't put in the transaction itself. In order to check if transaction meets the difficulty requirements or not, server recalculates the sha512 hash of the transaction body. As mentioned before, you should change the value of the 'nonce' key to get the transaction data with sha512 hash containing 'difficulty' of leading bits equal to 0.

Let's take the following transaction body (shown as JSON, binary value of the 'h' key shown as hex-encoded string):

{
  "k":17,
  "t":1541067579755,
  "nonce":0,
  "h":"957216f45873f7d09466610b887f1634359b000820bc91119e0efea70d2de64d"
}

Here is the hex dump of the MessagePack-encoded transaction body:

84a16b11a174cf00000166cec9216ba56e6f6e636500a168c420957216f45873
f7d09466610b887f1634359b000820bc91119e0efea70d2de64d

The sha512 hash of this transaction body is

3890c8e314282271d4050d049adf70722210e4147551b76edfc74e2fb9977bbf
5ef41f4cc83d38144adc6bc52c93d3d1fb30473b043bf2f3b91c05dfcb6835a0

The first byte of the hash is 0x38 or 00111000 in binary format. This means the difficulty of preparation for this transaction body is 2 (hash has 2 leading 0 bits).

In case we changed the value of the 'nonce' key the hash of the transaction body would change.

Here is the same transaction but we've changed the value of the 'nonce' key to 210 (shown as JSON, binary value of the 'h' key shown as hex-encoded string):

{
  "k":17,
  "t":1541067579755,
  "nonce":210,
  "h":"957216f45873f7d09466610b887f1634359b000820bc91119e0efea70d2de64d"
}

Here is the hex dump of the MessagePack-encoded transaction body:

84a16b11a174cf00000166cec9216ba56e6f6e6365ccd2a168c420957216f458
73f7d09466610b887f1634359b000820bc91119e0efea70d2de64d

The sha512 hash of this transaction body is

0014e384d970d49feb87c476720f52942dc09ee086a57e2505a32a00b1747135
1872ea751e6b323c5d319a0fb5eb2f28c1fb2f8cad4e7d1b6ff8debbc52eb78f

The binary representation of the first two bytes of that hash is

00000000  00010100
  0x00      0x14

As you can see, this hash has 11 leading 0 bits, so the difficulty of preparation for this transaction body is 11.

BSig container and signature format

The BSig container is a binary data of TLV format (Tag - Length - Value).

bsig

Each signature may contain additional data, which is signed with main payload (body, data for sign).

Here are predefined fields.

name length tag type
timestamp 8 1 uint64
pubkey vary 2 binary
createduration 8 3 uint64
OTHER vary 240 binary
purpose vary 254 string
signature vary 255 binary

The public key is mandatory. Every BSig should contain the public key tag.

Let's look at the signing procedure by an example.

Let's pretend that we have the private key 0102030405060708090001020304050607080900010203040506070809000102 and we want to sign the string 'Hello, world!'.

First of all we need to calculate public key, for this private key it'd be 02B1912FABA80FCECD2A64C574FEFE422C61106001EC588AF1BD9D7548B81064CB.

Also, we put the current timestamp into container.

Here is the binary data we have at this step:

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

The next step is appending of data for signing to binary from the previous step.

# 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

Here is the resulting binary for sign (shown as hexdump):

022102B1912FABA80FCECD2A64C574FEFE422C61106001EC588AF1BD9D
7548B81064CB010800000164B250D80048656C6C6F2C20776F726C6421

The sha256 hash of this whole binary will be 60C3B88A5F32816F574C8FABFB45A35338A20D7C1678F20DABDBBD7F94568F15.

At the next step we calculate signature of the hash from the previous step. The signature is

304402205250D827749F285CE174137EC88B394092E43B9E6C6774045EE5E6ED502322520
2204D1628F019E57BF19C1A0FE37193355A059F22CF8203D85E112FF3B4873D46FE

Please note, we always deal with binary data. You should sign the binary data of hash (NOT it's ASCII characters representation).

At the next step, we should remove the payload which we appended to container and prepend the container with the signature tag.

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

Generic transactions (token transfer and/or smart contract call)

transacton_v2_generic

Token transfer and smart contract calling transactions must contain the following mandatory keys:

  • 'f' (from) - source address, must be 8 byte binary (0xc4 MessagePack type),
  • 'to' (to) - destination address, must be 8 byte binary (0xc4),
  • 's' (seq) - tx nonce, must be positive integer (0x00 - 0x7f or 0xcc - 0xcf)
  • 't' (timestamp) - tx unixtime in milliseconds, positive integer (0x00 - 0x7f or 0xcc - 0xcf),
  • 'p' (payload) - array of amounts (see below, 0xdc or 0x90 - 0x9f)

Also, there is a couple of optional keys:

  • 'c' (call) - for transaction intended to call smartcontract method. This attribute should contain 2 element array (0x92), the first element is the method name (string), the second is an array of arguments (arbitrary types, but tx call with incorrect types will be dropped by smart contract).

  • 'e' (extradata) - map with arbitrary extra data which might be used by smart contract or wallet application. The key 'code' is reserved for 'deploy' method and should not be used for any other purposes (types 0x80 - 0x8f or 0xde - 0xdf). In order to place some text or comment to transaction it's recommended to use the key with the name 'msg'.

Attribute 'p' (payload) is an array of 3 element arrays (0x93).

Here is an example of payload (shown as JSON format):

[
  [ purpose, "currency name", amount ],
  [ purpose, "currency name", amount ],
  [ 0x00, "SK", 10 ],
  [ 0x01, "SK", 3 ]
]

The first element is purpose (positive fixint, 0x00 - 0x7f) from JSON shown before.

The second element is the currency name (binary, 0xc4). If the currency name contains only ASCII characters with codes 32-126 you also can use the string type (0xa0 - 0xbf).

The third element is amount (integer, 0x00 - 0x7f, 0xcc - 0xcf). This field MUST be only the integer type. You CAN NOT use here the float type or any other type.

In case this array contains more than 3 elements, all extra elements should be ignored (it might be array generated by software with a newer version of the protocol, for example).

Clients MUST NOT add extra fields to payload array when creating a transaction, because it might break compatibility with new versions.

Here is an example of whole transaction (218 bytes, shown as base64 encoded binary):

g6Rib2R5xFCHoWsQoWbECIAAIAACAAADonRvxAiAACAAAgAABaFzzwAFeYouTBkw
oXTPAAABZstPb6ShcJKTAKJTSxGTAaNGRUUDoWWBo21zZ6VoZWxsb6NzaWeRxHb/
RzBFAiBSpsU9BM3tcsK+7lAFUdgOiHsZlvw90gwM9mKIMtMVvQIhAM4K0Qn6jgm8
2czyso2LupaosplS6eJ7Su2jpxMujOj7AiECsZEvq6gPzs0qZMV0/v5CLGEQYAHs
WIrxvZ11SLgQZMsBCAAAAWbLT2+ko3ZlcgI=

The same transaction shown as hex dump:

# 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

The transaction container is a MessagePack fixmap (shown as JSON-like format, binary data shown as hex dump):

{
  "body":
      c45087a16b10a166c4088000200002000003a2746fc4088000200002000005a1
      73cf0005798a2e4c1930a174cf00000166cb4f6fa4a170929300a2534b119301
      a346454503a16581a36d7367a568656c6c6f,

  "sig":
      ff473045022052a6c53d04cded72c2beee500551d80e887b1996fc3dd20c0cf6
      628832d315bd022100ce0ad109fa8e09bcd9ccf2b28d8bba96a8b29952e9e27b
      4aeda3a7132e8ce8fb022102b1912faba80fcecd2a64c574fefe422c61106001
      ec588af1bd9d7548b81064cb010800000166cb4f6fa4,

  "ver": 2
}

Here is the transaction body with comments:

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

Here is the sig value with comments:

# 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
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.