Safe Haskell | None |
---|---|
Language | Haskell2010 |
Schema for the ledger
Synopsis
- data AccountState = AccountState {}
- type AccountStateId = Key AccountState
- data PendingSendBlock = PendingSendBlock {}
- type PendingSendBlockId = Key PendingSendBlock
- data BlockHeader = BlockHeader {}
- type BlockHeaderId = Key BlockHeader
- data OpenBlock = OpenBlock {
- openBlockHeaderId :: !(Key BlockHeader)
- openBlockSourceId :: !(Key BlockHeader)
- openBlockBalance :: !Amount
- type OpenBlockId = Key OpenBlock
- data SendBlock = SendBlock {
- sendBlockHeaderId :: !(Key BlockHeader)
- sendBlockPreviousId :: !(Key BlockHeader)
- sendBlockDestination :: !Account
- sendBlockBalance :: !Amount
- type SendBlockId = Key SendBlock
- data ReceiveBlock = ReceiveBlock {
- receiveBlockHeaderId :: !(Key BlockHeader)
- receiveBlockPreviousId :: !(Key BlockHeader)
- receiveBlockSourceId :: !(Key BlockHeader)
- receiveBlockBalance :: !Amount
- type ReceiveBlockId = Key ReceiveBlock
- data ChangeBlock = ChangeBlock {
- changeBlockHeaderId :: !(Key BlockHeader)
- changeBlockPreviousId :: !(Key BlockHeader)
- type ChangeBlockId = Key ChangeBlock
- migrateData :: Migration
Documentation
data AccountState #
A bit of elucidation of the decisions made during the design of this schema:
Account
is really just a PublicKey, which is a 32 byte blob. AccountState
has a unique constraint on the Account
value, since it uniquely identifies
each account. At the same time AccountState
has an 8 byte primary key which
is an Int64 and is much more efficient for lookups than blobs. So reusing the
AccounState
as a foreign key in all of the blocks we achieve three things:
- Deduplication of data (each block stores at least 48 bytes less data: (32-8)*2) and we gonna have a lot of blocks
- Ensure that sql queries are faster since indexing and serializing integers is faster than binary blobs. Negative affect will be on the retrieval of blocks, since queries will span more tables, which will only affect the block explorer and we don't need to optimize it as much as the blockchain state update during the actual node operation.
- Most importantly, enforcement of consistency, having a foreign key on
AccountState
ensures that the referenced account indeed exists on the- blockchain. So for example it is impossible to set a representative to some
- bogus account address.
Last point leads up to the reason why we use Account
in the SendBlock
's
destination instead of AccountStateId
When somebody creates a SendBlock
, the receiver of the money might never
exist. Until a matching OpenBlock
is created the referenced account is not
known to the blockchain. A good example would be the burn account with
address set to all zeros. It can never be opened, but anyone can send money
into that account address. That is why we can't have a foreign key onto the
AccountState
in SendBlock
's destination
and in PendingSendBlock
's
destination
fields.
Representative is optional for older block types Send
and Change
from the
Protocol
. For these blocks representative will point to the same account as
the previous block in the account chain (i.e. no representative change).
Basically will do the same thing as the State
block does for such block
types. State
block type, on the other hand, MUST have the representative
field for all block types in emulates. In other words it is required for the
state block the representative
field to NOT be a Maybe
.
Instances
type AccountStateId = Key AccountState #
data PendingSendBlock #
Instances
type PendingSendBlockId = Key PendingSendBlock #
data BlockHeader #
Instances
type BlockHeaderId = Key BlockHeader #
OpenBlock | |
|
Instances
type OpenBlockId = Key OpenBlock #
SendBlock | |
|
Instances
type SendBlockId = Key SendBlock #
data ReceiveBlock #
ReceiveBlock | |
|
Instances
type ReceiveBlockId = Key ReceiveBlock #
data ChangeBlock #
ChangeBlock | |
|
Instances
type ChangeBlockId = Key ChangeBlock #
migrateData :: Migration #