Nyzo techRelease notesNyzo 631: graffiti script

Nyzo 631: graffiti script

Nyzo version 631 (commit on GitHub) adds a client script to support the graffiti Micropay example.

This version affects the client.

In ClientDataManager, an additional exit condition was added for when the trusted entry points file is empty.

In the run loop, the frozen edge is passed to NyzoScriptManager.

RN_631 image 0

NyzoScriptCommand was added to CommandManager to make the command available in the client.

RN_631 image 1

The NyzoScriptCommand takes a single argument, the account identifier.

RN_631 image 2

The NyzoScriptCommand does not require validation or confirmation, and it is not long-running.

RN_631 image 3

The NyzoScriptCommand fetches the state of the script for the specified account. The state metadata is provided for HTML and console responses using a CommandTable passed to a SimpleExecutionResult. For an endpoint response, the full state is returned. This includes the same metadata as the HTML and console responses, along with the JSON or binary (encoded as Base64) state data.

RN_631 image 4

The GraffitiScript implements the behavior for the graffiti Micropay example. The graffiti wall is 288 pixels by 45 pixels, and the color and amount of each pixel is tracked.

For building the script mechanism, this particular script is included directly in the Java codebase. Eventually, we intend to allow all users to register scripts on the blockchain, at which time this script will be removed from the Java codebase and be a peer with all other Nyzo scripts.

RN_631 image 5

The update() method implements the NyzoScript interface. It receives the current state, if one is available, along with a list of transactions.

This implementation first ensures that the input data is in the expected format. This also handles a null input state properly.

RN_631 image 6

Pixel data is extracted from the transactions, and the pixels and amounts are set in the data arrays. The colors are indexes in a typical CGA 16-color palette. The amounts are the micronyzo amounts of the transaction that specified the color for a position. In order for a pixel to be updated, the amount of the transaction must be at least twice the current amount for the pixel.

RN_631 image 7

The bitStringForSenderData() method produces a String object that uses '0' and '1' characters to represent the bits of a byte array. This is helpful for processing input transactions, which utilize sub-byte divisions in encoding pixels.

RN_631 image 8

The NyzoScript interface defines a single method, update(). The inputs are a NyzoScriptState and list of transactions, and the output is a NyzoScriptState.

RN_631 image 9

The NyzoScriptManager is responsible for loading scripts, loading states, and storing states. While full tracking of processed blocks is not yet implemented, the height of the highest block processed is stored to avoid repeatedly attempting to process the same block.

RN_631 image 10

The registerScript() method adds a script to the script manager's map and, if necessary, generates an initial state for the script.

RN_631 image 11

The registerScripts() method registers all scripts with the manager. Currently, only the GraffitiScript is available.

The scriptForAccount() method provides a script, if available, for the requested account.

RN_631 image 12

The stateJsonStringForAccount() method reads the state, if available, that has been persisted for an account. The stateForAccount() method converts this to a NyzoScriptState object.

RN_631 image 13

The processBlock() method checks if a block is non-null and whether it is above the highest block processed. After processing, the height of the highest block processed is updated in PersistentData.

RN_631 image 14

The processBlockInternal() method builds a map of transactions based on transaction receiver. For each account receiving transactions for which a script is available, the state is loaded from file, the script is processed, and the updated state is written back to file.

RN_631 image 15

The stateFileForAccount() provides the file location where the state for an account is stored.

RN_631 image 16

The NyzoScriptState class structures the state for scripts. It stores the height at which the state was first created, the height at which the state was last updated, the type of data stored in the data array, whether the state contains any unconfirmed (not yet in blockchain) data, and the actual state data.

Two constructors are provided. A script should use the two-argument constructor, providing only the data and data type. The script manager uses the five-argument constructor, setting the state metadata.

RN_631 image 17

Accessors are provided for all fields.

RN_631 image 18

The renderJson() method serializes the state to a JSON string. The renderDataArrayJson() method provides a JSON-suitable representation of the data byte array.

RN_631 image 19

The fromJsonString() method deserializes a NyzoScriptState object from its JSON serialization.

RN_631 image 20

The NyzoScriptStateContentType enumeration allows specification of either binary or JSON state data within a NyzoScriptState.

RN_631 image 21

NyzoScriptStateTest ensures that serialization and deserialization of NyzoScriptState behave as expected.

RN_631 image 23

The testDeserialization() method defines 3 strings and their corresponding states. This includes one invalid state string that results in a null state.

RN_631 image 24

The parsed state and expected state are compared for equality with respect to nullity. If both are non-null, all properties are also compared.

RN_631 image 25

The testSerialization() method defines 2 states and their corresponding JSON representations.

RN_631 image 26

As the comment notes, knowledge of a custom renderer allows the string representation of the state to be precisely predictable. Both the rendered state and expected state are also parsed into JsonObject representations, and the properties of those representations are compared. At the moment, checking properties is totally unnecessary. While checking parseability with the Json class is useful, if the strings are character-for-character identical, they will certainly not possess different properties after parsing. However, this code might become useful in the future if the String comparison is no longer possible due to renderer changes.

RN_631 image 27

NyzoScriptStateTest was added to the test suite in TestUtil.

RN_631 image 28