Blockchain Updates#
Blockchain Updates is a node extension that streams every change the chain goes through. Each block and microblock arrives with the balances, data entries, tokens, leases, scripts and aliases it changed, both before and after. When the node switches to another fork, a rollback event says exactly what to undo. An indexer, an explorer back end or a service that reacts to payments can follow the chain from one subscription, without polling the REST API.
Note
Verified against node-scala v1.8.0 on 2026-10-24: the extension’s source (grpc-server/src/main/scala/com/decentralchain/events/) and its schema, dcc/events/grpc/blockchain_updates.proto and dcc/events/events.proto in io.decentralchain:protobuf-schemas 1.6.6, the version node v1.8.0 builds against. The commands below were not run against a live node as part of this documentation pass.
When to Use It#
You need |
Use |
|---|---|
Current state: one balance, one data entry, one transaction |
The node REST API |
History and search: asset lists, past trades, paginated transactions |
The Data Service API |
Every state change, in order, as it happens, including rollbacks |
Blockchain Updates |
Run It on Your Own Node#
Important
There is no public Blockchain Updates endpoint. The public nodes do not expose port 6881 (see Node gRPC API). Run your own node, for example by following Join the Public Testnet, and enable the extension there.
The extension is part of the node’s grpc-server module, which the official Docker image already contains. For other installs, see Node Extensions. Enable it by adding its class to dcc.extensions in the node’s configuration file, inside the dcc { } block:
dcc {
# ... the rest of your configuration ...
extensions = [
"com.decentralchain.events.BlockchainUpdates"
# "com.decentralchain.api.grpc.GRPCServerExtension" # the other gRPC APIs on port 6870, if you also want them
]
}
With Docker, publish the port on the host’s loopback interface only, next to the other ports in the docker run command:
-p 127.0.0.1:6881:6881
Settings, under dcc.blockchain-updates:
Setting |
Default |
Meaning |
|---|---|---|
|
|
Port the API listens on |
|
|
Shortest interval at which a client may send keep-alive pings. A client that pings more often is disconnected |
|
|
Threads that serve subscriptions |
Warning
The extension listens on all network interfaces (0.0.0.0). Unlike the other gRPC APIs, it does not follow dcc.grpc.host, and it has no authentication. Keep port 6881 behind a firewall, or publish it only on 127.0.0.1 as above.
History Starts When You Enable It#
The extension keeps its own store in the blockchain-updates directory inside the node’s data directory, and it records only blocks the node processes while the extension is running. Plan for this:
Enable it before the node’s first sync if you need history from genesis. The extension starts before the genesis block is applied, so it records every block from height 1.
If you enable it on a node that has already synced, the extension logs a warning and starts recording from the next block. Earlier heights are not available from this node.
The same applies if the store falls behind the chain, for example after an unclean shutdown. The extension resets and resumes from the next block. A consumer then sees a gap and must fill it from another source.
If the store is ahead of the chain, the extension rolls it back to the node’s height at startup. If the two disagree about the last block, the node refuses to start with
Last update ID ... does not match last block ID. Deleting theblockchain-updatesdirectory clears that error, and recording then resumes from the next block.
The API#
The service is dcc.events.grpc.BlockchainUpdatesApi. It has three methods:
Method |
Request |
Returns |
|---|---|---|
|
|
The update for one height |
|
|
All updates in the range, in one response |
|
|
A stream: the stored updates from |
Rules the node enforces:
from_heightmust be at least 1. The schema’s comment calls it optional, but the default of 0 is rejected (fromHeight must be > 0).from_heightcannot be above the node’s current height.to_heightof 0, or noto_height, makesSubscriberun indefinitely. Otherwise the stream ends after that height.GetBlockUpdatefor the current height returns the block as it stands so far, with its microblocks merged in. A height above the current one is an error.GetBlockUpdatesRangereturns the whole range in one message, so keep ranges short. UseSubscribefor long stretches.
Try It with grpcurl#
The server supports gRPC reflection, so grpcurl v1.8.8 or later can call it with no .proto files. The connection is plaintext:
# The service list includes dcc.events.grpc.BlockchainUpdatesApi
grpcurl -plaintext 127.0.0.1:6881 list
# One block
grpcurl -plaintext -d '{"height": 1000}' \
127.0.0.1:6881 dcc.events.grpc.BlockchainUpdatesApi/GetBlockUpdate
# Heights 1000 to 1010, then the stream ends
grpcurl -plaintext -d '{"from_height": 1000, "to_height": 1010}' \
127.0.0.1:6881 dcc.events.grpc.BlockchainUpdatesApi/Subscribe
# From height 1000 onward, then follow the chain
grpcurl -plaintext -d '{"from_height": 1000}' \
127.0.0.1:6881 dcc.events.grpc.BlockchainUpdatesApi/Subscribe
grpcurl prints byte fields (block and transaction IDs, addresses, public keys) as base64. The REST API shows the same values in Base58, so decode and re-encode them to compare.
From Code#
Generate a client from the node’s own schema, dcc/events/grpc/blockchain_updates.proto and the files it imports. Its Maven Central artifact is io.decentralchain:protobuf-schemas:1.6.6 (classifier protobuf-src), and the same files are in the SDK monorepo under packages/sdk/protobuf-schemas. The TypeScript client @decentralchain/node-api-grpc wraps this API as mkBlockchainUpdatesApi, but it is not published yet; see Node gRPC API.
Warning
Do not generate a client from the .proto files in the published @decentralchain/protobuf-serialization 3.0.0 package. They still use the previous protobuf package names, so the client would request a service that a v1.8.0 node does not serve.
What an Update Contains#
Each message is a BlockchainUpdated with the block id and height and one of two bodies.
append, a block or a microblock was added:
Field |
Content |
|---|---|
|
The block (with |
|
The IDs of the transactions it contains, in order |
|
Per transaction: the sender’s address and, by type, resolved recipients, order details, or an invocation’s function, arguments, payments and result |
|
Changes made by the block itself, such as the block reward |
|
One state update per transaction, in the same order as |
rollback, blocks or microblocks were removed:
Field |
Content |
|---|---|
|
|
|
Transactions that are no longer on the chain |
|
The removed blocks |
|
The state to restore |
|
Features whose activation was undone |
A state update lists changed balances, leasing_for_address, data_entries, assets, individual_leases, scripts and deleted_aliases. Balances, leasing totals, data entries, token details and scripts carry their value before and after the change, so a consumer can apply or reverse them without looking anything up. A lease update carries only the lease’s new status, and a deleted alias only its name. referenced_assets on the outer message gives the name and decimals of every token the update mentions.
Writing a Reliable Consumer#
Store your position. After applying an update, save its
heightandid. To resume, subscribe from that height; the stream starts with that height again. If the first update’sidequals the stored one, skip it. If it differs, that height changed while you were away (it gained microblocks or was replaced on a fork), so revert what you applied for it before applying the new update.Treat microblocks as provisional. The block at the top of the chain grows microblock by microblock, and a
MICROBLOCKrollback can remove the most recent ones. Apply them, but be ready to undo them.Handle a rollback at any height. A fork switch rolls back recent blocks. An operator-forced rollback (
POST /debug/rollback, see Sync and Rollback) can reach further back, even below the finalized height. Undo usingrollback_state_updateand continue with the next append.Keep up. The node buffers at most 250 updates for each subscriber. If a client falls that far behind, the node ends its stream, and the client must reconnect from its stored height.
Ping no more often than
min-keep-alive. Set the client’s keep-alive interval to 5 minutes or more, or the node disconnects it.