Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: exponent to precision, minor fixes


Priority

Status
colourRed
titleMUST

Type of change request

Status
subtletrue
colourGreen
titleFEATURE

Epic link
Status

Status
subtletrue
titleDRAFT

Target release



Glossary

  • quantity - an entity of Iroha state that is used to measure assets
  • floating point notation - a representation of a rational number N  in a predefined range with fixed relative precision: N = K * 10e, where K and e are some integer numbers from a fixed range.
  • significand - the K number in floating point notationexponent
  • precision - the number p  equal to -e number in floating point notation and to the number of rightmost digits of significand that form the decimal fractional part (separator position)
  • uint256 - integer type with range from 0 to 2256

Vision

Current state

Iroha model has Asset entity, which is measured by quantity. The quantity is a floating point number with the following constraints:

  • significand: 0 < K  < 2256
  • exponent: -256 < e  ≤ 0precision: 0  ≤ p < 256

Iroha has several commands that include asset quantity specification:

  • AddAssetQuantity
  • SubtractAssetQuantity
  • TransferAsset

and a query that contains asset quantity in response:

  • GetAccountAssets

Also there are ways of retrieving submitted transactions that can include the commands listed above (that contain asset quantity):

  • GetBlock
  • FetchCommits
  • GetPendingTransactions

In all of them the asset quantity is represented as a string, while it semantically means a floating point number.

The API of Iroha uses Protocol Buffers, which built-in integer types are capable of representing numbers up to 264.

Problem statement

Using the string representation of floating point number causes several problems:

  • what are the valid forms of number representation (consider 000.0000 - is it a valid quantity?)
  • quantities equality (01 seems equal to 1.0 , but the strings differ)
  • parsing strings into numbers (we have the significand limit of 2256 which is larger than c++ standard types allow, and we used regular expressions to parse them, which seems a poor architectural decision)
  • overflow detection - it just gets undetected now

Solution Criteria

  • each valid number (see current state) is represented in exactly one way
  • simple parsing
  • convenient API

Choosing a solution

Using integers

Description:

All the described problems proceed from representing a floating point number as a string. So one approach consists in changing the representation of asset quantity to integers. Inside Iroha we already use a 256-bit integer type, so the transition will be comfortable. But protobuf does not support such large integers, which implies some tricks. For example, we can create the following protobuf message to represent uint256:

Code Block
message Uint256le {
	uint64 i0 = 1;
	uint64 i1 = 2;
	uint64 i2 = 3;
	uint64 i3 = 4;
}
message Quantity {
	Uint256le significand = 1;
	uint32 exponentprecision = 2;
}

The conversion is done like little-endian number (de)serialization.

Code Block
n = i0 + i1 << 64 + i2 << 64^2 + i3 << 64^3


Code Block
i0 = n
i1 = n << 64
i2 = n << 64^2
i3 = n << 64^3

Pros:

  • conversion rules are very straightforward
  • invalid quantity is almost impossible to create (the only exception is out-of-range exponent precision, but all other approaches also suffer from that)
  • memory efficiency
  • best CPU efficiency (fast single-pass conversion)

Cons:

  • manual protobuf  (de)serialization with bit shifting
  • additional protobuf message type for uint256

Using string & integer

Description:

We can simplify the representation by moving the exponent precision part out of the string into an integer. significand  is left in string representation, but we need less complicated rules and parsing algorithm for that string.

Code Block
message Quantity {
	string significand = 1;
	uint32 exponentprecision = 2;
}

The rules for significand string:

  • only decimal digits are allowed
  • number range limit

There is a tricky part in dealing with range limit. The boost multiprecision library uint256  type that we use now will not report does not provide overflow detection when parsing a string. So a KISS approach would be:

  1.  first char is zero → error
  2. length exceeds 78 → error
  3. length is exactly 78 and the most significant digit is greater than 1 → error
  4. length is exactly 78 and parsed number is less than 1078 → error (the largest number possible after overflow is 2 * 1078 - 1 - 2256 < 1078)

These rules guarantee the 1-to-1 mapping between uint256 and any valid quantity.

Pros:

  • simple protobuf API
  • good CPU efficiency (fast string checks)

Cons:

  • worst memory efficiency (1 string + 1 32-bit int)
  • dark byte magics for efficient overflow detection

Staying with a string

Description:

We still can stay with a single string to represent a quantity, while improving the rules and parsing algorithms to satisfy the solution criteria. Possible algorithm of string validation:

  • first chat is zero → error
  • any char is not digit or decimal separator → error
  • more than one decimal separators → error
  • last char is decimal separator → error
  • there is a decimal separator and the last char is zero → error
  • the string with decimal separator removed does not pass overflow test (see the algorithm above) → error

Pros:

  • no changes to API structure

Cons:

  • dealing with the string becomes very tricky - harder to guarantee reliable bugprone operation
  • bad memory and CPU efficiency
  • the format of the number representation is not very intuitive, because most interpreters that we got used to do not provide 1-to-1 mapping, so the API users will have to struggle with the rules we define for the string.

Functional details

Environmental objectives: None

Changelog 

#Change descriptionAffected componentChange motivationDependency (optional)
1What is changedWhere it is changed

Why it is done


After #1

Before #1

etc.

Research strategy

#Research activityDetailsAcceptance criteriaResponsible (accepter) 
1



Documentation effort

#Target readerDocumentation description
1

QA activity


#Validation activityIntentionActionsExpected result 
1TestingTest component X and check if …

Given X,

When Y

AND

When Y1

Then Z

OR

Then Z1

Tasks

Jira
serverHyperledger JIRA
columnskey,summary,type,created,updated,due,assignee,reporter,priority,status,resolution
maximumIssues20
jqlQueryProject = IR
serverId6326cb0b-65b2-38fd-a82c-67a89277103b



Template data

Priorities 

Status
colourRed
titleMUST
 
Status
colourYellow
titleSHOULD
 
Status
colourGreen
titleCOULD
 
Status
colourGrey
titleWON't

Change request type 

Status
subtletrue
colourYellow
titleFeature
 
Status
subtletrue
colourRed
titleBuG FIX

Status 

Status
subtletrue
colourGrey
titleBACKLOG
 
Status
subtletrue
colourBlue
titleWORK IN PROGRESS
 
Status
subtletrue
colourGreen
titleDONE