Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove segment pointers #84

Merged
merged 2 commits into from
Mar 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 69 additions & 99 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,52 +97,48 @@ there must be a strict serialization rules. This rules are formed by the data st

```javascript
let type = Exonum.newType({
size: 12,
fields: {
balance: {type: Exonum.Uint32, size: 4, from: 0, to: 4},
name: {type: Exonum.String, size: 8, from: 4, to: 12}
}
fields: [
{ name: 'balance', type: Exonum.Uint32 },
{ name: 'name', type: Exonum.String }
]
})
```

**Exonum.newType** function requires a single argument of `Object` type with next structure:

| Property | Description | Type |
|---|---|---|
| **size** | The total length in bytes. | `Number` |
| **fields** | List of fields. | `Object` |
| **fields** | List of fields. | `Array` |

Field structure:

| Field | Description | Type |
|---|---|---|
| **type** | Definition of the field type. | [Built-in type](#built-in-types), [array](#arrays) or [custom data type](#nested-data-types) defined by the developer. |
| **size** | Total length of the field in bytes. | `Number` |
| **from** | The beginning of the field segment in the byte array. | `Number` |
| **to** | The end of the field segment in the byte array. | `Number` |
| **name** | Field name. | `String` |
| **type** | Definition of the field type. | [Built-in type](#built-in-types), [array](#arrays) or [custom data type](#nested-data-types) defined by the developer. |

### Built-in types

There are several primitive types are built it into the library.
These types must be used when constructing custom data types.

| Name | Size | Description | Type |
|---|---|---|---|
| **Int8** | 1 | Number in a range from `-128` to `127`. | `Number` |
| **Int16** | 2 | Number in a range from `-32768` to `32767`. | `Number` |
| **Int32** | 4 | Number in a range from `-2147483648` to `2147483647`. | `Number` |
| **Int64** | 8 | Number in a range from `-9223372036854775808` to `9223372036854775807`. | `Number` or `String`\* |
| **Uint8** | 1 | Number in a range from `0` to `255`. | `Number` |
| **Uint16** | 2 | Number in a range from `0` to `65535`. | `Number` |
| **Uint32** | 4 | Number in a range from `0` to `4294967295`. | `Number` |
| **Uint64** | 8 | Number in a range from `0` to `18446744073709551615`. | `Number` or `String`\* |
| **Float32** | 4 | Floating point number in a range from `-3.40282347e+38f32` to `3.40282347e+38f32`. | `Number` or `String`\* |
| **Float64** | 8 | Floating point number in a range from `-1.7976931348623157e+308f64` to `1.7976931348623157e+308f64`. | `Number` or `String`\* |
| **String** | 8\*\* | A string of variable length consisting of UTF-8 characters. | `String` |
| **Hash** | 32 | Hexadecimal string. | `String` |
| **PublicKey** | 32 | Hexadecimal string. | `String` |
| **Digest** | 64 | Hexadecimal string. | `String` |
| **Bool** | 1 | Value of boolean type. | `Boolean` |
| Name | Description | Type |
|---|---|---|
| **Int8** | Number in a range from `-128` to `127`. | `Number` |
| **Int16** | Number in a range from `-32768` to `32767`. | `Number` |
| **Int32** | Number in a range from `-2147483648` to `2147483647`. | `Number` |
| **Int64** | Number in a range from `-9223372036854775808` to `9223372036854775807`. | `Number` or `String`\* |
| **Uint8** | Number in a range from `0` to `255`. | `Number` |
| **Uint16** | Number in a range from `0` to `65535`. | `Number` |
| **Uint32** | Number in a range from `0` to `4294967295`. | `Number` |
| **Uint64** | Number in a range from `0` to `18446744073709551615`. | `Number` or `String`\* |
| **Float32** | Floating point number in a range from `-3.40282347e+38f32` to `3.40282347e+38f32`. | `Number` or `String`\* |
| **Float64** | Floating point number in a range from `-1.7976931348623157e+308f64` to `1.7976931348623157e+308f64`. | `Number` or `String`\* |
| **String** | A string of variable length consisting of UTF-8 characters. | `String` |
| **Hash** | Hexadecimal string. | `String` |
| **PublicKey** | Hexadecimal string. | `String` |
| **Digest** | Hexadecimal string. | `String` |
| **Bool** | Value of boolean type. | `Boolean` |

*\*JavaScript limits minimum and maximum integer number.
Minimum safe integer in JavaScript is `-(2^53-1)` which is equal to `-9007199254740991`.
Expand All @@ -151,38 +147,28 @@ For unsafe numbers out of the safe range use `String` only.
To determine either number is safe use built-in JavaScript function
[Number.isSafeInteger()][is-safe-integer].*

*\*\*Size of 8 bytes is due to the specifics of string [serialization][docs:architecture:serialization:segment-pointers]
using segment pointers.
Actual string length is limited only by the general message size limits which is depends on OS, browser and
hardware configuration.*

### Nested data types

Custom data type defined by the developer can be a field of other custom data type.

A nested type, regardless of its real size, always takes **8 bytes** in the parent type due to the specifics of its
[serialization][docs:architecture:serialization:segment-pointers] using segment pointers.

An example of a nested type:

```javascript
// Define a nested data type
let date = Exonum.newType({
size: 4,
fields: {
day: {type: Exonum.Uint8, size: 1, from: 0, to: 1},
month: {type: Exonum.Uint8, size: 1, from: 1, to: 2},
year: {type: Exonum.Uint16, size: 2, from: 2, to: 4}
}
fields: [
{ name: 'day', type: Exonum.Uint8 },
{ name: 'month', type: Exonum.Uint8 },
{ name: 'year', type: Exonum.Uint16 }
]
})

// Define a data type
let payment = Exonum.newType({
size: 16,
fields: {
date: {type: date, size: 8, from: 0, to: 8},
amount: {type: Exonum.Uint64, size: 8, from: 8, to: 16}
}
fields: [
{ name: 'date', type: date },
{ name: 'amount', type: Exonum.Uint64 }
]
})
```

Expand All @@ -197,27 +183,21 @@ in the Rust language.

| Property | Description | Type |
|---|---|---|
| **size** | Length of the nested field type. | `Number` |
| **type** | Definition of the field type. | [Built-in type](#built-in-types), array or [custom data type](#nested-data-types) defined by the developer. |

An array, regardless of its real size, always takes **8 bytes** in the parent type due to the specifics of its
[serialization][docs:architecture:serialization:segment-pointers] using segment pointers.

An example of an array type field:

```javascript
// Define an array
let year = Exonum.newArray({
size: 2,
type: Exonum.Uint16
})

// Define a data type
let type = Exonum.newType({
size: 8,
fields: {
years: {type: year, size: 8, from: 0, to: 8}
}
fields: [
{ name: 'years', type: year }
]
})
```

Expand All @@ -226,22 +206,19 @@ An example of an array nested in an array:
```javascript
// Define an array
let distance = Exonum.newArray({
size: 4,
type: Exonum.Uint32
})

// Define an array with child elements of an array type
let distances = Exonum.newArray({
size: 8,
type: distance
})

// Define a data type
let type = Exonum.newType({
size: 8,
fields: {
measurements: {type: distances, size: 8, from: 0, to: 8}
}
fields: [
{ name: 'measurements', type: distances }
]
})
```

Expand All @@ -268,13 +245,12 @@ An example of serialization into a byte array:
```javascript
// Define a data type
let user = Exonum.newType({
size: 21,
fields: {
firstName: {type: Exonum.String, size: 8, from: 0, to: 8},
lastName: {type: Exonum.String, size: 8, from: 8, to: 16},
age: {type: Exonum.Uint8, size: 1, from: 16, to: 17},
balance: {type: Exonum.Uint32, size: 4, from: 17, to: 21}
}
fields: [
{ name: 'firstName', type: Exonum.String },
{ name: 'lastName', type: Exonum.String },
{ name: 'age', type: Exonum.Uint8 },
{ name: 'balance', type: Exonum.Uint32 }
]
})

// Data to be serialized
Expand Down Expand Up @@ -319,13 +295,12 @@ An example of hash calculation:
```javascript
// Define a data type
let user = Exonum.newType({
size: 21,
fields: {
firstName: {type: Exonum.String, size: 8, from: 0, to: 8},
lastName: {type: Exonum.String, size: 8, from: 8, to: 16},
age: {type: Exonum.Uint8, size: 1, from: 16, to: 17},
balance: {type: Exonum.Uint32, size: 4, from: 17, to: 21}
}
fields: [
{ name: 'firstName', type: Exonum.String },
{ name: 'lastName', type: Exonum.String },
{ name: 'age', type: Exonum.Uint8 },
{ name: 'balance', type: Exonum.Uint32 }
]
})

// Data that has been hashed
Expand Down Expand Up @@ -399,13 +374,12 @@ An example of data signing:
```javascript
// Define a data type
let user = Exonum.newType({
size: 21,
fields: {
firstName: {type: Exonum.String, size: 8, from: 0, to: 8},
lastName: {type: Exonum.String, size: 8, from: 8, to: 16},
age: {type: Exonum.Uint8, size: 1, from: 16, to: 17},
balance: {type: Exonum.Uint32, size: 4, from: 17, to: 21}
}
fields: [
{ name: 'firstName', type: Exonum.String },
{ name: 'lastName', type: Exonum.String },
{ name: 'age', type: Exonum.Uint8 },
{ name: 'balance', type: Exonum.Uint32 }
]
})

// Data to be signed
Expand Down Expand Up @@ -453,13 +427,12 @@ An example of signature verification:
```javascript
// Define a data type
let user = Exonum.newType({
size: 21,
fields: {
firstName: {type: Exonum.String, size: 8, from: 0, to: 8},
lastName: {type: Exonum.String, size: 8, from: 8, to: 16},
age: {type: Exonum.Uint8, size: 1, from: 16, to: 17},
balance: {type: Exonum.Uint32, size: 4, from: 17, to: 21}
}
fields: [
{ name: 'firstName', type: Exonum.String },
{ name: 'lastName', type: Exonum.String },
{ name: 'age', type: Exonum.Uint8 },
{ name: 'balance', type: Exonum.Uint32 }
]
})

// Data that has been signed
Expand Down Expand Up @@ -503,12 +476,11 @@ let sendFunds = Exonum.newMessage({
protocol_version: 0,
service_id: 130,
message_id: 128,
size: 72,
fields: {
from: {type: Exonum.Hash, size: 32, from: 0, to: 32},
to: {type: Exonum.Hash, size: 32, from: 32, to: 64},
amount: {type: Exonum.Uint64, size: 8, from: 64, to: 72}
}
fields: [
{ name: 'from', type: Exonum.Hash },
{ name: 'to', type: Exonum.Hash },
{ name: 'amount', type: Exonum.Uint64 }
]
})
```

Expand All @@ -521,8 +493,7 @@ let sendFunds = Exonum.newMessage({
| **service_id** | [Service ID][docs:architecture:serialization:service-id]. | `Number` |
| **message_id** | [Message ID][docs:architecture:serialization:message-id]. | `Number` |
| **signature** | Signature as hexadecimal string. *Optional.* | `String` |
| **size** | The total length in bytes. | `Number` |
| **fields** | List of fields. | `Object` |
| **fields** | List of fields. | `Array` |

Field structure is identical to field structure of [custom data type](#define-data-type).

Expand Down Expand Up @@ -713,7 +684,6 @@ Exonum Client is licensed under the Apache License (Version 2.0). See [LICENSE](
[docs:clients]: https://exonum.com/doc/architecture/clients
[docs:architecture:services]: https://exonum.com/doc/architecture/services
[docs:architecture:serialization]: https://exonum.com/doc/architecture/serialization
[docs:architecture:serialization:segment-pointers]: https://exonum.com/doc/architecture/serialization/#segment-pointers
[docs:architecture:serialization:network-id]: https://exonum.com/doc/architecture/serialization/#etwork-id
[docs:architecture:serialization:protocol-version]: https://exonum.com/doc/architecture/serialization/#protocol-version
[docs:architecture:serialization:service-id]: https://exonum.com/doc/architecture/serialization/#service-id
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "exonum-client",
"version": "0.5.0",
"version": "0.6.0",
"description": "Light Client for Exonum Blockchain",
"main": "./lib/index.js",
"engines": {
Expand Down
45 changes: 21 additions & 24 deletions src/blockchain/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,21 @@ const PROTOCOL_VERSION = 0
const CORE_SERVICE_ID = 0
const PRECOMMIT_MESSAGE_ID = 4
const Block = newType({
size: 112,
fields: {
schema_version: { type: primitive.Uint16, size: 2, from: 0, to: 2 },
proposer_id: { type: primitive.Uint16, size: 2, from: 2, to: 4 },
height: { type: primitive.Uint64, size: 8, from: 4, to: 12 },
tx_count: { type: primitive.Uint32, size: 4, from: 12, to: 16 },
prev_hash: { type: primitive.Hash, size: 32, from: 16, to: 48 },
tx_hash: { type: primitive.Hash, size: 32, from: 48, to: 80 },
state_hash: { type: primitive.Hash, size: 32, from: 80, to: 112 }
}
fields: [
{ name: 'schema_version', type: primitive.Uint16 },
{ name: 'proposer_id', type: primitive.Uint16 },
{ name: 'height', type: primitive.Uint64 },
{ name: 'tx_count', type: primitive.Uint32 },
{ name: 'prev_hash', type: primitive.Hash },
{ name: 'tx_hash', type: primitive.Hash },
{ name: 'state_hash', type: primitive.Hash }
]
})
const SystemTime = newType({
size: 12,
fields: {
secs: { type: primitive.Uint64, size: 8, from: 0, to: 8 },
nanos: { type: primitive.Uint32, size: 4, from: 8, to: 12 }
}
fields: [
{ name: 'secs', type: primitive.Uint64 },
{ name: 'nanos', type: primitive.Uint32 }
]
})

/**
Expand Down Expand Up @@ -63,19 +61,18 @@ export function verifyBlock (data, validators, networkId) {
}

const Precommit = newMessage({
size: 90,
network_id: networkId,
protocol_version: PROTOCOL_VERSION,
message_id: PRECOMMIT_MESSAGE_ID,
service_id: CORE_SERVICE_ID,
fields: {
validator: { type: primitive.Uint16, size: 2, from: 0, to: 2 },
height: { type: primitive.Uint64, size: 8, from: 2, to: 10 },
round: { type: primitive.Uint32, size: 4, from: 10, to: 14 },
propose_hash: { type: primitive.Hash, size: 32, from: 14, to: 46 },
block_hash: { type: primitive.Hash, size: 32, from: 46, to: 78 },
time: { type: SystemTime, size: 12, from: 78, to: 90 }
}
fields: [
{ name: 'validator', type: primitive.Uint16 },
{ name: 'height', type: primitive.Uint64 },
{ name: 'round', type: primitive.Uint32 },
{ name: 'propose_hash', type: primitive.Hash },
{ name: 'block_hash', type: primitive.Hash },
{ name: 'time', type: SystemTime }
]
})

const validatorsTotalNumber = validators.length
Expand Down
Loading