THIS IS OUTDATED INFORMATION GO HERE > https://github.com/xaya/xaya/tree/master/doc/xaya
The main interface of the Bitcoin Core daemon is through the various provided JSON RPC methods as well as ZeroMQ for notifications.
Xaya inherits these interfaces. However, Xaya focuses on providing the backbone for individual game engines. Thus it makes sense to also provide an additional interface that is optimised for this purpose, tailored specifically for the Xaya game model.
For sending moves to the daemon (the "write" side of the interface), the basic RPC methods inherited and adapted from Namecoin should be used:
$ name_register p/name {}
$ name_update p/name {"g":{"chess":"e4"}}
$ name_update p/name {} {"destAddress":"CaQb9k5Amibwjuhbfd4bqdwycBMK95Mw8n"}
The most important and fundamental task of each game engine is to keep the current game state updated with the Xaya blockchain. For this, it must process moves from attached and detached blocks as discussed in the Xaya game model.
The Xaya daemon provides ZeroMQ publishers for attached and detached blocks. They provide subscribers with all the required information to update game states.
For this, the daemon can be configured to track a list of game IDs.
These are all the games that the user is running. Then, for each block
that is attached to the blockchain and each tracked game, the daemon sends
out a game-block-attach
message that contains all the information
necessary for the corresponding game engine to step forward in time.
For the actual message, we reuse the multi-part format introduced by Bitcoin Core's ZeroMQ interface. In particular, the message is a ZeroMQ multipart message of the following format:
game-block-attach json GAMEID|DATA|SEQ
Here, |
denotes the boundary between distinct message parts. The first
part is the command string. It allows each game engine to subscribe to
game-block-attach json GAMEID
in order to receive exactly the updates relevant to it.
json
denotes the format that is used; JSON is the only available format
for now, but more might be defined in the future.
SEQ
is a sequence number encoded as little-endian 32-bit integer, which
counts the number of messages sent already for a particular command string
(including the game ID). This allows receivers to detect missed messages.
The DATA
part, finally, is a JSON object with the relevant information:
{
"block":
{
"hash": ATTACHED-BLOCK-HASH,
"parent": PREVIOUS-BLOCK-HASH,
"height": BLOCK-HEIGHT,
"timestamp": BLOCK-TIME,
"rngseed": RNG-SEED,
},
"cmd": ADMIN-COMMAND,
"moves":
[
{
"txid": TXID,
"name": UPDATED-NAME,
"move": MOVE,
"out":
{
ADDRESS1: AMOUNT1,
ADDRESS2: AMOUNT2,
...
},
},
...
],
}
The placeholders have the following meaning:
ATTACHED-BLOCK-HASH
: The hash of the newly-attached block, i.e. the block that contains all the moves listed below.PREVIOUS-BLOCK-HASH
: The hash of the previously-current block, i.e. the block on top of which the new one is attached.RNG-SEED
,BLOCK-HEIGHT
andBLOCK-TIME
: Additional data about the attached block, which might be used by the game engine in the update logic.ADMIN-COMMAND
: If the block contains an update the name game'sg/
name, then this field is set to the game-specific admin command specified with that update.TXID
: The Xaya transaction ID of the transaction that performed the given move. This is mostly useful as a key and to correlate a single transaction through different endpoints of the API (if necessary).UPDATED-NAME
: The account name that performed a move, without thep/
prefix.MOVE
: The actual move data, as it is given in.g[GAMEID]
of the name update's value.ADDRESS
n andAMOUNT
n: Xaya addresses and amounts that were transacted in the move transaction, as described in the model for currency transaction in games.
Note that not all transactions from the block are included in the moves
list.
It contains only those that are relevant for the current game, which are
all name updates and registrations that mention the game ID in their value.
Similarly, the daemon also provides a game-block-detach
message for blocks
that are detached during a reorg:
game-block-detach json GAMEID|DATA|SEQ
In this message, DATA
is exactly the same data that was sent previously
when the same block was attached. This means that DATA.hash
is the hash
of the block being detached and DATA.parent
is the block that will be current
after the detachment.
The game engine must undo the
block by either restoring the game state corresponding to DATA.parent
from its archive, or backwards-processing DATA.moves
to go from the
game state of DATA.hash
back to that of DATA.parent
.
The typical mode of operation is that the game engine's current state
corresponds to the tip of the current Xaya blockchain. In this case,
whenever a new block comes in and game-block-attach
is published,
DATA.parent
equals the block associated with the current game state.
Similarly, for game-block-detach
during a reorg, DATA.hash
is exactly
the block hash for the current game state.
For these cases, the game engine can simply process the incoming message to update its game state accordingly. This allows it to keep up-to-date with the Xaya blockchain in real time.
NOTE: Notifications sent because of genuine changes in the best chain
will not contain a reqtoken
field (unlike notifications that were
explicitly requested). Notifications with a reqtoken
field should normally be ignored unless they were explicitly requested!
However, the current state of an engine may go out-of-sync with the Xaya daemon. This could be because the game engine was not running for some time even though the daemon was, and it missed some block attach and detach operations. This situation also occurs when the engine for a new game is installed and attached to the Xaya daemon for the first time and needs to do an initial sync.
If the game engine determines it is out-of-sync (for instance, because it
received a game-block-attach
message with a DATA.parent
block hash that
does not match its game state), it can explicitly request the updates it needs
to be resent through RPC:
$ game_sendupdates GAMEID FROM-BLOCK [TO-BLOCK]
FROM-BLOCK
should be the block hash that is associated with its current game
state (it can be the genesis block, known to correspond to an initial game
state, for a full sync). If given, TO-BLOCK
is the block hash that the
game wants to update to; it can be omitted, in which case it is assumed to be
the current tip of the blockchain.
If the Xaya daemon knows both block hashes and there is a sequence of block
attachments and detachments that bring FROM-BLOCK
to TO-BLOCK
, the RPC will
immediately return success and trigger sending those updates
in the background (through the same game-block-attach
and game-block-detach
notifications that would be sent during
normal operation).
The RPC itself will return a JSON object that contains various information
about the updates that have been triggered. In particular, these fields
will be returned:
toblock
: The hash of the target block to which notifications have been triggered. This will be some block hash "between"FROM-BLOCK
andTO-BLOCK
(if it was set) or the current best tip.ancestor
: The block hash of the last common ancestor ofFROM-BLOCK
andTO-BLOCK
. This can be useful for game engines to decide whether to roll the detached blocks backwards or instead look up a cached game state for the common ancestor and only process all attached blocks forward from there on.reqtoken
: A unique string for this request, which will be included in thereqtoken
field of all notifications triggered as a result of this call. This can be used to distinguish notifications that are sent due to changes in the best chain (which won't have areqtoken
field) from notifications sent due to thisgame_sendupdates
call.
If the requested block hashes are unknown or no valid sequence can be found, the RPC returns an error. In that case, the game engine can try to recover by requesting updates from an older state that it has in its archive, or by syncing from scratch in the worst case.
For cases where the sequence of updates for the full request is very long
(e.g. when a game is synced from scratch), Xaya Core may decide to send only
a part of the updates. In that case, the value of toblock
returned from
the RPC indicates to which target block updates have been triggered. Once
those have been received, the game daemon should send another game_sendupdates
request for the remaining blocks and continue to do so until it has arrived
at its desired target block.
NOTE: After sending a game_sendupdates
request, a game engine should only
process notifications with the corresponding reqtoken
until it is up-to-date
with the returned toblock
. From then on, it can resume
normal operation.
A special case is that of a completely new game, which did not exist before a certain block. In this case, the game engine can hardcode a block hash known to be before the start of the game, so that it only requests updates from that block onwards on the initial sync. This avoids processing potentially years of old blocks known to be irrelevant.
The Xaya daemon can partially optimise this process itself:
For all blocks that are requested and known to be before the game's g/
name
was registered, it can just send a message without any moves. This makes
it possible to create the messages just from the in-memory tree of block headers
without the need to load and process full blocks from disk.
(However, this requires the daemon to keep a record of the registration of each
game ID. It can only be enabled if -namehistory
is turned on, because then
this information is readily available.)
Besides updating the game state itself, games engines where users can actively play will likely also need to know which names the user owns, i.e. has the private keys for in their wallet. This can also change, as names can be sent to or from the user's wallet. Thus, it is necessary to provide also an interface that allows game engines to inquire and stay up-to-date with the list of the user's names.
The Xaya daemon's interface provides two complementary methods for this.
First, the RPC method name_list
inherited from Namecoin can be used to
request the full list of names owned by the user. This allows the game
to get up-to-date immediately, for instance, at startup.
(Also name_pending
may be relevant to inquire about pending operations
in the node's mempool.)
Second, the daemon exposes the player-ownership
ZeroMQ publisher that
gets notified whenever any p/
name changes its ownership status.
(This means that it was previously owned by the wallet and now it isn't,
or that it was not owned before and is now associated with
an address in the wallet.
It does not include address changes of any name, as this would be almost
every name update in the blockchain.)
Whenever a name update changes the ownership status of a name or a new name
owned by the wallet is registered, one of the following notifications is sent:
player-ownership json pending|DATA|SEQ
player-ownership json confirmed|DATA|SEQ
The "pending" notification is sent as soon as a relevant unconfirmed
transaction is seen, e.g. added to the mempool. The "confirmed" notification
is sent when an ownership change has been confirmed. The DATA
value is
a string encoding a JSON object of the following form:
{
"txid": TXID,
"name": NAME,
"state": STATE,
}
The placeholders have the following meaning:
TXID
: The Xaya transaction ID of the name update.NAME
: The account name that changed ownership, without thep/
prefix.STATE
: A string indicating the name's state. This can be"own"
,"foreign"
or"unregistered
"."own"
indicates that the wallet holds the key for this name."foreign"
means that the name is not owned by the wallet."unregistered
" is for special situations during a reorg (see below).
If a name update changes ownership, typically first a
player-ownership pending
notification will be sent when the transaction
is added to the mempool. Later, when it is confirmed, a matching
player-ownership confirmed
is sent. It may, however, happen that the
transaction is only seen in the block confirming it, in which case only the
"confirmed" notification occurs.
When a block containing such a transaction is detached during a reorg,
a player-ownership confirmed
notification is sent for the previous
ownership state; if the initial registration of the name is detached, the
state will be "unregistered"
. If the now-unconfirmed name transaction
is re-added to the mempool, a matching player-ownership pending
notification
(for the new state) is also sent.
Games may also want to be notified about moves as soon as possible, even
if they are still unconfirmed. This allows them to show, for instance,
a "forecast" of what other players will likely do in the future.
For this, the game-pending-move
ZeroMQ publisher is exposed. Whenever
a name operation referencing a game is added to the mempool (including when
it is re-added after a block detach), the following notification is sent
for each tracked game:
game-pending-move json GAMEID|DATA|SEQ
DATA
is a description of the move in the same form as in the moves
array
for game-block-attach
notifications.